Releases: kristjanvalur/py-asynkit
Releases · kristjanvalur/py-asynkit
v0.17.6
Features
- CoroStart autostart parameter: Added
autostartparameter toCoroStart.__init__()- When
autostart=False, coroutine is not started automatically on construction - Allows creating
CoroStartobject before callingstart()explicitly - Useful for advanced use cases requiring precise control over coroutine startup timing
- Default behavior unchanged (
autostart=True)
- When
Tests
- asyncio.wait_for() compatibility: Added comprehensive tests for
asyncio.wait_for()with eager executiontest_wait_for: Tests timeout and fast completion scenariostest_wait_for_zero_timeout: Tests edge case of zero timeout- Validates that
asyncio.wait_for()works correctly with eager task factory
Documentation
- asyncio.timeout() workarounds: Added
asyncio.wait_for()as recommended workaround- Listed as the recommended alternative to
asyncio.timeout()for eager execution - Works correctly without requiring additional
await asyncio.sleep(0)calls - Updated workarounds section in README.md
- Listed as the recommended alternative to
v0.17.5
Breaking Changes
- API Rename:
create_eager_factory()renamed tocreate_eager_task_factory()to match Python 3.12 API- Signature updated:
custom_task_constructorparameter (required) instead ofinner_factory(optional) - Now matches
asyncio.create_eager_task_factory()signature from Python 3.12+ - Pre-created
eager_task_factoryinstance unchanged - Added to compatibility layer:
asyncio.create_eager_task_factoryavailable on Python < 3.12 viaasynkit.compat.enable_eager_tasks()
- Signature updated:
Bug Fixes
- Eager Execution Loop Mismatch: Fixed eager execution when running event loop doesn't match task's loop
- When the running event loop does not match the one for which the task is created, eager execution should not be attempted
- This includes during creation of the initial task for the loop (before the loop is marked as "running")
- Previously, eager execution during task factory time would fail with "RuntimeError: no running event loop"
- Now correctly detects loop mismatch and falls back to standard task creation
- Added regression tests demonstrating the fix with both
run_until_complete()andasyncio.run()patterns - Note: Python 3.12+ native
asyncio.create_eager_task_factory()already handles this correctly
v0.17.3
Performance Improvements
- Eager Task Factory Micro-optimization: Improved hot path performance in task creation
- Moved
kwargs.pop("eager_start", None)from factory entry to inner delegation path - Eliminates unnecessary dictionary operations for synchronous eager completions
- Only processes
eager_startparameter when actually creating Task objects - Reduces overhead in the common case where coroutines complete immediately
- Moved
Testing
- Cross-version Compatibility: Enhanced benchmark compatibility for older Python versions
- Added
hasattr(asyncio, 'eager_task_factory')version checking in performance tests - Graceful degradation when Python 3.12+ eager features are unavailable
- Maintained full testing coverage across Python 3.10-3.14
- Added
v0.17.2
Build System
- Free-threaded Python Support: Added support for Python 3.13+ free-threaded builds
- C extension declares
Py_MOD_GIL_NOT_USEDfor GIL-free operation - Enhanced CI workflows with free-threaded Python targets (
cp313t-*,cp314t-*) - Proper GIL status detection and testing in CI environments
- C extension declares
Internal Improvements
-
Per-module State Architecture: Modernized C extension for multi-interpreter isolation
- Replaced global variables with per-module state storage
- Uses
PyType_FromModuleAndSpec()andPyType_GetModuleByDef()for Python 3.11+ - Version compatibility layer for Python 3.10 support
- Multi-phase initialization with proper garbage collection support
-
CI Enhancements: Improved wheel testing and validation
- Added functional assertions to replace print-based testing
- Enhanced error detection and reporting in build validation
v0.17.1
Performance Improvements
- GhostTaskHelper Optimization: Refactored ghost task management for better performance and maintainability
- Simplified from instance-based to static class design with per-loop task storage
- Eliminated complex WeakKeyDictionary-based instance management
- Reduced object creation overhead and lookup complexity
- Streamlined eager task factory implementation with fewer parameter passing layers
- More efficient memory usage with single ghost task per event loop
Code Modernization
- Python 3.12+ Exception Semantics: Added support for modern exception handling APIs
- Implemented
NEW_EXCmacro for conditional compilation based on Python version - Uses
PyErr_GetRaisedException()/PyErr_SetRaisedException()on Python 3.12+ - Maintains backward compatibility with
PyErr_Fetch()/PyErr_Restore()on older versions - All 568 tests pass with new exception semantics
- Implemented
Testing and Quality Assurance
-
Enhanced Performance Benchmarking: Improved accuracy and reliability of performance measurements
- Fixed
eager_startparameter detection using runtime testing instead of version assumptions - Added 2σ outlier filtering for more accurate statistical analysis
- Corrected min/max statistical aggregation to use actual minimum/maximum values across runs
- Enhanced reporting with comprehensive performance analysis and proper error handling
- Added robust Python 3.14+ compatibility detection for native eager execution features
- Fixed
-
Compiler Warning Resolution: Achieved clean compilation with strict warning flags
- Enabled comprehensive warning detection:
-Wall -Wextra -Wstrict-prototypes - Clean compilation under both debug and optimized build configurations
- Enabled comprehensive warning detection:
Documentation
- Updated API Documentation: Corrected misleading claims about
eager_startparameter availability- Removed incorrect references to
eager_start=Trueparameter in older Python versions - Clarified actual functionality vs Python 3.12+ native eager execution features
- Updated docstrings to reflect simplified implementation approach
- Removed incorrect references to
v0.17.0
Performance Improvements
-
Ghost Task Pattern for Eager Execution: Replaced wrapper task approach with high-performance ghost task pattern
- Achieved 5x latency improvement: 1.5μs vs 7.8μs (wrapper task approach)
- Only 7% overhead vs baseline (1.5μs vs 1.4μs pre-wrapper baseline)
- Reusable ghost task provides task context during eager execution without creating wrapper tasks
- C extension performance: 1.03μs mean latency in optimal path
- Trade-off: Performance improvement comes at cost of strict
current_task()compatibility- Before first blocking call: returns parent task or ghost task (not the actual task)
- After first blocking call: returns actual task as expected
- Maintains compatibility with framework detection libraries (anyio, sniffio) which only need a valid task
- See docs/eager_tasks.md for details
-
C Extension Optimization: Implemented
tp_iternextfast path for CoroStartWrapper- Uses
call_iter_next()helper to accesstp_iternextslot when available, falling back to method lookup for better performance - This is the path used by Python's event loop for regular
awaitoperations - Added
call_iter_next()helper function for direct slot access - Optimized
StopIteration(None)case by returning NULL without setting exception (tp_iternext protocol optimization) - Restructured and cleaned up C extension code for better maintainability
- Reduces overhead in the critical path of coroutine execution
- Uses
Documentation
- Eager Task Behavior Documentation: Added comprehensive documentation of
current_task()behavior- Created detailed section in
docs/eager_tasks.mdexplaining ghost task pattern - Documents when ghost task vs parent task is returned
- Explains framework compatibility (anyio, sniffio)
- Provides code examples showing affected vs robust patterns
- Compares with Python 3.12+ native eager task behavior
- README.md updated with brief references linking to detailed documentation
- Updated feature list to distinguish global (
eager_task_factory) vs selective (@eager) eager execution
- Created detailed section in
v0.16.4
Bug Fixes
- C Extension Exception handling: Added a missing exception test case.
Code Quality
- Build Configuration Simplification: Streamlined DEBUG/NDEBUG macro usage to follow standard C conventions
- Removed custom
DEBUGmacro in favor of standardNDEBUGmacro - Removed
-DDEBUGcompiler flag fromsetup.py - Debug builds now use
-UNDEBUGto undefine NDEBUG (enables assertions) - Optimized builds use
-DNDEBUGto define NDEBUG (disables assertions) - Simplified
get_build_info()to return onlybuild_typefield ("debug" or "optimized") - Updated
fast_build.shscript to match simplified API
- Removed custom
API Improvements
- Implementation Info Consistency: Fixed
get_implementation_info()to return consistent dictionary structure- Pure Python fallback now includes empty
build_infodict for API consistency - Both C extension and pure Python branches now return same dictionary keys
- Enables safer code that can check
if info['build_info']:without key errors
- Pure Python fallback now includes empty
v0.16.3
Code Quality
- C Extension Improvements: Refactored
corostart.cfor improved maintainability- Added module-level documentation explaining performance optimization approach
- Reorganized forward declarations for better code structure
- Added
get_build_info()function to expose build configuration (debug/optimized mode) - Extracted
extract_stopiteration_value()helper function for better code reuse - Improved memory safety with proper exception handling
- No functional changes - purely internal cleanup and documentation
Developer Tools
- Build Script Consolidation: Unified fast build scripts into canonical location
- Moved
fast_build.shfrom root toscripts/directory - Enhanced script with simplified testing using
get_build_info() - Added
ASYNKIT_FORCE_CEXT=1flag for stricter builds - Removed duplicate and stray test files from repository
- Moved
v0.16.2
Packaging Fix
- Binary Wheel Fix: Fixed wheel packaging to exclude C extension source directory
- Added
exclude = ["asynkit._cext"]to[tool.setuptools.packages.find]to exclude source package - Added
[tool.setuptools.exclude-package-data]with"*" = ["_cext/*"]to exclude source files - Binary wheels now contain only the compiled extension module (
.so/.pyd), not the source directory - Fixes issue with Bazel's
rules_pythonwhich automatically creates__init__.pyin directories - Python's import system was resolving
_cextas an empty package instead of the compiled module - Resolves 4-5x performance degradation when C extension fails to load
- Source distributions (sdist) still correctly include the
_cext/directory for building
- Added
v0.16.1
Build System
- Removed Universal Wheel: No longer publishing universal (
py3-none-any) wheel to PyPI- Only platform-specific wheels (with C extension) and source distribution are now published
- Prevents package managers from incorrectly selecting the pure Python fallback wheel
- Ensures users get optimal performance with C extension by default
- Follows best practice of projects like PyYAML and MarkupSafe
- Source distribution still available for platforms without pre-built wheels