diff options
author | Neil Schemenauer <nas-github@arctrix.com> | 2025-04-09 16:18:54 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-04-09 16:18:54 -0700 |
commit | d687900f98114bb5910daad9553ae381d7daf94b (patch) | |
tree | 6f7c31164aa867d1bbf8c82f5eeb4cb9129dd3b0 /Lib/threading.py | |
parent | e5237541a098e32a70fc621dee08721a72be7eb8 (diff) | |
download | cpython-d687900f98114bb5910daad9553ae381d7daf94b.tar.gz cpython-d687900f98114bb5910daad9553ae381d7daf94b.zip |
gh-128384: Use a context variable for warnings.catch_warnings (gh-130010)
Make `warnings.catch_warnings()` use a context variable for holding
the warning filtering state if the `sys.flags.context_aware_warnings`
flag is set to true. This makes using the context manager thread-safe in
multi-threaded programs.
Add the `sys.flags.thread_inherit_context` flag. If true, starting a new
thread with `threading.Thread` will use a copy of the context
from the caller of `Thread.start()`.
Both these flags are set to true by default for the free-threaded build
and false for the default build.
Move the Python implementation of warnings.py into _py_warnings.py.
Make _contextvars a builtin module.
Co-authored-by: Kumar Aditya <kumaraditya@python.org>
Diffstat (limited to 'Lib/threading.py')
-rw-r--r-- | Lib/threading.py | 24 |
1 files changed, 22 insertions, 2 deletions
diff --git a/Lib/threading.py b/Lib/threading.py index 0dc1d324c98..c4cc4dd2b00 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -3,6 +3,7 @@ import os as _os import sys as _sys import _thread +import _contextvars from time import monotonic as _time from _weakrefset import WeakSet @@ -876,7 +877,7 @@ class Thread: _initialized = False def __init__(self, group=None, target=None, name=None, - args=(), kwargs=None, *, daemon=None): + args=(), kwargs=None, *, daemon=None, context=None): """This constructor should always be called with keyword arguments. Arguments are: *group* should be None; reserved for future extension when a ThreadGroup @@ -893,6 +894,14 @@ class Thread: *kwargs* is a dictionary of keyword arguments for the target invocation. Defaults to {}. + *context* is the contextvars.Context value to use for the thread. + The default value is None, which means to check + sys.flags.thread_inherit_context. If that flag is true, use a copy + of the context of the caller. If false, use an empty context. To + explicitly start with an empty context, pass a new instance of + contextvars.Context(). To explicitly start with a copy of the current + context, pass the value from contextvars.copy_context(). + If a subclass overrides the constructor, it must make sure to invoke the base class constructor (Thread.__init__()) before doing anything else to the thread. @@ -922,6 +931,7 @@ class Thread: self._daemonic = daemon else: self._daemonic = current_thread().daemon + self._context = context self._ident = None if _HAVE_THREAD_NATIVE_ID: self._native_id = None @@ -977,6 +987,16 @@ class Thread: with _active_limbo_lock: _limbo[self] = self + + if self._context is None: + # No context provided + if _sys.flags.thread_inherit_context: + # start with a copy of the context of the caller + self._context = _contextvars.copy_context() + else: + # start with an empty context + self._context = _contextvars.Context() + try: # Start joinable thread _start_joinable_thread(self._bootstrap, handle=self._handle, @@ -1056,7 +1076,7 @@ class Thread: _sys.setprofile(_profile_hook) try: - self.run() + self._context.run(self.run) except: self._invoke_excepthook(self) finally: |