<!--
SPDX-FileCopyrightText: 2025 Ilya Egorov <0x42005e1f@gmail.com>
SPDX-License-Identifier: CC-BY-4.0
-->

Changelog
=========

All notable changes to this project will be documented in this file.

The format is based on
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).

Commit messages are consistent with
[Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/).

[0.10.0] - 2025-11-04
---------------------

### Added

- `culsans.Queue.waiting` as the third `aiologic`-like property. Useful when
  you need to reliably obtain the total number of waiting ones.
- Timeout handling has been improved in line with the latest changes in
  `aiologic` (support for very large numbers, additional checking for `NaN`,
  use of the clock functions from `aiologic.lowlevel`). This is particularly
  relevant for `aiologic>=0.15.0`, which implements safe timeouts, but has
  almost no impact on older versions.
- The properties of `culsans.Queue` now return proxies instead of protocols for
  type checkers. This allows, for example, accessing the wrapped queue via the
  proxy attribute without type errors.
- The proxies are now represented in a readable format, which should make
  debugging a little easier.

### Changed

- The priority queues now use stricter bounds for the type variable: collection
  elements must be rich comparable (implement `__lt__()` or `__gt__()` method).
  This corresponds to recent changes in `typeshed` for the standard queues (see
  [python/typeshed#14418](https://github.com/python/typeshed/issues/14418)) and
  makes them safer.

### Fixed

- For the underlying lock, `aiologic.lowlevel._thread` was used, which has been
  declared deprecated in the latest version of `aiologic`.
- With green checkpoints enabled, the end time was recalculated for the timeout
  after rescheduling, which could lead to doubling the actual wait time
  (`0.9.0` regression).

[0.9.0] - 2025-07-16
--------------------

### Changed

- Checkpoint functions are now always called before queue operations are
  performed (previously they were called after). This ensures that all queue
  methods behave as expected on cancellations, but it may increase the number
  of explicit context switches.
- The build system has been changed from `setuptools` to `uv` + `hatch`. It
  keeps the same `pyproject.toml` format, but has better performance, better
  logging, and builds cleaner source distributions (without `setup.cfg`).
- The version identifier is now generated dynamically and includes the latest
  commit information for development versions, which simplifies bug reporting.
  It is also passed to archives generated by GitHub (via `.git_archival.txt`)
  and source distributions (via `PKG-INFO`).

### Fixed

- For asynchronous checkpoints, `aiologic.lowlevel.checkpoint()` was used,
  which has been declared deprecated in the latest version of `aiologic`.
- With checkpoints enabled (`trio` case by default), the get methods could lose
  items on cancellations, and for the put methods, it was impossible to
  determine whether the put was successful or not on the same cancellations
  (`0.2.1` regression).

[0.8.0] - 2025-01-19
--------------------

### Added

- Python 3.8 support. This makes the list of supported versions consistent with
  that of `aiologic`. Previously, the lowest supported version was 3.9.
- `culsans.MixedQueue` as a queue protocol that provides both types of blocking
  methods via prefixes. Can be used to generalize `culsans.Queue` and its
  derivatives by type checkers, as it does not include `janus.Queue`-specific
  and other foreign methods and properties/attributes.

### Changed

- Interfaces and type hints have been improved:
  + Now `aiologic>=0.13.0` is used (previously `>=0.12.0` was used), which
    provides type annotations. This removes mypy-specific type ignores.
  + All fields are annotated. A side effect is that the queue subclasses now
    define their own slot for storing data.
- The source code tree has been significantly changed for better IDEs support.
  The same applies to exports, which are now checker-friendly.

[0.7.1] - 2024-12-23
--------------------

### Fixed

- For `culsans.QueueShutDown` on Python below 3.13, backported exceptions were
  defined, but they caused name conflicts for type checkers. Now, all queue
  shutdown exceptions reference the same class (on Python below 3.13).

[0.7.0] - 2024-12-23
--------------------

### Added

- `culsans.QueueEmpty`, `culsans.QueueFull`, and `culsans.QueueShutDown` as
  exceptions compatible with any interface (they inherit both types). They are
  now also raised instead of specialized exceptions, allowing any type to be
  used in try-catch.
- The remaining non-blocking methods and both types of blocking methods to
  `culsans.Queue` via prefixes (`sync_` and `async_`). The main reason for this
  is to move the entire implementation from the proxy classes to the queue
  classes. However, they can also be used as a simpler, shorter style of
  working with queues (similar to `aiologic`, but with `sync_` instead of
  `green_`).
- `culsans.Queue.putting` and `culsans.Queue.getting` as `aiologic`-like
  properties. They can be used to obtain the number of waiting ones for a given
  operation type. But note, `culsans.Queue.getting` also includes the number of
  peekers.
- `culsans.Queue` now inherits from `culsans.BaseQueue` instead of `Generic`.
  This improves type safety and allows introspection at runtime.
- Direct access (without the `_` prefix) to the synchronization primitives
  used, to better mimic the `queue` module.

[0.6.0] - 2024-12-14
--------------------

### Changed

- The behavior of Janus-specific methods now corresponds to `janus>=2.0.0`
  (instead of `1.2.0`). The only change is that after calling
  `culsans.Queue.close()`, `*QueueShutDown` is now raised instead of
  `RuntimeError`.

[0.5.0] - 2024-12-14
--------------------

### Added

- `culsans.Queue.aclose()` method, which replicates the behavior of the
  same-named Janus method. This makes the interface compliant with the Janus
  API version 1.2.0 (instead of 1.1.0).

[0.4.0] - 2024-11-17
--------------------

### Added

- `peekable()` methods and related `culsans.Queue._peekable()` private method
  (for overriding). They simplify non-peekable subclass creation by providing a
  unified contract for how to deal with it from the user's side.
- `culsans.UnsupportedOperation` exception, which is raised when attempting to
  call any of the peek methods for a non-peekable queue.

[0.3.0] - 2024-11-08
--------------------

### Added

- `culsans.Queue.close()` and `culsans.Queue.wait_closed()` methods,
  `culsans.Queue.closed` property to implement compatibility with
  `janus>=1.1.0`. For the most part, they behave similarly to the originals
  (including the exception raised after closing), but semantically they are
  closer to the queue shutdown methods from Python 3.13. This differs from the
  `janus` behavior, but solves
  [aio-libs/janus#237](https://github.com/aio-libs/janus/issues/237).
- `peek()` and `peek_nowait()` methods, related `culsans.Queue._peek()` private
  method (for overriding), as a way to retrieve an item from a queue without
  removing it. In a sense, they implement partial compatibility with the
  `gevent` queues, but peek/front is also a well-known third type of queue
  operation.
- `clear()` method and related `culsans.Queue._clear()` private method (for
  overriding). Atomically clears the queue, ensuring that other threads do not
  affect the clearing process, and updates the `unfinished_tasks` property at
  the same time. Solves
  [aio-libs/janus#645](https://github.com/aio-libs/janus/issues/645).

[0.2.1] - 2024-11-04
--------------------

### Fixed

- Mixed use of both types of methods could lead to deadlocks (due to the use of
  a shared wait queue for the underlying lock). This could be considered
  expected behavior if it did not also affect non-blocking methods (due to the
  blocking use of the condition variables).

[0.2.0] - 2024-11-04
--------------------

### Added

- `culsans.Queue.maxsize` can now be changed dynamically at runtime (growing &
  shrinking). This allows for more complex logic to be implemented, whereby the
  maximum queue size is adjusted according to certain external conditions.
  Related:
  [python/cpython#54319](https://github.com/python/cpython/issues/54319).

### Changed

- The protocols, and therefore the proxies, no longer include the implicit
  `__dict__`, thereby preventing unknown attributes from being set. This makes
  them safer.

[0.1.0] - 2024-11-02
--------------------

### Added

- Janus-like mixed queues and all related API (excluding some Janus-specific
  methods that seem redundant on Python 3.13, in favor of new methods such as
  `shutdown()`). They use the same patterns as the `queue` module, but rely on
  the condition variables from `aiologic`. This makes them 4-8 times faster
  than `janus.Queue` in multi-threaded tests, simplifies usage, and expands the
  number of supported use cases (multiple event loops, `trio` support, etc.).

[0.10.0]: https://github.com/x42005e1f/culsans/compare/0.9.0...0.10.0
[0.9.0]: https://github.com/x42005e1f/culsans/compare/0.8.0...0.9.0
[0.8.0]: https://github.com/x42005e1f/culsans/compare/0.7.1...0.8.0
[0.7.1]: https://github.com/x42005e1f/culsans/compare/0.7.0...0.7.1
[0.7.0]: https://github.com/x42005e1f/culsans/compare/0.6.0...0.7.0
[0.6.0]: https://github.com/x42005e1f/culsans/compare/0.5.0...0.6.0
[0.5.0]: https://github.com/x42005e1f/culsans/compare/0.4.0...0.5.0
[0.4.0]: https://github.com/x42005e1f/culsans/compare/0.3.0...0.4.0
[0.3.0]: https://github.com/x42005e1f/culsans/compare/0.2.1...0.3.0
[0.2.1]: https://github.com/x42005e1f/culsans/compare/0.2.0...0.2.1
[0.2.0]: https://github.com/x42005e1f/culsans/compare/0.1.0...0.2.0
[0.1.0]: https://github.com/x42005e1f/culsans/releases/tag/0.1.0
