1 """Tests for 'site'.
2
3 Tests assume the initial paths in sys.path once the interpreter has begun
4 executing have not been removed.
5
6 """
7 import unittest
8 import test.support
9 from test import support
10 from test.support import os_helper
11 from test.support import socket_helper
12 from test.support import captured_stderr
13 from test.support.os_helper import TESTFN, EnvironmentVarGuard
14 import ast
15 import builtins
16 import glob
17 import io
18 import os
19 import re
20 import shutil
21 import subprocess
22 import sys
23 import sysconfig
24 import tempfile
25 import urllib.error
26 import urllib.request
27 from unittest import mock
28 from copy import copy
29
30 # These tests are not particularly useful if Python was invoked with -S.
31 # If you add tests that are useful under -S, this skip should be moved
32 # to the class level.
33 if sys.flags.no_site:
34 raise unittest.SkipTest("Python was invoked with -S")
35
36 import site
37
38
39 HAS_USER_SITE = (site.USER_SITE is not None)
40 OLD_SYS_PATH = None
41
42
43 def setUpModule():
44 global OLD_SYS_PATH
45 OLD_SYS_PATH = sys.path[:]
46
47 if site.ENABLE_USER_SITE and not os.path.isdir(site.USER_SITE):
48 # need to add user site directory for tests
49 try:
50 os.makedirs(site.USER_SITE)
51 # modify sys.path: will be restored by tearDownModule()
52 site.addsitedir(site.USER_SITE)
53 except PermissionError as exc:
54 raise unittest.SkipTest('unable to create user site directory (%r): %s'
55 % (site.USER_SITE, exc))
56
57
58 def tearDownModule():
59 sys.path[:] = OLD_SYS_PATH
60
61
62 class ESC[4;38;5;81mHelperFunctionsTests(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
63 """Tests for helper functions.
64 """
65
66 def setUp(self):
67 """Save a copy of sys.path"""
68 self.sys_path = sys.path[:]
69 self.old_base = site.USER_BASE
70 self.old_site = site.USER_SITE
71 self.old_prefixes = site.PREFIXES
72 self.original_vars = sysconfig._CONFIG_VARS
73 self.old_vars = copy(sysconfig._CONFIG_VARS)
74
75 def tearDown(self):
76 """Restore sys.path"""
77 sys.path[:] = self.sys_path
78 site.USER_BASE = self.old_base
79 site.USER_SITE = self.old_site
80 site.PREFIXES = self.old_prefixes
81 sysconfig._CONFIG_VARS = self.original_vars
82 # _CONFIG_VARS is None before get_config_vars() is called
83 if sysconfig._CONFIG_VARS is not None:
84 sysconfig._CONFIG_VARS.clear()
85 sysconfig._CONFIG_VARS.update(self.old_vars)
86
87 def test_makepath(self):
88 # Test makepath() have an absolute path for its first return value
89 # and a case-normalized version of the absolute path for its
90 # second value.
91 path_parts = ("Beginning", "End")
92 original_dir = os.path.join(*path_parts)
93 abs_dir, norm_dir = site.makepath(*path_parts)
94 self.assertEqual(os.path.abspath(original_dir), abs_dir)
95 if original_dir == os.path.normcase(original_dir):
96 self.assertEqual(abs_dir, norm_dir)
97 else:
98 self.assertEqual(os.path.normcase(abs_dir), norm_dir)
99
100 def test_init_pathinfo(self):
101 dir_set = site._init_pathinfo()
102 for entry in [site.makepath(path)[1] for path in sys.path
103 if path and os.path.exists(path)]:
104 self.assertIn(entry, dir_set,
105 "%s from sys.path not found in set returned "
106 "by _init_pathinfo(): %s" % (entry, dir_set))
107
108 def pth_file_tests(self, pth_file):
109 """Contain common code for testing results of reading a .pth file"""
110 self.assertIn(pth_file.imported, sys.modules,
111 "%s not in sys.modules" % pth_file.imported)
112 self.assertIn(site.makepath(pth_file.good_dir_path)[0], sys.path)
113 self.assertFalse(os.path.exists(pth_file.bad_dir_path))
114
115 def test_addpackage(self):
116 # Make sure addpackage() imports if the line starts with 'import',
117 # adds directories to sys.path for any line in the file that is not a
118 # comment or import that is a valid directory name for where the .pth
119 # file resides; invalid directories are not added
120 pth_file = PthFile()
121 pth_file.cleanup(prep=True) # to make sure that nothing is
122 # pre-existing that shouldn't be
123 try:
124 pth_file.create()
125 site.addpackage(pth_file.base_dir, pth_file.filename, set())
126 self.pth_file_tests(pth_file)
127 finally:
128 pth_file.cleanup()
129
130 def make_pth(self, contents, pth_dir='.', pth_name=TESTFN):
131 # Create a .pth file and return its (abspath, basename).
132 pth_dir = os.path.abspath(pth_dir)
133 pth_basename = pth_name + '.pth'
134 pth_fn = os.path.join(pth_dir, pth_basename)
135 with open(pth_fn, 'w', encoding='utf-8') as pth_file:
136 self.addCleanup(lambda: os.remove(pth_fn))
137 pth_file.write(contents)
138 return pth_dir, pth_basename
139
140 def test_addpackage_import_bad_syntax(self):
141 # Issue 10642
142 pth_dir, pth_fn = self.make_pth("import bad-syntax\n")
143 with captured_stderr() as err_out:
144 site.addpackage(pth_dir, pth_fn, set())
145 self.assertRegex(err_out.getvalue(), "line 1")
146 self.assertRegex(err_out.getvalue(),
147 re.escape(os.path.join(pth_dir, pth_fn)))
148 # XXX: the previous two should be independent checks so that the
149 # order doesn't matter. The next three could be a single check
150 # but my regex foo isn't good enough to write it.
151 self.assertRegex(err_out.getvalue(), 'Traceback')
152 self.assertRegex(err_out.getvalue(), r'import bad-syntax')
153 self.assertRegex(err_out.getvalue(), 'SyntaxError')
154
155 def test_addpackage_import_bad_exec(self):
156 # Issue 10642
157 pth_dir, pth_fn = self.make_pth("randompath\nimport nosuchmodule\n")
158 with captured_stderr() as err_out:
159 site.addpackage(pth_dir, pth_fn, set())
160 self.assertRegex(err_out.getvalue(), "line 2")
161 self.assertRegex(err_out.getvalue(),
162 re.escape(os.path.join(pth_dir, pth_fn)))
163 # XXX: ditto previous XXX comment.
164 self.assertRegex(err_out.getvalue(), 'Traceback')
165 self.assertRegex(err_out.getvalue(), 'ModuleNotFoundError')
166
167 def test_addpackage_empty_lines(self):
168 # Issue 33689
169 pth_dir, pth_fn = self.make_pth("\n\n \n\n")
170 known_paths = site.addpackage(pth_dir, pth_fn, set())
171 self.assertEqual(known_paths, set())
172
173 def test_addpackage_import_bad_pth_file(self):
174 # Issue 5258
175 pth_dir, pth_fn = self.make_pth("abc\x00def\n")
176 with captured_stderr() as err_out:
177 self.assertFalse(site.addpackage(pth_dir, pth_fn, set()))
178 self.maxDiff = None
179 self.assertEqual(err_out.getvalue(), "")
180 for path in sys.path:
181 if isinstance(path, str):
182 self.assertNotIn("abc\x00def", path)
183
184 def test_addsitedir(self):
185 # Same tests for test_addpackage since addsitedir() essentially just
186 # calls addpackage() for every .pth file in the directory
187 pth_file = PthFile()
188 pth_file.cleanup(prep=True) # Make sure that nothing is pre-existing
189 # that is tested for
190 try:
191 pth_file.create()
192 site.addsitedir(pth_file.base_dir, set())
193 self.pth_file_tests(pth_file)
194 finally:
195 pth_file.cleanup()
196
197 # This tests _getuserbase, hence the double underline
198 # to distinguish from a test for getuserbase
199 def test__getuserbase(self):
200 self.assertEqual(site._getuserbase(), sysconfig._getuserbase())
201
202 @unittest.skipUnless(HAS_USER_SITE, 'need user site')
203 def test_get_path(self):
204 if sys.platform == 'darwin' and sys._framework:
205 scheme = 'osx_framework_user'
206 else:
207 scheme = os.name + '_user'
208 self.assertEqual(os.path.normpath(site._get_path(site._getuserbase())),
209 sysconfig.get_path('purelib', scheme))
210
211 @unittest.skipUnless(site.ENABLE_USER_SITE, "requires access to PEP 370 "
212 "user-site (site.ENABLE_USER_SITE)")
213 @support.requires_subprocess()
214 def test_s_option(self):
215 # (ncoghlan) Change this to use script_helper...
216 usersite = os.path.normpath(site.USER_SITE)
217 self.assertIn(usersite, sys.path)
218
219 env = os.environ.copy()
220 rc = subprocess.call([sys.executable, '-c',
221 'import sys; sys.exit(%r in sys.path)' % usersite],
222 env=env)
223 self.assertEqual(rc, 1)
224
225 env = os.environ.copy()
226 rc = subprocess.call([sys.executable, '-s', '-c',
227 'import sys; sys.exit(%r in sys.path)' % usersite],
228 env=env)
229 if usersite == site.getsitepackages()[0]:
230 self.assertEqual(rc, 1)
231 else:
232 self.assertEqual(rc, 0, "User site still added to path with -s")
233
234 env = os.environ.copy()
235 env["PYTHONNOUSERSITE"] = "1"
236 rc = subprocess.call([sys.executable, '-c',
237 'import sys; sys.exit(%r in sys.path)' % usersite],
238 env=env)
239 if usersite == site.getsitepackages()[0]:
240 self.assertEqual(rc, 1)
241 else:
242 self.assertEqual(rc, 0,
243 "User site still added to path with PYTHONNOUSERSITE")
244
245 env = os.environ.copy()
246 env["PYTHONUSERBASE"] = "/tmp"
247 rc = subprocess.call([sys.executable, '-c',
248 'import sys, site; sys.exit(site.USER_BASE.startswith("/tmp"))'],
249 env=env)
250 self.assertEqual(rc, 1,
251 "User base not set by PYTHONUSERBASE")
252
253 @unittest.skipUnless(HAS_USER_SITE, 'need user site')
254 def test_getuserbase(self):
255 site.USER_BASE = None
256 user_base = site.getuserbase()
257
258 # the call sets site.USER_BASE
259 self.assertEqual(site.USER_BASE, user_base)
260
261 # let's set PYTHONUSERBASE and see if it uses it
262 site.USER_BASE = None
263 import sysconfig
264 sysconfig._CONFIG_VARS = None
265
266 with EnvironmentVarGuard() as environ:
267 environ['PYTHONUSERBASE'] = 'xoxo'
268 self.assertTrue(site.getuserbase().startswith('xoxo'),
269 site.getuserbase())
270
271 @unittest.skipUnless(HAS_USER_SITE, 'need user site')
272 def test_getusersitepackages(self):
273 site.USER_SITE = None
274 site.USER_BASE = None
275 user_site = site.getusersitepackages()
276
277 # the call sets USER_BASE *and* USER_SITE
278 self.assertEqual(site.USER_SITE, user_site)
279 self.assertTrue(user_site.startswith(site.USER_BASE), user_site)
280 self.assertEqual(site.USER_BASE, site.getuserbase())
281
282 def test_getsitepackages(self):
283 site.PREFIXES = ['xoxo']
284 dirs = site.getsitepackages()
285 if os.sep == '/':
286 # OS X, Linux, FreeBSD, etc
287 if sys.platlibdir != "lib":
288 self.assertEqual(len(dirs), 2)
289 wanted = os.path.join('xoxo', sys.platlibdir,
290 'python%d.%d' % sys.version_info[:2],
291 'site-packages')
292 self.assertEqual(dirs[0], wanted)
293 else:
294 self.assertEqual(len(dirs), 1)
295 wanted = os.path.join('xoxo', 'lib',
296 'python%d.%d' % sys.version_info[:2],
297 'site-packages')
298 self.assertEqual(dirs[-1], wanted)
299 else:
300 # other platforms
301 self.assertEqual(len(dirs), 2)
302 self.assertEqual(dirs[0], 'xoxo')
303 wanted = os.path.join('xoxo', 'lib', 'site-packages')
304 self.assertEqual(os.path.normcase(dirs[1]),
305 os.path.normcase(wanted))
306
307 @unittest.skipUnless(HAS_USER_SITE, 'need user site')
308 def test_no_home_directory(self):
309 # bpo-10496: getuserbase() and getusersitepackages() must not fail if
310 # the current user has no home directory (if expanduser() returns the
311 # path unchanged).
312 site.USER_SITE = None
313 site.USER_BASE = None
314
315 with EnvironmentVarGuard() as environ, \
316 mock.patch('os.path.expanduser', lambda path: path):
317
318 del environ['PYTHONUSERBASE']
319 del environ['APPDATA']
320
321 user_base = site.getuserbase()
322 self.assertTrue(user_base.startswith('~' + os.sep),
323 user_base)
324
325 user_site = site.getusersitepackages()
326 self.assertTrue(user_site.startswith(user_base), user_site)
327
328 with mock.patch('os.path.isdir', return_value=False) as mock_isdir, \
329 mock.patch.object(site, 'addsitedir') as mock_addsitedir, \
330 support.swap_attr(site, 'ENABLE_USER_SITE', True):
331
332 # addusersitepackages() must not add user_site to sys.path
333 # if it is not an existing directory
334 known_paths = set()
335 site.addusersitepackages(known_paths)
336
337 mock_isdir.assert_called_once_with(user_site)
338 mock_addsitedir.assert_not_called()
339 self.assertFalse(known_paths)
340
341 def test_trace(self):
342 message = "bla-bla-bla"
343 for verbose, out in (True, message + "\n"), (False, ""):
344 with mock.patch('sys.flags', mock.Mock(verbose=verbose)), \
345 mock.patch('sys.stderr', io.StringIO()):
346 site._trace(message)
347 self.assertEqual(sys.stderr.getvalue(), out)
348
349
350 class ESC[4;38;5;81mPthFile(ESC[4;38;5;149mobject):
351 """Helper class for handling testing of .pth files"""
352
353 def __init__(self, filename_base=TESTFN, imported="time",
354 good_dirname="__testdir__", bad_dirname="__bad"):
355 """Initialize instance variables"""
356 self.filename = filename_base + ".pth"
357 self.base_dir = os.path.abspath('')
358 self.file_path = os.path.join(self.base_dir, self.filename)
359 self.imported = imported
360 self.good_dirname = good_dirname
361 self.bad_dirname = bad_dirname
362 self.good_dir_path = os.path.join(self.base_dir, self.good_dirname)
363 self.bad_dir_path = os.path.join(self.base_dir, self.bad_dirname)
364
365 def create(self):
366 """Create a .pth file with a comment, blank lines, an ``import
367 <self.imported>``, a line with self.good_dirname, and a line with
368 self.bad_dirname.
369
370 Creation of the directory for self.good_dir_path (based off of
371 self.good_dirname) is also performed.
372
373 Make sure to call self.cleanup() to undo anything done by this method.
374
375 """
376 FILE = open(self.file_path, 'w')
377 try:
378 print("#import @bad module name", file=FILE)
379 print("\n", file=FILE)
380 print("import %s" % self.imported, file=FILE)
381 print(self.good_dirname, file=FILE)
382 print(self.bad_dirname, file=FILE)
383 finally:
384 FILE.close()
385 os.mkdir(self.good_dir_path)
386
387 def cleanup(self, prep=False):
388 """Make sure that the .pth file is deleted, self.imported is not in
389 sys.modules, and that both self.good_dirname and self.bad_dirname are
390 not existing directories."""
391 if os.path.exists(self.file_path):
392 os.remove(self.file_path)
393 if prep:
394 self.imported_module = sys.modules.get(self.imported)
395 if self.imported_module:
396 del sys.modules[self.imported]
397 else:
398 if self.imported_module:
399 sys.modules[self.imported] = self.imported_module
400 if os.path.exists(self.good_dir_path):
401 os.rmdir(self.good_dir_path)
402 if os.path.exists(self.bad_dir_path):
403 os.rmdir(self.bad_dir_path)
404
405 class ESC[4;38;5;81mImportSideEffectTests(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
406 """Test side-effects from importing 'site'."""
407
408 def setUp(self):
409 """Make a copy of sys.path"""
410 self.sys_path = sys.path[:]
411
412 def tearDown(self):
413 """Restore sys.path"""
414 sys.path[:] = self.sys_path
415
416 def test_abs_paths_cached_None(self):
417 """Test for __cached__ is None.
418
419 Regarding to PEP 3147, __cached__ can be None.
420
421 See also: https://bugs.python.org/issue30167
422 """
423 sys.modules['test'].__cached__ = None
424 site.abs_paths()
425 self.assertIsNone(sys.modules['test'].__cached__)
426
427 def test_no_duplicate_paths(self):
428 # No duplicate paths should exist in sys.path
429 # Handled by removeduppaths()
430 site.removeduppaths()
431 seen_paths = set()
432 for path in sys.path:
433 self.assertNotIn(path, seen_paths)
434 seen_paths.add(path)
435
436 @unittest.skip('test not implemented')
437 def test_add_build_dir(self):
438 # Test that the build directory's Modules directory is used when it
439 # should be.
440 # XXX: implement
441 pass
442
443 def test_setting_quit(self):
444 # 'quit' and 'exit' should be injected into builtins
445 self.assertTrue(hasattr(builtins, "quit"))
446 self.assertTrue(hasattr(builtins, "exit"))
447
448 def test_setting_copyright(self):
449 # 'copyright', 'credits', and 'license' should be in builtins
450 self.assertTrue(hasattr(builtins, "copyright"))
451 self.assertTrue(hasattr(builtins, "credits"))
452 self.assertTrue(hasattr(builtins, "license"))
453
454 def test_setting_help(self):
455 # 'help' should be set in builtins
456 self.assertTrue(hasattr(builtins, "help"))
457
458 def test_sitecustomize_executed(self):
459 # If sitecustomize is available, it should have been imported.
460 if "sitecustomize" not in sys.modules:
461 try:
462 import sitecustomize
463 except ImportError:
464 pass
465 else:
466 self.fail("sitecustomize not imported automatically")
467
468 @unittest.skipUnless(hasattr(urllib.request, "HTTPSHandler"),
469 'need SSL support to download license')
470 @test.support.requires_resource('network')
471 @test.support.system_must_validate_cert
472 def test_license_exists_at_url(self):
473 # This test is a bit fragile since it depends on the format of the
474 # string displayed by license in the absence of a LICENSE file.
475 url = license._Printer__data.split()[1]
476 req = urllib.request.Request(url, method='HEAD')
477 # Reset global urllib.request._opener
478 self.addCleanup(urllib.request.urlcleanup)
479 try:
480 with socket_helper.transient_internet(url):
481 with urllib.request.urlopen(req) as data:
482 code = data.getcode()
483 except urllib.error.HTTPError as e:
484 code = e.code
485 self.assertEqual(code, 200, msg="Can't find " + url)
486
487
488 class ESC[4;38;5;81mStartupImportTests(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
489
490 @support.requires_subprocess()
491 def test_startup_imports(self):
492 # Get sys.path in isolated mode (python3 -I)
493 popen = subprocess.Popen([sys.executable, '-X', 'utf8', '-I',
494 '-c', 'import sys; print(repr(sys.path))'],
495 stdout=subprocess.PIPE,
496 encoding='utf-8',
497 errors='surrogateescape')
498 stdout = popen.communicate()[0]
499 self.assertEqual(popen.returncode, 0, repr(stdout))
500 isolated_paths = ast.literal_eval(stdout)
501
502 # bpo-27807: Even with -I, the site module executes all .pth files
503 # found in sys.path (see site.addpackage()). Skip the test if at least
504 # one .pth file is found.
505 for path in isolated_paths:
506 pth_files = glob.glob(os.path.join(glob.escape(path), "*.pth"))
507 if pth_files:
508 self.skipTest(f"found {len(pth_files)} .pth files in: {path}")
509
510 # This tests checks which modules are loaded by Python when it
511 # initially starts upon startup.
512 popen = subprocess.Popen([sys.executable, '-X', 'utf8', '-I', '-v',
513 '-c', 'import sys; print(set(sys.modules))'],
514 stdout=subprocess.PIPE,
515 stderr=subprocess.PIPE,
516 encoding='utf-8',
517 errors='surrogateescape')
518 stdout, stderr = popen.communicate()
519 self.assertEqual(popen.returncode, 0, (stdout, stderr))
520 modules = ast.literal_eval(stdout)
521
522 self.assertIn('site', modules)
523
524 # http://bugs.python.org/issue19205
525 re_mods = {'re', '_sre', 're._compiler', 're._constants', 're._parser'}
526 self.assertFalse(modules.intersection(re_mods), stderr)
527
528 # http://bugs.python.org/issue9548
529 self.assertNotIn('locale', modules, stderr)
530
531 # http://bugs.python.org/issue19209
532 self.assertNotIn('copyreg', modules, stderr)
533
534 # http://bugs.python.org/issue19218
535 collection_mods = {'_collections', 'collections', 'functools',
536 'heapq', 'itertools', 'keyword', 'operator',
537 'reprlib', 'types', 'weakref'
538 }.difference(sys.builtin_module_names)
539 self.assertFalse(modules.intersection(collection_mods), stderr)
540
541 @support.requires_subprocess()
542 def test_startup_interactivehook(self):
543 r = subprocess.Popen([sys.executable, '-c',
544 'import sys; sys.exit(hasattr(sys, "__interactivehook__"))']).wait()
545 self.assertTrue(r, "'__interactivehook__' not added by site")
546
547 @support.requires_subprocess()
548 def test_startup_interactivehook_isolated(self):
549 # issue28192 readline is not automatically enabled in isolated mode
550 r = subprocess.Popen([sys.executable, '-I', '-c',
551 'import sys; sys.exit(hasattr(sys, "__interactivehook__"))']).wait()
552 self.assertFalse(r, "'__interactivehook__' added in isolated mode")
553
554 @support.requires_subprocess()
555 def test_startup_interactivehook_isolated_explicit(self):
556 # issue28192 readline can be explicitly enabled in isolated mode
557 r = subprocess.Popen([sys.executable, '-I', '-c',
558 'import site, sys; site.enablerlcompleter(); sys.exit(hasattr(sys, "__interactivehook__"))']).wait()
559 self.assertTrue(r, "'__interactivehook__' not added by enablerlcompleter()")
560
561 class ESC[4;38;5;81m_pthFileTests(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
562
563 if sys.platform == 'win32':
564 def _create_underpth_exe(self, lines, exe_pth=True):
565 import _winapi
566 temp_dir = tempfile.mkdtemp()
567 self.addCleanup(os_helper.rmtree, temp_dir)
568 exe_file = os.path.join(temp_dir, os.path.split(sys.executable)[1])
569 dll_src_file = _winapi.GetModuleFileName(sys.dllhandle)
570 dll_file = os.path.join(temp_dir, os.path.split(dll_src_file)[1])
571 shutil.copy(sys.executable, exe_file)
572 shutil.copy(dll_src_file, dll_file)
573 for fn in glob.glob(os.path.join(os.path.split(dll_src_file)[0], "vcruntime*.dll")):
574 shutil.copy(fn, os.path.join(temp_dir, os.path.split(fn)[1]))
575 if exe_pth:
576 _pth_file = os.path.splitext(exe_file)[0] + '._pth'
577 else:
578 _pth_file = os.path.splitext(dll_file)[0] + '._pth'
579 with open(_pth_file, 'w', encoding='utf8') as f:
580 for line in lines:
581 print(line, file=f)
582 return exe_file
583 else:
584 def _create_underpth_exe(self, lines, exe_pth=True):
585 if not exe_pth:
586 raise unittest.SkipTest("library ._pth file not supported on this platform")
587 temp_dir = tempfile.mkdtemp()
588 self.addCleanup(os_helper.rmtree, temp_dir)
589 exe_file = os.path.join(temp_dir, os.path.split(sys.executable)[1])
590 os.symlink(sys.executable, exe_file)
591 _pth_file = exe_file + '._pth'
592 with open(_pth_file, 'w') as f:
593 for line in lines:
594 print(line, file=f)
595 return exe_file
596
597 def _calc_sys_path_for_underpth_nosite(self, sys_prefix, lines):
598 sys_path = []
599 for line in lines:
600 if not line or line[0] == '#':
601 continue
602 abs_path = os.path.abspath(os.path.join(sys_prefix, line))
603 sys_path.append(abs_path)
604 return sys_path
605
606 @support.requires_subprocess()
607 def test_underpth_basic(self):
608 libpath = test.support.STDLIB_DIR
609 exe_prefix = os.path.dirname(sys.executable)
610 pth_lines = ['#.', '# ..', *sys.path, '.', '..']
611 exe_file = self._create_underpth_exe(pth_lines)
612 sys_path = self._calc_sys_path_for_underpth_nosite(
613 os.path.dirname(exe_file),
614 pth_lines)
615
616 output = subprocess.check_output([exe_file, '-X', 'utf8', '-c',
617 'import sys; print("\\n".join(sys.path) if sys.flags.no_site else "")'
618 ], encoding='utf-8', errors='surrogateescape')
619 actual_sys_path = output.rstrip().split('\n')
620 self.assertTrue(actual_sys_path, "sys.flags.no_site was False")
621 self.assertEqual(
622 actual_sys_path,
623 sys_path,
624 "sys.path is incorrect"
625 )
626
627 @support.requires_subprocess()
628 def test_underpth_nosite_file(self):
629 libpath = test.support.STDLIB_DIR
630 exe_prefix = os.path.dirname(sys.executable)
631 pth_lines = [
632 'fake-path-name',
633 *[libpath for _ in range(200)],
634 '',
635 '# comment',
636 ]
637 exe_file = self._create_underpth_exe(pth_lines)
638 sys_path = self._calc_sys_path_for_underpth_nosite(
639 os.path.dirname(exe_file),
640 pth_lines)
641
642 env = os.environ.copy()
643 env['PYTHONPATH'] = 'from-env'
644 env['PATH'] = '{}{}{}'.format(exe_prefix, os.pathsep, os.getenv('PATH'))
645 output = subprocess.check_output([exe_file, '-c',
646 'import sys; print("\\n".join(sys.path) if sys.flags.no_site else "")'
647 ], env=env, encoding='utf-8', errors='surrogateescape')
648 actual_sys_path = output.rstrip().split('\n')
649 self.assertTrue(actual_sys_path, "sys.flags.no_site was False")
650 self.assertEqual(
651 actual_sys_path,
652 sys_path,
653 "sys.path is incorrect"
654 )
655
656 @support.requires_subprocess()
657 def test_underpth_file(self):
658 libpath = test.support.STDLIB_DIR
659 exe_prefix = os.path.dirname(sys.executable)
660 exe_file = self._create_underpth_exe([
661 'fake-path-name',
662 *[libpath for _ in range(200)],
663 '',
664 '# comment',
665 'import site'
666 ])
667 sys_prefix = os.path.dirname(exe_file)
668 env = os.environ.copy()
669 env['PYTHONPATH'] = 'from-env'
670 env['PATH'] = '{};{}'.format(exe_prefix, os.getenv('PATH'))
671 rc = subprocess.call([exe_file, '-c',
672 'import sys; sys.exit(not sys.flags.no_site and '
673 '%r in sys.path and %r in sys.path and %r not in sys.path and '
674 'all("\\r" not in p and "\\n" not in p for p in sys.path))' % (
675 os.path.join(sys_prefix, 'fake-path-name'),
676 libpath,
677 os.path.join(sys_prefix, 'from-env'),
678 )], env=env)
679 self.assertTrue(rc, "sys.path is incorrect")
680
681 @support.requires_subprocess()
682 def test_underpth_dll_file(self):
683 libpath = test.support.STDLIB_DIR
684 exe_prefix = os.path.dirname(sys.executable)
685 exe_file = self._create_underpth_exe([
686 'fake-path-name',
687 *[libpath for _ in range(200)],
688 '',
689 '# comment',
690 'import site'
691 ], exe_pth=False)
692 sys_prefix = os.path.dirname(exe_file)
693 env = os.environ.copy()
694 env['PYTHONPATH'] = 'from-env'
695 env['PATH'] = '{};{}'.format(exe_prefix, os.getenv('PATH'))
696 rc = subprocess.call([exe_file, '-c',
697 'import sys; sys.exit(not sys.flags.no_site and '
698 '%r in sys.path and %r in sys.path and %r not in sys.path and '
699 'all("\\r" not in p and "\\n" not in p for p in sys.path))' % (
700 os.path.join(sys_prefix, 'fake-path-name'),
701 libpath,
702 os.path.join(sys_prefix, 'from-env'),
703 )], env=env)
704 self.assertTrue(rc, "sys.path is incorrect")
705
706
707 if __name__ == "__main__":
708 unittest.main()