Repository navigation
Release 1.1.1: document how thread nesting differs by Python build - #24
Merged
Merged
Conversation
On free-threaded Python 3.14 a new thread starts in a copy of the context that started it. A thread pool starts workers lazily and reuses them, so each worker keeps the section it started under, and work submitted later from another section is reported under the first one. Regular builds report the same work at the top level. The concurrency guide said pool work is always top-level (a comment the docs test never asserted, and false on 3.14t) and that free-threaded builds nest thread work with no extra work. It now explains the difference and shows how to get the same report on every build: run each call in copy_context().run to nest it, or Context().run to keep it top-level. Both examples assert their results. New tests pin how plain threads and reused pool workers nest on each kind of build, and check both recipes. The library can't fix this itself: it can't tell an intentionally inherited context from a stale one. Behaviour is unchanged. Bump __version__ to 1.1.1 and update the bug template's placeholder.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this change?
The bug. On free-threaded Python 3.14 (3.14t), a new thread starts in a copy of the context that started it.
ThreadPoolExecutorstarts its workers lazily and reuses them, so each worker keeps the section it started under for as long as it lives. Work submitted later from a different section gets reported under the first one:Why only docs and tests. The library can't tell a context a thread was meant to inherit from a stale one, so it can't fix this itself. What was wrong was the guide. It said pool work is always recorded at the top level, in a comment the docs test never asserted and that is false on 3.14t. It also said free-threaded builds nest thread work "without extra work", which is only true for a brand-new plain thread.
Docs (
docs/guide/concurrency.md, Threads section):-X thread_inherit_context/sys.flags.thread_inherit_context.pool.submit(contextvars.copy_context().run, fn, ...)to nest under the current section, andcontextvars.Context().runto keep work at the top level. Both examples assert their results, and the pool is reused across two sections to show the first recipe copes with reuse.pool.map: a context can't be entered by two threads at once.Tests (4 new ones in
TestThreading): how a plain thread nests and how a reused pool worker nests, each pinned per build viasys.flags.thread_inherit_context, plus both recipes checked with no branching on the build.Release: bumps
__version__to 1.1.1, adds the[1.1.1]changelog section under### Documentation, and updates the bug template's version placeholder. There's no API or behaviour change, so this is a patch release.Checklist
uv run pytest --covpasses (124 tests, 100% statement and branch coverage). It also passes locally on 3.11, 3.12, 3.13, 3.14 and 3.14t, and the thread tests pass on 3.14 with-X thread_inherit_context=1and on 3.14t with=0, so both expectations are exercised on both builds.uv run ruff checkanduv run ruff format --checkpassuv run basedpyrightpasses (0 errors, 0 warnings)CHANGELOG.mdupdateduv lock --check,uv buildandtwine check --strictpass, and the wheel is 1.1.1.-W -n.