1# bpo-42260: Test _PyInterpreterState_GetConfigCopy() 2# and _PyInterpreterState_SetConfig(). 3# 4# Test run in a subinterpreter since set_config(get_config()) 5# does reset sys attributes to their state of the Python startup 6# (before the site module is run). 7 8import _testinternalcapi 9import os 10import sys 11import unittest 12 13 14MS_WINDOWS = (os.name == 'nt') 15MAX_HASH_SEED = 4294967295 16 17class SetConfigTests(unittest.TestCase): 18 def setUp(self): 19 self.old_config = _testinternalcapi.get_config() 20 self.sys_copy = dict(sys.__dict__) 21 22 def tearDown(self): 23 _testinternalcapi.set_config(self.old_config) 24 sys.__dict__.clear() 25 sys.__dict__.update(self.sys_copy) 26 27 def set_config(self, **kwargs): 28 _testinternalcapi.set_config(self.old_config | kwargs) 29 30 def check(self, **kwargs): 31 self.set_config(**kwargs) 32 for key, value in kwargs.items(): 33 self.assertEqual(getattr(sys, key), value, 34 (key, value)) 35 36 def test_set_invalid(self): 37 invalid_uint = -1 38 NULL = None 39 invalid_wstr = NULL 40 # PyWideStringList strings must be non-NULL 41 invalid_wstrlist = ["abc", NULL, "def"] 42 43 type_tests = [] 44 value_tests = [ 45 # enum 46 ('_config_init', 0), 47 ('_config_init', 4), 48 # unsigned long 49 ("hash_seed", -1), 50 ("hash_seed", MAX_HASH_SEED + 1), 51 ] 52 53 # int (unsigned) 54 options = [ 55 '_config_init', 56 'isolated', 57 'use_environment', 58 'dev_mode', 59 'install_signal_handlers', 60 'use_hash_seed', 61 'faulthandler', 62 'tracemalloc', 63 'import_time', 64 'show_ref_count', 65 'dump_refs', 66 'malloc_stats', 67 'parse_argv', 68 'site_import', 69 'bytes_warning', 70 'inspect', 71 'interactive', 72 'optimization_level', 73 'parser_debug', 74 'write_bytecode', 75 'verbose', 76 'quiet', 77 'user_site_directory', 78 'configure_c_stdio', 79 'buffered_stdio', 80 'pathconfig_warnings', 81 'module_search_paths_set', 82 'skip_source_first_line', 83 '_install_importlib', 84 '_init_main', 85 '_isolated_interpreter', 86 ] 87 if MS_WINDOWS: 88 options.append('legacy_windows_stdio') 89 for key in options: 90 value_tests.append((key, invalid_uint)) 91 type_tests.append((key, "abc")) 92 type_tests.append((key, 2.0)) 93 94 # wchar_t* 95 for key in ( 96 'filesystem_encoding', 97 'filesystem_errors', 98 'stdio_encoding', 99 'stdio_errors', 100 'check_hash_pycs_mode', 101 'program_name', 102 'platlibdir', 103 # optional wstr: 104 # 'pythonpath_env' 105 # 'home' 106 # 'pycache_prefix' 107 # 'run_command' 108 # 'run_module' 109 # 'run_filename' 110 # 'executable' 111 # 'prefix' 112 # 'exec_prefix' 113 # 'base_executable' 114 # 'base_prefix' 115 # 'base_exec_prefix' 116 ): 117 value_tests.append((key, invalid_wstr)) 118 type_tests.append((key, b'bytes')) 119 type_tests.append((key, 123)) 120 121 # PyWideStringList 122 for key in ( 123 'orig_argv', 124 'argv', 125 'xoptions', 126 'warnoptions', 127 'module_search_paths', 128 ): 129 value_tests.append((key, invalid_wstrlist)) 130 type_tests.append((key, 123)) 131 type_tests.append((key, "abc")) 132 type_tests.append((key, [123])) 133 type_tests.append((key, [b"bytes"])) 134 135 136 if MS_WINDOWS: 137 value_tests.append(('legacy_windows_stdio', invalid_uint)) 138 139 for exc_type, tests in ( 140 (ValueError, value_tests), 141 (TypeError, type_tests), 142 ): 143 for key, value in tests: 144 config = self.old_config | {key: value} 145 with self.subTest(key=key, value=value, exc_type=exc_type): 146 with self.assertRaises(exc_type): 147 _testinternalcapi.set_config(config) 148 149 def test_flags(self): 150 for sys_attr, key, value in ( 151 ("debug", "parser_debug", 1), 152 ("inspect", "inspect", 2), 153 ("interactive", "interactive", 3), 154 ("optimize", "optimization_level", 4), 155 ("verbose", "verbose", 1), 156 ("bytes_warning", "bytes_warning", 10), 157 ("quiet", "quiet", 11), 158 ("isolated", "isolated", 12), 159 ): 160 with self.subTest(sys=sys_attr, key=key, value=value): 161 self.set_config(**{key: value, 'parse_argv': 0}) 162 self.assertEqual(getattr(sys.flags, sys_attr), value) 163 164 self.set_config(write_bytecode=0) 165 self.assertEqual(sys.flags.dont_write_bytecode, True) 166 self.assertEqual(sys.dont_write_bytecode, True) 167 168 self.set_config(write_bytecode=1) 169 self.assertEqual(sys.flags.dont_write_bytecode, False) 170 self.assertEqual(sys.dont_write_bytecode, False) 171 172 self.set_config(user_site_directory=0, isolated=0) 173 self.assertEqual(sys.flags.no_user_site, 1) 174 self.set_config(user_site_directory=1, isolated=0) 175 self.assertEqual(sys.flags.no_user_site, 0) 176 177 self.set_config(site_import=0) 178 self.assertEqual(sys.flags.no_site, 1) 179 self.set_config(site_import=1) 180 self.assertEqual(sys.flags.no_site, 0) 181 182 self.set_config(dev_mode=0) 183 self.assertEqual(sys.flags.dev_mode, False) 184 self.set_config(dev_mode=1) 185 self.assertEqual(sys.flags.dev_mode, True) 186 187 self.set_config(use_environment=0, isolated=0) 188 self.assertEqual(sys.flags.ignore_environment, 1) 189 self.set_config(use_environment=1, isolated=0) 190 self.assertEqual(sys.flags.ignore_environment, 0) 191 192 self.set_config(use_hash_seed=1, hash_seed=0) 193 self.assertEqual(sys.flags.hash_randomization, 0) 194 self.set_config(use_hash_seed=0, hash_seed=0) 195 self.assertEqual(sys.flags.hash_randomization, 1) 196 self.set_config(use_hash_seed=1, hash_seed=123) 197 self.assertEqual(sys.flags.hash_randomization, 1) 198 199 def test_options(self): 200 self.check(warnoptions=[]) 201 self.check(warnoptions=["default", "ignore"]) 202 203 self.set_config(xoptions=[]) 204 self.assertEqual(sys._xoptions, {}) 205 self.set_config(xoptions=["dev", "tracemalloc=5"]) 206 self.assertEqual(sys._xoptions, {"dev": True, "tracemalloc": "5"}) 207 208 def test_pathconfig(self): 209 self.check( 210 executable='executable', 211 prefix="prefix", 212 base_prefix="base_prefix", 213 exec_prefix="exec_prefix", 214 base_exec_prefix="base_exec_prefix", 215 platlibdir="platlibdir") 216 217 self.set_config(base_executable="base_executable") 218 self.assertEqual(sys._base_executable, "base_executable") 219 220 # When base_xxx is NULL, value is copied from xxxx 221 self.set_config( 222 executable='executable', 223 prefix="prefix", 224 exec_prefix="exec_prefix", 225 base_executable=None, 226 base_prefix=None, 227 base_exec_prefix=None) 228 self.assertEqual(sys._base_executable, "executable") 229 self.assertEqual(sys.base_prefix, "prefix") 230 self.assertEqual(sys.base_exec_prefix, "exec_prefix") 231 232 def test_path(self): 233 self.set_config(module_search_paths_set=1, 234 module_search_paths=['a', 'b', 'c']) 235 self.assertEqual(sys.path, ['a', 'b', 'c']) 236 237 # Leave sys.path unchanged if module_search_paths_set=0 238 self.set_config(module_search_paths_set=0, 239 module_search_paths=['new_path']) 240 self.assertEqual(sys.path, ['a', 'b', 'c']) 241 242 def test_argv(self): 243 self.set_config(parse_argv=0, 244 argv=['python_program', 'args'], 245 orig_argv=['orig', 'orig_args']) 246 self.assertEqual(sys.argv, ['python_program', 'args']) 247 self.assertEqual(sys.orig_argv, ['orig', 'orig_args']) 248 249 self.set_config(parse_argv=0, 250 argv=[], 251 orig_argv=[]) 252 self.assertEqual(sys.argv, ['']) 253 self.assertEqual(sys.orig_argv, []) 254 255 def test_pycache_prefix(self): 256 self.check(pycache_prefix=None) 257 self.check(pycache_prefix="pycache_prefix") 258 259 260if __name__ == "__main__": 261 unittest.main() 262