start_server()now accepts an optionalrunnerargument (default:asyncio.run) to allow using custom coroutine runner implementations such asuvloop.run, for forward compatibility with Python 3.16 and later (#99)
- Use thread-local storage to store per-task states and avoid lock contention in free-threaded builds (#96)
- Replace
lru_cache()with theaio-libs/async_lrupackage while preserving backward-compatibility of the API and improving typing support (#97)
- Use weak key dict to prevent memroy leak when storing task states by task scopes (#95)
- Treat explicitly uncancelled termination as a non-error in
cancel_and_wait()(#92) - Ensure consistency when nesting and mixing
aiotools.TaskScopeandasyncio.TaskGroupwith different shield options and reimplementShieldScopebased on the improvedTaskScope(#93)
- Add
shieldandtimeoutoptions toTaskScope, with a shortcutmove_on_after()context manager, based on a newShieldScope, while extendingcancel_and_wait()to accept multiple awaitables (#90) - Support Python 3.14 including
TaskScopeintegration with asyncio's new call-graph inspection, updated signature of allowing arbitrary kwargs increate_task(), and improved support for the new default "forkserver" start method of multiprocessing inafork()andstart_server()(#91)
A post-release to fix typo in docs and packaging configurations without any functional changes.
- Now it requires Python 3.11 or later to ensure safety and structured concurrency (#53)
- Cancelling and awaiting a timer task returned by
create_timer()now raisesasyncio.CancelledErrorto keep consistency with the best practice for writing asyncio tasks. You now should usecancel_and_wait()to safely consume or re-raise it. (#86) - Migrate the project's dependency manager to uv (#87)
- Add
TaskContextandTaskScopeto reuse the core concepts and logics for structured concurrency inSupervisor, a structured cancellation helpercancel_and_wait(), and other coroutine aggregation utilities likeas_completed_safe(),gather_safe(), andrace(). (#58) - Make the entire package type-annotated (#89)
- Add higher-level coroutine aggregation utilities:
as_completed_safe(),gather_safe(), andrace()based on a modified version of @DontPanicO'sSupervisorimplementation (#53) - Add
aiotools.context.resetting()as a sync/async context manager to auto-reset the given context variable (#62) - Add type checker support - now includes py.typed in the package to indicate to type checkers like mypy that typing is supported. (#63)
- Add Python 3.12 support (#64)
- Add Python 3.13 compatibility (#71)
- Replace manual
os.fork()withmultiprocessingto use platform-specific recommended subprocess mechanisms (e.g., "spawn" in macOS to avoid undefined behavior of native frameworks) (#79) - Explicitly override
loop._clock_resolutionwith a coarse-grained value to prevent getting stuck when using VirtualClock with a realistic timestamp due to the floating point precision issue (#81) - Allow importing aiotools in the Windows CI by using Windows-specific type definitions while disabling fork/server tests (#84)
- Ensure the stop signal returned from the server context managers always have a valid value defaulting to SIGTERM (#85)
- Prevent timer tasks from being cancelled by unhandled tick task exceptions (#86)
- Correct the type annotation of the callback argument in
create_timer()(#61)
- PersistentTaskGroup no longer stores the history of unhandled exceptions and raises them as an exception group to prevent memory leaks (#54)
- Add
as_completed_safe()which enhancesasyncio.as_completed()usingPersistentTaskGroup(#52)
- Improve checks for pidfd availability to avoid corner cases that may fail on Linux kernel 5.1 and 5.2 where
signal.pidfd_send_signal()is available butos.pidfd_open()is not (#51)
- Explicitly attach the event loop to the
PidfdChildWatcherwhen first initialized (#50)
- Fix regression of the default imports in macOS by removing the unused code that caused the misleading fix in #47 (#49)
- Add the
closing_async()async context manager, in addition toaclosing()(#48)
- Allow importing aiotools on Windows platforms, removing incompatible modules from the default
__all__import list (#47)
- Add
wait_timeoutoption tostart_server()(#46)
- Resolve singal races by minimizing expose of event loop in
afork()-ed child processes (#46)
- Now the CI runs with Python 3.11a6 or later, with stdlib support of
asyncio.TaskGroup(#45)
- Propagate task results and exceptions via separate future instances if they are
await-ed by the caller ofcreate_task()inPersistentTaskGroup, in addition to invocation of task group exception handler. Note thatawait-ing those futures hangs indefinitely in Python 3.6 but we don't fix it since Python 3.6 is EoL as of December 2021. (#44)
- Fix feature detection for
ExceptionGroupand letMultiErrorinheritExceptionGroupinstead ofBaseExceptionGroup(#42)
- Restore the default export of
MultiErrorfor backward compatibility (#40) - Set
current_ptaskgrouponly whenPersistentTaskGroupis used via theasync withstatement. (#41)
- Fix missing naming support of
TaskGroupin Python 3.11 (#39)
- Add support for Python 3.9's
msgargument toTask.cancel(). (#32) - Fix "unexpected cancel" bug in
TaskGroup. (#35) - Rewrite PersistentTaskGroup to use Python 3.11's latest additions such as
Task.uncancel()andTask.cancelling()while still supporting older Python versions (#36) - Add
PersistentTaskGroup.all()to enumerate all non-terminated persistent task groups (#38)
- ptaskgroup: Implement
PersistentTaskGroup(#30) - server: Expose
process_indexcontext variable for worker processes (#31)
- Add support for Python 3.10. (#28)
- Fix documentation builds on Python 3.10 and Sphinx 4.x, by removing the 3rd-party autodoc-typehints extension and custom stylesheet overrides. (#28)
- fork: Handle children's segfault (core-dump with signals) explicitly in
PidfdChildProcess(#27)
- Avoid side effects of custom
clone()function and resorts back to the combinatino ofos.fork()andos.pidfd_open()for now (#25)
- server: The
use_threadingargument forstart_server()is completely deprecated. (#23)
- Now the primary target is Python 3.9, though we still support from Python 3.6 (#22)
- fork: Add a new module
forkto support PID file descriptors in Linux 5.4+ and a POSIX-compatible fallback to asynchornously fork the Python process without signal/PID races. (#22) - server: Completely rewrote the module using the new
forkmodule with handling of various edge cases such as async failures of sibiling child processes (#23)
- Fix a potential memory leak with
TaskGroupwhen it's used for long-lived asyncio tasks. (#21)
- Add a
current_taskgroupcontext-variable to the taskgroup module (only available for Python 3.7 or later)
- Fix missing auto-import of
taskgroupmodule exports in theaiotoolsroot package.
- Adopt an implementation of the taskgroup API as
aiotools.taskgroupfrom EdgeDB (#18) - Add
timer.VirtualClockwhich provides a virtual clock that makes a block of asyncio codes usingasyncio.sleep()to complete instantly and deterministically (#19)
- A maintenance release to fix up the
defermodule exports in theaiotoolsnamespace.
- defer: A new module that emulates Golang's
defer()API with asyncio awareness.
- server: Rewrite internals of the worker main functions to use native
async withinstead of manually unrolling__aenter__()and__aexit__()dunder methods, to keep the code simple and avoid potential bugs.
- Python 3.8 is now officially supported.
- server: Fix errors when
multiprocessing.set_start_method("spawn")is used.- NOTE: This is now the default for macOS since Python 3.8.
- KNOWN ISSUE: #12
- Remove some packaging hacks in
__init__.pyand let setuptools read the version from a separateaiotools/VERSIONtext file.
- context: Fix
aclosing()'s__aexit__()exception arguments.
- context, server: Catch asyncio.CancelledError along with BaseException to make the cancellation behavior consistent in Python 3.6, 3.7, and 3.8.
- server: Fix yields of the received stop signal in main/worker context managers when using threaded workers.
- server: Updated stop signal handling and now user-defined worker/main context managers have a way to distinguish the stop signal received. See the updated docs for more details.
- This ia a technical release to fix a test case preventing the automated CI release procedure.
- Improve support for Python 3.6/3.7 using a small compatibility module against asyncio.
- func: Add
expire_afteroption tolru_cache()function.
- Minor updates to the documentation
- Add support for Python 3.7
- context: Updated to work like Python 3.7
- context: Deprecated
AsyncContextDecoratorstuffs in Python 3.7+ - context: Added an alias to
contextlib.AsyncExitStackin the standard library.
- Introduce a new module
aiotools.iterwithaiter()function which corresponds to an async version of the builtiniter().
- server: Remove use of unncessary setpgrp syscall, which is also blocked by Docker's default seccomp profile!
- server: Ooops! (a finally block should have been an else block)
- server: Improve inner beauty (code readability)
- server: Improve reliability and portability of worker-to-main interrupts
- server: Fix a race condition related to handling of worker initialization errors with multiple workers
- func: Add
lru_cache()which is a coroutine version offunctools.lru_cache()
- server: Fix a race condition related to signal handling in the multiprocessing module during termination
- server: Improve error handling during initialization of workers (automatic shutdown of other workers and the main loop after logging the exception)
- Add a new module
aiotools.funcwithapartial()function which is an async version offunctools.partial()in the standard library
- Add
aclosing()context manager likeclosing()in the standard library - Speed up Travis CI builds for packaging
- Now provide README in rst as well as CHANGES (this file)
server: Fix spawning subprocesses in child workers- Add support for
uvloop
- Add
use_threadingargument to - Add initial documentation (which currently not served on readthedocs.io due to Python version problem)
- Add
extra_procsargument tostart_server()function - Add socket and ZeroMQ server examples
- Improve CI configs
- Improve CI scripts
- Adopt editorconfig
- Add
start_server()function using multiprocessing with automatic children lifecycle management - Clarify the semantics of
AsyncContextGroupusingasyncio.gather()withreturn_exceptions=True
- Add abstract types for
AsyncContextManager - Rename
AsyncGenContextManagertoAsyncContextManager - Add
AsyncContextGroup
- Initial release