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