• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import argparse
2import os
3import sys
4from test import support
5
6
7USAGE = """\
8python -m test [options] [test_name1 [test_name2 ...]]
9python path/to/Lib/test/regrtest.py [options] [test_name1 [test_name2 ...]]
10"""
11
12DESCRIPTION = """\
13Run Python regression tests.
14
15If no arguments or options are provided, finds all files matching
16the pattern "test_*" in the Lib/test subdirectory and runs
17them in alphabetical order (but see -M and -u, below, for exceptions).
18
19For more rigorous testing, it is useful to use the following
20command line:
21
22python -E -Wd -m test [options] [test_name1 ...]
23"""
24
25EPILOG = """\
26Additional option details:
27
28-r randomizes test execution order. You can use --randseed=int to provide an
29int seed value for the randomizer; this is useful for reproducing troublesome
30test orders.
31
32-s On the first invocation of regrtest using -s, the first test file found
33or the first test file given on the command line is run, and the name of
34the next test is recorded in a file named pynexttest.  If run from the
35Python build directory, pynexttest is located in the 'build' subdirectory,
36otherwise it is located in tempfile.gettempdir().  On subsequent runs,
37the test in pynexttest is run, and the next test is written to pynexttest.
38When the last test has been run, pynexttest is deleted.  In this way it
39is possible to single step through the test files.  This is useful when
40doing memory analysis on the Python interpreter, which process tends to
41consume too many resources to run the full regression test non-stop.
42
43-S is used to continue running tests after an aborted run.  It will
44maintain the order a standard run (ie, this assumes -r is not used).
45This is useful after the tests have prematurely stopped for some external
46reason and you want to start running from where you left off rather
47than starting from the beginning.
48
49-f reads the names of tests from the file given as f's argument, one
50or more test names per line.  Whitespace is ignored.  Blank lines and
51lines beginning with '#' are ignored.  This is especially useful for
52whittling down failures involving interactions among tests.
53
54-L causes the leaks(1) command to be run just before exit if it exists.
55leaks(1) is available on Mac OS X and presumably on some other
56FreeBSD-derived systems.
57
58-R runs each test several times and examines sys.gettotalrefcount() to
59see if the test appears to be leaking references.  The argument should
60be of the form stab:run:fname where 'stab' is the number of times the
61test is run to let gettotalrefcount settle down, 'run' is the number
62of times further it is run and 'fname' is the name of the file the
63reports are written to.  These parameters all have defaults (5, 4 and
64"reflog.txt" respectively), and the minimal invocation is '-R :'.
65
66-M runs tests that require an exorbitant amount of memory. These tests
67typically try to ascertain containers keep working when containing more than
682 billion objects, which only works on 64-bit systems. There are also some
69tests that try to exhaust the address space of the process, which only makes
70sense on 32-bit systems with at least 2Gb of memory. The passed-in memlimit,
71which is a string in the form of '2.5Gb', determines howmuch memory the
72tests will limit themselves to (but they may go slightly over.) The number
73shouldn't be more memory than the machine has (including swap memory). You
74should also keep in mind that swap memory is generally much, much slower
75than RAM, and setting memlimit to all available RAM or higher will heavily
76tax the machine. On the other hand, it is no use running these tests with a
77limit of less than 2.5Gb, and many require more than 20Gb. Tests that expect
78to use more than memlimit memory will be skipped. The big-memory tests
79generally run very, very long.
80
81-u is used to specify which special resource intensive tests to run,
82such as those requiring large file support or network connectivity.
83The argument is a comma-separated list of words indicating the
84resources to test.  Currently only the following are defined:
85
86    all -       Enable all special resources.
87
88    none -      Disable all special resources (this is the default).
89
90    audio -     Tests that use the audio device.  (There are known
91                cases of broken audio drivers that can crash Python or
92                even the Linux kernel.)
93
94    curses -    Tests that use curses and will modify the terminal's
95                state and output modes.
96
97    largefile - It is okay to run some test that may create huge
98                files.  These tests can take a long time and may
99                consume >2GB of disk space temporarily.
100
101    network -   It is okay to run tests that use external network
102                resource, e.g. testing SSL support for sockets.
103
104    decimal -   Test the decimal module against a large suite that
105                verifies compliance with standards.
106
107    cpu -       Used for certain CPU-heavy tests.
108
109    subprocess  Run all tests for the subprocess module.
110
111    urlfetch -  It is okay to download files required on testing.
112
113    gui -       Run tests that require a running GUI.
114
115    tzdata -    Run tests that require timezone data.
116
117To enable all resources except one, use '-uall,-<resource>'.  For
118example, to run all the tests except for the gui tests, give the
119option '-uall,-gui'.
120"""
121
122
123RESOURCE_NAMES = ('audio', 'curses', 'largefile', 'network',
124                  'decimal', 'cpu', 'subprocess', 'urlfetch', 'gui', 'tzdata')
125
126class _ArgParser(argparse.ArgumentParser):
127
128    def error(self, message):
129        super().error(message + "\nPass -h or --help for complete help.")
130
131
132def _create_parser():
133    # Set prog to prevent the uninformative "__main__.py" from displaying in
134    # error messages when using "python -m test ...".
135    parser = _ArgParser(prog='regrtest.py',
136                        usage=USAGE,
137                        description=DESCRIPTION,
138                        epilog=EPILOG,
139                        add_help=False,
140                        formatter_class=argparse.RawDescriptionHelpFormatter)
141
142    # Arguments with this clause added to its help are described further in
143    # the epilog's "Additional option details" section.
144    more_details = '  See the section at bottom for more details.'
145
146    group = parser.add_argument_group('General options')
147    # We add help explicitly to control what argument group it renders under.
148    group.add_argument('-h', '--help', action='help',
149                       help='show this help message and exit')
150    group.add_argument('--timeout', metavar='TIMEOUT', type=float,
151                        help='dump the traceback and exit if a test takes '
152                             'more than TIMEOUT seconds; disabled if TIMEOUT '
153                             'is negative or equals to zero')
154    group.add_argument('--wait', action='store_true',
155                       help='wait for user input, e.g., allow a debugger '
156                            'to be attached')
157    group.add_argument('--slaveargs', metavar='ARGS')
158    group.add_argument('-S', '--start', metavar='START',
159                       help='the name of the test at which to start.' +
160                            more_details)
161
162    group = parser.add_argument_group('Verbosity')
163    group.add_argument('-v', '--verbose', action='count',
164                       help='run tests in verbose mode with output to stdout')
165    group.add_argument('-w', '--verbose2', action='store_true',
166                       help='re-run failed tests in verbose mode')
167    group.add_argument('-W', '--verbose3', action='store_true',
168                       help='display test output on failure')
169    group.add_argument('-q', '--quiet', action='store_true',
170                       help='no output unless one or more tests fail')
171    group.add_argument('-o', '--slowest', action='store_true', dest='print_slow',
172                       help='print the slowest 10 tests')
173    group.add_argument('--header', action='store_true',
174                       help='print header with interpreter info')
175
176    group = parser.add_argument_group('Selecting tests')
177    group.add_argument('-r', '--randomize', action='store_true',
178                       help='randomize test execution order.' + more_details)
179    group.add_argument('--randseed', metavar='SEED',
180                       dest='random_seed', type=int,
181                       help='pass a random seed to reproduce a previous '
182                            'random run')
183    group.add_argument('-f', '--fromfile', metavar='FILE',
184                       help='read names of tests to run from a file.' +
185                            more_details)
186    group.add_argument('-x', '--exclude', action='store_true',
187                       help='arguments are tests to *exclude*')
188    group.add_argument('-s', '--single', action='store_true',
189                       help='single step through a set of tests.' +
190                            more_details)
191    group.add_argument('-m', '--match', metavar='PAT',
192                       dest='match_tests',
193                       help='match test cases and methods with glob pattern PAT')
194    group.add_argument('-G', '--failfast', action='store_true',
195                       help='fail as soon as a test fails (only with -v or -W)')
196    group.add_argument('-u', '--use', metavar='RES1,RES2,...',
197                       action='append', type=resources_list,
198                       help='specify which special resource intensive tests '
199                            'to run.' + more_details)
200    group.add_argument('-M', '--memlimit', metavar='LIMIT',
201                       help='run very large memory-consuming tests.' +
202                            more_details)
203    group.add_argument('--testdir', metavar='DIR',
204                       type=relative_filename,
205                       help='execute test files in the specified directory '
206                            '(instead of the Python stdlib test suite)')
207
208    group = parser.add_argument_group('Special runs')
209    group.add_argument('-l', '--findleaks', action='store_true',
210                       help='if GC is available detect tests that leak memory')
211    group.add_argument('-L', '--runleaks', action='store_true',
212                       help='run the leaks(1) command just before exit.' +
213                            more_details)
214    group.add_argument('-R', '--huntrleaks', metavar='RUNCOUNTS',
215                       type=huntrleaks,
216                       help='search for reference leaks (needs debug build, '
217                            'very slow).' + more_details)
218    group.add_argument('-j', '--multiprocess', metavar='PROCESSES',
219                       dest='use_mp', type=int,
220                       help='run PROCESSES processes at once')
221    group.add_argument('-T', '--coverage', action='store_true',
222                       dest='trace',
223                       help='turn on code coverage tracing using the trace '
224                            'module')
225    group.add_argument('-D', '--coverdir', metavar='DIR',
226                       type=relative_filename,
227                       help='directory where coverage files are put')
228    group.add_argument('-N', '--nocoverdir',
229                       action='store_const', const=None, dest='coverdir',
230                       help='put coverage files alongside modules')
231    group.add_argument('-t', '--threshold', metavar='THRESHOLD',
232                       type=int,
233                       help='call gc.set_threshold(THRESHOLD)')
234    group.add_argument('-n', '--nowindows', action='store_true',
235                       help='suppress error message boxes on Windows')
236    group.add_argument('-F', '--forever', action='store_true',
237                       help='run the specified tests in a loop, until an '
238                            'error happens')
239    group.add_argument('--list-tests', action='store_true',
240                       help="only write the name of tests that will be run, "
241                            "don't execute them")
242    group.add_argument('-P', '--pgo', dest='pgo', action='store_true',
243                       help='enable Profile Guided Optimization training')
244
245    return parser
246
247
248def relative_filename(string):
249    # CWD is replaced with a temporary dir before calling main(), so we
250    # join it with the saved CWD so it ends up where the user expects.
251    return os.path.join(support.SAVEDCWD, string)
252
253
254def huntrleaks(string):
255    args = string.split(':')
256    if len(args) not in (2, 3):
257        raise argparse.ArgumentTypeError(
258            'needs 2 or 3 colon-separated arguments')
259    nwarmup = int(args[0]) if args[0] else 5
260    ntracked = int(args[1]) if args[1] else 4
261    fname = args[2] if len(args) > 2 and args[2] else 'reflog.txt'
262    return nwarmup, ntracked, fname
263
264
265def resources_list(string):
266    u = [x.lower() for x in string.split(',')]
267    for r in u:
268        if r == 'all' or r == 'none':
269            continue
270        if r[0] == '-':
271            r = r[1:]
272        if r not in RESOURCE_NAMES:
273            raise argparse.ArgumentTypeError('invalid resource: ' + r)
274    return u
275
276
277def _parse_args(args, **kwargs):
278    # Defaults
279    ns = argparse.Namespace(testdir=None, verbose=0, quiet=False,
280         exclude=False, single=False, randomize=False, fromfile=None,
281         findleaks=False, use_resources=None, trace=False, coverdir='coverage',
282         runleaks=False, huntrleaks=False, verbose2=False, print_slow=False,
283         random_seed=None, use_mp=None, verbose3=False, forever=False,
284         header=False, failfast=False, match_tests=None, pgo=False)
285    for k, v in kwargs.items():
286        if not hasattr(ns, k):
287            raise TypeError('%r is an invalid keyword argument '
288                            'for this function' % k)
289        setattr(ns, k, v)
290    if ns.use_resources is None:
291        ns.use_resources = []
292
293    parser = _create_parser()
294    # Issue #14191: argparse doesn't support "intermixed" positional and
295    # optional arguments. Use parse_known_args() as workaround.
296    ns.args = parser.parse_known_args(args=args, namespace=ns)[1]
297    for arg in ns.args:
298        if arg.startswith('-'):
299            parser.error("unrecognized arguments: %s" % arg)
300            sys.exit(1)
301
302    if ns.single and ns.fromfile:
303        parser.error("-s and -f don't go together!")
304    if ns.use_mp is not None and ns.trace:
305        parser.error("-T and -j don't go together!")
306    if ns.use_mp is not None and ns.findleaks:
307        parser.error("-l and -j don't go together!")
308    if ns.failfast and not (ns.verbose or ns.verbose3):
309        parser.error("-G/--failfast needs either -v or -W")
310    if ns.pgo and (ns.verbose or ns.verbose2 or ns.verbose3):
311        parser.error("--pgo/-v don't go together!")
312
313    if ns.nowindows:
314        print("Warning: the --nowindows (-n) option is deprecated. "
315              "Use -vv to display assertions in stderr.", file=sys.stderr)
316
317    if ns.quiet:
318        ns.verbose = 0
319    if ns.timeout is not None:
320        if ns.timeout <= 0:
321            ns.timeout = None
322    if ns.use_mp is not None:
323        if ns.use_mp <= 0:
324            # Use all cores + extras for tests that like to sleep
325            ns.use_mp = 2 + (os.cpu_count() or 1)
326    if ns.use:
327        for a in ns.use:
328            for r in a:
329                if r == 'all':
330                    ns.use_resources[:] = RESOURCE_NAMES
331                    continue
332                if r == 'none':
333                    del ns.use_resources[:]
334                    continue
335                remove = False
336                if r[0] == '-':
337                    remove = True
338                    r = r[1:]
339                if remove:
340                    if r in ns.use_resources:
341                        ns.use_resources.remove(r)
342                elif r not in ns.use_resources:
343                    ns.use_resources.append(r)
344    if ns.random_seed is not None:
345        ns.randomize = True
346
347    return ns
348