• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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