1"""Tests for 'site'. 2 3Tests assume the initial paths in sys.path once the interpreter has begun 4executing have not been removed. 5 6""" 7import unittest 8import test.support 9from test import support 10from test.support import os_helper 11from test.support import socket_helper 12from test.support import captured_stderr 13from test.support.os_helper import TESTFN, EnvironmentVarGuard, change_cwd 14import ast 15import builtins 16import encodings 17import glob 18import io 19import os 20import re 21import shutil 22import subprocess 23import sys 24import sysconfig 25import tempfile 26import urllib.error 27import urllib.request 28from unittest import mock 29from 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. 34if sys.flags.no_site: 35 raise unittest.SkipTest("Python was invoked with -S") 36 37import site 38 39 40HAS_USER_SITE = (site.USER_SITE is not None) 41OLD_SYS_PATH = None 42 43 44def 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 59def tearDownModule(): 60 sys.path[:] = OLD_SYS_PATH 61 62 63class HelperFunctionsTests(unittest.TestCase): 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 351class PthFile(object): 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 406class ImportSideEffectTests(unittest.TestCase): 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 @test.support.requires_resource('network') 470 @test.support.system_must_validate_cert 471 @unittest.skipUnless(hasattr(urllib.request, "HTTPSHandler"), 472 'need SSL support to download license') 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 489class StartupImportTests(unittest.TestCase): 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 562class _pthFileTests(unittest.TestCase): 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') 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, '-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 708if __name__ == "__main__": 709 unittest.main() 710