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