ยปCore Development>Code coverage>Lib/test/test_timeit.py

Python code coverage for Lib/test/test_timeit.py

#countcontent
1n/aimport timeit
2n/aimport unittest
3n/aimport sys
4n/aimport io
5n/afrom textwrap import dedent
6n/a
7n/afrom test.support import captured_stdout
8n/afrom test.support import captured_stderr
9n/a
10n/a# timeit's default number of iterations.
11n/aDEFAULT_NUMBER = 1000000
12n/a
13n/a# timeit's default number of repetitions.
14n/aDEFAULT_REPEAT = 5
15n/a
16n/a# XXX: some tests are commented out that would improve the coverage but take a
17n/a# long time to run because they test the default number of loops, which is
18n/a# large. The tests could be enabled if there was a way to override the default
19n/a# number of loops during testing, but this would require changing the signature
20n/a# of some functions that use the default as a default argument.
21n/a
22n/aclass FakeTimer:
23n/a BASE_TIME = 42.0
24n/a def __init__(self, seconds_per_increment=1.0):
25n/a self.count = 0
26n/a self.setup_calls = 0
27n/a self.seconds_per_increment=seconds_per_increment
28n/a timeit._fake_timer = self
29n/a
30n/a def __call__(self):
31n/a return self.BASE_TIME + self.count * self.seconds_per_increment
32n/a
33n/a def inc(self):
34n/a self.count += 1
35n/a
36n/a def setup(self):
37n/a self.setup_calls += 1
38n/a
39n/a def wrap_timer(self, timer):
40n/a """Records 'timer' and returns self as callable timer."""
41n/a self.saved_timer = timer
42n/a return self
43n/a
44n/aclass TestTimeit(unittest.TestCase):
45n/a
46n/a def tearDown(self):
47n/a try:
48n/a del timeit._fake_timer
49n/a except AttributeError:
50n/a pass
51n/a
52n/a def test_reindent_empty(self):
53n/a self.assertEqual(timeit.reindent("", 0), "")
54n/a self.assertEqual(timeit.reindent("", 4), "")
55n/a
56n/a def test_reindent_single(self):
57n/a self.assertEqual(timeit.reindent("pass", 0), "pass")
58n/a self.assertEqual(timeit.reindent("pass", 4), "pass")
59n/a
60n/a def test_reindent_multi_empty(self):
61n/a self.assertEqual(timeit.reindent("\n\n", 0), "\n\n")
62n/a self.assertEqual(timeit.reindent("\n\n", 4), "\n \n ")
63n/a
64n/a def test_reindent_multi(self):
65n/a self.assertEqual(timeit.reindent(
66n/a "print()\npass\nbreak", 0),
67n/a "print()\npass\nbreak")
68n/a self.assertEqual(timeit.reindent(
69n/a "print()\npass\nbreak", 4),
70n/a "print()\n pass\n break")
71n/a
72n/a def test_timer_invalid_stmt(self):
73n/a self.assertRaises(ValueError, timeit.Timer, stmt=None)
74n/a self.assertRaises(SyntaxError, timeit.Timer, stmt='return')
75n/a self.assertRaises(SyntaxError, timeit.Timer, stmt='yield')
76n/a self.assertRaises(SyntaxError, timeit.Timer, stmt='yield from ()')
77n/a self.assertRaises(SyntaxError, timeit.Timer, stmt='break')
78n/a self.assertRaises(SyntaxError, timeit.Timer, stmt='continue')
79n/a self.assertRaises(SyntaxError, timeit.Timer, stmt='from timeit import *')
80n/a
81n/a def test_timer_invalid_setup(self):
82n/a self.assertRaises(ValueError, timeit.Timer, setup=None)
83n/a self.assertRaises(SyntaxError, timeit.Timer, setup='return')
84n/a self.assertRaises(SyntaxError, timeit.Timer, setup='yield')
85n/a self.assertRaises(SyntaxError, timeit.Timer, setup='yield from ()')
86n/a self.assertRaises(SyntaxError, timeit.Timer, setup='break')
87n/a self.assertRaises(SyntaxError, timeit.Timer, setup='continue')
88n/a self.assertRaises(SyntaxError, timeit.Timer, setup='from timeit import *')
89n/a
90n/a fake_setup = "import timeit\ntimeit._fake_timer.setup()"
91n/a fake_stmt = "import timeit\ntimeit._fake_timer.inc()"
92n/a
93n/a def fake_callable_setup(self):
94n/a self.fake_timer.setup()
95n/a
96n/a def fake_callable_stmt(self):
97n/a self.fake_timer.inc()
98n/a
99n/a def timeit(self, stmt, setup, number=None, globals=None):
100n/a self.fake_timer = FakeTimer()
101n/a t = timeit.Timer(stmt=stmt, setup=setup, timer=self.fake_timer,
102n/a globals=globals)
103n/a kwargs = {}
104n/a if number is None:
105n/a number = DEFAULT_NUMBER
106n/a else:
107n/a kwargs['number'] = number
108n/a delta_time = t.timeit(**kwargs)
109n/a self.assertEqual(self.fake_timer.setup_calls, 1)
110n/a self.assertEqual(self.fake_timer.count, number)
111n/a self.assertEqual(delta_time, number)
112n/a
113n/a # Takes too long to run in debug build.
114n/a #def test_timeit_default_iters(self):
115n/a # self.timeit(self.fake_stmt, self.fake_setup)
116n/a
117n/a def test_timeit_zero_iters(self):
118n/a self.timeit(self.fake_stmt, self.fake_setup, number=0)
119n/a
120n/a def test_timeit_few_iters(self):
121n/a self.timeit(self.fake_stmt, self.fake_setup, number=3)
122n/a
123n/a def test_timeit_callable_stmt(self):
124n/a self.timeit(self.fake_callable_stmt, self.fake_setup, number=3)
125n/a
126n/a def test_timeit_callable_setup(self):
127n/a self.timeit(self.fake_stmt, self.fake_callable_setup, number=3)
128n/a
129n/a def test_timeit_callable_stmt_and_setup(self):
130n/a self.timeit(self.fake_callable_stmt,
131n/a self.fake_callable_setup, number=3)
132n/a
133n/a # Takes too long to run in debug build.
134n/a #def test_timeit_function(self):
135n/a # delta_time = timeit.timeit(self.fake_stmt, self.fake_setup,
136n/a # timer=FakeTimer())
137n/a # self.assertEqual(delta_time, DEFAULT_NUMBER)
138n/a
139n/a def test_timeit_function_zero_iters(self):
140n/a delta_time = timeit.timeit(self.fake_stmt, self.fake_setup, number=0,
141n/a timer=FakeTimer())
142n/a self.assertEqual(delta_time, 0)
143n/a
144n/a def test_timeit_globals_args(self):
145n/a global _global_timer
146n/a _global_timer = FakeTimer()
147n/a t = timeit.Timer(stmt='_global_timer.inc()', timer=_global_timer)
148n/a self.assertRaises(NameError, t.timeit, number=3)
149n/a timeit.timeit(stmt='_global_timer.inc()', timer=_global_timer,
150n/a globals=globals(), number=3)
151n/a local_timer = FakeTimer()
152n/a timeit.timeit(stmt='local_timer.inc()', timer=local_timer,
153n/a globals=locals(), number=3)
154n/a
155n/a def repeat(self, stmt, setup, repeat=None, number=None):
156n/a self.fake_timer = FakeTimer()
157n/a t = timeit.Timer(stmt=stmt, setup=setup, timer=self.fake_timer)
158n/a kwargs = {}
159n/a if repeat is None:
160n/a repeat = DEFAULT_REPEAT
161n/a else:
162n/a kwargs['repeat'] = repeat
163n/a if number is None:
164n/a number = DEFAULT_NUMBER
165n/a else:
166n/a kwargs['number'] = number
167n/a delta_times = t.repeat(**kwargs)
168n/a self.assertEqual(self.fake_timer.setup_calls, repeat)
169n/a self.assertEqual(self.fake_timer.count, repeat * number)
170n/a self.assertEqual(delta_times, repeat * [float(number)])
171n/a
172n/a # Takes too long to run in debug build.
173n/a #def test_repeat_default(self):
174n/a # self.repeat(self.fake_stmt, self.fake_setup)
175n/a
176n/a def test_repeat_zero_reps(self):
177n/a self.repeat(self.fake_stmt, self.fake_setup, repeat=0)
178n/a
179n/a def test_repeat_zero_iters(self):
180n/a self.repeat(self.fake_stmt, self.fake_setup, number=0)
181n/a
182n/a def test_repeat_few_reps_and_iters(self):
183n/a self.repeat(self.fake_stmt, self.fake_setup, repeat=3, number=5)
184n/a
185n/a def test_repeat_callable_stmt(self):
186n/a self.repeat(self.fake_callable_stmt, self.fake_setup,
187n/a repeat=3, number=5)
188n/a
189n/a def test_repeat_callable_setup(self):
190n/a self.repeat(self.fake_stmt, self.fake_callable_setup,
191n/a repeat=3, number=5)
192n/a
193n/a def test_repeat_callable_stmt_and_setup(self):
194n/a self.repeat(self.fake_callable_stmt, self.fake_callable_setup,
195n/a repeat=3, number=5)
196n/a
197n/a # Takes too long to run in debug build.
198n/a #def test_repeat_function(self):
199n/a # delta_times = timeit.repeat(self.fake_stmt, self.fake_setup,
200n/a # timer=FakeTimer())
201n/a # self.assertEqual(delta_times, DEFAULT_REPEAT * [float(DEFAULT_NUMBER)])
202n/a
203n/a def test_repeat_function_zero_reps(self):
204n/a delta_times = timeit.repeat(self.fake_stmt, self.fake_setup, repeat=0,
205n/a timer=FakeTimer())
206n/a self.assertEqual(delta_times, [])
207n/a
208n/a def test_repeat_function_zero_iters(self):
209n/a delta_times = timeit.repeat(self.fake_stmt, self.fake_setup, number=0,
210n/a timer=FakeTimer())
211n/a self.assertEqual(delta_times, DEFAULT_REPEAT * [0.0])
212n/a
213n/a def assert_exc_string(self, exc_string, expected_exc_name):
214n/a exc_lines = exc_string.splitlines()
215n/a self.assertGreater(len(exc_lines), 2)
216n/a self.assertTrue(exc_lines[0].startswith('Traceback'))
217n/a self.assertTrue(exc_lines[-1].startswith(expected_exc_name))
218n/a
219n/a def test_print_exc(self):
220n/a s = io.StringIO()
221n/a t = timeit.Timer("1/0")
222n/a try:
223n/a t.timeit()
224n/a except:
225n/a t.print_exc(s)
226n/a self.assert_exc_string(s.getvalue(), 'ZeroDivisionError')
227n/a
228n/a MAIN_DEFAULT_OUTPUT = "1 loop, best of 5: 1 sec per loop\n"
229n/a
230n/a def run_main(self, seconds_per_increment=1.0, switches=None, timer=None):
231n/a if timer is None:
232n/a timer = FakeTimer(seconds_per_increment=seconds_per_increment)
233n/a if switches is None:
234n/a args = []
235n/a else:
236n/a args = switches[:]
237n/a args.append(self.fake_stmt)
238n/a # timeit.main() modifies sys.path, so save and restore it.
239n/a orig_sys_path = sys.path[:]
240n/a with captured_stdout() as s:
241n/a timeit.main(args=args, _wrap_timer=timer.wrap_timer)
242n/a sys.path[:] = orig_sys_path[:]
243n/a return s.getvalue()
244n/a
245n/a def test_main_bad_switch(self):
246n/a s = self.run_main(switches=['--bad-switch'])
247n/a self.assertEqual(s, dedent("""\
248n/a option --bad-switch not recognized
249n/a use -h/--help for command line help
250n/a """))
251n/a
252n/a def test_main_seconds(self):
253n/a s = self.run_main(seconds_per_increment=5.5)
254n/a self.assertEqual(s, "1 loop, best of 5: 5.5 sec per loop\n")
255n/a
256n/a def test_main_milliseconds(self):
257n/a s = self.run_main(seconds_per_increment=0.0055)
258n/a self.assertEqual(s, "50 loops, best of 5: 5.5 msec per loop\n")
259n/a
260n/a def test_main_microseconds(self):
261n/a s = self.run_main(seconds_per_increment=0.0000025, switches=['-n100'])
262n/a self.assertEqual(s, "100 loops, best of 5: 2.5 usec per loop\n")
263n/a
264n/a def test_main_fixed_iters(self):
265n/a s = self.run_main(seconds_per_increment=2.0, switches=['-n35'])
266n/a self.assertEqual(s, "35 loops, best of 5: 2 sec per loop\n")
267n/a
268n/a def test_main_setup(self):
269n/a s = self.run_main(seconds_per_increment=2.0,
270n/a switches=['-n35', '-s', 'print("CustomSetup")'])
271n/a self.assertEqual(s, "CustomSetup\n" * DEFAULT_REPEAT +
272n/a "35 loops, best of 5: 2 sec per loop\n")
273n/a
274n/a def test_main_multiple_setups(self):
275n/a s = self.run_main(seconds_per_increment=2.0,
276n/a switches=['-n35', '-s', 'a = "CustomSetup"', '-s', 'print(a)'])
277n/a self.assertEqual(s, "CustomSetup\n" * DEFAULT_REPEAT +
278n/a "35 loops, best of 5: 2 sec per loop\n")
279n/a
280n/a def test_main_fixed_reps(self):
281n/a s = self.run_main(seconds_per_increment=60.0, switches=['-r9'])
282n/a self.assertEqual(s, "1 loop, best of 9: 60 sec per loop\n")
283n/a
284n/a def test_main_negative_reps(self):
285n/a s = self.run_main(seconds_per_increment=60.0, switches=['-r-5'])
286n/a self.assertEqual(s, "1 loop, best of 1: 60 sec per loop\n")
287n/a
288n/a @unittest.skipIf(sys.flags.optimize >= 2, "need __doc__")
289n/a def test_main_help(self):
290n/a s = self.run_main(switches=['-h'])
291n/a # Note: It's not clear that the trailing space was intended as part of
292n/a # the help text, but since it's there, check for it.
293n/a self.assertEqual(s, timeit.__doc__ + ' ')
294n/a
295n/a def test_main_verbose(self):
296n/a s = self.run_main(switches=['-v'])
297n/a self.assertEqual(s, dedent("""\
298n/a 1 loop -> 1 secs
299n/a
300n/a raw times: 1 sec, 1 sec, 1 sec, 1 sec, 1 sec
301n/a
302n/a 1 loop, best of 5: 1 sec per loop
303n/a """))
304n/a
305n/a def test_main_very_verbose(self):
306n/a s = self.run_main(seconds_per_increment=0.000_030, switches=['-vv'])
307n/a self.assertEqual(s, dedent("""\
308n/a 1 loop -> 3e-05 secs
309n/a 2 loops -> 6e-05 secs
310n/a 5 loops -> 0.00015 secs
311n/a 10 loops -> 0.0003 secs
312n/a 20 loops -> 0.0006 secs
313n/a 50 loops -> 0.0015 secs
314n/a 100 loops -> 0.003 secs
315n/a 200 loops -> 0.006 secs
316n/a 500 loops -> 0.015 secs
317n/a 1000 loops -> 0.03 secs
318n/a 2000 loops -> 0.06 secs
319n/a 5000 loops -> 0.15 secs
320n/a 10000 loops -> 0.3 secs
321n/a
322n/a raw times: 300 msec, 300 msec, 300 msec, 300 msec, 300 msec
323n/a
324n/a 10000 loops, best of 5: 30 usec per loop
325n/a """))
326n/a
327n/a def test_main_with_time_unit(self):
328n/a unit_sec = self.run_main(seconds_per_increment=0.003,
329n/a switches=['-u', 'sec'])
330n/a self.assertEqual(unit_sec,
331n/a "100 loops, best of 5: 0.003 sec per loop\n")
332n/a unit_msec = self.run_main(seconds_per_increment=0.003,
333n/a switches=['-u', 'msec'])
334n/a self.assertEqual(unit_msec,
335n/a "100 loops, best of 5: 3 msec per loop\n")
336n/a unit_usec = self.run_main(seconds_per_increment=0.003,
337n/a switches=['-u', 'usec'])
338n/a self.assertEqual(unit_usec,
339n/a "100 loops, best of 5: 3e+03 usec per loop\n")
340n/a # Test invalid unit input
341n/a with captured_stderr() as error_stringio:
342n/a invalid = self.run_main(seconds_per_increment=0.003,
343n/a switches=['-u', 'parsec'])
344n/a self.assertEqual(error_stringio.getvalue(),
345n/a "Unrecognized unit. Please select nsec, usec, msec, or sec.\n")
346n/a
347n/a def test_main_exception(self):
348n/a with captured_stderr() as error_stringio:
349n/a s = self.run_main(switches=['1/0'])
350n/a self.assert_exc_string(error_stringio.getvalue(), 'ZeroDivisionError')
351n/a
352n/a def test_main_exception_fixed_reps(self):
353n/a with captured_stderr() as error_stringio:
354n/a s = self.run_main(switches=['-n1', '1/0'])
355n/a self.assert_exc_string(error_stringio.getvalue(), 'ZeroDivisionError')
356n/a
357n/a def autorange(self, seconds_per_increment=1/1024, callback=None):
358n/a timer = FakeTimer(seconds_per_increment=seconds_per_increment)
359n/a t = timeit.Timer(stmt=self.fake_stmt, setup=self.fake_setup, timer=timer)
360n/a return t.autorange(callback)
361n/a
362n/a def test_autorange(self):
363n/a num_loops, time_taken = self.autorange()
364n/a self.assertEqual(num_loops, 500)
365n/a self.assertEqual(time_taken, 500/1024)
366n/a
367n/a def test_autorange_second(self):
368n/a num_loops, time_taken = self.autorange(seconds_per_increment=1.0)
369n/a self.assertEqual(num_loops, 1)
370n/a self.assertEqual(time_taken, 1.0)
371n/a
372n/a def test_autorange_with_callback(self):
373n/a def callback(a, b):
374n/a print("{} {:.3f}".format(a, b))
375n/a with captured_stdout() as s:
376n/a num_loops, time_taken = self.autorange(callback=callback)
377n/a self.assertEqual(num_loops, 500)
378n/a self.assertEqual(time_taken, 500/1024)
379n/a expected = ('1 0.001\n'
380n/a '2 0.002\n'
381n/a '5 0.005\n'
382n/a '10 0.010\n'
383n/a '20 0.020\n'
384n/a '50 0.049\n'
385n/a '100 0.098\n'
386n/a '200 0.195\n'
387n/a '500 0.488\n')
388n/a self.assertEqual(s.getvalue(), expected)
389n/a
390n/a
391n/aif __name__ == '__main__':
392n/a unittest.main()