| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  | import argparse | 
					
						
							| 
									
										
										
										
											2023-09-10 02:24:38 +02:00
										 |  |  | import os.path | 
					
						
							| 
									
										
										
										
											2022-06-21 14:42:32 +02:00
										 |  |  | import shlex | 
					
						
							| 
									
										
										
										
											2015-10-08 11:34:07 -07:00
										 |  |  | import sys | 
					
						
							| 
									
										
										
										
											2023-11-10 18:17:45 +01:00
										 |  |  | from test.support import os_helper, Py_DEBUG | 
					
						
							| 
									
										
										
										
											2023-11-30 23:00:14 +00:00
										 |  |  | from .utils import ALL_RESOURCES, RESOURCE_NAMES, TestFilter | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-26 10:38:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  | USAGE = """\
 | 
					
						
							|  |  |  | python -m test [options] [test_name1 [test_name2 ...]] | 
					
						
							|  |  |  | python path/to/Lib/test/regrtest.py [options] [test_name1 [test_name2 ...]] | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | DESCRIPTION = """\
 | 
					
						
							|  |  |  | Run Python regression tests. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | If no arguments or options are provided, finds all files matching | 
					
						
							|  |  |  | the pattern "test_*" in the Lib/test subdirectory and runs | 
					
						
							|  |  |  | them in alphabetical order (but see -M and -u, below, for exceptions). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | For more rigorous testing, it is useful to use the following | 
					
						
							|  |  |  | command line: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | python -E -Wd -m test [options] [test_name1 ...] | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | EPILOG = """\
 | 
					
						
							|  |  |  | Additional option details: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-02 14:44:29 +02:00
										 |  |  | -r randomizes test execution order. You can use --randseed=int to provide an | 
					
						
							| 
									
										
										
										
											2023-10-04 09:42:12 +03:00
										 |  |  | int seed value for the randomizer. The randseed value will be used | 
					
						
							|  |  |  | to set seeds for all random usages in tests | 
					
						
							|  |  |  | (including randomizing the tests order if -r is set). | 
					
						
							|  |  |  | By default we always set random seed, but do not randomize test order. | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | -s On the first invocation of regrtest using -s, the first test file found | 
					
						
							|  |  |  | or the first test file given on the command line is run, and the name of | 
					
						
							|  |  |  | the next test is recorded in a file named pynexttest.  If run from the | 
					
						
							|  |  |  | Python build directory, pynexttest is located in the 'build' subdirectory, | 
					
						
							|  |  |  | otherwise it is located in tempfile.gettempdir().  On subsequent runs, | 
					
						
							|  |  |  | the test in pynexttest is run, and the next test is written to pynexttest. | 
					
						
							|  |  |  | When the last test has been run, pynexttest is deleted.  In this way it | 
					
						
							|  |  |  | is possible to single step through the test files.  This is useful when | 
					
						
							|  |  |  | doing memory analysis on the Python interpreter, which process tends to | 
					
						
							|  |  |  | consume too many resources to run the full regression test non-stop. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | -S is used to continue running tests after an aborted run.  It will | 
					
						
							|  |  |  | maintain the order a standard run (ie, this assumes -r is not used). | 
					
						
							|  |  |  | This is useful after the tests have prematurely stopped for some external | 
					
						
							|  |  |  | reason and you want to start running from where you left off rather | 
					
						
							|  |  |  | than starting from the beginning. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | -f reads the names of tests from the file given as f's argument, one | 
					
						
							|  |  |  | or more test names per line.  Whitespace is ignored.  Blank lines and | 
					
						
							|  |  |  | lines beginning with '#' are ignored.  This is especially useful for | 
					
						
							|  |  |  | whittling down failures involving interactions among tests. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | -L causes the leaks(1) command to be run just before exit if it exists. | 
					
						
							|  |  |  | leaks(1) is available on Mac OS X and presumably on some other | 
					
						
							|  |  |  | FreeBSD-derived systems. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | -R runs each test several times and examines sys.gettotalrefcount() to | 
					
						
							|  |  |  | see if the test appears to be leaking references.  The argument should | 
					
						
							|  |  |  | be of the form stab:run:fname where 'stab' is the number of times the | 
					
						
							|  |  |  | test is run to let gettotalrefcount settle down, 'run' is the number | 
					
						
							|  |  |  | of times further it is run and 'fname' is the name of the file the | 
					
						
							|  |  |  | reports are written to.  These parameters all have defaults (5, 4 and | 
					
						
							|  |  |  | "reflog.txt" respectively), and the minimal invocation is '-R :'. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | -M runs tests that require an exorbitant amount of memory. These tests | 
					
						
							|  |  |  | typically try to ascertain containers keep working when containing more than | 
					
						
							|  |  |  | 2 billion objects, which only works on 64-bit systems. There are also some | 
					
						
							|  |  |  | tests that try to exhaust the address space of the process, which only makes | 
					
						
							|  |  |  | sense on 32-bit systems with at least 2Gb of memory. The passed-in memlimit, | 
					
						
							| 
									
										
										
										
											2018-12-31 06:41:39 +01:00
										 |  |  | which is a string in the form of '2.5Gb', determines how much memory the | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  | tests will limit themselves to (but they may go slightly over.) The number | 
					
						
							|  |  |  | shouldn't be more memory than the machine has (including swap memory). You | 
					
						
							|  |  |  | should also keep in mind that swap memory is generally much, much slower | 
					
						
							|  |  |  | than RAM, and setting memlimit to all available RAM or higher will heavily | 
					
						
							|  |  |  | tax the machine. On the other hand, it is no use running these tests with a | 
					
						
							|  |  |  | limit of less than 2.5Gb, and many require more than 20Gb. Tests that expect | 
					
						
							|  |  |  | to use more than memlimit memory will be skipped. The big-memory tests | 
					
						
							|  |  |  | generally run very, very long. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | -u is used to specify which special resource intensive tests to run, | 
					
						
							|  |  |  | such as those requiring large file support or network connectivity. | 
					
						
							|  |  |  | The argument is a comma-separated list of words indicating the | 
					
						
							|  |  |  | resources to test.  Currently only the following are defined: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     all -       Enable all special resources. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     none -      Disable all special resources (this is the default). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     audio -     Tests that use the audio device.  (There are known | 
					
						
							|  |  |  |                 cases of broken audio drivers that can crash Python or | 
					
						
							|  |  |  |                 even the Linux kernel.) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     curses -    Tests that use curses and will modify the terminal's | 
					
						
							|  |  |  |                 state and output modes. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     largefile - It is okay to run some test that may create huge | 
					
						
							|  |  |  |                 files.  These tests can take a long time and may | 
					
						
							| 
									
										
										
										
											2017-11-08 14:44:44 -08:00
										 |  |  |                 consume >2 GiB of disk space temporarily. | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     network -   It is okay to run tests that use external network | 
					
						
							|  |  |  |                 resource, e.g. testing SSL support for sockets. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     decimal -   Test the decimal module against a large suite that | 
					
						
							|  |  |  |                 verifies compliance with standards. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cpu -       Used for certain CPU-heavy tests. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-05 17:56:30 +03:00
										 |  |  |     walltime -  Long running but not CPU-bound tests. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  |     subprocess  Run all tests for the subprocess module. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     urlfetch -  It is okay to download files required on testing. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     gui -       Run tests that require a running GUI. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-22 18:47:04 -04:00
										 |  |  |     tzdata -    Run tests that require timezone data. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  | To enable all resources except one, use '-uall,-<resource>'.  For | 
					
						
							|  |  |  | example, to run all the tests except for the gui tests, give the | 
					
						
							|  |  |  | option '-uall,-gui'. | 
					
						
							| 
									
										
										
										
											2017-06-09 10:18:48 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | --matchfile filters tests using a text file, one pattern per line. | 
					
						
							|  |  |  | Pattern examples: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - test method: test_stat_attributes | 
					
						
							|  |  |  | - test class: FileTests | 
					
						
							|  |  |  | - test identifier: test_os.FileTests.test_stat_attributes | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-22 20:25:58 +02:00
										 |  |  | class Namespace(argparse.Namespace): | 
					
						
							|  |  |  |     def __init__(self, **kwargs) -> None: | 
					
						
							| 
									
										
										
										
											2023-09-26 17:22:50 +02:00
										 |  |  |         self.ci = False | 
					
						
							| 
									
										
										
										
											2021-07-22 20:25:58 +02:00
										 |  |  |         self.testdir = None | 
					
						
							|  |  |  |         self.verbose = 0 | 
					
						
							|  |  |  |         self.quiet = False | 
					
						
							|  |  |  |         self.exclude = False | 
					
						
							| 
									
										
										
										
											2023-09-09 03:37:48 +02:00
										 |  |  |         self.cleanup = False | 
					
						
							|  |  |  |         self.wait = False | 
					
						
							|  |  |  |         self.list_cases = False | 
					
						
							|  |  |  |         self.list_tests = False | 
					
						
							| 
									
										
										
										
											2021-07-22 20:25:58 +02:00
										 |  |  |         self.single = False | 
					
						
							|  |  |  |         self.randomize = False | 
					
						
							|  |  |  |         self.fromfile = None | 
					
						
							|  |  |  |         self.fail_env_changed = False | 
					
						
							|  |  |  |         self.use_resources = None | 
					
						
							|  |  |  |         self.trace = False | 
					
						
							|  |  |  |         self.coverdir = 'coverage' | 
					
						
							|  |  |  |         self.runleaks = False | 
					
						
							| 
									
										
										
										
											2023-09-14 19:33:18 +01:00
										 |  |  |         self.huntrleaks: tuple[int, int, str] | None = None | 
					
						
							| 
									
										
										
										
											2023-09-03 23:37:15 +02:00
										 |  |  |         self.rerun = False | 
					
						
							| 
									
										
										
										
											2021-07-22 20:25:58 +02:00
										 |  |  |         self.verbose3 = False | 
					
						
							|  |  |  |         self.print_slow = False | 
					
						
							|  |  |  |         self.random_seed = None | 
					
						
							|  |  |  |         self.use_mp = None | 
					
						
							|  |  |  |         self.forever = False | 
					
						
							|  |  |  |         self.header = False | 
					
						
							|  |  |  |         self.failfast = False | 
					
						
							| 
									
										
										
										
											2023-11-30 23:00:14 +00:00
										 |  |  |         self.match_tests: TestFilter = [] | 
					
						
							| 
									
										
										
										
											2021-07-22 20:25:58 +02:00
										 |  |  |         self.pgo = False | 
					
						
							|  |  |  |         self.pgo_extended = False | 
					
						
							| 
									
										
										
										
											2023-09-09 03:03:39 +02:00
										 |  |  |         self.worker_json = None | 
					
						
							| 
									
										
										
										
											2023-09-09 03:37:48 +02:00
										 |  |  |         self.start = None | 
					
						
							|  |  |  |         self.timeout = None | 
					
						
							| 
									
										
										
										
											2023-09-10 01:41:21 +02:00
										 |  |  |         self.memlimit = None | 
					
						
							|  |  |  |         self.threshold = None | 
					
						
							| 
									
										
										
										
											2023-09-10 03:07:05 +02:00
										 |  |  |         self.fail_rerun = False | 
					
						
							|  |  |  |         self.tempdir = None | 
					
						
							| 
									
										
										
										
											2023-09-26 23:59:11 +02:00
										 |  |  |         self._add_python_opts = True | 
					
						
							| 
									
										
										
										
											2021-07-22 20:25:58 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         super().__init__(**kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  | class _ArgParser(argparse.ArgumentParser): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def error(self, message): | 
					
						
							|  |  |  |         super().error(message + "\nPass -h or --help for complete help.") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-21 17:44:46 +03:00
										 |  |  | class FilterAction(argparse.Action): | 
					
						
							|  |  |  |     def __call__(self, parser, namespace, value, option_string=None): | 
					
						
							|  |  |  |         items = getattr(namespace, self.dest) | 
					
						
							|  |  |  |         items.append((value, self.const)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class FromFileFilterAction(argparse.Action): | 
					
						
							|  |  |  |     def __call__(self, parser, namespace, value, option_string=None): | 
					
						
							|  |  |  |         items = getattr(namespace, self.dest) | 
					
						
							|  |  |  |         with open(value, encoding='utf-8') as fp: | 
					
						
							|  |  |  |             for line in fp: | 
					
						
							|  |  |  |                 items.append((line.strip(), self.const)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  | def _create_parser(): | 
					
						
							|  |  |  |     # Set prog to prevent the uninformative "__main__.py" from displaying in | 
					
						
							|  |  |  |     # error messages when using "python -m test ...". | 
					
						
							|  |  |  |     parser = _ArgParser(prog='regrtest.py', | 
					
						
							|  |  |  |                         usage=USAGE, | 
					
						
							|  |  |  |                         description=DESCRIPTION, | 
					
						
							|  |  |  |                         epilog=EPILOG, | 
					
						
							|  |  |  |                         add_help=False, | 
					
						
							|  |  |  |                         formatter_class=argparse.RawDescriptionHelpFormatter) | 
					
						
							| 
									
										
										
										
											2023-10-21 17:44:46 +03:00
										 |  |  |     parser.set_defaults(match_tests=[]) | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Arguments with this clause added to its help are described further in | 
					
						
							|  |  |  |     # the epilog's "Additional option details" section. | 
					
						
							|  |  |  |     more_details = '  See the section at bottom for more details.' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     group = parser.add_argument_group('General options') | 
					
						
							|  |  |  |     # We add help explicitly to control what argument group it renders under. | 
					
						
							|  |  |  |     group.add_argument('-h', '--help', action='help', | 
					
						
							|  |  |  |                        help='show this help message and exit') | 
					
						
							| 
									
										
										
										
											2023-09-26 17:22:50 +02:00
										 |  |  |     group.add_argument('--fast-ci', action='store_true', | 
					
						
							|  |  |  |                        help='Fast Continuous Integration (CI) mode used by ' | 
					
						
							|  |  |  |                             'GitHub Actions') | 
					
						
							|  |  |  |     group.add_argument('--slow-ci', action='store_true', | 
					
						
							|  |  |  |                        help='Slow Continuous Integration (CI) mode used by ' | 
					
						
							|  |  |  |                             'buildbot workers') | 
					
						
							|  |  |  |     group.add_argument('--timeout', metavar='TIMEOUT', | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  |                         help='dump the traceback and exit if a test takes ' | 
					
						
							|  |  |  |                              'more than TIMEOUT seconds; disabled if TIMEOUT ' | 
					
						
							|  |  |  |                              'is negative or equals to zero') | 
					
						
							|  |  |  |     group.add_argument('--wait', action='store_true', | 
					
						
							|  |  |  |                        help='wait for user input, e.g., allow a debugger ' | 
					
						
							|  |  |  |                             'to be attached') | 
					
						
							|  |  |  |     group.add_argument('-S', '--start', metavar='START', | 
					
						
							|  |  |  |                        help='the name of the test at which to start.' + | 
					
						
							|  |  |  |                             more_details) | 
					
						
							| 
									
										
										
										
											2022-05-02 15:51:34 -07:00
										 |  |  |     group.add_argument('-p', '--python', metavar='PYTHON', | 
					
						
							|  |  |  |                        help='Command to run Python test subprocesses with.') | 
					
						
							| 
									
										
										
										
											2023-10-04 09:42:12 +03:00
										 |  |  |     group.add_argument('--randseed', metavar='SEED', | 
					
						
							|  |  |  |                        dest='random_seed', type=int, | 
					
						
							|  |  |  |                        help='pass a global random seed') | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     group = parser.add_argument_group('Verbosity') | 
					
						
							|  |  |  |     group.add_argument('-v', '--verbose', action='count', | 
					
						
							|  |  |  |                        help='run tests in verbose mode with output to stdout') | 
					
						
							| 
									
										
										
										
											2023-09-03 23:37:15 +02:00
										 |  |  |     group.add_argument('-w', '--rerun', action='store_true', | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  |                        help='re-run failed tests in verbose mode') | 
					
						
							| 
									
										
										
										
											2023-09-03 23:37:15 +02:00
										 |  |  |     group.add_argument('--verbose2', action='store_true', dest='rerun', | 
					
						
							|  |  |  |                        help='deprecated alias to --rerun') | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  |     group.add_argument('-W', '--verbose3', action='store_true', | 
					
						
							|  |  |  |                        help='display test output on failure') | 
					
						
							|  |  |  |     group.add_argument('-q', '--quiet', action='store_true', | 
					
						
							|  |  |  |                        help='no output unless one or more tests fail') | 
					
						
							| 
									
										
										
										
											2016-08-17 11:25:43 +02:00
										 |  |  |     group.add_argument('-o', '--slowest', action='store_true', dest='print_slow', | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  |                        help='print the slowest 10 tests') | 
					
						
							|  |  |  |     group.add_argument('--header', action='store_true', | 
					
						
							|  |  |  |                        help='print header with interpreter info') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     group = parser.add_argument_group('Selecting tests') | 
					
						
							|  |  |  |     group.add_argument('-r', '--randomize', action='store_true', | 
					
						
							|  |  |  |                        help='randomize test execution order.' + more_details) | 
					
						
							|  |  |  |     group.add_argument('-f', '--fromfile', metavar='FILE', | 
					
						
							|  |  |  |                        help='read names of tests to run from a file.' + | 
					
						
							|  |  |  |                             more_details) | 
					
						
							|  |  |  |     group.add_argument('-x', '--exclude', action='store_true', | 
					
						
							|  |  |  |                        help='arguments are tests to *exclude*') | 
					
						
							|  |  |  |     group.add_argument('-s', '--single', action='store_true', | 
					
						
							|  |  |  |                        help='single step through a set of tests.' + | 
					
						
							|  |  |  |                             more_details) | 
					
						
							|  |  |  |     group.add_argument('-m', '--match', metavar='PAT', | 
					
						
							| 
									
										
										
										
											2023-10-21 17:44:46 +03:00
										 |  |  |                        dest='match_tests', action=FilterAction, const=True, | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  |                        help='match test cases and methods with glob pattern PAT') | 
					
						
							| 
									
										
										
										
											2019-11-19 23:46:49 +00:00
										 |  |  |     group.add_argument('-i', '--ignore', metavar='PAT', | 
					
						
							| 
									
										
										
										
											2023-10-21 17:44:46 +03:00
										 |  |  |                        dest='match_tests', action=FilterAction, const=False, | 
					
						
							| 
									
										
										
										
											2019-11-19 23:46:49 +00:00
										 |  |  |                        help='ignore test cases and methods with glob pattern PAT') | 
					
						
							| 
									
										
										
										
											2017-06-09 10:18:48 +02:00
										 |  |  |     group.add_argument('--matchfile', metavar='FILENAME', | 
					
						
							| 
									
										
										
										
											2023-10-21 17:44:46 +03:00
										 |  |  |                        dest='match_tests', | 
					
						
							|  |  |  |                        action=FromFileFilterAction, const=True, | 
					
						
							| 
									
										
										
										
											2017-06-09 10:18:48 +02:00
										 |  |  |                        help='similar to --match but get patterns from a ' | 
					
						
							|  |  |  |                             'text file, one pattern per line') | 
					
						
							| 
									
										
										
										
											2019-11-19 23:46:49 +00:00
										 |  |  |     group.add_argument('--ignorefile', metavar='FILENAME', | 
					
						
							| 
									
										
										
										
											2023-10-21 17:44:46 +03:00
										 |  |  |                        dest='match_tests', | 
					
						
							|  |  |  |                        action=FromFileFilterAction, const=False, | 
					
						
							| 
									
										
										
										
											2019-11-19 23:46:49 +00:00
										 |  |  |                        help='similar to --matchfile but it receives patterns ' | 
					
						
							|  |  |  |                             'from text file to ignore') | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  |     group.add_argument('-G', '--failfast', action='store_true', | 
					
						
							|  |  |  |                        help='fail as soon as a test fails (only with -v or -W)') | 
					
						
							|  |  |  |     group.add_argument('-u', '--use', metavar='RES1,RES2,...', | 
					
						
							|  |  |  |                        action='append', type=resources_list, | 
					
						
							|  |  |  |                        help='specify which special resource intensive tests ' | 
					
						
							|  |  |  |                             'to run.' + more_details) | 
					
						
							|  |  |  |     group.add_argument('-M', '--memlimit', metavar='LIMIT', | 
					
						
							|  |  |  |                        help='run very large memory-consuming tests.' + | 
					
						
							|  |  |  |                             more_details) | 
					
						
							|  |  |  |     group.add_argument('--testdir', metavar='DIR', | 
					
						
							|  |  |  |                        type=relative_filename, | 
					
						
							|  |  |  |                        help='execute test files in the specified directory ' | 
					
						
							|  |  |  |                             '(instead of the Python stdlib test suite)') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     group = parser.add_argument_group('Special runs') | 
					
						
							|  |  |  |     group.add_argument('-L', '--runleaks', action='store_true', | 
					
						
							|  |  |  |                        help='run the leaks(1) command just before exit.' + | 
					
						
							|  |  |  |                             more_details) | 
					
						
							|  |  |  |     group.add_argument('-R', '--huntrleaks', metavar='RUNCOUNTS', | 
					
						
							|  |  |  |                        type=huntrleaks, | 
					
						
							|  |  |  |                        help='search for reference leaks (needs debug build, ' | 
					
						
							|  |  |  |                             'very slow).' + more_details) | 
					
						
							|  |  |  |     group.add_argument('-j', '--multiprocess', metavar='PROCESSES', | 
					
						
							|  |  |  |                        dest='use_mp', type=int, | 
					
						
							|  |  |  |                        help='run PROCESSES processes at once') | 
					
						
							|  |  |  |     group.add_argument('-T', '--coverage', action='store_true', | 
					
						
							|  |  |  |                        dest='trace', | 
					
						
							|  |  |  |                        help='turn on code coverage tracing using the trace ' | 
					
						
							|  |  |  |                             'module') | 
					
						
							|  |  |  |     group.add_argument('-D', '--coverdir', metavar='DIR', | 
					
						
							|  |  |  |                        type=relative_filename, | 
					
						
							|  |  |  |                        help='directory where coverage files are put') | 
					
						
							|  |  |  |     group.add_argument('-N', '--nocoverdir', | 
					
						
							|  |  |  |                        action='store_const', const=None, dest='coverdir', | 
					
						
							|  |  |  |                        help='put coverage files alongside modules') | 
					
						
							|  |  |  |     group.add_argument('-t', '--threshold', metavar='THRESHOLD', | 
					
						
							|  |  |  |                        type=int, | 
					
						
							|  |  |  |                        help='call gc.set_threshold(THRESHOLD)') | 
					
						
							|  |  |  |     group.add_argument('-n', '--nowindows', action='store_true', | 
					
						
							|  |  |  |                        help='suppress error message boxes on Windows') | 
					
						
							|  |  |  |     group.add_argument('-F', '--forever', action='store_true', | 
					
						
							|  |  |  |                        help='run the specified tests in a loop, until an ' | 
					
						
							| 
									
										
										
										
											2019-05-13 19:17:54 +02:00
										 |  |  |                             'error happens; imply --failfast') | 
					
						
							| 
									
										
										
										
											2015-10-03 00:21:12 +02:00
										 |  |  |     group.add_argument('--list-tests', action='store_true', | 
					
						
							|  |  |  |                        help="only write the name of tests that will be run, " | 
					
						
							|  |  |  |                             "don't execute them") | 
					
						
							| 
									
										
										
										
											2017-06-16 17:36:19 +08:00
										 |  |  |     group.add_argument('--list-cases', action='store_true', | 
					
						
							|  |  |  |                        help='only write the name of test cases that will be run' | 
					
						
							|  |  |  |                             ' , don\'t execute them') | 
					
						
							| 
									
										
										
										
											2015-10-02 16:20:49 -07:00
										 |  |  |     group.add_argument('-P', '--pgo', dest='pgo', action='store_true', | 
					
						
							| 
									
										
										
										
											2019-07-22 12:54:25 -07:00
										 |  |  |                        help='enable Profile Guided Optimization (PGO) training') | 
					
						
							|  |  |  |     group.add_argument('--pgo-extended', action='store_true', | 
					
						
							|  |  |  |                        help='enable extended PGO training (slower training)') | 
					
						
							| 
									
										
										
										
											2017-06-26 18:33:19 +02:00
										 |  |  |     group.add_argument('--fail-env-changed', action='store_true', | 
					
						
							|  |  |  |                        help='if a test file alters the environment, mark ' | 
					
						
							|  |  |  |                             'the test as failed') | 
					
						
							| 
									
										
										
										
											2023-09-03 23:37:15 +02:00
										 |  |  |     group.add_argument('--fail-rerun', action='store_true', | 
					
						
							|  |  |  |                        help='if a test failed and then passed when re-run, ' | 
					
						
							|  |  |  |                             'mark the tests as failed') | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-18 09:10:26 -07:00
										 |  |  |     group.add_argument('--junit-xml', dest='xmlpath', metavar='FILENAME', | 
					
						
							|  |  |  |                        help='writes JUnit-style XML results to the specified ' | 
					
						
							|  |  |  |                             'file') | 
					
						
							| 
									
										
										
										
											2019-06-24 12:03:00 +02:00
										 |  |  |     group.add_argument('--tempdir', metavar='PATH', | 
					
						
							| 
									
										
										
										
											2018-11-17 04:14:36 -08:00
										 |  |  |                        help='override the working directory for the test run') | 
					
						
							| 
									
										
										
										
											2019-06-24 12:03:00 +02:00
										 |  |  |     group.add_argument('--cleanup', action='store_true', | 
					
						
							|  |  |  |                        help='remove old test_python_* directories') | 
					
						
							| 
									
										
										
										
											2023-09-26 23:59:11 +02:00
										 |  |  |     group.add_argument('--dont-add-python-opts', dest='_add_python_opts', | 
					
						
							|  |  |  |                        action='store_false', | 
					
						
							| 
									
										
										
										
											2023-09-26 20:46:52 +02:00
										 |  |  |                        help="internal option, don't use it") | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  |     return parser | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def relative_filename(string): | 
					
						
							|  |  |  |     # CWD is replaced with a temporary dir before calling main(), so we | 
					
						
							|  |  |  |     # join it with the saved CWD so it ends up where the user expects. | 
					
						
							| 
									
										
										
										
											2020-06-30 21:46:06 +08:00
										 |  |  |     return os.path.join(os_helper.SAVEDCWD, string) | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def huntrleaks(string): | 
					
						
							|  |  |  |     args = string.split(':') | 
					
						
							|  |  |  |     if len(args) not in (2, 3): | 
					
						
							|  |  |  |         raise argparse.ArgumentTypeError( | 
					
						
							|  |  |  |             'needs 2 or 3 colon-separated arguments') | 
					
						
							|  |  |  |     nwarmup = int(args[0]) if args[0] else 5 | 
					
						
							|  |  |  |     ntracked = int(args[1]) if args[1] else 4 | 
					
						
							|  |  |  |     fname = args[2] if len(args) > 2 and args[2] else 'reflog.txt' | 
					
						
							|  |  |  |     return nwarmup, ntracked, fname | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def resources_list(string): | 
					
						
							|  |  |  |     u = [x.lower() for x in string.split(',')] | 
					
						
							|  |  |  |     for r in u: | 
					
						
							|  |  |  |         if r == 'all' or r == 'none': | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if r[0] == '-': | 
					
						
							|  |  |  |             r = r[1:] | 
					
						
							|  |  |  |         if r not in RESOURCE_NAMES: | 
					
						
							|  |  |  |             raise argparse.ArgumentTypeError('invalid resource: ' + r) | 
					
						
							|  |  |  |     return u | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _parse_args(args, **kwargs): | 
					
						
							|  |  |  |     # Defaults | 
					
						
							| 
									
										
										
										
											2021-07-22 20:25:58 +02:00
										 |  |  |     ns = Namespace() | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  |     for k, v in kwargs.items(): | 
					
						
							|  |  |  |         if not hasattr(ns, k): | 
					
						
							|  |  |  |             raise TypeError('%r is an invalid keyword argument ' | 
					
						
							|  |  |  |                             'for this function' % k) | 
					
						
							|  |  |  |         setattr(ns, k, v) | 
					
						
							|  |  |  |     if ns.use_resources is None: | 
					
						
							|  |  |  |         ns.use_resources = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     parser = _create_parser() | 
					
						
							| 
									
										
										
										
											2016-10-17 18:13:46 +02:00
										 |  |  |     # Issue #14191: argparse doesn't support "intermixed" positional and | 
					
						
							|  |  |  |     # optional arguments. Use parse_known_args() as workaround. | 
					
						
							|  |  |  |     ns.args = parser.parse_known_args(args=args, namespace=ns)[1] | 
					
						
							|  |  |  |     for arg in ns.args: | 
					
						
							|  |  |  |         if arg.startswith('-'): | 
					
						
							|  |  |  |             parser.error("unrecognized arguments: %s" % arg) | 
					
						
							| 
									
										
										
										
											2023-09-26 17:22:50 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if ns.timeout is not None: | 
					
						
							|  |  |  |         # Support "--timeout=" (no value) so Makefile.pre.pre TESTTIMEOUT | 
					
						
							|  |  |  |         # can be used by "make buildbottest" and "make test". | 
					
						
							|  |  |  |         if ns.timeout != "": | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 ns.timeout = float(ns.timeout) | 
					
						
							|  |  |  |             except ValueError: | 
					
						
							|  |  |  |                 parser.error(f"invalid timeout value: {ns.timeout!r}") | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             ns.timeout = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Continuous Integration (CI): common options for fast/slow CI modes | 
					
						
							|  |  |  |     if ns.slow_ci or ns.fast_ci: | 
					
						
							|  |  |  |         # Similar to options: | 
					
						
							|  |  |  |         # | 
					
						
							|  |  |  |         #     -j0 --randomize --fail-env-changed --fail-rerun --rerun | 
					
						
							| 
									
										
										
										
											2023-09-29 21:49:39 +02:00
										 |  |  |         #     --slowest --verbose3 | 
					
						
							| 
									
										
										
										
											2023-09-26 17:22:50 +02:00
										 |  |  |         if ns.use_mp is None: | 
					
						
							|  |  |  |             ns.use_mp = 0 | 
					
						
							|  |  |  |         ns.randomize = True | 
					
						
							|  |  |  |         ns.fail_env_changed = True | 
					
						
							| 
									
										
										
										
											2023-09-27 16:09:23 +02:00
										 |  |  |         if ns.python is None: | 
					
						
							|  |  |  |             ns.rerun = True | 
					
						
							| 
									
										
										
										
											2023-09-26 17:22:50 +02:00
										 |  |  |         ns.print_slow = True | 
					
						
							|  |  |  |         ns.verbose3 = True | 
					
						
							| 
									
										
										
										
											2023-09-26 20:46:52 +02:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2023-09-26 23:59:11 +02:00
										 |  |  |         ns._add_python_opts = False | 
					
						
							| 
									
										
										
										
											2023-09-26 17:22:50 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # When both --slow-ci and --fast-ci options are present, | 
					
						
							|  |  |  |     # --slow-ci has the priority | 
					
						
							|  |  |  |     if ns.slow_ci: | 
					
						
							|  |  |  |         # Similar to: -u "all" --timeout=1200 | 
					
						
							| 
									
										
										
										
											2023-10-15 13:34:28 -05:00
										 |  |  |         if ns.use is None: | 
					
						
							|  |  |  |             ns.use = [] | 
					
						
							|  |  |  |         ns.use.insert(0, ['all']) | 
					
						
							| 
									
										
										
										
											2023-09-26 17:22:50 +02:00
										 |  |  |         if ns.timeout is None: | 
					
						
							|  |  |  |             ns.timeout = 1200  # 20 minutes | 
					
						
							|  |  |  |     elif ns.fast_ci: | 
					
						
							|  |  |  |         # Similar to: -u "all,-cpu" --timeout=600 | 
					
						
							| 
									
										
										
										
											2023-10-15 13:34:28 -05:00
										 |  |  |         if ns.use is None: | 
					
						
							|  |  |  |             ns.use = [] | 
					
						
							|  |  |  |         ns.use.insert(0, ['all', '-cpu']) | 
					
						
							| 
									
										
										
										
											2023-09-26 17:22:50 +02:00
										 |  |  |         if ns.timeout is None: | 
					
						
							|  |  |  |             ns.timeout = 600  # 10 minutes | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if ns.single and ns.fromfile: | 
					
						
							|  |  |  |         parser.error("-s and -f don't go together!") | 
					
						
							| 
									
										
										
										
											2023-11-10 18:17:45 +01:00
										 |  |  |     if ns.trace: | 
					
						
							|  |  |  |         if ns.use_mp is not None: | 
					
						
							|  |  |  |             if not Py_DEBUG: | 
					
						
							|  |  |  |                 parser.error("need --with-pydebug to use -T and -j together") | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             print( | 
					
						
							|  |  |  |                 "Warning: collecting coverage without -j is imprecise. Configure" | 
					
						
							|  |  |  |                 " --with-pydebug and run -m test -T -j for best results.", | 
					
						
							|  |  |  |                 file=sys.stderr | 
					
						
							|  |  |  |             ) | 
					
						
							| 
									
										
										
										
											2022-06-21 14:42:32 +02:00
										 |  |  |     if ns.python is not None: | 
					
						
							|  |  |  |         if ns.use_mp is None: | 
					
						
							|  |  |  |             parser.error("-p requires -j!") | 
					
						
							|  |  |  |         # The "executable" may be two or more parts, e.g. "node python.js" | 
					
						
							|  |  |  |         ns.python = shlex.split(ns.python) | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  |     if ns.failfast and not (ns.verbose or ns.verbose3): | 
					
						
							|  |  |  |         parser.error("-G/--failfast needs either -v or -W") | 
					
						
							| 
									
										
										
										
											2023-09-03 23:37:15 +02:00
										 |  |  |     if ns.pgo and (ns.verbose or ns.rerun or ns.verbose3): | 
					
						
							| 
									
										
										
										
											2015-10-02 16:20:49 -07:00
										 |  |  |         parser.error("--pgo/-v don't go together!") | 
					
						
							| 
									
										
										
										
											2019-07-22 12:54:25 -07:00
										 |  |  |     if ns.pgo_extended: | 
					
						
							|  |  |  |         ns.pgo = True  # pgo_extended implies pgo | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-08 09:05:36 -07:00
										 |  |  |     if ns.nowindows: | 
					
						
							|  |  |  |         print("Warning: the --nowindows (-n) option is deprecated. " | 
					
						
							|  |  |  |               "Use -vv to display assertions in stderr.", file=sys.stderr) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  |     if ns.quiet: | 
					
						
							|  |  |  |         ns.verbose = 0 | 
					
						
							|  |  |  |     if ns.timeout is not None: | 
					
						
							| 
									
										
										
										
											2015-10-03 00:21:12 +02:00
										 |  |  |         if ns.timeout <= 0: | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  |             ns.timeout = None | 
					
						
							|  |  |  |     if ns.use: | 
					
						
							|  |  |  |         for a in ns.use: | 
					
						
							|  |  |  |             for r in a: | 
					
						
							|  |  |  |                 if r == 'all': | 
					
						
							| 
									
										
										
										
											2017-07-20 15:46:32 +02:00
										 |  |  |                     ns.use_resources[:] = ALL_RESOURCES | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  |                     continue | 
					
						
							|  |  |  |                 if r == 'none': | 
					
						
							|  |  |  |                     del ns.use_resources[:] | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |                 remove = False | 
					
						
							|  |  |  |                 if r[0] == '-': | 
					
						
							|  |  |  |                     remove = True | 
					
						
							|  |  |  |                     r = r[1:] | 
					
						
							|  |  |  |                 if remove: | 
					
						
							|  |  |  |                     if r in ns.use_resources: | 
					
						
							|  |  |  |                         ns.use_resources.remove(r) | 
					
						
							|  |  |  |                 elif r not in ns.use_resources: | 
					
						
							|  |  |  |                     ns.use_resources.append(r) | 
					
						
							|  |  |  |     if ns.random_seed is not None: | 
					
						
							|  |  |  |         ns.randomize = True | 
					
						
							| 
									
										
										
										
											2017-05-04 15:21:12 +02:00
										 |  |  |     if ns.verbose: | 
					
						
							|  |  |  |         ns.header = True | 
					
						
							| 
									
										
										
										
											2023-11-01 04:28:55 +01:00
										 |  |  |     # When -jN option is used, a worker process does not use --verbose3 | 
					
						
							|  |  |  |     # and so -R 3:3 -jN --verbose3 just works as expected: there is no false | 
					
						
							|  |  |  |     # alarm about memory leak. | 
					
						
							|  |  |  |     if ns.huntrleaks and ns.verbose3 and ns.use_mp is None: | 
					
						
							| 
									
										
										
										
											2017-05-18 13:03:24 -07:00
										 |  |  |         ns.verbose3 = False | 
					
						
							| 
									
										
										
										
											2023-11-01 04:28:55 +01:00
										 |  |  |         # run_single_test() replaces sys.stdout with io.StringIO if verbose3 | 
					
						
							|  |  |  |         # is true. In this case, huntrleaks sees an write into StringIO as | 
					
						
							|  |  |  |         # a memory leak, whereas it is not (gh-71290). | 
					
						
							| 
									
										
										
										
											2017-05-18 13:03:24 -07:00
										 |  |  |         print("WARNING: Disable --verbose3 because it's incompatible with " | 
					
						
							| 
									
										
										
										
											2023-11-01 04:28:55 +01:00
										 |  |  |               "--huntrleaks without -jN option", | 
					
						
							| 
									
										
										
										
											2017-05-18 13:03:24 -07:00
										 |  |  |               file=sys.stderr) | 
					
						
							| 
									
										
										
										
											2019-05-13 19:17:54 +02:00
										 |  |  |     if ns.forever: | 
					
						
							|  |  |  |         # --forever implies --failfast | 
					
						
							|  |  |  |         ns.failfast = True | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-09 00:41:26 +02:00
										 |  |  |     if ns.huntrleaks: | 
					
						
							|  |  |  |         warmup, repetitions, _ = ns.huntrleaks | 
					
						
							|  |  |  |         if warmup < 1 or repetitions < 1: | 
					
						
							|  |  |  |             msg = ("Invalid values for the --huntrleaks/-R parameters. The " | 
					
						
							|  |  |  |                    "number of warmups and repetitions must be at least 1 " | 
					
						
							|  |  |  |                    "each (1:1).") | 
					
						
							|  |  |  |             print(msg, file=sys.stderr, flush=True) | 
					
						
							|  |  |  |             sys.exit(2) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-26 09:43:45 +02:00
										 |  |  |     return ns |