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