Release 0.9.1
π pyochain 0.9.1 β Release Notes
Date: 2026-01-15 π
π Highlights
This release is a critical bugfix and performance improvement release:
- CRITICAL FIX: Fixed a severe performance regression introduced in 0.7.0 where iterating over
Iterobjects fell back to slow__next__()calls instead of delegating to the underlying iterator. Up to 10x faster. - Rust Migration: Moved
try_findimplementation to Rust β Achieving +15-30% speedup across all use cases. - Code Quality: Various internal Rust code improvements for maintainability.
- Documentation: Fixes on API reference generation. Website is now live again.
π Critical Bug Fix
Iter Performance Regression
Issue: After migrating to abstract traits in 0.7.0, the Iter.__iter__() method was accidentally removed.
This caused Python to fall back to calling __next__() repeatedly when Iter objects were passed to functions expecting Iterator objects, resulting in dramatically slower performance.
Expected behavior: Iter wraps any iterable and converts it to an iterator by calling iter() on it, storing the result in self._inner. When Iter.__iter__() is called, it should directly return self._inner rather than self. This delegation is crucial because:
- It bypasses
Iter's Python-level__next__()implementation - The underlying iterator's native (often C-level)
__next__()is called instead - This allows maximum efficiency regardless of the original iterable type (list, tuple, generator, etc.)
Fix: Restored Iter.__iter__() to properly delegate to self._inner, restoring original performance characteristics. Also explicitly calls __iter__() in PyoIterator provided methods as additional safeguard.
Impact: Any code passing Iter objects to functions that iterate over them (e.g., list(iter_obj), tuple(iter_obj), func(iter_obj) where func iterates) will see performance return to expected levels.
π Performance Improvements
try_find Migration to Rust
Moved Iter.try_find() implementation from Python to Rust for better performance across all scenarios:
ββββββββββββ³ββββββββββββββββββββββββββββββ³βββββββββββββββββββ³βββββββββββββββββββββ³ββββββββββ
β Category β Operation β Rust (s, median) β Python (s, median) β Speedup β
β‘βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ©
β try_find β find_at_middle β 0.0067 β 0.0087 β 1.30x β
β try_find β find_at_end β 0.0132 β 0.0163 β 1.24x β
β try_find β find_not_found β 0.0148 β 0.0168 β 1.14x β
β try_find β find_error_late β 0.0143 β 0.0171 β 1.20x β
β try_find β find_with_complex_predicate β 0.0020 β 0.0025 β 1.23x β
ββββββββββββ΄ββββββββββββββββββββββββββββββ΄βββββββββββββββββββ΄βββββββββββββββββββββ΄ββββββββββ
Median speedup: 1.23x
Rust wins: 5/5
This act as a proof-of-concept for further migrations of iteration algorithms which are not calling Python itertools, builtins functions, or cytoolz functions (as those are already very efficient).