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
8 import _testinternalcapi
9 import os
10 import sys
11 import unittest
12 from test.support import MS_WINDOWS
13
14
15 MAX_HASH_SEED = 4294967295
16
17 class ESC[4;38;5;81mSetConfigTests(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
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
263 if __name__ == "__main__":
264 unittest.main()