mirror of
https://github.com/python/cpython.git
synced 2026-05-04 09:31:02 +00:00
Merge 99835c7191 into 68fe899feb
This commit is contained in:
commit
fbce46477a
3 changed files with 115 additions and 90 deletions
|
|
@ -259,11 +259,12 @@ def run_main(self, seconds_per_increment=1.0, switches=None, timer=None):
|
|||
return s.getvalue()
|
||||
|
||||
def test_main_bad_switch(self):
|
||||
s = self.run_main(switches=['--bad-switch'])
|
||||
self.assertEqual(s, dedent("""\
|
||||
option --bad-switch not recognized
|
||||
use -h/--help for command line help
|
||||
"""))
|
||||
with captured_stderr() as error_stringio:
|
||||
s = self.run_main(switches=["--bad-switch"])
|
||||
self.assertEqual(s, "")
|
||||
self.assertIn(
|
||||
"unrecognized arguments: --bad-switch", error_stringio.getvalue()
|
||||
)
|
||||
|
||||
def test_main_seconds(self):
|
||||
s = self.run_main(seconds_per_increment=5.5)
|
||||
|
|
@ -301,10 +302,11 @@ def test_main_negative_reps(self):
|
|||
s = self.run_main(seconds_per_increment=60.0, switches=['-r-5'])
|
||||
self.assertEqual(s, "1 loop, best of 1: 60 sec per loop\n")
|
||||
|
||||
@unittest.skipIf(sys.flags.optimize >= 2, "need __doc__")
|
||||
def test_main_help(self):
|
||||
s = self.run_main(switches=['-h'])
|
||||
self.assertEqual(s, timeit.__doc__)
|
||||
self.assertIn("Tool for measuring execution time", s)
|
||||
self.assertIn("-n", s)
|
||||
self.assertIn("--number", s)
|
||||
|
||||
def test_main_verbose(self):
|
||||
s = self.run_main(switches=['-v'])
|
||||
|
|
@ -353,10 +355,12 @@ def test_main_with_time_unit(self):
|
|||
"100 loops, best of 5: 3e+03 usec per loop\n")
|
||||
# Test invalid unit input
|
||||
with captured_stderr() as error_stringio:
|
||||
invalid = self.run_main(seconds_per_increment=0.003,
|
||||
switches=['-u', 'parsec'])
|
||||
self.assertEqual(error_stringio.getvalue(),
|
||||
"Unrecognized unit. Please select nsec, usec, msec, or sec.\n")
|
||||
invalid = self.run_main(
|
||||
seconds_per_increment=0.003, switches=["-u", "parsec"]
|
||||
)
|
||||
self.assertIn(
|
||||
"choose from nsec, usec, msec, sec", error_stringio.getvalue()
|
||||
)
|
||||
|
||||
def test_main_exception(self):
|
||||
with captured_stderr() as error_stringio:
|
||||
|
|
|
|||
178
Lib/timeit.py
178
Lib/timeit.py
|
|
@ -6,38 +6,6 @@
|
|||
|
||||
Library usage: see the Timer class.
|
||||
|
||||
Command line usage:
|
||||
python timeit.py [-n N] [-r N] [-s S] [-p] [-h] [-t T] [--] [statement]
|
||||
|
||||
Options:
|
||||
-n/--number N: how many times to execute 'statement' (default: see below)
|
||||
-r/--repeat N: how many times to repeat the timer (default 5)
|
||||
-s/--setup S: statement to be executed once initially (default 'pass').
|
||||
Execution time of this setup statement is NOT timed.
|
||||
-p/--process: use time.process_time() (default is time.perf_counter())
|
||||
-v/--verbose: print raw timing results; repeat for more digits precision
|
||||
-u/--unit: set the output time unit (nsec, usec, msec, or sec)
|
||||
-t/--target-time T: if --number is 0 the code will run until it
|
||||
takes *at least* this many seconds
|
||||
(default: 0.2)
|
||||
-h/--help: print this usage message and exit
|
||||
--: separate options from statement, use when statement starts with -
|
||||
statement: statement to be timed (default 'pass')
|
||||
|
||||
A multi-line statement may be given by specifying each line as a
|
||||
separate argument; indented lines are possible by enclosing an
|
||||
argument in quotes and using leading spaces. Multiple -s options are
|
||||
treated similarly.
|
||||
|
||||
If -n is not given, a suitable number of loops is calculated by trying
|
||||
increasing numbers from the sequence 1, 2, 5, 10, 20, 50, ... until the
|
||||
total time is at least --target-time seconds.
|
||||
|
||||
Note: there is a certain baseline overhead associated with executing a
|
||||
pass statement. It differs between versions. The code here doesn't try
|
||||
to hide it, but you should be aware of it. The baseline overhead can be
|
||||
measured by invoking the program without arguments.
|
||||
|
||||
Classes:
|
||||
|
||||
Timer
|
||||
|
|
@ -268,7 +236,7 @@ def main(args=None, *, _wrap_timer=None):
|
|||
is not None, it must be a callable that accepts a timer function
|
||||
and returns another timer function (used for unit testing).
|
||||
"""
|
||||
import getopt
|
||||
import argparse
|
||||
if args is None:
|
||||
args = sys.argv[1:]
|
||||
import _colorize
|
||||
|
|
@ -276,54 +244,106 @@ def main(args=None, *, _wrap_timer=None):
|
|||
theme = _colorize.get_theme(force_color=colorize).timeit
|
||||
reset = theme.reset
|
||||
|
||||
try:
|
||||
opts, args = getopt.getopt(args, "n:u:s:r:pt:vh",
|
||||
["number=", "setup=", "repeat=",
|
||||
"process", "target-time=",
|
||||
"verbose", "unit=", "help"])
|
||||
except getopt.error as err:
|
||||
print(err)
|
||||
print("use -h/--help for command line help")
|
||||
return 2
|
||||
epilog = """\
|
||||
A multi-line statement may be given by specifying each line as a
|
||||
separate argument; indented lines are possible by enclosing an
|
||||
argument in quotes and using leading spaces. Multiple `-s` options are
|
||||
treated similarly.
|
||||
|
||||
timer = default_timer
|
||||
stmt = "\n".join(args) or "pass"
|
||||
number = 0 # auto-determine
|
||||
target_time = default_target_time
|
||||
setup = []
|
||||
repeat = default_repeat
|
||||
verbose = 0
|
||||
time_unit = None
|
||||
If `-n` is not given, a suitable number of loops is calculated by trying
|
||||
increasing numbers from the sequence 1, 2, 5, 10, 20, 50, ... until the
|
||||
total time is at least `--target-time` seconds.
|
||||
|
||||
Note: there is a certain baseline overhead associated with executing a
|
||||
pass statement. It differs between versions. The code here doesn't try
|
||||
to hide it, but you should be aware of it. The baseline overhead can be
|
||||
measured by invoking the program without arguments."""
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="python -m timeit",
|
||||
description="""\
|
||||
Tool for measuring execution time of small code snippets.
|
||||
|
||||
This module avoids a number of common traps for measuring execution
|
||||
times. See also Tim Peters' introduction to the Algorithms chapter in
|
||||
the Python Cookbook, published by O'Reilly.
|
||||
|
||||
Library usage: see the Timer class.""",
|
||||
epilog=epilog,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-n",
|
||||
"--number",
|
||||
type=int,
|
||||
default=0,
|
||||
help="how many times to execute 'statement' (default: see below)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-r",
|
||||
"--repeat",
|
||||
type=int,
|
||||
default=default_repeat,
|
||||
help="how many times to repeat the timer (default %(default)s)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-s",
|
||||
"--setup",
|
||||
action="append",
|
||||
default=[],
|
||||
help="statement to be executed once initially "
|
||||
"(default 'pass'). Execution time of this "
|
||||
"setup statement is NOT timed.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-p",
|
||||
"--process",
|
||||
action="store_true",
|
||||
help="use time.process_time() (default is time.perf_counter())",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-t",
|
||||
"--target-time",
|
||||
type=float,
|
||||
default=default_target_time,
|
||||
help="if --number is 0 the code will run until it takes "
|
||||
"at least this many seconds (default %(default)s)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-v",
|
||||
"--verbose",
|
||||
action="count",
|
||||
default=0,
|
||||
help="print raw timing results; repeat for more digits precision",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-u",
|
||||
"--unit",
|
||||
default=None,
|
||||
choices=["nsec", "usec", "msec", "sec"],
|
||||
help="set the output time unit",
|
||||
)
|
||||
parser.add_argument(
|
||||
"statement",
|
||||
nargs="*",
|
||||
default=["pass"],
|
||||
help="statement to be timed (default 'pass')",
|
||||
)
|
||||
try:
|
||||
ns = parser.parse_args(args)
|
||||
except SystemExit as e:
|
||||
return e.code
|
||||
|
||||
timer = time.process_time if ns.process else default_timer
|
||||
stmt = "\n".join(ns.statement) or "pass"
|
||||
number = ns.number
|
||||
target_time = ns.target_time
|
||||
setup = "\n".join(ns.setup) or "pass"
|
||||
repeat = max(ns.repeat, 1)
|
||||
verbose = ns.verbose
|
||||
time_unit = ns.unit
|
||||
units = {"nsec": 1e-9, "usec": 1e-6, "msec": 1e-3, "sec": 1.0}
|
||||
precision = 3
|
||||
for o, a in opts:
|
||||
if o in ("-n", "--number"):
|
||||
number = int(a)
|
||||
if o in ("-s", "--setup"):
|
||||
setup.append(a)
|
||||
if o in ("-u", "--unit"):
|
||||
if a in units:
|
||||
time_unit = a
|
||||
else:
|
||||
print("Unrecognized unit. Please select nsec, usec, msec, or sec.",
|
||||
file=sys.stderr)
|
||||
return 2
|
||||
if o in ("-r", "--repeat"):
|
||||
repeat = int(a)
|
||||
if repeat <= 0:
|
||||
repeat = 1
|
||||
if o in ("-p", "--process"):
|
||||
timer = time.process_time
|
||||
if o in ("-t", "--target-time"):
|
||||
target_time = float(a)
|
||||
if o in ("-v", "--verbose"):
|
||||
if verbose:
|
||||
precision += 1
|
||||
verbose += 1
|
||||
if o in ("-h", "--help"):
|
||||
print(__doc__, end="")
|
||||
return 0
|
||||
setup = "\n".join(setup) or "pass"
|
||||
precision = 3 + max(verbose - 1, 0)
|
||||
|
||||
# Include the current directory, so that local imports work (sys.path
|
||||
# contains the directory of this script, rather than the current
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
Use argparse for colour help timeit CLI. Patch by Hugo van Kemenade.
|
||||
Loading…
Add table
Add a link
Reference in a new issue