mirror of
https://github.com/python/cpython.git
synced 2025-08-31 14:07:50 +00:00
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>
This commit is contained in:
parent
e5237541a0
commit
d687900f98
41 changed files with 1851 additions and 960 deletions
|
@ -151,6 +151,8 @@ 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(thread_inherit_context, INT, READ_ONLY, NO_SYS),
|
||||
SPEC(context_aware_warnings, 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
|
||||
|
@ -339,6 +341,14 @@ 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 context_aware_warnings=[0|1]: if true (1) then the warnings module will\n\
|
||||
use a context variables; if false (0) then the warnings module will\n\
|
||||
use module globals, which is not concurrent-safe; set to true for\n\
|
||||
free-threaded builds and false otherwise; also\n\
|
||||
PYTHON_CONTEXT_AWARE_WARNINGS\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\
|
||||
|
@ -426,6 +436,10 @@ 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: if true (1), threads inherit context vars\n"
|
||||
" (-X thread_inherit_context)\n"
|
||||
"PYTHON_CONTEXT_AWARE_WARNINGS: if true (1), enable thread-safe warnings module\n"
|
||||
" behaviour (-X context_aware_warnings)\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"
|
||||
|
@ -923,6 +937,8 @@ config_check_consistency(const PyConfig *config)
|
|||
assert(config->cpu_count != 0);
|
||||
// config->use_frozen_modules is initialized later
|
||||
// by _PyConfig_InitImportConfig().
|
||||
assert(config->thread_inherit_context >= 0);
|
||||
assert(config->context_aware_warnings >= 0);
|
||||
#ifdef __APPLE__
|
||||
assert(config->use_system_logger >= 0);
|
||||
#endif
|
||||
|
@ -1029,6 +1045,13 @@ _PyConfig_InitCompatConfig(PyConfig *config)
|
|||
config->_is_python_build = 0;
|
||||
config->code_debug_ranges = 1;
|
||||
config->cpu_count = -1;
|
||||
#ifdef Py_GIL_DISABLED
|
||||
config->thread_inherit_context = 1;
|
||||
config->context_aware_warnings = 1;
|
||||
#else
|
||||
config->thread_inherit_context = 0;
|
||||
config->context_aware_warnings = 0;
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
config->use_system_logger = USE_SYSTEM_LOGGER_DEFAULT;
|
||||
#endif
|
||||
|
@ -1061,6 +1084,13 @@ config_init_defaults(PyConfig *config)
|
|||
#ifdef MS_WINDOWS
|
||||
config->legacy_windows_stdio = 0;
|
||||
#endif
|
||||
#ifdef Py_GIL_DISABLED
|
||||
config->thread_inherit_context = 1;
|
||||
config->context_aware_warnings = 1;
|
||||
#else
|
||||
config->thread_inherit_context = 0;
|
||||
config->context_aware_warnings = 0;
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
config->use_system_logger = USE_SYSTEM_LOGGER_DEFAULT;
|
||||
#endif
|
||||
|
@ -1095,6 +1125,11 @@ PyConfig_InitIsolatedConfig(PyConfig *config)
|
|||
config->int_max_str_digits = _PY_LONG_DEFAULT_MAX_STR_DIGITS;
|
||||
config->safe_path = 1;
|
||||
config->pathconfig_warnings = 0;
|
||||
#ifdef Py_GIL_DISABLED
|
||||
config->thread_inherit_context = 1;
|
||||
#else
|
||||
config->thread_inherit_context = 0;
|
||||
#endif
|
||||
#ifdef MS_WINDOWS
|
||||
config->legacy_windows_stdio = 0;
|
||||
#endif
|
||||
|
@ -1924,6 +1959,58 @@ error:
|
|||
"n must be greater than 0");
|
||||
}
|
||||
|
||||
static PyStatus
|
||||
config_init_thread_inherit_context(PyConfig *config)
|
||||
{
|
||||
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_THREAD_INHERIT_CONTEXT=N: N is missing or invalid");
|
||||
}
|
||||
config->thread_inherit_context = enabled;
|
||||
}
|
||||
|
||||
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 thread_inherit_context=n: n is missing or invalid");
|
||||
}
|
||||
config->thread_inherit_context = enabled;
|
||||
}
|
||||
return _PyStatus_OK();
|
||||
}
|
||||
|
||||
static PyStatus
|
||||
config_init_context_aware_warnings(PyConfig *config)
|
||||
{
|
||||
const char *env = config_get_env(config, "PYTHON_CONTEXT_AWARE_WARNINGS");
|
||||
if (env) {
|
||||
int enabled;
|
||||
if (_Py_str_to_int(env, &enabled) < 0 || (enabled < 0) || (enabled > 1)) {
|
||||
return _PyStatus_ERR(
|
||||
"PYTHON_CONTEXT_AWARE_WARNINGS=N: N is missing or invalid");
|
||||
}
|
||||
config->context_aware_warnings = enabled;
|
||||
}
|
||||
|
||||
const wchar_t *xoption = config_get_xoption(config, L"context_aware_warnings");
|
||||
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 context_aware_warnings=n: n is missing or invalid");
|
||||
}
|
||||
config->context_aware_warnings = enabled;
|
||||
}
|
||||
return _PyStatus_OK();
|
||||
}
|
||||
|
||||
static PyStatus
|
||||
config_init_tlbc(PyConfig *config)
|
||||
{
|
||||
|
@ -2232,6 +2319,16 @@ config_read_complex_options(PyConfig *config)
|
|||
}
|
||||
#endif
|
||||
|
||||
status = config_init_thread_inherit_context(config);
|
||||
if (_PyStatus_EXCEPTION(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = config_init_context_aware_warnings(config);
|
||||
if (_PyStatus_EXCEPTION(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = config_init_tlbc(config);
|
||||
if (_PyStatus_EXCEPTION(status)) {
|
||||
return status;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue