gh-96512: Move int_max_str_digits setting to PyConfig (#96944)

It had to live as a global outside of PyConfig for stable ABI reasons in
the pre-3.12 backports.

This removes the `_Py_global_config_int_max_str_digits` and gets rid of
the equivalent field in the internal `struct _is PyInterpreterState` as
code can just use the existing nested config struct within that.

Adds tests to verify unique settings and configs in subinterpreters.
This commit is contained in:
Gregory P. Smith 2022-10-03 13:55:45 -07:00 committed by GitHub
parent cfbc7dd910
commit b0f89cb431
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 111 additions and 24 deletions

View file

@ -999,6 +999,39 @@ class SubinterpreterTest(unittest.TestCase):
self.assertEqual(ret, 0)
self.assertEqual(pickle.load(f), {'a': '123x', 'b': '123'})
def test_py_config_isoloated_per_interpreter(self):
# A config change in one interpreter must not leak to out to others.
#
# This test could verify ANY config value, it just happens to have been
# written around the time of int_max_str_digits. Refactoring is okay.
code = """if 1:
import sys, _testinternalcapi
# Any config value would do, this happens to be the one being
# double checked at the time this test was written.
config = _testinternalcapi.get_config()
config['int_max_str_digits'] = 55555
_testinternalcapi.set_config(config)
sub_value = _testinternalcapi.get_config()['int_max_str_digits']
assert sub_value == 55555, sub_value
"""
before_config = _testinternalcapi.get_config()
assert before_config['int_max_str_digits'] != 55555
self.assertEqual(support.run_in_subinterp(code), 0,
'subinterp code failure, check stderr.')
after_config = _testinternalcapi.get_config()
self.assertIsNot(
before_config, after_config,
"Expected get_config() to return a new dict on each call")
self.assertEqual(before_config, after_config,
"CAUTION: Tests executed after this may be "
"running under an altered config.")
# try:...finally: calling set_config(before_config) not done
# as that results in sys.argv, sys.path, and sys.warnoptions
# "being modified by test_capi" per test.regrtest. So if this
# test fails, assume that the environment in this process may
# be altered and suspect.
def test_mutate_exception(self):
"""
Exceptions saved in global module state get shared between

View file

@ -882,7 +882,8 @@ class CmdLineTest(unittest.TestCase):
return tuple(int(i) for i in out.split())
res = assert_python_ok('-c', code)
self.assertEqual(res2int(res), (-1, sys.get_int_max_str_digits()))
current_max = sys.get_int_max_str_digits()
self.assertEqual(res2int(res), (current_max, current_max))
res = assert_python_ok('-X', 'int_max_str_digits=0', '-c', code)
self.assertEqual(res2int(res), (0, 0))
res = assert_python_ok('-X', 'int_max_str_digits=4000', '-c', code)

View file

@ -434,6 +434,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'install_signal_handlers': 1,
'use_hash_seed': 0,
'hash_seed': 0,
'int_max_str_digits': sys.int_info.default_max_str_digits,
'faulthandler': 0,
'tracemalloc': 0,
'perf_profiling': 0,
@ -876,6 +877,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'platlibdir': 'my_platlibdir',
'module_search_paths': self.IGNORE_CONFIG,
'safe_path': 1,
'int_max_str_digits': 31337,
'check_hash_pycs_mode': 'always',
'pathconfig_warnings': 0,
@ -912,6 +914,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'platlibdir': 'env_platlibdir',
'module_search_paths': self.IGNORE_CONFIG,
'safe_path': 1,
'int_max_str_digits': 4567,
}
self.check_all_configs("test_init_compat_env", config, preconfig,
api=API_COMPAT)
@ -944,6 +947,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'platlibdir': 'env_platlibdir',
'module_search_paths': self.IGNORE_CONFIG,
'safe_path': 1,
'int_max_str_digits': 4567,
}
self.check_all_configs("test_init_python_env", config, preconfig,
api=API_PYTHON)

View file

@ -770,6 +770,26 @@ class IntStrDigitLimitsTests(unittest.TestCase):
with self.subTest(base=base):
self._other_base_helper(base)
def test_int_max_str_digits_is_per_interpreter(self):
# Changing the limit in one interpreter does not change others.
code = """if 1:
# Subinterpreters maintain and enforce their own limit
import sys
sys.set_int_max_str_digits(2323)
try:
int('3'*3333)
except ValueError:
pass
else:
raise AssertionError('Expected a int max str digits ValueError.')
"""
with support.adjust_int_max_str_digits(4000):
before_value = sys.get_int_max_str_digits()
self.assertEqual(support.run_in_subinterp(code), 0,
'subinterp code failure, check stderr.')
after_value = sys.get_int_max_str_digits()
self.assertEqual(before_value, after_value)
class IntSubclassStrDigitLimitsTests(IntStrDigitLimitsTests):
int_class = IntSubclass