Visitar URL original
gh-128555: Add 'context' keyword parameter to Thread. by nascheme 路 Pull Request #128209 路 python/cpython 路 GitHub
Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Rename flag to thread_inherit_context.
  • Loading branch information
nascheme committed Feb 11, 2025
commit 09e72b8d76ec25b1b23477ff7b8beb4218ee26a4
7 changes: 4 additions & 3 deletions Doc/library/sys.rst
Original file line number Diff line number Diff line change
Expand Up @@ -598,8 +598,9 @@ always available. Unless explicitly noted otherwise, all variables are read-only
* - .. attribute:: flags.gil
- :option:`-X gil <-X>` and :envvar:`PYTHON_GIL`

* - .. attribute:: flags.inherit_context
- :option:`-X inherit_context <-X>` and :envvar:`PYTHON_INHERIT_CONTEXT`
* - .. attribute:: flags.thread_inherit_context
- :option:`-X thread_inherit_context <-X>` and
:envvar:`PYTHON_THREAD_INHERIT_CONTEXT`

.. versionchanged:: 3.2
Added ``quiet`` attribute for the new :option:`-q` flag.
Expand Down Expand Up @@ -631,7 +632,7 @@ always available. Unless explicitly noted otherwise, all variables are read-only
Added the ``gil`` attribute.

.. versionchanged:: 3.14
Added the ``inherit_context`` attribute.
Added the ``thread_inherit_context`` attribute.


.. data:: float_info
Expand Down
13 changes: 6 additions & 7 deletions Doc/library/threading.rst
Original file line number Diff line number Diff line change
Expand Up @@ -361,14 +361,13 @@ since it is impossible to detect the termination of alien threads.

*context* is the :class:`~contextvars.Context` value to use when starting
the thread. The default value is ``None`` which indicates that the
:data:`sys.flags.inherit_context` flag controls the behaviour. If
:data:`sys.flags.thread_inherit_context` flag controls the behaviour. If
the flag is true, threads will start with a copy of the context of the
caller of :meth:`~Thread.start`. If false, they will start with
an empty context. To explicitly start with an empty context,
pass a new instance of :class:`~contextvars.Context()`. To explicitly
start with a copy of the current context, pass the value from
:func:`~contextvars.copy_context`. The flag defaults true on
free-threaded builds and false otherwise.
caller of :meth:`~Thread.start`. If false, they will start with an empty
context. To explicitly start with an empty context, pass a new instance of
:class:`~contextvars.Context()`. To explicitly start with a copy of the
current context, pass the value from :func:`~contextvars.copy_context`. The
flag defaults true on free-threaded builds and false otherwise.

If the subclass overrides the constructor, it must make sure to invoke the
base class constructor (``Thread.__init__()``) before doing anything else to
Expand Down
8 changes: 4 additions & 4 deletions Doc/using/cmdline.rst
Original file line number Diff line number Diff line change
Expand Up @@ -628,12 +628,12 @@ Miscellaneous options

.. versionadded:: 3.13

* :samp:`-X inherit_context={0,1}` causes :class:`~threading.Thread`
* :samp:`-X thread_inherit_context={0,1}` causes :class:`~threading.Thread`
to, by default, use a copy of context of of the caller of
``Thread.start()`` when starting. Otherwise, threads will start
with an empty context. If unset, the value of this option defaults
to ``1`` on free-threaded builds and to ``0`` otherwise. See also
:envvar:`PYTHON_INHERIT_CONTEXT`.
:envvar:`PYTHON_THREAD_INHERIT_CONTEXT`.

.. versionadded:: 3.14

Expand Down Expand Up @@ -1230,13 +1230,13 @@ conflict.

.. versionadded:: 3.13

.. envvar:: PYTHON_INHERIT_CONTEXT
.. envvar:: PYTHON_THREAD_INHERIT_CONTEXT

If this variable is set to ``1`` then :class:`~threading.Thread` will,
by default, use a copy of context of of the caller of ``Thread.start()``
when starting. Otherwise, new threads will start with an empty context.
If unset, this variable defaults to ``1`` on free-threaded builds and to
``0`` otherwise. See also :option:`-X inherit_context<-X>`.
``0`` otherwise. See also :option:`-X thread_inherit_context<-X>`.

.. versionadded:: 3.14

Expand Down
2 changes: 1 addition & 1 deletion Include/cpython/initconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ typedef struct PyConfig {
int use_frozen_modules;
int safe_path;
int int_max_str_digits;
int inherit_context;
int thread_inherit_context;
#ifdef __APPLE__
int use_system_logger;
#endif
Expand Down
6 changes: 3 additions & 3 deletions Lib/test/test_capi/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def test_config_get(self):
("filesystem_errors", str, None),
("hash_seed", int, None),
("home", str | None, None),
("inherit_context", int, None),
("thread_inherit_context", int, None),
("import_time", bool, None),
("inspect", bool, None),
("install_signal_handlers", bool, None),
Expand Down Expand Up @@ -171,7 +171,7 @@ def test_config_get_sys_flags(self):
("warn_default_encoding", "warn_default_encoding", False),
("safe_path", "safe_path", False),
("int_max_str_digits", "int_max_str_digits", False),
# "gil" and "inherit_context" are tested below
# "gil" and "thread_inherit_context" are tested below
):
with self.subTest(flag=flag, name=name, negate=negate):
value = config_get(name)
Expand All @@ -189,7 +189,7 @@ def test_config_get_sys_flags(self):
self.assertEqual(sys.flags.gil, expected)

expected_inherit_context = 1 if support.Py_GIL_DISABLED else 0
self.assertEqual(sys.flags.inherit_context, expected_inherit_context)
self.assertEqual(sys.flags.thread_inherit_context, expected_inherit_context)

def test_config_get_non_existent(self):
# Test PyConfig_Get() on non-existent option name
Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -392,14 +392,14 @@ def test_context_thread_inherit(self):
cvar = contextvars.ContextVar('cvar')

def run_context_none():
if sys.flags.inherit_context:
if sys.flags.thread_inherit_context:
expected = 1
else:
expected = None
self.assertEqual(cvar.get(None), expected)

# By default, context is inherited based on the
# sys.flags.inherit_context option.
# sys.flags.thread_inherit_context option.
cvar.set(1)
thread = threading.Thread(target=run_context_none)
thread.start()
Expand Down
6 changes: 3 additions & 3 deletions Lib/test/test_embed.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@
f'{VERSION_MINOR}{ABI_THREAD}/lib-dynload')

if support.Py_GIL_DISABLED:
DEFAULT_INHERIT_CONTEXT = 1
DEFAULT_THREAD_INHERIT_CONTEXT = 1
else:
DEFAULT_INHERIT_CONTEXT = 0
DEFAULT_THREAD_INHERIT_CONTEXT = 0

# If we are running from a build dir, but the stdlib has been installed,
# some tests need to expect different results.
Expand Down Expand Up @@ -590,7 +590,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'tracemalloc': 0,
'perf_profiling': 0,
'import_time': False,
'inherit_context': DEFAULT_INHERIT_CONTEXT,
'thread_inherit_context': DEFAULT_THREAD_INHERIT_CONTEXT,
'code_debug_ranges': True,
'show_ref_count': False,
'dump_refs': False,
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_sys.py
Original file line number Diff line number Diff line change
Expand Up @@ -1845,7 +1845,7 @@ def test_pythontypes(self):
# symtable entry
# XXX
# sys.flags
# FIXME: The +2 is for the 'gil' and 'inherit_context' flags and
# FIXME: The +2 is for the 'gil' and 'thread_inherit_context' flags and
# will not be necessary once gh-122575 is fixed
check(sys.flags, vsize('') + self.P * (2 + len(sys.flags)))

Expand Down
10 changes: 5 additions & 5 deletions Lib/threading.py
Original file line number Diff line number Diff line change
Expand Up @@ -891,11 +891,11 @@ class is implemented.

*context* is the contextvars.Context value to use for the thread.
The default value is None, which means to check
sys.flags.inherit_context. If that flag is true, use a copy of
the context of the caller. If false, use an empty context. To
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().
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
Expand Down Expand Up @@ -985,7 +985,7 @@ def start(self):

if self._context is None:
# No context provided
if _sys.flags.inherit_context:
if _sys.flags.thread_inherit_context:
# start with a copy of the context of the caller
self._context = _contextvars.copy_context()
else:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
Add the :data:`sys.flags.inherit_context` flag.
Add the :data:`sys.flags.thread_inherit_context` flag.

* This flag is set to true by default on the free-threaded build
and false otherwise. If the flag is true, starting a new thread using
:class:`threading.Thread` will, by default, use a copy of the
:class:`contextvars.Context` from the caller of
:meth:`threading.Thread.start` rather than using an empty context.

* Add the :option:`-X inherit_context <-X>` command-line option and
:envvar:`PYTHON_INHERIT_CONTEXT` environment variable, which set the
:data:`~sys.flags.inherit_context` flag.
* Add the :option:`-X thread_inherit_context <-X>` command-line option and
:envvar:`PYTHON_THREAD_INHERIT_CONTEXT` environment variable, which set the
:data:`~sys.flags.thread_inherit_context` flag.

* Add the ``context`` keyword parameter to :class:`~threading.Thread`. It can
be used to explicitly pass a context value to be used by a new thread.
Expand Down
40 changes: 21 additions & 19 deletions Python/initconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ static const PyConfigSpec PYCONFIG_SPEC[] = {
SPEC(filesystem_errors, WSTR, READ_ONLY, NO_SYS),
SPEC(hash_seed, ULONG, READ_ONLY, NO_SYS),
SPEC(home, WSTR_OPT, READ_ONLY, NO_SYS),
SPEC(inherit_context, INT, READ_ONLY, NO_SYS),
SPEC(thread_inherit_context, INT, READ_ONLY, NO_SYS),
SPEC(import_time, BOOL, READ_ONLY, NO_SYS),
SPEC(install_signal_handlers, BOOL, READ_ONLY, NO_SYS),
SPEC(isolated, BOOL, READ_ONLY, NO_SYS), // sys.flags.isolated
Expand Down Expand Up @@ -303,9 +303,6 @@ The following implementation-specific options are available:\n\
-X importtime: show how long each import takes; also PYTHONPROFILEIMPORTTIME\n\
-X int_max_str_digits=N: limit the size of int<->str conversions;\n\
0 disables the limit; also PYTHONINTMAXSTRDIGITS\n\
-X inherit_context=[0|1]: enable (1) or disable (0) threads inheriting context\n\
vars by default; enabled by default in the free-threaded build and\n\
disabled otherwise; also PYTHON_INHERIT_CONTEXT\n\
-X no_debug_ranges: don't include extra location information in code objects;\n\
also PYTHONNODEBUGRANGES\n\
-X perf: support the Linux \"perf\" profiler; also PYTHONPERFSUPPORT=1\n\
Expand All @@ -329,6 +326,9 @@ The following implementation-specific options are available:\n\
PYTHON_TLBC\n"
#endif
"\
-X thread_inherit_context=[0|1]: enable (1) or disable (0) threads inheriting\n\
context vars by default; enabled by default in the free-threaded\n\
build and disabled otherwise; also PYTHON_THREAD_INHERIT_CONTEXT\n\
-X tracemalloc[=N]: trace Python memory allocations; N sets a traceback limit\n \
of N frames (default: 1); also PYTHONTRACEMALLOC=N\n\
-X utf8[=0|1]: enable (1) or disable (0) UTF-8 mode; also PYTHONUTF8\n\
Expand Down Expand Up @@ -416,6 +416,8 @@ static const char usage_envvars[] =
#ifdef Py_GIL_DISABLED
"PYTHON_TLBC : when set to 0, disables thread-local bytecode (-X tlbc)\n"
#endif
"PYTHON_THREAD_INHERIT_CONTEXT: threads inherit context vars if 1\n"
" (-X thread_inherit_context)\n"
"PYTHONTRACEMALLOC: trace Python memory allocations (-X tracemalloc)\n"
"PYTHONUNBUFFERED: disable stdout/stderr buffering (-u)\n"
"PYTHONUTF8 : control the UTF-8 mode (-X utf8)\n"
Expand Down Expand Up @@ -891,7 +893,7 @@ config_check_consistency(const PyConfig *config)
assert(config->cpu_count != 0);
// config->use_frozen_modules is initialized later
// by _PyConfig_InitImportConfig().
assert(config->inherit_context >= 0);
assert(config->thread_inherit_context >= 0);
#ifdef __APPLE__
assert(config->use_system_logger >= 0);
#endif
Expand Down Expand Up @@ -998,9 +1000,9 @@ _PyConfig_InitCompatConfig(PyConfig *config)
config->code_debug_ranges = 1;
config->cpu_count = -1;
#ifdef Py_GIL_DISABLED
config->inherit_context = 1;
config->thread_inherit_context = 1;
#else
config->inherit_context = 0;
config->thread_inherit_context = 0;
#endif
#ifdef __APPLE__
config->use_system_logger = 0;
Expand Down Expand Up @@ -1035,9 +1037,9 @@ config_init_defaults(PyConfig *config)
config->legacy_windows_stdio = 0;
#endif
#ifdef Py_GIL_DISABLED
config->inherit_context = 1;
config->thread_inherit_context = 1;
#else
config->inherit_context = 0;
config->thread_inherit_context = 0;
#endif
#ifdef __APPLE__
config->use_system_logger = 0;
Expand Down Expand Up @@ -1074,9 +1076,9 @@ PyConfig_InitIsolatedConfig(PyConfig *config)
config->safe_path = 1;
config->pathconfig_warnings = 0;
#ifdef Py_GIL_DISABLED
config->inherit_context = 1;
config->thread_inherit_context = 1;
#else
config->inherit_context = 0;
config->thread_inherit_context = 0;
#endif
#ifdef MS_WINDOWS
config->legacy_windows_stdio = 0;
Expand Down Expand Up @@ -1908,27 +1910,27 @@ config_init_cpu_count(PyConfig *config)
}

static PyStatus
config_init_inherit_context(PyConfig *config)
config_init_thread_inherit_context(PyConfig *config)
{
const char *env = config_get_env(config, "PYTHON_INHERIT_CONTEXT");
const char *env = config_get_env(config, "PYTHON_THREAD_INHERIT_CONTEXT");
if (env) {
int enabled;
if (_Py_str_to_int(env, &enabled) < 0 || (enabled < 0) || (enabled > 1)) {
return _PyStatus_ERR(
"PYTHON_INHERIT_CONTEXT=N: N is missing or invalid");
"PYTHON_THREAD_INHERIT_CONTEXT=N: N is missing or invalid");
}
config->inherit_context = enabled;
config->thread_inherit_context = enabled;
}

const wchar_t *xoption = config_get_xoption(config, L"inherit_context");
const wchar_t *xoption = config_get_xoption(config, L"thread_inherit_context");
if (xoption) {
int enabled;
const wchar_t *sep = wcschr(xoption, L'=');
if (!sep || (config_wstr_to_int(sep + 1, &enabled) < 0) || (enabled < 0) || (enabled > 1)) {
return _PyStatus_ERR(
"-X inherit_context=n: n is missing or invalid");
"-X thread_inherit_context=n: n is missing or invalid");
}
config->inherit_context = enabled;
config->thread_inherit_context = enabled;
}
return _PyStatus_OK();
}
Expand Down Expand Up @@ -2212,7 +2214,7 @@ config_read_complex_options(PyConfig *config)
}
#endif

status = config_init_inherit_context(config);
status = config_init_thread_inherit_context(config);
if (_PyStatus_EXCEPTION(status)) {
return status;
}
Expand Down
4 changes: 2 additions & 2 deletions Python/sysmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -3141,7 +3141,7 @@ static PyStructSequence_Field flags_fields[] = {
{"safe_path", "-P"},
{"int_max_str_digits", "-X int_max_str_digits"},
{"gil", "-X gil"},
{"inherit_context", "-X inherit_context"},
{"thread_inherit_context", "-X thread_inherit_context"},
{0}
};

Expand Down Expand Up @@ -3245,7 +3245,7 @@ set_flags_from_config(PyInterpreterState *interp, PyObject *flags)
#else
SetFlagObj(PyLong_FromLong(1));
#endif
SetFlag(config->inherit_context);
SetFlag(config->thread_inherit_context);
#undef SetFlagObj
#undef SetFlag
return 0;
Expand Down