1import errno 2import importlib 3import io 4import os 5import shutil 6import socket 7import stat 8import subprocess 9import sys 10import sysconfig 11import tempfile 12import textwrap 13import unittest 14import warnings 15 16from test import support 17from test.support import import_helper 18from test.support import os_helper 19from test.support import script_helper 20from test.support import socket_helper 21from test.support import warnings_helper 22 23TESTFN = os_helper.TESTFN 24 25 26class TestSupport(unittest.TestCase): 27 @classmethod 28 def setUpClass(cls): 29 orig_filter_len = len(warnings.filters) 30 cls._warnings_helper_token = support.ignore_deprecations_from( 31 "test.support.warnings_helper", like=".*used in test_support.*" 32 ) 33 cls._test_support_token = support.ignore_deprecations_from( 34 __name__, like=".*You should NOT be seeing this.*" 35 ) 36 assert len(warnings.filters) == orig_filter_len + 2 37 38 @classmethod 39 def tearDownClass(cls): 40 orig_filter_len = len(warnings.filters) 41 support.clear_ignored_deprecations( 42 cls._warnings_helper_token, 43 cls._test_support_token, 44 ) 45 assert len(warnings.filters) == orig_filter_len - 2 46 47 def test_ignored_deprecations_are_silent(self): 48 """Test support.ignore_deprecations_from() silences warnings""" 49 with warnings.catch_warnings(record=True) as warning_objs: 50 warnings_helper._warn_about_deprecation() 51 warnings.warn("You should NOT be seeing this.", DeprecationWarning) 52 messages = [str(w.message) for w in warning_objs] 53 self.assertEqual(len(messages), 0, messages) 54 55 def test_import_module(self): 56 import_helper.import_module("ftplib") 57 self.assertRaises(unittest.SkipTest, 58 import_helper.import_module, "foo") 59 60 def test_import_fresh_module(self): 61 import_helper.import_fresh_module("ftplib") 62 63 def test_get_attribute(self): 64 self.assertEqual(support.get_attribute(self, "test_get_attribute"), 65 self.test_get_attribute) 66 self.assertRaises(unittest.SkipTest, support.get_attribute, self, "foo") 67 68 @unittest.skip("failing buildbots") 69 def test_get_original_stdout(self): 70 self.assertEqual(support.get_original_stdout(), sys.stdout) 71 72 def test_unload(self): 73 import sched 74 self.assertIn("sched", sys.modules) 75 import_helper.unload("sched") 76 self.assertNotIn("sched", sys.modules) 77 78 def test_unlink(self): 79 with open(TESTFN, "w", encoding="utf-8") as f: 80 pass 81 os_helper.unlink(TESTFN) 82 self.assertFalse(os.path.exists(TESTFN)) 83 os_helper.unlink(TESTFN) 84 85 def test_rmtree(self): 86 dirpath = os_helper.TESTFN + 'd' 87 subdirpath = os.path.join(dirpath, 'subdir') 88 os.mkdir(dirpath) 89 os.mkdir(subdirpath) 90 os_helper.rmtree(dirpath) 91 self.assertFalse(os.path.exists(dirpath)) 92 with support.swap_attr(support, 'verbose', 0): 93 os_helper.rmtree(dirpath) 94 95 os.mkdir(dirpath) 96 os.mkdir(subdirpath) 97 os.chmod(dirpath, stat.S_IRUSR|stat.S_IXUSR) 98 with support.swap_attr(support, 'verbose', 0): 99 os_helper.rmtree(dirpath) 100 self.assertFalse(os.path.exists(dirpath)) 101 102 os.mkdir(dirpath) 103 os.mkdir(subdirpath) 104 os.chmod(dirpath, 0) 105 with support.swap_attr(support, 'verbose', 0): 106 os_helper.rmtree(dirpath) 107 self.assertFalse(os.path.exists(dirpath)) 108 109 def test_forget(self): 110 mod_filename = TESTFN + '.py' 111 with open(mod_filename, 'w', encoding="utf-8") as f: 112 print('foo = 1', file=f) 113 sys.path.insert(0, os.curdir) 114 importlib.invalidate_caches() 115 try: 116 mod = __import__(TESTFN) 117 self.assertIn(TESTFN, sys.modules) 118 119 import_helper.forget(TESTFN) 120 self.assertNotIn(TESTFN, sys.modules) 121 finally: 122 del sys.path[0] 123 os_helper.unlink(mod_filename) 124 os_helper.rmtree('__pycache__') 125 126 @support.requires_working_socket() 127 def test_HOST(self): 128 s = socket.create_server((socket_helper.HOST, 0)) 129 s.close() 130 131 @support.requires_working_socket() 132 def test_find_unused_port(self): 133 port = socket_helper.find_unused_port() 134 s = socket.create_server((socket_helper.HOST, port)) 135 s.close() 136 137 @support.requires_working_socket() 138 def test_bind_port(self): 139 s = socket.socket() 140 socket_helper.bind_port(s) 141 s.listen() 142 s.close() 143 144 # Tests for temp_dir() 145 146 def test_temp_dir(self): 147 """Test that temp_dir() creates and destroys its directory.""" 148 parent_dir = tempfile.mkdtemp() 149 parent_dir = os.path.realpath(parent_dir) 150 151 try: 152 path = os.path.join(parent_dir, 'temp') 153 self.assertFalse(os.path.isdir(path)) 154 with os_helper.temp_dir(path) as temp_path: 155 self.assertEqual(temp_path, path) 156 self.assertTrue(os.path.isdir(path)) 157 self.assertFalse(os.path.isdir(path)) 158 finally: 159 os_helper.rmtree(parent_dir) 160 161 def test_temp_dir__path_none(self): 162 """Test passing no path.""" 163 with os_helper.temp_dir() as temp_path: 164 self.assertTrue(os.path.isdir(temp_path)) 165 self.assertFalse(os.path.isdir(temp_path)) 166 167 def test_temp_dir__existing_dir__quiet_default(self): 168 """Test passing a directory that already exists.""" 169 def call_temp_dir(path): 170 with os_helper.temp_dir(path) as temp_path: 171 raise Exception("should not get here") 172 173 path = tempfile.mkdtemp() 174 path = os.path.realpath(path) 175 try: 176 self.assertTrue(os.path.isdir(path)) 177 self.assertRaises(FileExistsError, call_temp_dir, path) 178 # Make sure temp_dir did not delete the original directory. 179 self.assertTrue(os.path.isdir(path)) 180 finally: 181 shutil.rmtree(path) 182 183 def test_temp_dir__existing_dir__quiet_true(self): 184 """Test passing a directory that already exists with quiet=True.""" 185 path = tempfile.mkdtemp() 186 path = os.path.realpath(path) 187 188 try: 189 with warnings_helper.check_warnings() as recorder: 190 with os_helper.temp_dir(path, quiet=True) as temp_path: 191 self.assertEqual(path, temp_path) 192 warnings = [str(w.message) for w in recorder.warnings] 193 # Make sure temp_dir did not delete the original directory. 194 self.assertTrue(os.path.isdir(path)) 195 finally: 196 shutil.rmtree(path) 197 198 self.assertEqual(len(warnings), 1, warnings) 199 warn = warnings[0] 200 self.assertTrue(warn.startswith(f'tests may fail, unable to create ' 201 f'temporary directory {path!r}: '), 202 warn) 203 204 @support.requires_fork() 205 def test_temp_dir__forked_child(self): 206 """Test that a forked child process does not remove the directory.""" 207 # See bpo-30028 for details. 208 # Run the test as an external script, because it uses fork. 209 script_helper.assert_python_ok("-c", textwrap.dedent(""" 210 import os 211 from test import support 212 from test.support import os_helper 213 with os_helper.temp_cwd() as temp_path: 214 pid = os.fork() 215 if pid != 0: 216 # parent process 217 218 # wait for the child to terminate 219 support.wait_process(pid, exitcode=0) 220 221 # Make sure that temp_path is still present. When the child 222 # process leaves the 'temp_cwd'-context, the __exit__()- 223 # method of the context must not remove the temporary 224 # directory. 225 if not os.path.isdir(temp_path): 226 raise AssertionError("Child removed temp_path.") 227 """)) 228 229 # Tests for change_cwd() 230 231 def test_change_cwd(self): 232 original_cwd = os.getcwd() 233 234 with os_helper.temp_dir() as temp_path: 235 with os_helper.change_cwd(temp_path) as new_cwd: 236 self.assertEqual(new_cwd, temp_path) 237 self.assertEqual(os.getcwd(), new_cwd) 238 239 self.assertEqual(os.getcwd(), original_cwd) 240 241 def test_change_cwd__non_existent_dir(self): 242 """Test passing a non-existent directory.""" 243 original_cwd = os.getcwd() 244 245 def call_change_cwd(path): 246 with os_helper.change_cwd(path) as new_cwd: 247 raise Exception("should not get here") 248 249 with os_helper.temp_dir() as parent_dir: 250 non_existent_dir = os.path.join(parent_dir, 'does_not_exist') 251 self.assertRaises(FileNotFoundError, call_change_cwd, 252 non_existent_dir) 253 254 self.assertEqual(os.getcwd(), original_cwd) 255 256 def test_change_cwd__non_existent_dir__quiet_true(self): 257 """Test passing a non-existent directory with quiet=True.""" 258 original_cwd = os.getcwd() 259 260 with os_helper.temp_dir() as parent_dir: 261 bad_dir = os.path.join(parent_dir, 'does_not_exist') 262 with warnings_helper.check_warnings() as recorder: 263 with os_helper.change_cwd(bad_dir, quiet=True) as new_cwd: 264 self.assertEqual(new_cwd, original_cwd) 265 self.assertEqual(os.getcwd(), new_cwd) 266 warnings = [str(w.message) for w in recorder.warnings] 267 268 self.assertEqual(len(warnings), 1, warnings) 269 warn = warnings[0] 270 self.assertTrue(warn.startswith(f'tests may fail, unable to change ' 271 f'the current working directory ' 272 f'to {bad_dir!r}: '), 273 warn) 274 275 # Tests for change_cwd() 276 277 def test_change_cwd__chdir_warning(self): 278 """Check the warning message when os.chdir() fails.""" 279 path = TESTFN + '_does_not_exist' 280 with warnings_helper.check_warnings() as recorder: 281 with os_helper.change_cwd(path=path, quiet=True): 282 pass 283 messages = [str(w.message) for w in recorder.warnings] 284 285 self.assertEqual(len(messages), 1, messages) 286 msg = messages[0] 287 self.assertTrue(msg.startswith(f'tests may fail, unable to change ' 288 f'the current working directory ' 289 f'to {path!r}: '), 290 msg) 291 292 # Tests for temp_cwd() 293 294 def test_temp_cwd(self): 295 here = os.getcwd() 296 with os_helper.temp_cwd(name=TESTFN): 297 self.assertEqual(os.path.basename(os.getcwd()), TESTFN) 298 self.assertFalse(os.path.exists(TESTFN)) 299 self.assertEqual(os.getcwd(), here) 300 301 302 def test_temp_cwd__name_none(self): 303 """Test passing None to temp_cwd().""" 304 original_cwd = os.getcwd() 305 with os_helper.temp_cwd(name=None) as new_cwd: 306 self.assertNotEqual(new_cwd, original_cwd) 307 self.assertTrue(os.path.isdir(new_cwd)) 308 self.assertEqual(os.getcwd(), new_cwd) 309 self.assertEqual(os.getcwd(), original_cwd) 310 311 def test_sortdict(self): 312 self.assertEqual(support.sortdict({3:3, 2:2, 1:1}), "{1: 1, 2: 2, 3: 3}") 313 314 def test_make_bad_fd(self): 315 fd = os_helper.make_bad_fd() 316 with self.assertRaises(OSError) as cm: 317 os.write(fd, b"foo") 318 self.assertEqual(cm.exception.errno, errno.EBADF) 319 320 def test_check_syntax_error(self): 321 support.check_syntax_error(self, "def class", lineno=1, offset=5) 322 with self.assertRaises(AssertionError): 323 support.check_syntax_error(self, "x=1") 324 325 def test_CleanImport(self): 326 import importlib 327 with import_helper.CleanImport("pprint"): 328 importlib.import_module("pprint") 329 330 def test_DirsOnSysPath(self): 331 with import_helper.DirsOnSysPath('foo', 'bar'): 332 self.assertIn("foo", sys.path) 333 self.assertIn("bar", sys.path) 334 self.assertNotIn("foo", sys.path) 335 self.assertNotIn("bar", sys.path) 336 337 def test_captured_stdout(self): 338 with support.captured_stdout() as stdout: 339 print("hello") 340 self.assertEqual(stdout.getvalue(), "hello\n") 341 342 def test_captured_stderr(self): 343 with support.captured_stderr() as stderr: 344 print("hello", file=sys.stderr) 345 self.assertEqual(stderr.getvalue(), "hello\n") 346 347 def test_captured_stdin(self): 348 with support.captured_stdin() as stdin: 349 stdin.write('hello\n') 350 stdin.seek(0) 351 # call test code that consumes from sys.stdin 352 captured = input() 353 self.assertEqual(captured, "hello") 354 355 def test_gc_collect(self): 356 support.gc_collect() 357 358 def test_python_is_optimized(self): 359 self.assertIsInstance(support.python_is_optimized(), bool) 360 361 def test_swap_attr(self): 362 class Obj: 363 pass 364 obj = Obj() 365 obj.x = 1 366 with support.swap_attr(obj, "x", 5) as x: 367 self.assertEqual(obj.x, 5) 368 self.assertEqual(x, 1) 369 self.assertEqual(obj.x, 1) 370 with support.swap_attr(obj, "y", 5) as y: 371 self.assertEqual(obj.y, 5) 372 self.assertIsNone(y) 373 self.assertFalse(hasattr(obj, 'y')) 374 with support.swap_attr(obj, "y", 5): 375 del obj.y 376 self.assertFalse(hasattr(obj, 'y')) 377 378 def test_swap_item(self): 379 D = {"x":1} 380 with support.swap_item(D, "x", 5) as x: 381 self.assertEqual(D["x"], 5) 382 self.assertEqual(x, 1) 383 self.assertEqual(D["x"], 1) 384 with support.swap_item(D, "y", 5) as y: 385 self.assertEqual(D["y"], 5) 386 self.assertIsNone(y) 387 self.assertNotIn("y", D) 388 with support.swap_item(D, "y", 5): 389 del D["y"] 390 self.assertNotIn("y", D) 391 392 class RefClass: 393 attribute1 = None 394 attribute2 = None 395 _hidden_attribute1 = None 396 __magic_1__ = None 397 398 class OtherClass: 399 attribute2 = None 400 attribute3 = None 401 __magic_1__ = None 402 __magic_2__ = None 403 404 def test_detect_api_mismatch(self): 405 missing_items = support.detect_api_mismatch(self.RefClass, 406 self.OtherClass) 407 self.assertEqual({'attribute1'}, missing_items) 408 409 missing_items = support.detect_api_mismatch(self.OtherClass, 410 self.RefClass) 411 self.assertEqual({'attribute3', '__magic_2__'}, missing_items) 412 413 def test_detect_api_mismatch__ignore(self): 414 ignore = ['attribute1', 'attribute3', '__magic_2__', 'not_in_either'] 415 416 missing_items = support.detect_api_mismatch( 417 self.RefClass, self.OtherClass, ignore=ignore) 418 self.assertEqual(set(), missing_items) 419 420 missing_items = support.detect_api_mismatch( 421 self.OtherClass, self.RefClass, ignore=ignore) 422 self.assertEqual(set(), missing_items) 423 424 def test_check__all__(self): 425 extra = {'tempdir'} 426 not_exported = {'template'} 427 support.check__all__(self, 428 tempfile, 429 extra=extra, 430 not_exported=not_exported) 431 432 extra = { 433 'TextTestResult', 434 'installHandler', 435 } 436 not_exported = {'load_tests', "TestProgram", "BaseTestSuite"} 437 support.check__all__(self, 438 unittest, 439 ("unittest.result", "unittest.case", 440 "unittest.suite", "unittest.loader", 441 "unittest.main", "unittest.runner", 442 "unittest.signals", "unittest.async_case"), 443 extra=extra, 444 not_exported=not_exported) 445 446 self.assertRaises(AssertionError, support.check__all__, self, unittest) 447 448 @unittest.skipUnless(hasattr(os, 'waitpid') and hasattr(os, 'WNOHANG'), 449 'need os.waitpid() and os.WNOHANG') 450 @support.requires_fork() 451 def test_reap_children(self): 452 # Make sure that there is no other pending child process 453 support.reap_children() 454 455 # Create a child process 456 pid = os.fork() 457 if pid == 0: 458 # child process: do nothing, just exit 459 os._exit(0) 460 461 was_altered = support.environment_altered 462 try: 463 support.environment_altered = False 464 stderr = io.StringIO() 465 466 for _ in support.sleeping_retry(support.SHORT_TIMEOUT): 467 with support.swap_attr(support.print_warning, 'orig_stderr', stderr): 468 support.reap_children() 469 470 # Use environment_altered to check if reap_children() found 471 # the child process 472 if support.environment_altered: 473 break 474 475 msg = "Warning -- reap_children() reaped child process %s" % pid 476 self.assertIn(msg, stderr.getvalue()) 477 self.assertTrue(support.environment_altered) 478 finally: 479 support.environment_altered = was_altered 480 481 # Just in case, check again that there is no other 482 # pending child process 483 support.reap_children() 484 485 @support.requires_subprocess() 486 def check_options(self, args, func, expected=None): 487 code = f'from test.support import {func}; print(repr({func}()))' 488 cmd = [sys.executable, *args, '-c', code] 489 env = {key: value for key, value in os.environ.items() 490 if not key.startswith('PYTHON')} 491 proc = subprocess.run(cmd, 492 stdout=subprocess.PIPE, 493 stderr=subprocess.DEVNULL, 494 universal_newlines=True, 495 env=env) 496 if expected is None: 497 expected = args 498 self.assertEqual(proc.stdout.rstrip(), repr(expected)) 499 self.assertEqual(proc.returncode, 0) 500 501 @support.requires_resource('cpu') 502 def test_args_from_interpreter_flags(self): 503 # Test test.support.args_from_interpreter_flags() 504 for opts in ( 505 # no option 506 [], 507 # single option 508 ['-B'], 509 ['-s'], 510 ['-S'], 511 ['-E'], 512 ['-v'], 513 ['-b'], 514 ['-P'], 515 ['-q'], 516 ['-I'], 517 # same option multiple times 518 ['-bb'], 519 ['-vvv'], 520 # -W options 521 ['-Wignore'], 522 # -X options 523 ['-X', 'dev'], 524 ['-Wignore', '-X', 'dev'], 525 ['-X', 'faulthandler'], 526 ['-X', 'importtime'], 527 ['-X', 'showrefcount'], 528 ['-X', 'tracemalloc'], 529 ['-X', 'tracemalloc=3'], 530 ): 531 with self.subTest(opts=opts): 532 self.check_options(opts, 'args_from_interpreter_flags') 533 534 self.check_options(['-I', '-E', '-s', '-P'], 535 'args_from_interpreter_flags', 536 ['-I']) 537 538 def test_optim_args_from_interpreter_flags(self): 539 # Test test.support.optim_args_from_interpreter_flags() 540 for opts in ( 541 # no option 542 [], 543 ['-O'], 544 ['-OO'], 545 ['-OOOO'], 546 ): 547 with self.subTest(opts=opts): 548 self.check_options(opts, 'optim_args_from_interpreter_flags') 549 550 @unittest.skipIf(support.is_apple_mobile, "Unstable on Apple Mobile") 551 @unittest.skipIf(support.is_emscripten, "Unstable in Emscripten") 552 @unittest.skipIf(support.is_wasi, "Unavailable on WASI") 553 def test_fd_count(self): 554 # We cannot test the absolute value of fd_count(): on old Linux kernel 555 # or glibc versions, os.urandom() keeps a FD open on /dev/urandom 556 # device and Python has 4 FD opens instead of 3. Test is unstable on 557 # Emscripten and Apple Mobile platforms; these platforms start and stop 558 # background threads that use pipes and epoll fds. 559 start = os_helper.fd_count() 560 fd = os.open(__file__, os.O_RDONLY) 561 try: 562 more = os_helper.fd_count() 563 finally: 564 os.close(fd) 565 self.assertEqual(more - start, 1) 566 567 def check_print_warning(self, msg, expected): 568 stderr = io.StringIO() 569 with support.swap_attr(support.print_warning, 'orig_stderr', stderr): 570 support.print_warning(msg) 571 self.assertEqual(stderr.getvalue(), expected) 572 573 def test_print_warning(self): 574 self.check_print_warning("msg", 575 "Warning -- msg\n") 576 self.check_print_warning("a\nb", 577 'Warning -- a\nWarning -- b\n') 578 579 def test_has_strftime_extensions(self): 580 if support.is_emscripten or sys.platform == "win32": 581 self.assertFalse(support.has_strftime_extensions) 582 else: 583 self.assertTrue(support.has_strftime_extensions) 584 585 def test_get_recursion_depth(self): 586 # test support.get_recursion_depth() 587 code = textwrap.dedent(""" 588 from test import support 589 import sys 590 591 def check(cond): 592 if not cond: 593 raise AssertionError("test failed") 594 595 # depth 1 596 check(support.get_recursion_depth() == 1) 597 598 # depth 2 599 def test_func(): 600 check(support.get_recursion_depth() == 2) 601 test_func() 602 603 def test_recursive(depth, limit): 604 if depth >= limit: 605 # cannot call get_recursion_depth() at this depth, 606 # it can raise RecursionError 607 return 608 get_depth = support.get_recursion_depth() 609 print(f"test_recursive: {depth}/{limit}: " 610 f"get_recursion_depth() says {get_depth}") 611 check(get_depth == depth) 612 test_recursive(depth + 1, limit) 613 614 # depth up to 25 615 with support.infinite_recursion(max_depth=25): 616 limit = sys.getrecursionlimit() 617 print(f"test with sys.getrecursionlimit()={limit}") 618 test_recursive(2, limit) 619 620 # depth up to 500 621 with support.infinite_recursion(max_depth=500): 622 limit = sys.getrecursionlimit() 623 print(f"test with sys.getrecursionlimit()={limit}") 624 test_recursive(2, limit) 625 """) 626 script_helper.assert_python_ok("-c", code) 627 628 def test_recursion(self): 629 # Test infinite_recursion() and get_recursion_available() functions. 630 def recursive_function(depth): 631 if depth: 632 recursive_function(depth - 1) 633 634 for max_depth in (5, 25, 250, 2500): 635 with support.infinite_recursion(max_depth): 636 available = support.get_recursion_available() 637 638 # Recursion up to 'available' additional frames should be OK. 639 recursive_function(available) 640 641 # Recursion up to 'available+1' additional frames must raise 642 # RecursionError. Avoid self.assertRaises(RecursionError) which 643 # can consume more than 3 frames and so raises RecursionError. 644 try: 645 recursive_function(available + 1) 646 except RecursionError: 647 pass 648 else: 649 self.fail("RecursionError was not raised") 650 651 # Test the bare minimumum: max_depth=3 652 with support.infinite_recursion(3): 653 try: 654 recursive_function(3) 655 except RecursionError: 656 pass 657 else: 658 self.fail("RecursionError was not raised") 659 660 def test_parse_memlimit(self): 661 parse = support._parse_memlimit 662 KiB = 1024 663 MiB = KiB * 1024 664 GiB = MiB * 1024 665 TiB = GiB * 1024 666 self.assertEqual(parse('0k'), 0) 667 self.assertEqual(parse('3k'), 3 * KiB) 668 self.assertEqual(parse('2.4m'), int(2.4 * MiB)) 669 self.assertEqual(parse('4g'), int(4 * GiB)) 670 self.assertEqual(parse('1t'), TiB) 671 672 for limit in ('', '3', '3.5.10k', '10x'): 673 with self.subTest(limit=limit): 674 with self.assertRaises(ValueError): 675 parse(limit) 676 677 def test_set_memlimit(self): 678 _4GiB = 4 * 1024 ** 3 679 TiB = 1024 ** 4 680 old_max_memuse = support.max_memuse 681 old_real_max_memuse = support.real_max_memuse 682 try: 683 if sys.maxsize > 2**32: 684 support.set_memlimit('4g') 685 self.assertEqual(support.max_memuse, _4GiB) 686 self.assertEqual(support.real_max_memuse, _4GiB) 687 688 big = 2**100 // TiB 689 support.set_memlimit(f'{big}t') 690 self.assertEqual(support.max_memuse, sys.maxsize) 691 self.assertEqual(support.real_max_memuse, big * TiB) 692 else: 693 support.set_memlimit('4g') 694 self.assertEqual(support.max_memuse, sys.maxsize) 695 self.assertEqual(support.real_max_memuse, _4GiB) 696 finally: 697 support.max_memuse = old_max_memuse 698 support.real_max_memuse = old_real_max_memuse 699 700 def test_copy_python_src_ignore(self): 701 # Get source directory 702 src_dir = sysconfig.get_config_var('abs_srcdir') 703 if not src_dir: 704 src_dir = sysconfig.get_config_var('srcdir') 705 src_dir = os.path.abspath(src_dir) 706 707 # Check that the source code is available 708 if not os.path.exists(src_dir): 709 self.skipTest(f"cannot access Python source code directory:" 710 f" {src_dir!r}") 711 # Check that the landmark copy_python_src_ignore() expects is available 712 # (Previously we looked for 'Lib\os.py', which is always present on Windows.) 713 landmark = os.path.join(src_dir, 'Modules') 714 if not os.path.exists(landmark): 715 self.skipTest(f"cannot access Python source code directory:" 716 f" {landmark!r} landmark is missing") 717 718 # Test support.copy_python_src_ignore() 719 720 # Source code directory 721 ignored = {'.git', '__pycache__'} 722 names = os.listdir(src_dir) 723 self.assertEqual(support.copy_python_src_ignore(src_dir, names), 724 ignored | {'build'}) 725 726 # Doc/ directory 727 path = os.path.join(src_dir, 'Doc') 728 self.assertEqual(support.copy_python_src_ignore(path, os.listdir(path)), 729 ignored | {'build', 'venv'}) 730 731 # Another directory 732 path = os.path.join(src_dir, 'Objects') 733 self.assertEqual(support.copy_python_src_ignore(path, os.listdir(path)), 734 ignored) 735 736 # XXX -follows a list of untested API 737 # make_legacy_pyc 738 # is_resource_enabled 739 # requires 740 # fcmp 741 # umaks 742 # findfile 743 # check_warnings 744 # EnvironmentVarGuard 745 # transient_internet 746 # run_with_locale 747 # bigmemtest 748 # precisionbigmemtest 749 # bigaddrspacetest 750 # requires_resource 751 # threading_cleanup 752 # reap_threads 753 # can_symlink 754 # skip_unless_symlink 755 # SuppressCrashReport 756 757 758if __name__ == '__main__': 759 unittest.main() 760