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