diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst
index 459846e55ccf70..c286e3fc4f2bda 100644
--- a/Doc/whatsnew/3.15.rst
+++ b/Doc/whatsnew/3.15.rst
@@ -1014,13 +1014,6 @@ symtable
(Contributed by Yashp002 in :gh:`143504`.)
-symtable
---------
-
-* Add :meth:`symtable.Function.get_cells` and :meth:`symtable.Symbol.is_cell` methods.
- (Contributed by Yashp002 in :gh:`143504`.)
-
-
sys
---
diff --git a/Lib/base64.py b/Lib/base64.py
index 36688ce43917ce..dcfcbcc95a39be 100644
--- a/Lib/base64.py
+++ b/Lib/base64.py
@@ -100,7 +100,13 @@ def b64decode(s, altchars=None, validate=_NOT_SPECIFIED, *, ignorechars=_NOT_SPE
break
s = s.translate(bytes.maketrans(altchars, b'+/'))
else:
- trans = bytes.maketrans(b'+/' + altchars, altchars + b'+/')
+ trans_in = set(b'+/') - set(altchars)
+ if len(trans_in) == 2:
+ # we can't use the reqult of unordered sets here
+ trans = bytes.maketrans(altchars + b'+/', b'+/' + altchars)
+ else:
+ trans = bytes.maketrans(altchars + bytes(trans_in),
+ b'+/' + bytes(set(altchars) - set(b'+/')))
s = s.translate(trans)
ignorechars = ignorechars.translate(trans)
if ignorechars is _NOT_SPECIFIED:
diff --git a/Lib/test/test_base64.py b/Lib/test/test_base64.py
index 69aa628db7c34c..9648624b267a54 100644
--- a/Lib/test/test_base64.py
+++ b/Lib/test/test_base64.py
@@ -293,6 +293,13 @@ def test_b64decode_altchars(self):
eq(base64.b64decode(data_str, altchars=altchars_str), res)
eq(base64.b64decode(data, altchars=altchars, ignorechars=b'\n'), res)
+ eq(base64.b64decode(b'/----', altchars=b'-+', ignorechars=b'/'), b'\xfb\xef\xbe')
+ eq(base64.b64decode(b'/----', altchars=b'+-', ignorechars=b'/'), b'\xff\xff\xff')
+ eq(base64.b64decode(b'+----', altchars=b'-/', ignorechars=b'+'), b'\xfb\xef\xbe')
+ eq(base64.b64decode(b'+----', altchars=b'/-', ignorechars=b'+'), b'\xff\xff\xff')
+ eq(base64.b64decode(b'+/+/', altchars=b'/+', ignorechars=b''), b'\xff\xef\xfe')
+ eq(base64.b64decode(b'/+/+', altchars=b'+/', ignorechars=b''), b'\xff\xef\xfe')
+
self.assertRaises(ValueError, base64.b64decode, b'', altchars=b'+')
self.assertRaises(ValueError, base64.b64decode, b'', altchars=b'+/-')
self.assertRaises(ValueError, base64.b64decode, '', altchars='+')
diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py
index e106ac20809f20..5f035c35367d64 100644
--- a/Lib/test/test_cmd_line.py
+++ b/Lib/test/test_cmd_line.py
@@ -3,6 +3,7 @@
# See test_cmd_line_script.py for testing of script execution
import os
+import re
import subprocess
import sys
import sysconfig
@@ -59,11 +60,22 @@ def test_help(self):
def test_help_env(self):
out = self.verify_valid_flag('--help-env')
self.assertIn(b'PYTHONHOME', out)
+ # Env vars in each section should be sorted alphabetically
+ # (ignoring underscores so PYTHON_FOO and PYTHONFOO intermix naturally)
+ sort_key = lambda name: name.replace(b'_', b'').lower()
+ sections = out.split(b'These variables have equivalent')
+ for section in sections:
+ envvars = re.findall(rb'^(PYTHON\w+)', section, re.MULTILINE)
+ self.assertEqual(envvars, sorted(envvars, key=sort_key),
+ "env vars should be sorted alphabetically")
@support.cpython_only
def test_help_xoptions(self):
out = self.verify_valid_flag('--help-xoptions')
self.assertIn(b'-X dev', out)
+ options = re.findall(rb'^-X (\w+)', out, re.MULTILINE)
+ self.assertEqual(options, sorted(options),
+ "options should be sorted alphabetically")
@support.cpython_only
def test_help_all(self):
diff --git a/Lib/test/test_pyexpat.py b/Lib/test/test_pyexpat.py
index 31bcee293b2b69..f8afc16d3cb4cb 100644
--- a/Lib/test/test_pyexpat.py
+++ b/Lib/test/test_pyexpat.py
@@ -701,6 +701,25 @@ def test_trigger_leak(self):
parser.ElementDeclHandler = lambda _1, _2: None
self.assertRaises(TypeError, parser.Parse, data, True)
+ @support.skip_if_unlimited_stack_size
+ @support.skip_emscripten_stack_overflow()
+ @support.skip_wasi_stack_overflow()
+ def test_deeply_nested_content_model(self):
+ # This should raise a RecursionError and not crash.
+ # See https://github.com/python/cpython/issues/145986.
+ N = 500_000
+ data = (
+ b'\n]>\n\n'
+ )
+
+ parser = expat.ParserCreate()
+ parser.ElementDeclHandler = lambda _1, _2: None
+ with support.infinite_recursion():
+ with self.assertRaises(RecursionError):
+ parser.Parse(data)
+
class MalformedInputTest(unittest.TestCase):
def test1(self):
xml = b"\0\r\n"
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
index 8974361c2537d2..a729efee18c3a1 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -858,24 +858,35 @@ def test_subinterp_intern_singleton(self):
'''))
self.assertTrue(sys._is_interned(s))
- def test_sys_flags(self):
+ def test_sys_flags_indexable_attributes(self):
self.assertTrue(sys.flags)
- attrs = ("debug",
+ # We've stopped assigning sequence indices to new sys.flags attributes:
+ # https://github.com/python/cpython/issues/122575#issuecomment-2416497086
+ indexable_attrs = ("debug",
"inspect", "interactive", "optimize",
"dont_write_bytecode", "no_user_site", "no_site",
"ignore_environment", "verbose", "bytes_warning", "quiet",
"hash_randomization", "isolated", "dev_mode", "utf8_mode",
- "warn_default_encoding", "safe_path", "int_max_str_digits",
- "lazy_imports")
- for attr in attrs:
+ "warn_default_encoding", "safe_path", "int_max_str_digits")
+ for attr_idx, attr in enumerate(indexable_attrs):
self.assertHasAttr(sys.flags, attr)
attr_type = bool if attr in ("dev_mode", "safe_path") else int
self.assertEqual(type(getattr(sys.flags, attr)), attr_type, attr)
+ attr_value = getattr(sys.flags, attr)
+ self.assertEqual(sys.flags[attr_idx], attr_value,
+ msg=f"sys.flags .{attr} vs [{attr_idx}]")
self.assertTrue(repr(sys.flags))
- self.assertEqual(len(sys.flags), len(attrs))
+ self.assertEqual(len(sys.flags), 18, msg="Do not increase, see GH-122575")
self.assertIn(sys.flags.utf8_mode, {0, 1, 2})
+ def test_sys_flags_name_only_attributes(self):
+ # non-tuple sequence fields (name only sys.flags attributes)
+ self.assertIsInstance(sys.flags.gil, int|type(None))
+ self.assertIsInstance(sys.flags.thread_inherit_context, int|type(None))
+ self.assertIsInstance(sys.flags.context_aware_warnings, int|type(None))
+ self.assertIsInstance(sys.flags.lazy_imports, int|type(None))
+
def assert_raise_on_new_sys_type(self, sys_attr):
# Users are intentionally prevented from creating new instances of
# sys.flags, sys.version_info, and sys.getwindowsversion.
@@ -1908,10 +1919,16 @@ def test_pythontypes(self):
# symtable entry
# XXX
# sys.flags
- # FIXME: The +3 is for the 'gil', 'thread_inherit_context' and
- # 'context_aware_warnings' flags and will not be necessary once
- # gh-122575 is fixed
- check(sys.flags, vsize('') + self.P + self.P * (3 + len(sys.flags)))
+ # FIXME: The non_sequence_fields adjustment is for these flags:
+ # - 'gil'
+ # - 'thread_inherit_context'
+ # - 'context_aware_warnings'
+ # - 'lazy_imports'
+ # Not needing to increment this every time we add a new field
+ # per GH-122575 would be nice...
+ # Q: What is the actual point of this sys.flags C size derived from PyStructSequence_Field array assertion?
+ non_sequence_fields = 4
+ check(sys.flags, vsize('') + self.P + self.P * (non_sequence_fields + len(sys.flags)))
def test_asyncgen_hooks(self):
old = sys.get_asyncgen_hooks()
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-03-15-20-47-34.gh-issue-145990.14BUzw.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-03-15-20-47-34.gh-issue-145990.14BUzw.rst
new file mode 100644
index 00000000000000..f66c156b4bc916
--- /dev/null
+++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-03-15-20-47-34.gh-issue-145990.14BUzw.rst
@@ -0,0 +1 @@
+``python --help-xoptions`` is now sorted by ``-X`` option name.
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-03-15-21-45-35.gh-issue-145990.tmXwRB.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-03-15-21-45-35.gh-issue-145990.tmXwRB.rst
new file mode 100644
index 00000000000000..21b9a524d005f9
--- /dev/null
+++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-03-15-21-45-35.gh-issue-145990.tmXwRB.rst
@@ -0,0 +1 @@
+``python --help-env`` sections are now sorted by environment variable name.
diff --git a/Misc/NEWS.d/next/Library/2026-03-15-10-17-51.gh-issue-145968.gZexry.rst b/Misc/NEWS.d/next/Library/2026-03-15-10-17-51.gh-issue-145968.gZexry.rst
new file mode 100644
index 00000000000000..9eae1dc400838a
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-03-15-10-17-51.gh-issue-145968.gZexry.rst
@@ -0,0 +1,2 @@
+Fix translation in :func:`base64.b64decode` when altchars overlaps with the
+standard ones.
diff --git a/Misc/NEWS.d/next/Security/2026-03-14-17-31-39.gh-issue-145986.ifSSr8.rst b/Misc/NEWS.d/next/Security/2026-03-14-17-31-39.gh-issue-145986.ifSSr8.rst
new file mode 100644
index 00000000000000..79536d1fef543f
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2026-03-14-17-31-39.gh-issue-145986.ifSSr8.rst
@@ -0,0 +1,4 @@
+:mod:`xml.parsers.expat`: Fixed a crash caused by unbounded C recursion when
+converting deeply nested XML content models with
+:meth:`~xml.parsers.expat.xmlparser.ElementDeclHandler`.
+This addresses :cve:`2026-4224`.
diff --git a/Misc/NEWS.d/next/Tools-Demos/2026-03-15-20-59-29.gh-issue-145976.rEdUI-.rst b/Misc/NEWS.d/next/Tools-Demos/2026-03-15-20-59-29.gh-issue-145976.rEdUI-.rst
new file mode 100644
index 00000000000000..17b0f2d797fa48
--- /dev/null
+++ b/Misc/NEWS.d/next/Tools-Demos/2026-03-15-20-59-29.gh-issue-145976.rEdUI-.rst
@@ -0,0 +1,2 @@
+Remove :file:`Misc/indent.pro`, a configuration file for GNU
+:manpage:`indent(1)`.
diff --git a/Misc/README b/Misc/README
index 038f842e0bc02e..1993c58ad8c960 100644
--- a/Misc/README
+++ b/Misc/README
@@ -9,8 +9,7 @@ Files found here
ACKS Acknowledgements
HISTORY News from previous releases -- oldest last
-indent.pro GNU indent profile approximating my C style
-NEWS News for this release (for some meaning of "this")
+NEWS.d/ News files for this release (for some meaning of "this")
python-config.in Python script template for python-config
python.man UNIX man page for the python interpreter
python.pc.in Package configuration info template for pkg-config
diff --git a/Misc/indent.pro b/Misc/indent.pro
deleted file mode 100644
index 02cceb62021453..00000000000000
--- a/Misc/indent.pro
+++ /dev/null
@@ -1,24 +0,0 @@
---blank-lines-after-declarations
---blank-lines-after-procedures
---braces-after-func-def-line
---braces-on-if-line
---braces-on-struct-decl-line
---break-after-boolean-operator
---comment-indentation25
---comment-line-length79
---continue-at-parentheses
---dont-cuddle-do-while
---dont-cuddle-else
---indent-level4
---line-length79
---no-space-after-casts
---no-space-after-function-call-names
---no-space-after-parentheses
---no-tabs
---procnames-start-lines
---space-after-for
---space-after-if
---space-after-while
---swallow-optional-blank-lines
--T PyCFunction
--T PyObject
diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c
index e9255038eee5b5..cadc6706243524 100644
--- a/Modules/pyexpat.c
+++ b/Modules/pyexpat.c
@@ -3,6 +3,7 @@
#endif
#include "Python.h"
+#include "pycore_ceval.h" // _Py_EnterRecursiveCall()
#include "pycore_import.h" // _PyImport_SetModule()
#include "pycore_pyhash.h" // _Py_HashSecret
#include "pycore_traceback.h" // _PyTraceback_Add()
@@ -607,6 +608,10 @@ static PyObject *
conv_content_model(XML_Content * const model,
PyObject *(*conv_string)(void *))
{
+ if (_Py_EnterRecursiveCall(" in conv_content_model")) {
+ return NULL;
+ }
+
PyObject *result = NULL;
PyObject *children = PyTuple_New(model->numchildren);
int i;
@@ -618,7 +623,7 @@ conv_content_model(XML_Content * const model,
conv_string);
if (child == NULL) {
Py_XDECREF(children);
- return NULL;
+ goto done;
}
PyTuple_SET_ITEM(children, i, child);
}
@@ -626,6 +631,8 @@ conv_content_model(XML_Content * const model,
model->type, model->quant,
conv_string, model->name, children);
}
+done:
+ _Py_LeaveRecursiveCall();
return result;
}
diff --git a/Python/initconfig.c b/Python/initconfig.c
index 57629ff8c57380..caf42f5247c2f2 100644
--- a/Python/initconfig.c
+++ b/Python/initconfig.c
@@ -304,9 +304,15 @@ arg ...: arguments passed to program in sys.argv[1:]\n\
static const char usage_xoptions[] = "\
The following implementation-specific options are available:\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 cpu_count=N: override the return value of os.cpu_count();\n\
-X cpu_count=default cancels overriding; also PYTHON_CPU_COUNT\n\
-X dev : enable Python Development Mode; also PYTHONDEVMODE\n\
+-X disable-remote-debug: disable remote debugging; also PYTHON_DISABLE_REMOTE_DEBUG\n\
-X faulthandler: dump the Python traceback on fatal errors;\n\
also PYTHONFAULTHANDLER\n\
-X frozen_modules=[on|off]: whether to use frozen modules; the default is \"on\"\n\
@@ -319,16 +325,18 @@ The following implementation-specific options are available:\n\
"\
-X importtime[=2]: show how long each import takes; use -X importtime=2 to\n\
log imports of already-loaded modules; also PYTHONPROFILEIMPORTTIME\n\
--X lazy_imports=[all|none|normal]: control global lazy imports;\n\
- default is normal; also PYTHON_LAZY_IMPORTS\n\
-X int_max_str_digits=N: limit the size of int<->str conversions;\n\
0 disables the limit; also PYTHONINTMAXSTRDIGITS\n\
+-X lazy_imports=[all|none|normal]: control global lazy imports;\n\
+ default is normal; also PYTHON_LAZY_IMPORTS\n\
-X no_debug_ranges: don't include extra location information in code objects;\n\
also PYTHONNODEBUGRANGES\n\
+-X pathconfig_warnings=[0|1]: if true (1) then path configuration is allowed\n\
+ to log warnings into stderr; if false (0) suppress these warnings;\n\
+ set to true by default; also PYTHON_PATHCONFIG_WARNINGS\n\
-X perf: support the Linux \"perf\" profiler; also PYTHONPERFSUPPORT=1\n\
-X perf_jit: support the Linux \"perf\" profiler with DWARF support;\n\
also PYTHON_PERF_JIT_SUPPORT=1\n\
--X disable-remote-debug: disable remote debugging; also PYTHON_DISABLE_REMOTE_DEBUG\n\
"
#ifdef Py_DEBUG
"-X presite=MOD: import this module before site; also PYTHON_PRESITE\n"
@@ -343,24 +351,17 @@ The following implementation-specific options are available:\n\
"\
-X showrefcount: output the total reference count and number of used\n\
memory blocks when the program finishes or after each statement in\n\
- the interactive interpreter; only works on debug builds\n"
+ the interactive interpreter; only works on debug builds\n\
+-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\
+"
#ifdef Py_GIL_DISABLED
"-X tlbc=[0|1]: enable (1) or disable (0) thread-local bytecode. Also\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 pathconfig_warnings=[0|1]: if true (1) then path configuration is allowed\n\
- to log warnings into stderr; if false (0) suppress these warnings;\n\
- set to true by default; also PYTHON_PATHCONFIG_WARNINGS\n\
--X tracemalloc[=N]: trace Python memory allocations; N sets a traceback limit\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\
-X warn_default_encoding: enable opt-in EncodingWarning for 'encoding=None';\n\
@@ -370,34 +371,19 @@ The following implementation-specific options are available:\n\
/* Envvars that don't have equivalent command-line options are listed first */
static const char usage_envvars[] =
"Environment variables that change behavior:\n"
-"PYTHONSTARTUP : file executed on interactive startup (no default)\n"
-"PYTHONPATH : '%lc'-separated list of directories prefixed to the\n"
-" default module search path. The result is sys.path.\n"
-"PYTHONHOME : alternate directory (or %lc).\n"
-" The default module search path uses %s.\n"
-"PYTHONPLATLIBDIR: override sys.platlibdir\n"
+"PYTHONASYNCIODEBUG: enable asyncio debug mode\n"
+"PYTHON_BASIC_REPL: use the traditional parser-based REPL\n"
+"PYTHONBREAKPOINT: if this variable is set to 0, it disables the default\n"
+" debugger. It can be set to the callable of your debugger of\n"
+" choice.\n"
"PYTHONCASEOK : ignore case in 'import' statements (Windows)\n"
-"PYTHONIOENCODING: encoding[:errors] used for stdin/stdout/stderr\n"
-"PYTHONHASHSEED : if this variable is set to 'random', a random value is used\n"
-" to seed the hashes of str and bytes objects. It can also be\n"
-" set to an integer in the range [0,4294967295] to get hash\n"
-" values with a predictable seed.\n"
-"PYTHONMALLOC : set the Python memory allocators and/or install debug hooks\n"
-" on Python memory allocators. Use PYTHONMALLOC=debug to\n"
-" install debug hooks.\n"
-"PYTHONMALLOCSTATS: print memory allocator statistics\n"
"PYTHONCOERCECLOCALE: if this variable is set to 0, it disables the locale\n"
" coercion behavior. Use PYTHONCOERCECLOCALE=warn to request\n"
" display of locale coercion and locale compatibility warnings\n"
" on stderr.\n"
-"PYTHONBREAKPOINT: if this variable is set to 0, it disables the default\n"
-" debugger. It can be set to the callable of your debugger of\n"
-" choice.\n"
"PYTHON_COLORS : if this variable is set to 1, the interpreter will colorize\n"
" various kinds of output. Setting it to 0 deactivates\n"
" this behavior.\n"
-"PYTHON_HISTORY : the location of a .python_history file.\n"
-"PYTHONASYNCIODEBUG: enable asyncio debug mode\n"
#ifdef Py_TRACE_REFS
"PYTHONDUMPREFS : dump objects and reference counts still alive after shutdown\n"
"PYTHONDUMPREFSFILE: dump objects and reference counts to the specified file\n"
@@ -405,14 +391,31 @@ static const char usage_envvars[] =
#ifdef __APPLE__
"PYTHONEXECUTABLE: set sys.argv[0] to this value (macOS only)\n"
#endif
+"PYTHONHASHSEED : if this variable is set to 'random', a random value is used\n"
+" to seed the hashes of str and bytes objects. It can also be\n"
+" set to an integer in the range [0,4294967295] to get hash\n"
+" values with a predictable seed.\n"
+"PYTHON_HISTORY : the location of a .python_history file.\n"
+"PYTHONHOME : alternate directory (or %lc).\n"
+" The default module search path uses %s.\n"
+"PYTHONIOENCODING: encoding[:errors] used for stdin/stdout/stderr\n"
#ifdef MS_WINDOWS
"PYTHONLEGACYWINDOWSFSENCODING: use legacy \"mbcs\" encoding for file system\n"
"PYTHONLEGACYWINDOWSSTDIO: use legacy Windows stdio\n"
#endif
+"PYTHONMALLOC : set the Python memory allocators and/or install debug hooks\n"
+" on Python memory allocators. Use PYTHONMALLOC=debug to\n"
+" install debug hooks.\n"
+"PYTHONMALLOCSTATS: print memory allocator statistics\n"
+"PYTHONPATH : '%lc'-separated list of directories prefixed to the\n"
+" default module search path. The result is sys.path.\n"
+"PYTHONPLATLIBDIR: override sys.platlibdir\n"
+"PYTHONSTARTUP : file executed on interactive startup (no default)\n"
"PYTHONUSERBASE : defines the user base directory (site.USER_BASE)\n"
-"PYTHON_BASIC_REPL: use the traditional parser-based REPL\n"
"\n"
"These variables have equivalent command-line options (see --help for details):\n"
+"PYTHON_CONTEXT_AWARE_WARNINGS: if true (1), enable thread-safe warnings\n"
+" module behaviour (-X context_aware_warnings)\n"
"PYTHON_CPU_COUNT: override the return value of os.cpu_count() (-X cpu_count)\n"
"PYTHONDEBUG : enable parser debug mode (-d)\n"
"PYTHONDEVMODE : enable Python Development Mode (-X dev)\n"
@@ -427,31 +430,29 @@ static const char usage_envvars[] =
"PYTHONINSPECT : inspect interactively after running script (-i)\n"
"PYTHONINTMAXSTRDIGITS: limit the size of int<->str conversions;\n"
" 0 disables the limit (-X int_max_str_digits=N)\n"
+"PYTHON_LAZY_IMPORTS: control global lazy imports (-X lazy_imports)\n"
"PYTHONNODEBUGRANGES: don't include extra location information in code objects\n"
" (-X no_debug_ranges)\n"
"PYTHONNOUSERSITE: disable user site directory (-s)\n"
"PYTHONOPTIMIZE : enable level 1 optimizations (-O)\n"
-"PYTHONPERFSUPPORT: support the Linux \"perf\" profiler (-X perf)\n"
"PYTHON_PERF_JIT_SUPPORT: enable Linux \"perf\" profiler support with JIT\n"
" (-X perf_jit)\n"
+"PYTHONPERFSUPPORT: support the Linux \"perf\" profiler (-X perf)\n"
#ifdef Py_DEBUG
"PYTHON_PRESITE: import this module before site (-X presite)\n"
#endif
"PYTHONPROFILEIMPORTTIME: show how long each import takes (-X importtime)\n"
-"PYTHON_LAZY_IMPORTS: control global lazy imports (-X lazy_imports)\n"
"PYTHONPYCACHEPREFIX: root directory for bytecode cache (pyc) files\n"
" (-X pycache_prefix)\n"
"PYTHONSAFEPATH : don't prepend a potentially unsafe path to sys.path.\n"
#ifdef Py_STATS
"PYTHONSTATS : turns on statistics gathering (-X pystats)\n"
#endif
+"PYTHON_THREAD_INHERIT_CONTEXT: if true (1), threads inherit context vars\n"
+" (-X thread_inherit_context)\n"
#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"
@@ -2946,7 +2947,7 @@ config_usage(int error, const wchar_t* program)
static void
config_envvars_usage(void)
{
- printf(usage_envvars, (wint_t)DELIM, (wint_t)DELIM, PYTHONHOMEHELP);
+ printf(usage_envvars, (wint_t)DELIM, PYTHONHOMEHELP, (wint_t)DELIM);
}
static void
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index 893a116565e37e..646b8a1c3c3a84 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -3495,11 +3495,12 @@ static PyStructSequence_Field flags_fields[] = {
{"dev_mode", "-X dev"},
{"utf8_mode", "-X utf8"},
{"warn_default_encoding", "-X warn_default_encoding"},
- {"safe_path", "-P"},
+ {"safe_path", "-P"},
{"int_max_str_digits", "-X int_max_str_digits"},
+ // Fields below are only usable by sys.flags attribute name, not index:
{"gil", "-X gil"},
{"thread_inherit_context", "-X thread_inherit_context"},
- {"context_aware_warnings", "-X context_aware_warnings"},
+ {"context_aware_warnings", "-X context_aware_warnings"},
{"lazy_imports", "-X lazy_imports"},
{0}
};
@@ -3510,7 +3511,9 @@ static PyStructSequence_Desc flags_desc = {
"sys.flags", /* name */
flags__doc__, /* doc */
flags_fields, /* fields */
- 19
+ 18 /* NB - do not increase beyond 3.13's value of 18. */
+ // New sys.flags fields should NOT be tuple addressable per
+ // https://github.com/python/cpython/issues/122575#issuecomment-2416497086
};
static void