Skip to content

Commit 4a71946

Browse files
authored
gh-122575: gh-142349: fix sys.flags tuple size (it unintentionally increased) (GH-145988)
the lazy imports PEP initial implementation (3.15 alpha) inadvertently incremented the length of the sys.flags tuple. In a way that did not do anything useful or related to the lazy imports setting (it exposed sys.flags.gil in the tuple). This fixes that to hard code the length to the 3.13 & 3.14 released length of 18 and have our tests and code comments make it clear that we've since stopped making new sys.flags attributes available via sequence index.
1 parent ec5e3a5 commit 4a71946

File tree

2 files changed

+33
-13
lines changed

2 files changed

+33
-13
lines changed

Lib/test/test_sys.py

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -858,24 +858,35 @@ def test_subinterp_intern_singleton(self):
858858
'''))
859859
self.assertTrue(sys._is_interned(s))
860860

861-
def test_sys_flags(self):
861+
def test_sys_flags_indexable_attributes(self):
862862
self.assertTrue(sys.flags)
863-
attrs = ("debug",
863+
# We've stopped assigning sequence indices to new sys.flags attributes:
864+
# https://github.com/python/cpython/issues/122575#issuecomment-2416497086
865+
indexable_attrs = ("debug",
864866
"inspect", "interactive", "optimize",
865867
"dont_write_bytecode", "no_user_site", "no_site",
866868
"ignore_environment", "verbose", "bytes_warning", "quiet",
867869
"hash_randomization", "isolated", "dev_mode", "utf8_mode",
868-
"warn_default_encoding", "safe_path", "int_max_str_digits",
869-
"lazy_imports")
870-
for attr in attrs:
870+
"warn_default_encoding", "safe_path", "int_max_str_digits")
871+
for attr_idx, attr in enumerate(indexable_attrs):
871872
self.assertHasAttr(sys.flags, attr)
872873
attr_type = bool if attr in ("dev_mode", "safe_path") else int
873874
self.assertEqual(type(getattr(sys.flags, attr)), attr_type, attr)
875+
attr_value = getattr(sys.flags, attr)
876+
self.assertEqual(sys.flags[attr_idx], attr_value,
877+
msg=f"sys.flags .{attr} vs [{attr_idx}]")
874878
self.assertTrue(repr(sys.flags))
875-
self.assertEqual(len(sys.flags), len(attrs))
879+
self.assertEqual(len(sys.flags), 18, msg="Do not increase, see GH-122575")
876880

877881
self.assertIn(sys.flags.utf8_mode, {0, 1, 2})
878882

883+
def test_sys_flags_name_only_attributes(self):
884+
# non-tuple sequence fields (name only sys.flags attributes)
885+
self.assertIsInstance(sys.flags.gil, int|type(None))
886+
self.assertIsInstance(sys.flags.thread_inherit_context, int|type(None))
887+
self.assertIsInstance(sys.flags.context_aware_warnings, int|type(None))
888+
self.assertIsInstance(sys.flags.lazy_imports, int|type(None))
889+
879890
def assert_raise_on_new_sys_type(self, sys_attr):
880891
# Users are intentionally prevented from creating new instances of
881892
# sys.flags, sys.version_info, and sys.getwindowsversion.
@@ -1908,10 +1919,16 @@ def test_pythontypes(self):
19081919
# symtable entry
19091920
# XXX
19101921
# sys.flags
1911-
# FIXME: The +3 is for the 'gil', 'thread_inherit_context' and
1912-
# 'context_aware_warnings' flags and will not be necessary once
1913-
# gh-122575 is fixed
1914-
check(sys.flags, vsize('') + self.P + self.P * (3 + len(sys.flags)))
1922+
# FIXME: The non_sequence_fields adjustment is for these flags:
1923+
# - 'gil'
1924+
# - 'thread_inherit_context'
1925+
# - 'context_aware_warnings'
1926+
# - 'lazy_imports'
1927+
# Not needing to increment this every time we add a new field
1928+
# per GH-122575 would be nice...
1929+
# Q: What is the actual point of this sys.flags C size derived from PyStructSequence_Field array assertion?
1930+
non_sequence_fields = 4
1931+
check(sys.flags, vsize('') + self.P + self.P * (non_sequence_fields + len(sys.flags)))
19151932

19161933
def test_asyncgen_hooks(self):
19171934
old = sys.get_asyncgen_hooks()

Python/sysmodule.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3495,11 +3495,12 @@ static PyStructSequence_Field flags_fields[] = {
34953495
{"dev_mode", "-X dev"},
34963496
{"utf8_mode", "-X utf8"},
34973497
{"warn_default_encoding", "-X warn_default_encoding"},
3498-
{"safe_path", "-P"},
3498+
{"safe_path", "-P"},
34993499
{"int_max_str_digits", "-X int_max_str_digits"},
3500+
// Fields below are only usable by sys.flags attribute name, not index:
35003501
{"gil", "-X gil"},
35013502
{"thread_inherit_context", "-X thread_inherit_context"},
3502-
{"context_aware_warnings", "-X context_aware_warnings"},
3503+
{"context_aware_warnings", "-X context_aware_warnings"},
35033504
{"lazy_imports", "-X lazy_imports"},
35043505
{0}
35053506
};
@@ -3510,7 +3511,9 @@ static PyStructSequence_Desc flags_desc = {
35103511
"sys.flags", /* name */
35113512
flags__doc__, /* doc */
35123513
flags_fields, /* fields */
3513-
19
3514+
18 /* NB - do not increase beyond 3.13's value of 18. */
3515+
// New sys.flags fields should NOT be tuple addressable per
3516+
// https://github.com/python/cpython/issues/122575#issuecomment-2416497086
35143517
};
35153518

35163519
static void

0 commit comments

Comments
 (0)