Summary
Make the Promise state-read contract safe for free-threaded CPython, or explicitly define free-threaded Python as unsupported.
Promise currently writes result data before it advances _state. Methods such as done(), result(), exception(), cancelled(), intermediate_promise(), and unpacked_once() read these fields without synchronization.
Rationale
The current design is correct for CPython builds with the GIL. A reader can observe a stale earlier state, which is benign.
Free-threaded CPython does not provide the same GIL-based ordering assumption. A reader could observe a terminal _state before it observes the associated _result, _exception, or _intermediate_promise write. For example, Promise.result() could pass _assert_done() and then see _result is UNCHANGED.
This is not a current production bug for the supported GIL-based runtime. It is future compatibility work.
Affected area
promising/promise.py
- State writers:
_set_intermediate_promise_from_loop(), _set_result_from_loop(), _set_exception_from_loop(), _set_state()
- State readers:
done(), result(), exception(), cancelled(), intermediate_promise(), unpacked_once(), and unpacked_once_or_done()
Required changes
- Decide whether free-threaded CPython is a supported runtime.
- If it is supported, add synchronization that establishes ordering between data writes and
_state transitions.
- If it is not supported, document this runtime limitation in the package support policy and keep the existing GIL-based contract explicit.
- Add tests that cover the selected contract where practical.
Acceptance criteria
- The project documents whether free-threaded CPython is supported.
- If supported, state readers cannot observe a terminal state without its matching result, exception, or intermediate value.
- The implementation and tests preserve the existing behavior on GIL-based CPython.
Backlinks
Summary
Make the
Promisestate-read contract safe for free-threaded CPython, or explicitly define free-threaded Python as unsupported.Promisecurrently writes result data before it advances_state. Methods such asdone(),result(),exception(),cancelled(),intermediate_promise(), andunpacked_once()read these fields without synchronization.Rationale
The current design is correct for CPython builds with the GIL. A reader can observe a stale earlier state, which is benign.
Free-threaded CPython does not provide the same GIL-based ordering assumption. A reader could observe a terminal
_statebefore it observes the associated_result,_exception, or_intermediate_promisewrite. For example,Promise.result()could pass_assert_done()and then see_result is UNCHANGED.This is not a current production bug for the supported GIL-based runtime. It is future compatibility work.
Affected area
promising/promise.py_set_intermediate_promise_from_loop(),_set_result_from_loop(),_set_exception_from_loop(),_set_state()done(),result(),exception(),cancelled(),intermediate_promise(),unpacked_once(), andunpacked_once_or_done()Required changes
_statetransitions.Acceptance criteria
Backlinks
Promise- stop extending it fromasyncio.Future#102: RefactorPromise- stop extending it fromasyncio.Future#102Promise- stop extending it fromasyncio.Future#102 (comment)