mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	 2731913dd5
			
		
	
	
		2731913dd5
		
			
		
	
	
	
	
		
			
			In free-threaded builds, running with `PYTHON_GIL=0` will now disable the GIL. Follow-up issues track work to re-enable the GIL when loading an incompatible extension, and to disable the GIL by default. In order to support re-enabling the GIL at runtime, all GIL-related data structures are initialized as usual, and disabling the GIL simply sets a flag that causes `take_gil()` and `drop_gil()` to return early.
		
			
				
	
	
		
			291 lines
		
	
	
	
		
			9.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			291 lines
		
	
	
	
		
			9.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # bpo-42260: Test _PyInterpreterState_GetConfigCopy()
 | |
| # and _PyInterpreterState_SetConfig().
 | |
| #
 | |
| # Test run in a subprocess since set_config(get_config())
 | |
| # does reset sys attributes to their state of the Python startup
 | |
| # (before the site module is run).
 | |
| 
 | |
| import _testinternalcapi
 | |
| import os
 | |
| import sys
 | |
| import unittest
 | |
| from test import support
 | |
| from test.support import MS_WINDOWS
 | |
| 
 | |
| 
 | |
| MAX_HASH_SEED = 4294967295
 | |
| 
 | |
| 
 | |
| BOOL_OPTIONS = [
 | |
|     'isolated',
 | |
|     'use_environment',
 | |
|     'dev_mode',
 | |
|     'install_signal_handlers',
 | |
|     'use_hash_seed',
 | |
|     'faulthandler',
 | |
|     'import_time',
 | |
|     'code_debug_ranges',
 | |
|     'show_ref_count',
 | |
|     'dump_refs',
 | |
|     'malloc_stats',
 | |
|     'parse_argv',
 | |
|     'site_import',
 | |
|     'warn_default_encoding',
 | |
|     'inspect',
 | |
|     'interactive',
 | |
|     'parser_debug',
 | |
|     'write_bytecode',
 | |
|     'quiet',
 | |
|     'user_site_directory',
 | |
|     'configure_c_stdio',
 | |
|     'buffered_stdio',
 | |
|     'use_frozen_modules',
 | |
|     'safe_path',
 | |
|     'pathconfig_warnings',
 | |
|     'module_search_paths_set',
 | |
|     'skip_source_first_line',
 | |
|     '_install_importlib',
 | |
|     '_init_main',
 | |
|     '_is_python_build',
 | |
| ]
 | |
| if MS_WINDOWS:
 | |
|     BOOL_OPTIONS.append('legacy_windows_stdio')
 | |
| 
 | |
| 
 | |
| class SetConfigTests(unittest.TestCase):
 | |
|     def setUp(self):
 | |
|         self.old_config = _testinternalcapi.get_config()
 | |
|         self.sys_copy = dict(sys.__dict__)
 | |
| 
 | |
|     def tearDown(self):
 | |
|         _testinternalcapi.reset_path_config()
 | |
|         _testinternalcapi.set_config(self.old_config)
 | |
|         sys.__dict__.clear()
 | |
|         sys.__dict__.update(self.sys_copy)
 | |
| 
 | |
|     def set_config(self, **kwargs):
 | |
|         _testinternalcapi.set_config(self.old_config | kwargs)
 | |
| 
 | |
|     def check(self, **kwargs):
 | |
|         self.set_config(**kwargs)
 | |
|         for key, value in kwargs.items():
 | |
|             self.assertEqual(getattr(sys, key), value,
 | |
|                              (key, value))
 | |
| 
 | |
|     def test_set_invalid(self):
 | |
|         invalid_uint = -1
 | |
|         NULL = None
 | |
|         invalid_wstr = NULL
 | |
|         # PyWideStringList strings must be non-NULL
 | |
|         invalid_wstrlist = ["abc", NULL, "def"]
 | |
| 
 | |
|         type_tests = []
 | |
|         value_tests = [
 | |
|             # enum
 | |
|             ('_config_init', 0),
 | |
|             ('_config_init', 4),
 | |
|             # unsigned long
 | |
|             ("hash_seed", -1),
 | |
|             ("hash_seed", MAX_HASH_SEED + 1),
 | |
|         ]
 | |
| 
 | |
|         # int (unsigned)
 | |
|         int_options = [
 | |
|             '_config_init',
 | |
|             'bytes_warning',
 | |
|             'optimization_level',
 | |
|             'tracemalloc',
 | |
|             'verbose',
 | |
|         ]
 | |
|         int_options.extend(BOOL_OPTIONS)
 | |
|         for key in int_options:
 | |
|             value_tests.append((key, invalid_uint))
 | |
|             type_tests.append((key, "abc"))
 | |
|             type_tests.append((key, 2.0))
 | |
| 
 | |
|         # wchar_t*
 | |
|         for key in (
 | |
|             'filesystem_encoding',
 | |
|             'filesystem_errors',
 | |
|             'stdio_encoding',
 | |
|             'stdio_errors',
 | |
|             'check_hash_pycs_mode',
 | |
|             'program_name',
 | |
|             'platlibdir',
 | |
|             # optional wstr:
 | |
|             # 'pythonpath_env'
 | |
|             # 'home'
 | |
|             # 'pycache_prefix'
 | |
|             # 'run_command'
 | |
|             # 'run_module'
 | |
|             # 'run_filename'
 | |
|             # 'executable'
 | |
|             # 'prefix'
 | |
|             # 'exec_prefix'
 | |
|             # 'base_executable'
 | |
|             # 'base_prefix'
 | |
|             # 'base_exec_prefix'
 | |
|         ):
 | |
|             value_tests.append((key, invalid_wstr))
 | |
|             type_tests.append((key, b'bytes'))
 | |
|             type_tests.append((key, 123))
 | |
| 
 | |
|         # PyWideStringList
 | |
|         for key in (
 | |
|             'orig_argv',
 | |
|             'argv',
 | |
|             'xoptions',
 | |
|             'warnoptions',
 | |
|             'module_search_paths',
 | |
|         ):
 | |
|             value_tests.append((key, invalid_wstrlist))
 | |
|             type_tests.append((key, 123))
 | |
|             type_tests.append((key, "abc"))
 | |
|             type_tests.append((key, [123]))
 | |
|             type_tests.append((key, [b"bytes"]))
 | |
| 
 | |
| 
 | |
|         if MS_WINDOWS:
 | |
|             value_tests.append(('legacy_windows_stdio', invalid_uint))
 | |
| 
 | |
|         for exc_type, tests in (
 | |
|             (ValueError, value_tests),
 | |
|             (TypeError, type_tests),
 | |
|         ):
 | |
|             for key, value in tests:
 | |
|                 config = self.old_config | {key: value}
 | |
|                 with self.subTest(key=key, value=value, exc_type=exc_type):
 | |
|                     with self.assertRaises(exc_type):
 | |
|                         _testinternalcapi.set_config(config)
 | |
| 
 | |
|     def test_flags(self):
 | |
|         bool_options = set(BOOL_OPTIONS)
 | |
|         for sys_attr, key, value in (
 | |
|             ("debug", "parser_debug", 1),
 | |
|             ("inspect", "inspect", 2),
 | |
|             ("interactive", "interactive", 3),
 | |
|             ("optimize", "optimization_level", 4),
 | |
|             ("verbose", "verbose", 1),
 | |
|             ("bytes_warning", "bytes_warning", 10),
 | |
|             ("quiet", "quiet", 11),
 | |
|             ("isolated", "isolated", 12),
 | |
|         ):
 | |
|             with self.subTest(sys=sys_attr, key=key, value=value):
 | |
|                 self.set_config(**{key: value, 'parse_argv': 0})
 | |
|                 if key in bool_options:
 | |
|                     self.assertEqual(getattr(sys.flags, sys_attr), int(bool(value)))
 | |
|                 else:
 | |
|                     self.assertEqual(getattr(sys.flags, sys_attr), value)
 | |
| 
 | |
|         self.set_config(write_bytecode=0)
 | |
|         self.assertEqual(sys.flags.dont_write_bytecode, True)
 | |
|         self.assertEqual(sys.dont_write_bytecode, True)
 | |
| 
 | |
|         self.set_config(write_bytecode=1)
 | |
|         self.assertEqual(sys.flags.dont_write_bytecode, False)
 | |
|         self.assertEqual(sys.dont_write_bytecode, False)
 | |
| 
 | |
|         self.set_config(user_site_directory=0, isolated=0)
 | |
|         self.assertEqual(sys.flags.no_user_site, 1)
 | |
|         self.set_config(user_site_directory=1, isolated=0)
 | |
|         self.assertEqual(sys.flags.no_user_site, 0)
 | |
| 
 | |
|         self.set_config(site_import=0)
 | |
|         self.assertEqual(sys.flags.no_site, 1)
 | |
|         self.set_config(site_import=1)
 | |
|         self.assertEqual(sys.flags.no_site, 0)
 | |
| 
 | |
|         self.set_config(dev_mode=0)
 | |
|         self.assertEqual(sys.flags.dev_mode, False)
 | |
|         self.set_config(dev_mode=1)
 | |
|         self.assertEqual(sys.flags.dev_mode, True)
 | |
| 
 | |
|         self.set_config(use_environment=0, isolated=0)
 | |
|         self.assertEqual(sys.flags.ignore_environment, 1)
 | |
|         self.set_config(use_environment=1, isolated=0)
 | |
|         self.assertEqual(sys.flags.ignore_environment, 0)
 | |
| 
 | |
|         self.set_config(use_hash_seed=1, hash_seed=0)
 | |
|         self.assertEqual(sys.flags.hash_randomization, 0)
 | |
|         self.set_config(use_hash_seed=0, hash_seed=0)
 | |
|         self.assertEqual(sys.flags.hash_randomization, 1)
 | |
|         self.set_config(use_hash_seed=1, hash_seed=123)
 | |
|         self.assertEqual(sys.flags.hash_randomization, 1)
 | |
| 
 | |
|         if support.Py_GIL_DISABLED:
 | |
|             self.set_config(enable_gil=-1)
 | |
|             self.assertEqual(sys.flags.gil, None)
 | |
|             self.set_config(enable_gil=0)
 | |
|             self.assertEqual(sys.flags.gil, 0)
 | |
|             self.set_config(enable_gil=1)
 | |
|             self.assertEqual(sys.flags.gil, 1)
 | |
|         else:
 | |
|             # Builds without Py_GIL_DISABLED don't have
 | |
|             # PyConfig.enable_gil. sys.flags.gil is always defined to 1, for
 | |
|             # consistency.
 | |
|             self.assertEqual(sys.flags.gil, 1)
 | |
| 
 | |
|     def test_options(self):
 | |
|         self.check(warnoptions=[])
 | |
|         self.check(warnoptions=["default", "ignore"])
 | |
| 
 | |
|         self.set_config(xoptions=[])
 | |
|         self.assertEqual(sys._xoptions, {})
 | |
|         self.set_config(xoptions=["dev", "tracemalloc=5"])
 | |
|         self.assertEqual(sys._xoptions, {"dev": True, "tracemalloc": "5"})
 | |
| 
 | |
|     def test_pathconfig(self):
 | |
|         self.check(
 | |
|             executable='executable',
 | |
|             prefix="prefix",
 | |
|             base_prefix="base_prefix",
 | |
|             exec_prefix="exec_prefix",
 | |
|             base_exec_prefix="base_exec_prefix",
 | |
|             platlibdir="platlibdir")
 | |
| 
 | |
|         self.set_config(base_executable="base_executable")
 | |
|         self.assertEqual(sys._base_executable, "base_executable")
 | |
| 
 | |
|         # When base_xxx is NULL, value is copied from xxxx
 | |
|         self.set_config(
 | |
|             executable='executable',
 | |
|             prefix="prefix",
 | |
|             exec_prefix="exec_prefix",
 | |
|             base_executable=None,
 | |
|             base_prefix=None,
 | |
|             base_exec_prefix=None)
 | |
|         self.assertEqual(sys._base_executable, "executable")
 | |
|         self.assertEqual(sys.base_prefix, "prefix")
 | |
|         self.assertEqual(sys.base_exec_prefix, "exec_prefix")
 | |
| 
 | |
|     def test_path(self):
 | |
|         self.set_config(module_search_paths_set=1,
 | |
|                         module_search_paths=['a', 'b', 'c'])
 | |
|         self.assertEqual(sys.path, ['a', 'b', 'c'])
 | |
| 
 | |
|         # sys.path is reset if module_search_paths_set=0
 | |
|         self.set_config(module_search_paths_set=0,
 | |
|                         module_search_paths=['new_path'])
 | |
|         self.assertNotEqual(sys.path, ['a', 'b', 'c'])
 | |
|         self.assertNotEqual(sys.path, ['new_path'])
 | |
| 
 | |
|     def test_argv(self):
 | |
|         self.set_config(parse_argv=0,
 | |
|                         argv=['python_program', 'args'],
 | |
|                         orig_argv=['orig', 'orig_args'])
 | |
|         self.assertEqual(sys.argv, ['python_program', 'args'])
 | |
|         self.assertEqual(sys.orig_argv, ['orig', 'orig_args'])
 | |
| 
 | |
|         self.set_config(parse_argv=0,
 | |
|                         argv=[],
 | |
|                         orig_argv=[])
 | |
|         self.assertEqual(sys.argv, [''])
 | |
|         self.assertEqual(sys.orig_argv, [])
 | |
| 
 | |
|     def test_pycache_prefix(self):
 | |
|         self.check(pycache_prefix=None)
 | |
|         self.check(pycache_prefix="pycache_prefix")
 | |
| 
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|     unittest.main()
 |