1#! /usr/bin/env python
2
3"""
4Usage:
5
6python -m test.regrtest [options] [test_name1 [test_name2 ...]]
7python path/to/Lib/test/regrtest.py [options] [test_name1 [test_name2 ...]]
8
9
10If no arguments or options are provided, finds all files matching
11the pattern "test_*" in the Lib/test subdirectory and runs
12them in alphabetical order (but see -M and -u, below, for exceptions).
13
14For more rigorous testing, it is useful to use the following
15command line:
16
17python -E -tt -Wd -3 -m test.regrtest [options] [test_name1 ...]
18
19
20Options:
21
22-h/--help       -- print this text and exit
23
24Verbosity
25
26-v/--verbose    -- run tests in verbose mode with output to stdout
27-w/--verbose2   -- re-run failed tests in verbose mode
28-W/--verbose3   -- re-run failed tests in verbose mode immediately
29-q/--quiet      -- no output unless one or more tests fail
30-S/--slow       -- print the slowest 10 tests
31   --header     -- print header with interpreter info
32
33Selecting tests
34
35-r/--randomize  -- randomize test execution order (see below)
36   --randseed   -- pass a random seed to reproduce a previous random run
37-f/--fromfile   -- read names of tests to run from a file (see below)
38-x/--exclude    -- arguments are tests to *exclude*
39-s/--single     -- single step through a set of tests (see below)
40-u/--use RES1,RES2,...
41                -- specify which special resource intensive tests to run
42-M/--memlimit LIMIT
43                -- run very large memory-consuming tests
44
45Special runs
46
47-l/--findleaks  -- if GC is available detect tests that leak memory
48-L/--runleaks   -- run the leaks(1) command just before exit
49-R/--huntrleaks RUNCOUNTS
50                -- search for reference leaks (needs debug build, v. slow)
51-j/--multiprocess PROCESSES
52                -- run PROCESSES processes at once
53-T/--coverage   -- turn on code coverage tracing using the trace module
54-D/--coverdir DIRECTORY
55                -- Directory where coverage files are put
56-N/--nocoverdir -- Put coverage files alongside modules
57-t/--threshold THRESHOLD
58                -- call gc.set_threshold(THRESHOLD)
59-F/--forever    -- run the specified tests in a loop, until an error happens
60
61
62Additional Option Details:
63
64-r randomizes test execution order. You can use --randseed=int to provide a
65int seed value for the randomizer; this is useful for reproducing troublesome
66test orders.
67
68-s On the first invocation of regrtest using -s, the first test file found
69or the first test file given on the command line is run, and the name of
70the next test is recorded in a file named pynexttest.  If run from the
71Python build directory, pynexttest is located in the 'build' subdirectory,
72otherwise it is located in tempfile.gettempdir().  On subsequent runs,
73the test in pynexttest is run, and the next test is written to pynexttest.
74When the last test has been run, pynexttest is deleted.  In this way it
75is possible to single step through the test files.  This is useful when
76doing memory analysis on the Python interpreter, which process tends to
77consume too many resources to run the full regression test non-stop.
78
79-f reads the names of tests from the file given as f's argument, one
80or more test names per line.  Whitespace is ignored.  Blank lines and
81lines beginning with '#' are ignored.  This is especially useful for
82whittling down failures involving interactions among tests.
83
84-L causes the leaks(1) command to be run just before exit if it exists.
85leaks(1) is available on Mac OS X and presumably on some other
86FreeBSD-derived systems.
87
88-R runs each test several times and examines sys.gettotalrefcount() to
89see if the test appears to be leaking references.  The argument should
90be of the form stab:run:fname where 'stab' is the number of times the
91test is run to let gettotalrefcount settle down, 'run' is the number
92of times further it is run and 'fname' is the name of the file the
93reports are written to.  These parameters all have defaults (5, 4 and
94"reflog.txt" respectively), and the minimal invocation is '-R :'.
95
96-M runs tests that require an exorbitant amount of memory. These tests
97typically try to ascertain containers keep working when containing more than
982 billion objects, which only works on 64-bit systems. There are also some
99tests that try to exhaust the address space of the process, which only makes
100sense on 32-bit systems with at least 2Gb of memory. The passed-in memlimit,
101which is a string in the form of '2.5Gb', determines howmuch memory the
102tests will limit themselves to (but they may go slightly over.) The number
103shouldn't be more memory than the machine has (including swap memory). You
104should also keep in mind that swap memory is generally much, much slower
105than RAM, and setting memlimit to all available RAM or higher will heavily
106tax the machine. On the other hand, it is no use running these tests with a
107limit of less than 2.5Gb, and many require more than 20Gb. Tests that expect
108to use more than memlimit memory will be skipped. The big-memory tests
109generally run very, very long.
110
111-u is used to specify which special resource intensive tests to run,
112such as those requiring large file support or network connectivity.
113The argument is a comma-separated list of words indicating the
114resources to test.  Currently only the following are defined:
115
116    all -       Enable all special resources.
117
118    audio -     Tests that use the audio device.  (There are known
119                cases of broken audio drivers that can crash Python or
120                even the Linux kernel.)
121
122    curses -    Tests that use curses and will modify the terminal's
123                state and output modes.
124
125    largefile - It is okay to run some test that may create huge
126                files.  These tests can take a long time and may
127                consume >2GB of disk space temporarily.
128
129    network -   It is okay to run tests that use external network
130                resource, e.g. testing SSL support for sockets.
131
132    bsddb -     It is okay to run the bsddb testsuite, which takes
133                a long time to complete.
134
135    decimal -   Test the decimal module against a large suite that
136                verifies compliance with standards.
137
138    cpu -       Used for certain CPU-heavy tests.
139
140    subprocess  Run all tests for the subprocess module.
141
142    urlfetch -  It is okay to download files required on testing.
143
144    gui -       Run tests that require a running GUI.
145
146    xpickle -   Test pickle and cPickle against Python 2.4, 2.5 and 2.6 to
147                test backwards compatibility. These tests take a long time
148                to run.
149
150To enable all resources except one, use '-uall,-<resource>'.  For
151example, to run all the tests except for the bsddb tests, give the
152option '-uall,-bsddb'.
153"""
154
155import StringIO
156import getopt
157import json
158import os
159import random
160import re
161import shutil
162import sys
163import time
164import traceback
165import warnings
166import unittest
167import tempfile
168import imp
169import platform
170import sysconfig
171
172
173# Some times __path__ and __file__ are not absolute (e.g. while running from
174# Lib/) and, if we change the CWD to run the tests in a temporary dir, some
175# imports might fail.  This affects only the modules imported before os.chdir().
176# These modules are searched first in sys.path[0] (so '' -- the CWD) and if
177# they are found in the CWD their __file__ and __path__ will be relative (this
178# happens before the chdir).  All the modules imported after the chdir, are
179# not found in the CWD, and since the other paths in sys.path[1:] are absolute
180# (site.py absolutize them), the __file__ and __path__ will be absolute too.
181# Therefore it is necessary to absolutize manually the __file__ and __path__ of
182# the packages to prevent later imports to fail when the CWD is different.
183for module in sys.modules.itervalues():
184    if hasattr(module, '__path__'):
185        module.__path__ = [os.path.abspath(path) for path in module.__path__]
186    if hasattr(module, '__file__'):
187        module.__file__ = os.path.abspath(module.__file__)
188
189
190# MacOSX (a.k.a. Darwin) has a default stack size that is too small
191# for deeply recursive regular expressions.  We see this as crashes in
192# the Python test suite when running test_re.py and test_sre.py.  The
193# fix is to set the stack limit to 2048.
194# This approach may also be useful for other Unixy platforms that
195# suffer from small default stack limits.
196if sys.platform == 'darwin':
197    try:
198        import resource
199    except ImportError:
200        pass
201    else:
202        soft, hard = resource.getrlimit(resource.RLIMIT_STACK)
203        newsoft = min(hard, max(soft, 1024*2048))
204        resource.setrlimit(resource.RLIMIT_STACK, (newsoft, hard))
205
206# Test result constants.
207PASSED = 1
208FAILED = 0
209ENV_CHANGED = -1
210SKIPPED = -2
211RESOURCE_DENIED = -3
212INTERRUPTED = -4
213
214from test import test_support
215
216RESOURCE_NAMES = ('audio', 'curses', 'largefile', 'network', 'bsddb',
217                  'decimal', 'cpu', 'subprocess', 'urlfetch', 'gui',
218                  'xpickle')
219
220TEMPDIR = os.path.abspath(tempfile.gettempdir())
221
222
223def usage(code, msg=''):
224    print __doc__
225    if msg: print msg
226    sys.exit(code)
227
228
229def main(tests=None, testdir=None, verbose=0, quiet=False,
230         exclude=False, single=False, randomize=False, fromfile=None,
231         findleaks=False, use_resources=None, trace=False, coverdir='coverage',
232         runleaks=False, huntrleaks=False, verbose2=False, print_slow=False,
233         random_seed=None, use_mp=None, verbose3=False, forever=False,
234         header=False):
235    """Execute a test suite.
236
237    This also parses command-line options and modifies its behavior
238    accordingly.
239
240    tests -- a list of strings containing test names (optional)
241    testdir -- the directory in which to look for tests (optional)
242
243    Users other than the Python test suite will certainly want to
244    specify testdir; if it's omitted, the directory containing the
245    Python test suite is searched for.
246
247    If the tests argument is omitted, the tests listed on the
248    command-line will be used.  If that's empty, too, then all *.py
249    files beginning with test_ will be used.
250
251    The other default arguments (verbose, quiet, exclude,
252    single, randomize, findleaks, use_resources, trace, coverdir,
253    print_slow, and random_seed) allow programmers calling main()
254    directly to set the values that would normally be set by flags
255    on the command line.
256    """
257
258    test_support.record_original_stdout(sys.stdout)
259    try:
260        opts, args = getopt.getopt(sys.argv[1:], 'hvqxsSrf:lu:t:TD:NLR:FwWM:j:',
261            ['help', 'verbose', 'verbose2', 'verbose3', 'quiet',
262             'exclude', 'single', 'slow', 'randomize', 'fromfile=', 'findleaks',
263             'use=', 'threshold=', 'trace', 'coverdir=', 'nocoverdir',
264             'runleaks', 'huntrleaks=', 'memlimit=', 'randseed=',
265             'multiprocess=', 'slaveargs=', 'forever', 'header'])
266    except getopt.error, msg:
267        usage(2, msg)
268
269    # Defaults
270    if random_seed is None:
271        random_seed = random.randrange(10000000)
272    if use_resources is None:
273        use_resources = []
274    for o, a in opts:
275        if o in ('-h', '--help'):
276            usage(0)
277        elif o in ('-v', '--verbose'):
278            verbose += 1
279        elif o in ('-w', '--verbose2'):
280            verbose2 = True
281        elif o in ('-W', '--verbose3'):
282            verbose3 = True
283        elif o in ('-q', '--quiet'):
284            quiet = True;
285            verbose = 0
286        elif o in ('-x', '--exclude'):
287            exclude = True
288        elif o in ('-s', '--single'):
289            single = True
290        elif o in ('-S', '--slow'):
291            print_slow = True
292        elif o in ('-r', '--randomize'):
293            randomize = True
294        elif o == '--randseed':
295            random_seed = int(a)
296        elif o in ('-f', '--fromfile'):
297            fromfile = a
298        elif o in ('-l', '--findleaks'):
299            findleaks = True
300        elif o in ('-L', '--runleaks'):
301            runleaks = True
302        elif o in ('-t', '--threshold'):
303            import gc
304            gc.set_threshold(int(a))
305        elif o in ('-T', '--coverage'):
306            trace = True
307        elif o in ('-D', '--coverdir'):
308            coverdir = os.path.join(os.getcwd(), a)
309        elif o in ('-N', '--nocoverdir'):
310            coverdir = None
311        elif o in ('-R', '--huntrleaks'):
312            huntrleaks = a.split(':')
313            if len(huntrleaks) not in (2, 3):
314                print a, huntrleaks
315                usage(2, '-R takes 2 or 3 colon-separated arguments')
316            if not huntrleaks[0]:
317                huntrleaks[0] = 5
318            else:
319                huntrleaks[0] = int(huntrleaks[0])
320            if not huntrleaks[1]:
321                huntrleaks[1] = 4
322            else:
323                huntrleaks[1] = int(huntrleaks[1])
324            if len(huntrleaks) == 2 or not huntrleaks[2]:
325                huntrleaks[2:] = ["reflog.txt"]
326        elif o in ('-M', '--memlimit'):
327            test_support.set_memlimit(a)
328        elif o in ('-u', '--use'):
329            u = [x.lower() for x in a.split(',')]
330            for r in u:
331                if r == 'all':
332                    use_resources[:] = RESOURCE_NAMES
333                    continue
334                remove = False
335                if r[0] == '-':
336                    remove = True
337                    r = r[1:]
338                if r not in RESOURCE_NAMES:
339                    usage(1, 'Invalid -u/--use option: ' + a)
340                if remove:
341                    if r in use_resources:
342                        use_resources.remove(r)
343                elif r not in use_resources:
344                    use_resources.append(r)
345        elif o in ('-F', '--forever'):
346            forever = True
347        elif o in ('-j', '--multiprocess'):
348            use_mp = int(a)
349        elif o == '--header':
350            header = True
351        elif o == '--slaveargs':
352            args, kwargs = json.loads(a)
353            try:
354                result = runtest(*args, **kwargs)
355            except BaseException, e:
356                result = INTERRUPTED, e.__class__.__name__
357            print   # Force a newline (just in case)
358            print json.dumps(result)
359            sys.exit(0)
360        else:
361            print >>sys.stderr, ("No handler for option {}.  Please "
362                "report this as a bug at http://bugs.python.org.").format(o)
363            sys.exit(1)
364    if single and fromfile:
365        usage(2, "-s and -f don't go together!")
366    if use_mp and trace:
367        usage(2, "-T and -j don't go together!")
368    if use_mp and findleaks:
369        usage(2, "-l and -j don't go together!")
370
371    good = []
372    bad = []
373    skipped = []
374    resource_denieds = []
375    environment_changed = []
376    interrupted = False
377
378    if findleaks:
379        try:
380            import gc
381        except ImportError:
382            print 'No GC available, disabling findleaks.'
383            findleaks = False
384        else:
385            # Uncomment the line below to report garbage that is not
386            # freeable by reference counting alone.  By default only
387            # garbage that is not collectable by the GC is reported.
388            #gc.set_debug(gc.DEBUG_SAVEALL)
389            found_garbage = []
390
391    if single:
392        filename = os.path.join(tempfile.gettempdir(), 'pynexttest')
393        try:
394            fp = open(filename, 'r')
395            next_test = fp.read().strip()
396            tests = [next_test]
397            fp.close()
398        except IOError:
399            pass
400
401    if fromfile:
402        tests = []
403        fp = open(os.path.join(test_support.SAVEDCWD, fromfile))
404        for line in fp:
405            guts = line.split() # assuming no test has whitespace in its name
406            if guts and not guts[0].startswith('#'):
407                tests.extend(guts)
408        fp.close()
409
410    # Strip .py extensions.
411    removepy(args)
412    removepy(tests)
413
414    stdtests = STDTESTS[:]
415    nottests = NOTTESTS.copy()
416    if exclude:
417        for arg in args:
418            if arg in stdtests:
419                stdtests.remove(arg)
420            nottests.add(arg)
421        args = []
422
423    # For a partial run, we do not need to clutter the output.
424    if verbose or header or not (quiet or single or tests or args):
425        # Print basic platform information
426        print "==", platform.python_implementation(), \
427                    " ".join(sys.version.split())
428        print "==  ", platform.platform(aliased=True), \
429                      "%s-endian" % sys.byteorder
430        print "==  ", os.getcwd()
431        print "Testing with flags:", sys.flags
432
433    alltests = findtests(testdir, stdtests, nottests)
434    selected = tests or args or alltests
435    if single:
436        selected = selected[:1]
437        try:
438            next_single_test = alltests[alltests.index(selected[0])+1]
439        except IndexError:
440            next_single_test = None
441    if randomize:
442        random.seed(random_seed)
443        print "Using random seed", random_seed
444        random.shuffle(selected)
445    if trace:
446        import trace
447        tracer = trace.Trace(ignoredirs=[sys.prefix, sys.exec_prefix],
448                             trace=False, count=True)
449
450    test_times = []
451    test_support.use_resources = use_resources
452    save_modules = sys.modules.keys()
453
454    def accumulate_result(test, result):
455        ok, test_time = result
456        test_times.append((test_time, test))
457        if ok == PASSED:
458            good.append(test)
459        elif ok == FAILED:
460            bad.append(test)
461        elif ok == ENV_CHANGED:
462            bad.append(test)
463            environment_changed.append(test)
464        elif ok == SKIPPED:
465            skipped.append(test)
466        elif ok == RESOURCE_DENIED:
467            skipped.append(test)
468            resource_denieds.append(test)
469
470    if forever:
471        def test_forever(tests=list(selected)):
472            while True:
473                for test in tests:
474                    yield test
475                    if bad:
476                        return
477        tests = test_forever()
478    else:
479        tests = iter(selected)
480
481    if use_mp:
482        try:
483            from threading import Thread
484        except ImportError:
485            print "Multiprocess option requires thread support"
486            sys.exit(2)
487        from Queue import Queue
488        from subprocess import Popen, PIPE
489        debug_output_pat = re.compile(r"\[\d+ refs\]$")
490        output = Queue()
491        def tests_and_args():
492            for test in tests:
493                args_tuple = (
494                    (test, verbose, quiet),
495                    dict(huntrleaks=huntrleaks, use_resources=use_resources)
496                )
497                yield (test, args_tuple)
498        pending = tests_and_args()
499        opt_args = test_support.args_from_interpreter_flags()
500        base_cmd = [sys.executable] + opt_args + ['-m', 'test.regrtest']
501        def work():
502            # A worker thread.
503            try:
504                while True:
505                    try:
506                        test, args_tuple = next(pending)
507                    except StopIteration:
508                        output.put((None, None, None, None))
509                        return
510                    # -E is needed by some tests, e.g. test_import
511                    popen = Popen(base_cmd + ['--slaveargs', json.dumps(args_tuple)],
512                                   stdout=PIPE, stderr=PIPE,
513                                   universal_newlines=True,
514                                   close_fds=(os.name != 'nt'))
515                    stdout, stderr = popen.communicate()
516                    # Strip last refcount output line if it exists, since it
517                    # comes from the shutdown of the interpreter in the subcommand.
518                    stderr = debug_output_pat.sub("", stderr)
519                    stdout, _, result = stdout.strip().rpartition("\n")
520                    if not result:
521                        output.put((None, None, None, None))
522                        return
523                    result = json.loads(result)
524                    if not quiet:
525                        stdout = test+'\n'+stdout
526                    output.put((test, stdout.rstrip(), stderr.rstrip(), result))
527            except BaseException:
528                output.put((None, None, None, None))
529                raise
530        workers = [Thread(target=work) for i in range(use_mp)]
531        for worker in workers:
532            worker.start()
533        finished = 0
534        try:
535            while finished < use_mp:
536                test, stdout, stderr, result = output.get()
537                if test is None:
538                    finished += 1
539                    continue
540                if stdout:
541                    print stdout
542                if stderr:
543                    print >>sys.stderr, stderr
544                sys.stdout.flush()
545                sys.stderr.flush()
546                if result[0] == INTERRUPTED:
547                    assert result[1] == 'KeyboardInterrupt'
548                    raise KeyboardInterrupt   # What else?
549                accumulate_result(test, result)
550        except KeyboardInterrupt:
551            interrupted = True
552            pending.close()
553        for worker in workers:
554            worker.join()
555    else:
556        for test in tests:
557            if not quiet:
558                print test
559                sys.stdout.flush()
560            if trace:
561                # If we're tracing code coverage, then we don't exit with status
562                # if on a false return value from main.
563                tracer.runctx('runtest(test, verbose, quiet)',
564                              globals=globals(), locals=vars())
565            else:
566                try:
567                    result = runtest(test, verbose, quiet, huntrleaks)
568                    accumulate_result(test, result)
569                    if verbose3 and result[0] == FAILED:
570                        print "Re-running test %r in verbose mode" % test
571                        runtest(test, True, quiet, huntrleaks)
572                except KeyboardInterrupt:
573                    interrupted = True
574                    break
575                except:
576                    raise
577            if findleaks:
578                gc.collect()
579                if gc.garbage:
580                    print "Warning: test created", len(gc.garbage),
581                    print "uncollectable object(s)."
582                    # move the uncollectable objects somewhere so we don't see
583                    # them again
584                    found_garbage.extend(gc.garbage)
585                    del gc.garbage[:]
586            # Unload the newly imported modules (best effort finalization)
587            for module in sys.modules.keys():
588                if module not in save_modules and module.startswith("test."):
589                    test_support.unload(module)
590
591    if interrupted:
592        # print a newline after ^C
593        print
594        print "Test suite interrupted by signal SIGINT."
595        omitted = set(selected) - set(good) - set(bad) - set(skipped)
596        print count(len(omitted), "test"), "omitted:"
597        printlist(omitted)
598    if good and not quiet:
599        if not bad and not skipped and not interrupted and len(good) > 1:
600            print "All",
601        print count(len(good), "test"), "OK."
602    if print_slow:
603        test_times.sort(reverse=True)
604        print "10 slowest tests:"
605        for time, test in test_times[:10]:
606            print "%s: %.1fs" % (test, time)
607    if bad:
608        bad = set(bad) - set(environment_changed)
609        if bad:
610            print count(len(bad), "test"), "failed:"
611            printlist(bad)
612        if environment_changed:
613            print "{} altered the execution environment:".format(
614                count(len(environment_changed), "test"))
615            printlist(environment_changed)
616    if skipped and not quiet:
617        print count(len(skipped), "test"), "skipped:"
618        printlist(skipped)
619
620        e = _ExpectedSkips()
621        plat = sys.platform
622        if e.isvalid():
623            surprise = set(skipped) - e.getexpected() - set(resource_denieds)
624            if surprise:
625                print count(len(surprise), "skip"), \
626                      "unexpected on", plat + ":"
627                printlist(surprise)
628            else:
629                print "Those skips are all expected on", plat + "."
630        else:
631            print "Ask someone to teach regrtest.py about which tests are"
632            print "expected to get skipped on", plat + "."
633
634    if verbose2 and bad:
635        print "Re-running failed tests in verbose mode"
636        for test in bad:
637            print "Re-running test %r in verbose mode" % test
638            sys.stdout.flush()
639            try:
640                test_support.verbose = True
641                ok = runtest(test, True, quiet, huntrleaks)
642            except KeyboardInterrupt:
643                # print a newline separate from the ^C
644                print
645                break
646            except:
647                raise
648
649    if single:
650        if next_single_test:
651            with open(filename, 'w') as fp:
652                fp.write(next_single_test + '\n')
653        else:
654            os.unlink(filename)
655
656    if trace:
657        r = tracer.results()
658        r.write_results(show_missing=True, summary=True, coverdir=coverdir)
659
660    if runleaks:
661        os.system("leaks %d" % os.getpid())
662
663    sys.exit(len(bad) > 0 or interrupted)
664
665
666STDTESTS = [
667    'test_grammar',
668    'test_opcodes',
669    'test_dict',
670    'test_builtin',
671    'test_exceptions',
672    'test_types',
673    'test_unittest',
674    'test_doctest',
675    'test_doctest2',
676]
677
678NOTTESTS = {
679    'test_support',
680    'test_future1',
681    'test_future2',
682}
683
684def findtests(testdir=None, stdtests=STDTESTS, nottests=NOTTESTS):
685    """Return a list of all applicable test modules."""
686    testdir = findtestdir(testdir)
687    names = os.listdir(testdir)
688    tests = []
689    others = set(stdtests) | nottests
690    for name in names:
691        modname, ext = os.path.splitext(name)
692        if modname[:5] == "test_" and ext == ".py" and modname not in others:
693            tests.append(modname)
694    return stdtests + sorted(tests)
695
696def runtest(test, verbose, quiet,
697            huntrleaks=False, use_resources=None):
698    """Run a single test.
699
700    test -- the name of the test
701    verbose -- if true, print more messages
702    quiet -- if true, don't print 'skipped' messages (probably redundant)
703    test_times -- a list of (time, test_name) pairs
704    huntrleaks -- run multiple times to test for leaks; requires a debug
705                  build; a triple corresponding to -R's three arguments
706    Returns one of the test result constants:
707        INTERRUPTED      KeyboardInterrupt when run under -j
708        RESOURCE_DENIED  test skipped because resource denied
709        SKIPPED          test skipped for some other reason
710        ENV_CHANGED      test failed because it changed the execution environment
711        FAILED           test failed
712        PASSED           test passed
713    """
714
715    test_support.verbose = verbose  # Tell tests to be moderately quiet
716    if use_resources is not None:
717        test_support.use_resources = use_resources
718    try:
719        return runtest_inner(test, verbose, quiet, huntrleaks)
720    finally:
721        cleanup_test_droppings(test, verbose)
722
723
724# Unit tests are supposed to leave the execution environment unchanged
725# once they complete.  But sometimes tests have bugs, especially when
726# tests fail, and the changes to environment go on to mess up other
727# tests.  This can cause issues with buildbot stability, since tests
728# are run in random order and so problems may appear to come and go.
729# There are a few things we can save and restore to mitigate this, and
730# the following context manager handles this task.
731
732class saved_test_environment:
733    """Save bits of the test environment and restore them at block exit.
734
735        with saved_test_environment(testname, verbose, quiet):
736            #stuff
737
738    Unless quiet is True, a warning is printed to stderr if any of
739    the saved items was changed by the test.  The attribute 'changed'
740    is initially False, but is set to True if a change is detected.
741
742    If verbose is more than 1, the before and after state of changed
743    items is also printed.
744    """
745
746    changed = False
747
748    def __init__(self, testname, verbose=0, quiet=False):
749        self.testname = testname
750        self.verbose = verbose
751        self.quiet = quiet
752
753    # To add things to save and restore, add a name XXX to the resources list
754    # and add corresponding get_XXX/restore_XXX functions.  get_XXX should
755    # return the value to be saved and compared against a second call to the
756    # get function when test execution completes.  restore_XXX should accept
757    # the saved value and restore the resource using it.  It will be called if
758    # and only if a change in the value is detected.
759    #
760    # Note: XXX will have any '.' replaced with '_' characters when determining
761    # the corresponding method names.
762
763    resources = ('sys.argv', 'cwd', 'sys.stdin', 'sys.stdout', 'sys.stderr',
764                 'os.environ', 'sys.path', 'asyncore.socket_map',
765                 'test_support.TESTFN',
766                )
767
768    def get_sys_argv(self):
769        return id(sys.argv), sys.argv, sys.argv[:]
770    def restore_sys_argv(self, saved_argv):
771        sys.argv = saved_argv[1]
772        sys.argv[:] = saved_argv[2]
773
774    def get_cwd(self):
775        return os.getcwd()
776    def restore_cwd(self, saved_cwd):
777        os.chdir(saved_cwd)
778
779    def get_sys_stdout(self):
780        return sys.stdout
781    def restore_sys_stdout(self, saved_stdout):
782        sys.stdout = saved_stdout
783
784    def get_sys_stderr(self):
785        return sys.stderr
786    def restore_sys_stderr(self, saved_stderr):
787        sys.stderr = saved_stderr
788
789    def get_sys_stdin(self):
790        return sys.stdin
791    def restore_sys_stdin(self, saved_stdin):
792        sys.stdin = saved_stdin
793
794    def get_os_environ(self):
795        return id(os.environ), os.environ, dict(os.environ)
796    def restore_os_environ(self, saved_environ):
797        os.environ = saved_environ[1]
798        os.environ.clear()
799        os.environ.update(saved_environ[2])
800
801    def get_sys_path(self):
802        return id(sys.path), sys.path, sys.path[:]
803    def restore_sys_path(self, saved_path):
804        sys.path = saved_path[1]
805        sys.path[:] = saved_path[2]
806
807    def get_asyncore_socket_map(self):
808        asyncore = sys.modules.get('asyncore')
809        # XXX Making a copy keeps objects alive until __exit__ gets called.
810        return asyncore and asyncore.socket_map.copy() or {}
811    def restore_asyncore_socket_map(self, saved_map):
812        asyncore = sys.modules.get('asyncore')
813        if asyncore is not None:
814            asyncore.close_all(ignore_all=True)
815            asyncore.socket_map.update(saved_map)
816
817    def get_test_support_TESTFN(self):
818        if os.path.isfile(test_support.TESTFN):
819            result = 'f'
820        elif os.path.isdir(test_support.TESTFN):
821            result = 'd'
822        else:
823            result = None
824        return result
825    def restore_test_support_TESTFN(self, saved_value):
826        if saved_value is None:
827            if os.path.isfile(test_support.TESTFN):
828                os.unlink(test_support.TESTFN)
829            elif os.path.isdir(test_support.TESTFN):
830                shutil.rmtree(test_support.TESTFN)
831
832    def resource_info(self):
833        for name in self.resources:
834            method_suffix = name.replace('.', '_')
835            get_name = 'get_' + method_suffix
836            restore_name = 'restore_' + method_suffix
837            yield name, getattr(self, get_name), getattr(self, restore_name)
838
839    def __enter__(self):
840        self.saved_values = dict((name, get()) for name, get, restore
841                                                   in self.resource_info())
842        return self
843
844    def __exit__(self, exc_type, exc_val, exc_tb):
845        saved_values = self.saved_values
846        del self.saved_values
847        for name, get, restore in self.resource_info():
848            current = get()
849            original = saved_values.pop(name)
850            # Check for changes to the resource's value
851            if current != original:
852                self.changed = True
853                restore(original)
854                if not self.quiet:
855                    print >>sys.stderr, (
856                          "Warning -- {} was modified by {}".format(
857                                                 name, self.testname))
858                    if self.verbose > 1:
859                        print >>sys.stderr, (
860                              "  Before: {}\n  After:  {} ".format(
861                                                  original, current))
862            # XXX (ncoghlan): for most resources (e.g. sys.path) identity
863            # matters at least as much as value. For others (e.g. cwd),
864            # identity is irrelevant. Should we add a mechanism to check
865            # for substitution in the cases where it matters?
866        return False
867
868
869def runtest_inner(test, verbose, quiet, huntrleaks=False):
870    test_support.unload(test)
871    if verbose:
872        capture_stdout = None
873    else:
874        capture_stdout = StringIO.StringIO()
875
876    test_time = 0.0
877    refleak = False  # True if the test leaked references.
878    try:
879        save_stdout = sys.stdout
880        try:
881            if capture_stdout:
882                sys.stdout = capture_stdout
883            if test.startswith('test.'):
884                abstest = test
885            else:
886                # Always import it from the test package
887                abstest = 'test.' + test
888            with saved_test_environment(test, verbose, quiet) as environment:
889                start_time = time.time()
890                the_package = __import__(abstest, globals(), locals(), [])
891                the_module = getattr(the_package, test)
892                # Old tests run to completion simply as a side-effect of
893                # being imported.  For tests based on unittest or doctest,
894                # explicitly invoke their test_main() function (if it exists).
895                indirect_test = getattr(the_module, "test_main", None)
896                if indirect_test is not None:
897                    indirect_test()
898                if huntrleaks:
899                    refleak = dash_R(the_module, test, indirect_test,
900                        huntrleaks)
901                test_time = time.time() - start_time
902        finally:
903            sys.stdout = save_stdout
904    except test_support.ResourceDenied, msg:
905        if not quiet:
906            print test, "skipped --", msg
907            sys.stdout.flush()
908        return RESOURCE_DENIED, test_time
909    except unittest.SkipTest, msg:
910        if not quiet:
911            print test, "skipped --", msg
912            sys.stdout.flush()
913        return SKIPPED, test_time
914    except KeyboardInterrupt:
915        raise
916    except test_support.TestFailed, msg:
917        print >>sys.stderr, "test", test, "failed --", msg
918        sys.stderr.flush()
919        return FAILED, test_time
920    except:
921        type, value = sys.exc_info()[:2]
922        print >>sys.stderr, "test", test, "crashed --", str(type) + ":", value
923        sys.stderr.flush()
924        if verbose:
925            traceback.print_exc(file=sys.stderr)
926            sys.stderr.flush()
927        return FAILED, test_time
928    else:
929        if refleak:
930            return FAILED, test_time
931        if environment.changed:
932            return ENV_CHANGED, test_time
933        # Except in verbose mode, tests should not print anything
934        if verbose or huntrleaks:
935            return PASSED, test_time
936        output = capture_stdout.getvalue()
937        if not output:
938            return PASSED, test_time
939        print "test", test, "produced unexpected output:"
940        print "*" * 70
941        print output
942        print "*" * 70
943        sys.stdout.flush()
944        return FAILED, test_time
945
946def cleanup_test_droppings(testname, verbose):
947    import stat
948    import gc
949
950    # First kill any dangling references to open files etc.
951    gc.collect()
952
953    # Try to clean up junk commonly left behind.  While tests shouldn't leave
954    # any files or directories behind, when a test fails that can be tedious
955    # for it to arrange.  The consequences can be especially nasty on Windows,
956    # since if a test leaves a file open, it cannot be deleted by name (while
957    # there's nothing we can do about that here either, we can display the
958    # name of the offending test, which is a real help).
959    for name in (test_support.TESTFN,
960                 "db_home",
961                ):
962        if not os.path.exists(name):
963            continue
964
965        if os.path.isdir(name):
966            kind, nuker = "directory", shutil.rmtree
967        elif os.path.isfile(name):
968            kind, nuker = "file", os.unlink
969        else:
970            raise SystemError("os.path says %r exists but is neither "
971                              "directory nor file" % name)
972
973        if verbose:
974            print "%r left behind %s %r" % (testname, kind, name)
975        try:
976            # if we have chmod, fix possible permissions problems
977            # that might prevent cleanup
978            if (hasattr(os, 'chmod')):
979                os.chmod(name, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
980            nuker(name)
981        except Exception, msg:
982            print >> sys.stderr, ("%r left behind %s %r and it couldn't be "
983                "removed: %s" % (testname, kind, name, msg))
984
985def dash_R(the_module, test, indirect_test, huntrleaks):
986    """Run a test multiple times, looking for reference leaks.
987
988    Returns:
989        False if the test didn't leak references; True if we detected refleaks.
990    """
991    # This code is hackish and inelegant, but it seems to do the job.
992    import copy_reg, _abcoll, _pyio
993
994    if not hasattr(sys, 'gettotalrefcount'):
995        raise Exception("Tracking reference leaks requires a debug build "
996                        "of Python")
997
998    # Save current values for dash_R_cleanup() to restore.
999    fs = warnings.filters[:]
1000    ps = copy_reg.dispatch_table.copy()
1001    pic = sys.path_importer_cache.copy()
1002    try:
1003        import zipimport
1004    except ImportError:
1005        zdc = None # Run unmodified on platforms without zipimport support
1006    else:
1007        zdc = zipimport._zip_directory_cache.copy()
1008    abcs = {}
1009    modules = _abcoll, _pyio
1010    for abc in [getattr(mod, a) for mod in modules for a in mod.__all__]:
1011        # XXX isinstance(abc, ABCMeta) leads to infinite recursion
1012        if not hasattr(abc, '_abc_registry'):
1013            continue
1014        for obj in abc.__subclasses__() + [abc]:
1015            abcs[obj] = obj._abc_registry.copy()
1016
1017    if indirect_test:
1018        def run_the_test():
1019            indirect_test()
1020    else:
1021        def run_the_test():
1022            imp.reload(the_module)
1023
1024    deltas = []
1025    nwarmup, ntracked, fname = huntrleaks
1026    fname = os.path.join(test_support.SAVEDCWD, fname)
1027    repcount = nwarmup + ntracked
1028    print >> sys.stderr, "beginning", repcount, "repetitions"
1029    print >> sys.stderr, ("1234567890"*(repcount//10 + 1))[:repcount]
1030    dash_R_cleanup(fs, ps, pic, zdc, abcs)
1031    for i in range(repcount):
1032        rc_before = sys.gettotalrefcount()
1033        run_the_test()
1034        sys.stderr.write('.')
1035        dash_R_cleanup(fs, ps, pic, zdc, abcs)
1036        rc_after = sys.gettotalrefcount()
1037        if i >= nwarmup:
1038            deltas.append(rc_after - rc_before)
1039    print >> sys.stderr
1040    if any(deltas):
1041        msg = '%s leaked %s references, sum=%s' % (test, deltas, sum(deltas))
1042        print >> sys.stderr, msg
1043        with open(fname, "a") as refrep:
1044            print >> refrep, msg
1045            refrep.flush()
1046        return True
1047    return False
1048
1049def dash_R_cleanup(fs, ps, pic, zdc, abcs):
1050    import gc, copy_reg
1051    import _strptime, linecache
1052    dircache = test_support.import_module('dircache', deprecated=True)
1053    import urlparse, urllib, urllib2, mimetypes, doctest
1054    import struct, filecmp
1055    from distutils.dir_util import _path_created
1056
1057    # Clear the warnings registry, so they can be displayed again
1058    for mod in sys.modules.values():
1059        if hasattr(mod, '__warningregistry__'):
1060            del mod.__warningregistry__
1061
1062    # Restore some original values.
1063    warnings.filters[:] = fs
1064    copy_reg.dispatch_table.clear()
1065    copy_reg.dispatch_table.update(ps)
1066    sys.path_importer_cache.clear()
1067    sys.path_importer_cache.update(pic)
1068    try:
1069        import zipimport
1070    except ImportError:
1071        pass # Run unmodified on platforms without zipimport support
1072    else:
1073        zipimport._zip_directory_cache.clear()
1074        zipimport._zip_directory_cache.update(zdc)
1075
1076    # clear type cache
1077    sys._clear_type_cache()
1078
1079    # Clear ABC registries, restoring previously saved ABC registries.
1080    for abc, registry in abcs.items():
1081        abc._abc_registry = registry.copy()
1082        abc._abc_cache.clear()
1083        abc._abc_negative_cache.clear()
1084
1085    # Clear assorted module caches.
1086    _path_created.clear()
1087    re.purge()
1088    _strptime._regex_cache.clear()
1089    urlparse.clear_cache()
1090    urllib.urlcleanup()
1091    urllib2.install_opener(None)
1092    dircache.reset()
1093    linecache.clearcache()
1094    mimetypes._default_mime_types()
1095    filecmp._cache.clear()
1096    struct._clearcache()
1097    doctest.master = None
1098    try:
1099        import ctypes
1100    except ImportError:
1101        # Don't worry about resetting the cache if ctypes is not supported
1102        pass
1103    else:
1104        ctypes._reset_cache()
1105
1106    # Collect cyclic trash.
1107    gc.collect()
1108
1109def findtestdir(path=None):
1110    return path or os.path.dirname(__file__) or os.curdir
1111
1112def removepy(names):
1113    if not names:
1114        return
1115    for idx, name in enumerate(names):
1116        basename, ext = os.path.splitext(name)
1117        if ext == '.py':
1118            names[idx] = basename
1119
1120def count(n, word):
1121    if n == 1:
1122        return "%d %s" % (n, word)
1123    else:
1124        return "%d %ss" % (n, word)
1125
1126def printlist(x, width=70, indent=4):
1127    """Print the elements of iterable x to stdout.
1128
1129    Optional arg width (default 70) is the maximum line length.
1130    Optional arg indent (default 4) is the number of blanks with which to
1131    begin each line.
1132    """
1133
1134    from textwrap import fill
1135    blanks = ' ' * indent
1136    # Print the sorted list: 'x' may be a '--random' list or a set()
1137    print fill(' '.join(str(elt) for elt in sorted(x)), width,
1138               initial_indent=blanks, subsequent_indent=blanks)
1139
1140# Map sys.platform to a string containing the basenames of tests
1141# expected to be skipped on that platform.
1142#
1143# Special cases:
1144#     test_pep277
1145#         The _ExpectedSkips constructor adds this to the set of expected
1146#         skips if not os.path.supports_unicode_filenames.
1147#     test_timeout
1148#         Controlled by test_timeout.skip_expected.  Requires the network
1149#         resource and a socket module.
1150#
1151# Tests that are expected to be skipped everywhere except on one platform
1152# are also handled separately.
1153
1154_expectations = {
1155    'win32':
1156        """
1157        test__locale
1158        test_bsddb185
1159        test_bsddb3
1160        test_commands
1161        test_crypt
1162        test_curses
1163        test_dbm
1164        test_dl
1165        test_fcntl
1166        test_fork1
1167        test_epoll
1168        test_gdbm
1169        test_grp
1170        test_ioctl
1171        test_largefile
1172        test_kqueue
1173        test_mhlib
1174        test_openpty
1175        test_ossaudiodev
1176        test_pipes
1177        test_poll
1178        test_posix
1179        test_pty
1180        test_pwd
1181        test_resource
1182        test_signal
1183        test_threadsignals
1184        test_timing
1185        test_wait3
1186        test_wait4
1187        """,
1188    'linux2':
1189        """
1190        test_bsddb185
1191        test_curses
1192        test_dl
1193        test_largefile
1194        test_kqueue
1195        test_ossaudiodev
1196        """,
1197    'unixware7':
1198        """
1199        test_bsddb
1200        test_bsddb185
1201        test_dl
1202        test_epoll
1203        test_largefile
1204        test_kqueue
1205        test_minidom
1206        test_openpty
1207        test_pyexpat
1208        test_sax
1209        test_sundry
1210        """,
1211    'openunix8':
1212        """
1213        test_bsddb
1214        test_bsddb185
1215        test_dl
1216        test_epoll
1217        test_largefile
1218        test_kqueue
1219        test_minidom
1220        test_openpty
1221        test_pyexpat
1222        test_sax
1223        test_sundry
1224        """,
1225    'sco_sv3':
1226        """
1227        test_asynchat
1228        test_bsddb
1229        test_bsddb185
1230        test_dl
1231        test_fork1
1232        test_epoll
1233        test_gettext
1234        test_largefile
1235        test_locale
1236        test_kqueue
1237        test_minidom
1238        test_openpty
1239        test_pyexpat
1240        test_queue
1241        test_sax
1242        test_sundry
1243        test_thread
1244        test_threaded_import
1245        test_threadedtempfile
1246        test_threading
1247        """,
1248    'riscos':
1249        """
1250        test_asynchat
1251        test_atexit
1252        test_bsddb
1253        test_bsddb185
1254        test_bsddb3
1255        test_commands
1256        test_crypt
1257        test_dbm
1258        test_dl
1259        test_fcntl
1260        test_fork1
1261        test_epoll
1262        test_gdbm
1263        test_grp
1264        test_largefile
1265        test_locale
1266        test_kqueue
1267        test_mmap
1268        test_openpty
1269        test_poll
1270        test_popen2
1271        test_pty
1272        test_pwd
1273        test_strop
1274        test_sundry
1275        test_thread
1276        test_threaded_import
1277        test_threadedtempfile
1278        test_threading
1279        test_timing
1280        """,
1281    'darwin':
1282        """
1283        test__locale
1284        test_bsddb
1285        test_bsddb3
1286        test_curses
1287        test_epoll
1288        test_gdb
1289        test_gdbm
1290        test_largefile
1291        test_locale
1292        test_kqueue
1293        test_minidom
1294        test_ossaudiodev
1295        test_poll
1296        """,
1297    'sunos5':
1298        """
1299        test_bsddb
1300        test_bsddb185
1301        test_curses
1302        test_dbm
1303        test_epoll
1304        test_kqueue
1305        test_gdbm
1306        test_gzip
1307        test_openpty
1308        test_zipfile
1309        test_zlib
1310        """,
1311    'hp-ux11':
1312        """
1313        test_bsddb
1314        test_bsddb185
1315        test_curses
1316        test_dl
1317        test_epoll
1318        test_gdbm
1319        test_gzip
1320        test_largefile
1321        test_locale
1322        test_kqueue
1323        test_minidom
1324        test_openpty
1325        test_pyexpat
1326        test_sax
1327        test_zipfile
1328        test_zlib
1329        """,
1330    'atheos':
1331        """
1332        test_bsddb185
1333        test_curses
1334        test_dl
1335        test_gdbm
1336        test_epoll
1337        test_largefile
1338        test_locale
1339        test_kqueue
1340        test_mhlib
1341        test_mmap
1342        test_poll
1343        test_popen2
1344        test_resource
1345        """,
1346    'cygwin':
1347        """
1348        test_bsddb185
1349        test_bsddb3
1350        test_curses
1351        test_dbm
1352        test_epoll
1353        test_ioctl
1354        test_kqueue
1355        test_largefile
1356        test_locale
1357        test_ossaudiodev
1358        test_socketserver
1359        """,
1360    'os2emx':
1361        """
1362        test_audioop
1363        test_bsddb185
1364        test_bsddb3
1365        test_commands
1366        test_curses
1367        test_dl
1368        test_epoll
1369        test_kqueue
1370        test_largefile
1371        test_mhlib
1372        test_mmap
1373        test_openpty
1374        test_ossaudiodev
1375        test_pty
1376        test_resource
1377        test_signal
1378        """,
1379    'freebsd4':
1380        """
1381        test_bsddb
1382        test_bsddb3
1383        test_epoll
1384        test_gdbm
1385        test_locale
1386        test_ossaudiodev
1387        test_pep277
1388        test_pty
1389        test_socketserver
1390        test_tcl
1391        test_tk
1392        test_ttk_guionly
1393        test_ttk_textonly
1394        test_timeout
1395        test_urllibnet
1396        test_multiprocessing
1397        """,
1398    'aix5':
1399        """
1400        test_bsddb
1401        test_bsddb185
1402        test_bsddb3
1403        test_bz2
1404        test_dl
1405        test_epoll
1406        test_gdbm
1407        test_gzip
1408        test_kqueue
1409        test_ossaudiodev
1410        test_tcl
1411        test_tk
1412        test_ttk_guionly
1413        test_ttk_textonly
1414        test_zipimport
1415        test_zlib
1416        """,
1417    'openbsd3':
1418        """
1419        test_ascii_formatd
1420        test_bsddb
1421        test_bsddb3
1422        test_ctypes
1423        test_dl
1424        test_epoll
1425        test_gdbm
1426        test_locale
1427        test_normalization
1428        test_ossaudiodev
1429        test_pep277
1430        test_tcl
1431        test_tk
1432        test_ttk_guionly
1433        test_ttk_textonly
1434        test_multiprocessing
1435        """,
1436    'netbsd3':
1437        """
1438        test_ascii_formatd
1439        test_bsddb
1440        test_bsddb185
1441        test_bsddb3
1442        test_ctypes
1443        test_curses
1444        test_dl
1445        test_epoll
1446        test_gdbm
1447        test_locale
1448        test_ossaudiodev
1449        test_pep277
1450        test_tcl
1451        test_tk
1452        test_ttk_guionly
1453        test_ttk_textonly
1454        test_multiprocessing
1455        """,
1456}
1457_expectations['freebsd5'] = _expectations['freebsd4']
1458_expectations['freebsd6'] = _expectations['freebsd4']
1459_expectations['freebsd7'] = _expectations['freebsd4']
1460_expectations['freebsd8'] = _expectations['freebsd4']
1461
1462class _ExpectedSkips:
1463    def __init__(self):
1464        import os.path
1465        from test import test_timeout
1466
1467        self.valid = False
1468        if sys.platform in _expectations:
1469            s = _expectations[sys.platform]
1470            self.expected = set(s.split())
1471
1472            # expected to be skipped on every platform, even Linux
1473            self.expected.add('test_linuxaudiodev')
1474
1475            if not os.path.supports_unicode_filenames:
1476                self.expected.add('test_pep277')
1477
1478            if test_timeout.skip_expected:
1479                self.expected.add('test_timeout')
1480
1481            if sys.maxint == 9223372036854775807L:
1482                self.expected.add('test_imageop')
1483
1484            if sys.platform != "darwin":
1485                MAC_ONLY = ["test_macos", "test_macostools", "test_aepack",
1486                            "test_plistlib", "test_scriptpackages",
1487                            "test_applesingle"]
1488                for skip in MAC_ONLY:
1489                    self.expected.add(skip)
1490            elif len(u'\0'.encode('unicode-internal')) == 4:
1491                self.expected.add("test_macostools")
1492
1493
1494            if sys.platform != "win32":
1495                # test_sqlite is only reliable on Windows where the library
1496                # is distributed with Python
1497                WIN_ONLY = ["test_unicode_file", "test_winreg",
1498                            "test_winsound", "test_startfile",
1499                            "test_sqlite", "test_msilib"]
1500                for skip in WIN_ONLY:
1501                    self.expected.add(skip)
1502
1503            if sys.platform != 'irix':
1504                IRIX_ONLY = ["test_imageop", "test_al", "test_cd", "test_cl",
1505                             "test_gl", "test_imgfile"]
1506                for skip in IRIX_ONLY:
1507                    self.expected.add(skip)
1508
1509            if sys.platform != 'sunos5':
1510                self.expected.add('test_sunaudiodev')
1511                self.expected.add('test_nis')
1512
1513            if not sys.py3kwarning:
1514                self.expected.add('test_py3kwarn')
1515
1516            self.valid = True
1517
1518    def isvalid(self):
1519        "Return true iff _ExpectedSkips knows about the current platform."
1520        return self.valid
1521
1522    def getexpected(self):
1523        """Return set of test names we expect to skip on current platform.
1524
1525        self.isvalid() must be true.
1526        """
1527
1528        assert self.isvalid()
1529        return self.expected
1530
1531if __name__ == '__main__':
1532    # findtestdir() gets the dirname out of __file__, so we have to make it
1533    # absolute before changing the working directory.
1534    # For example __file__ may be relative when running trace or profile.
1535    # See issue #9323.
1536    __file__ = os.path.abspath(__file__)
1537
1538    # sanity check
1539    assert __file__ == os.path.abspath(sys.argv[0])
1540
1541    # When tests are run from the Python build directory, it is best practice
1542    # to keep the test files in a subfolder.  It eases the cleanup of leftover
1543    # files using command "make distclean".
1544    if sysconfig.is_python_build():
1545        TEMPDIR = os.path.abspath('build')
1546        if not os.path.exists(TEMPDIR):
1547            os.mkdir(TEMPDIR)
1548
1549    # Define a writable temp dir that will be used as cwd while running
1550    # the tests. The name of the dir includes the pid to allow parallel
1551    # testing (see the -j option).
1552    TESTCWD = 'test_python_{}'.format(os.getpid())
1553
1554    TESTCWD = os.path.join(TEMPDIR, TESTCWD)
1555
1556    # Run the tests in a context manager that temporary changes the CWD to a
1557    # temporary and writable directory. If it's not possible to create or
1558    # change the CWD, the original CWD will be used. The original CWD is
1559    # available from test_support.SAVEDCWD.
1560    with test_support.temp_cwd(TESTCWD, quiet=True):
1561        main()
1562