• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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