aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Lib/threading.py
diff options
context:
space:
mode:
authorNeil Schemenauer <nas-github@arctrix.com>2025-04-09 16:18:54 -0700
committerGitHub <noreply@github.com>2025-04-09 16:18:54 -0700
commitd687900f98114bb5910daad9553ae381d7daf94b (patch)
tree6f7c31164aa867d1bbf8c82f5eeb4cb9129dd3b0 /Lib/threading.py
parente5237541a098e32a70fc621dee08721a72be7eb8 (diff)
downloadcpython-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.py24
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: