test_timeit.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. import timeit
  2. import unittest
  3. import sys
  4. from StringIO import StringIO
  5. import time
  6. from textwrap import dedent
  7. from test.test_support import run_unittest
  8. from test.test_support import captured_stdout
  9. from test.test_support import captured_stderr
  10. # timeit's default number of iterations.
  11. DEFAULT_NUMBER = 1000000
  12. # timeit's default number of repetitions.
  13. DEFAULT_REPEAT = 3
  14. # XXX: some tests are commented out that would improve the coverage but take a
  15. # long time to run because they test the default number of loops, which is
  16. # large. The tests could be enabled if there was a way to override the default
  17. # number of loops during testing, but this would require changing the signature
  18. # of some functions that use the default as a default argument.
  19. class FakeTimer:
  20. BASE_TIME = 42.0
  21. def __init__(self, seconds_per_increment=1.0):
  22. self.count = 0
  23. self.setup_calls = 0
  24. self.seconds_per_increment=seconds_per_increment
  25. timeit._fake_timer = self
  26. def __call__(self):
  27. return self.BASE_TIME + self.count * self.seconds_per_increment
  28. def inc(self):
  29. self.count += 1
  30. def setup(self):
  31. self.setup_calls += 1
  32. def wrap_timer(self, timer):
  33. """Records 'timer' and returns self as callable timer."""
  34. self.saved_timer = timer
  35. return self
  36. class TestTimeit(unittest.TestCase):
  37. def tearDown(self):
  38. try:
  39. del timeit._fake_timer
  40. except AttributeError:
  41. pass
  42. def test_reindent_empty(self):
  43. self.assertEqual(timeit.reindent("", 0), "")
  44. self.assertEqual(timeit.reindent("", 4), "")
  45. def test_reindent_single(self):
  46. self.assertEqual(timeit.reindent("pass", 0), "pass")
  47. self.assertEqual(timeit.reindent("pass", 4), "pass")
  48. def test_reindent_multi_empty(self):
  49. self.assertEqual(timeit.reindent("\n\n", 0), "\n\n")
  50. self.assertEqual(timeit.reindent("\n\n", 4), "\n \n ")
  51. def test_reindent_multi(self):
  52. self.assertEqual(timeit.reindent(
  53. "print()\npass\nbreak", 0),
  54. "print()\npass\nbreak")
  55. self.assertEqual(timeit.reindent(
  56. "print()\npass\nbreak", 4),
  57. "print()\n pass\n break")
  58. def test_timer_invalid_stmt(self):
  59. self.assertRaises(ValueError, timeit.Timer, stmt=None)
  60. self.assertRaises(SyntaxError, timeit.Timer, stmt='return')
  61. self.assertRaises(SyntaxError, timeit.Timer, stmt='yield')
  62. self.assertRaises(SyntaxError, timeit.Timer, stmt='break')
  63. self.assertRaises(SyntaxError, timeit.Timer, stmt='continue')
  64. def test_timer_invalid_setup(self):
  65. self.assertRaises(ValueError, timeit.Timer, setup=None)
  66. self.assertRaises(SyntaxError, timeit.Timer, setup='return')
  67. self.assertRaises(SyntaxError, timeit.Timer, setup='yield')
  68. self.assertRaises(SyntaxError, timeit.Timer, setup='break')
  69. self.assertRaises(SyntaxError, timeit.Timer, setup='continue')
  70. fake_setup = "import timeit; timeit._fake_timer.setup()"
  71. fake_stmt = "import timeit; timeit._fake_timer.inc()"
  72. def fake_callable_setup(self):
  73. self.fake_timer.setup()
  74. def fake_callable_stmt(self):
  75. self.fake_timer.inc()
  76. def timeit(self, stmt, setup, number=None):
  77. self.fake_timer = FakeTimer()
  78. t = timeit.Timer(stmt=stmt, setup=setup, timer=self.fake_timer)
  79. kwargs = {}
  80. if number is None:
  81. number = DEFAULT_NUMBER
  82. else:
  83. kwargs['number'] = number
  84. delta_time = t.timeit(**kwargs)
  85. self.assertEqual(self.fake_timer.setup_calls, 1)
  86. self.assertEqual(self.fake_timer.count, number)
  87. self.assertEqual(delta_time, number)
  88. # Takes too long to run in debug build.
  89. #def test_timeit_default_iters(self):
  90. # self.timeit(self.fake_stmt, self.fake_setup)
  91. def test_timeit_zero_iters(self):
  92. self.timeit(self.fake_stmt, self.fake_setup, number=0)
  93. def test_timeit_few_iters(self):
  94. self.timeit(self.fake_stmt, self.fake_setup, number=3)
  95. def test_timeit_callable_stmt(self):
  96. self.timeit(self.fake_callable_stmt, self.fake_setup, number=3)
  97. def test_timeit_callable_setup(self):
  98. self.timeit(self.fake_stmt, self.fake_callable_setup, number=3)
  99. def test_timeit_callable_stmt_and_setup(self):
  100. self.timeit(self.fake_callable_stmt,
  101. self.fake_callable_setup, number=3)
  102. # Takes too long to run in debug build.
  103. #def test_timeit_function(self):
  104. # delta_time = timeit.timeit(self.fake_stmt, self.fake_setup,
  105. # timer=FakeTimer())
  106. # self.assertEqual(delta_time, DEFAULT_NUMBER)
  107. def test_timeit_function_zero_iters(self):
  108. delta_time = timeit.timeit(self.fake_stmt, self.fake_setup, number=0,
  109. timer=FakeTimer())
  110. self.assertEqual(delta_time, 0)
  111. def repeat(self, stmt, setup, repeat=None, number=None):
  112. self.fake_timer = FakeTimer()
  113. t = timeit.Timer(stmt=stmt, setup=setup, timer=self.fake_timer)
  114. kwargs = {}
  115. if repeat is None:
  116. repeat = DEFAULT_REPEAT
  117. else:
  118. kwargs['repeat'] = repeat
  119. if number is None:
  120. number = DEFAULT_NUMBER
  121. else:
  122. kwargs['number'] = number
  123. delta_times = t.repeat(**kwargs)
  124. self.assertEqual(self.fake_timer.setup_calls, repeat)
  125. self.assertEqual(self.fake_timer.count, repeat * number)
  126. self.assertEqual(delta_times, repeat * [float(number)])
  127. # Takes too long to run in debug build.
  128. #def test_repeat_default(self):
  129. # self.repeat(self.fake_stmt, self.fake_setup)
  130. def test_repeat_zero_reps(self):
  131. self.repeat(self.fake_stmt, self.fake_setup, repeat=0)
  132. def test_repeat_zero_iters(self):
  133. self.repeat(self.fake_stmt, self.fake_setup, number=0)
  134. def test_repeat_few_reps_and_iters(self):
  135. self.repeat(self.fake_stmt, self.fake_setup, repeat=3, number=5)
  136. def test_repeat_callable_stmt(self):
  137. self.repeat(self.fake_callable_stmt, self.fake_setup,
  138. repeat=3, number=5)
  139. def test_repeat_callable_setup(self):
  140. self.repeat(self.fake_stmt, self.fake_callable_setup,
  141. repeat=3, number=5)
  142. def test_repeat_callable_stmt_and_setup(self):
  143. self.repeat(self.fake_callable_stmt, self.fake_callable_setup,
  144. repeat=3, number=5)
  145. # Takes too long to run in debug build.
  146. #def test_repeat_function(self):
  147. # delta_times = timeit.repeat(self.fake_stmt, self.fake_setup,
  148. # timer=FakeTimer())
  149. # self.assertEqual(delta_times, DEFAULT_REPEAT * [float(DEFAULT_NUMBER)])
  150. def test_repeat_function_zero_reps(self):
  151. delta_times = timeit.repeat(self.fake_stmt, self.fake_setup, repeat=0,
  152. timer=FakeTimer())
  153. self.assertEqual(delta_times, [])
  154. def test_repeat_function_zero_iters(self):
  155. delta_times = timeit.repeat(self.fake_stmt, self.fake_setup, number=0,
  156. timer=FakeTimer())
  157. self.assertEqual(delta_times, DEFAULT_REPEAT * [0.0])
  158. def assert_exc_string(self, exc_string, expected_exc_name):
  159. exc_lines = exc_string.splitlines()
  160. self.assertGreater(len(exc_lines), 2)
  161. self.assertTrue(exc_lines[0].startswith('Traceback'))
  162. self.assertTrue(exc_lines[-1].startswith(expected_exc_name))
  163. def test_print_exc(self):
  164. s = StringIO()
  165. t = timeit.Timer("1.0/0.0")
  166. try:
  167. t.timeit()
  168. except:
  169. t.print_exc(s)
  170. self.assert_exc_string(s.getvalue(), 'ZeroDivisionError')
  171. MAIN_DEFAULT_OUTPUT = "10 loops, best of 3: 1 sec per loop\n"
  172. def run_main(self, seconds_per_increment=1.0, switches=None, timer=None):
  173. if timer is None:
  174. timer = FakeTimer(seconds_per_increment=seconds_per_increment)
  175. if switches is None:
  176. args = []
  177. else:
  178. args = switches[:]
  179. args.append(self.fake_stmt)
  180. # timeit.main() modifies sys.path, so save and restore it.
  181. orig_sys_path = sys.path[:]
  182. with captured_stdout() as s:
  183. timeit.main(args=args, _wrap_timer=timer.wrap_timer)
  184. sys.path[:] = orig_sys_path[:]
  185. return s.getvalue()
  186. def test_main_bad_switch(self):
  187. s = self.run_main(switches=['--bad-switch'])
  188. self.assertEqual(s, dedent("""\
  189. option --bad-switch not recognized
  190. use -h/--help for command line help
  191. """))
  192. def test_main_seconds(self):
  193. s = self.run_main(seconds_per_increment=5.5)
  194. self.assertEqual(s, "10 loops, best of 3: 5.5 sec per loop\n")
  195. def test_main_milliseconds(self):
  196. s = self.run_main(seconds_per_increment=0.0055)
  197. self.assertEqual(s, "100 loops, best of 3: 5.5 msec per loop\n")
  198. def test_main_microseconds(self):
  199. s = self.run_main(seconds_per_increment=0.0000025, switches=['-n100'])
  200. self.assertEqual(s, "100 loops, best of 3: 2.5 usec per loop\n")
  201. def test_main_fixed_iters(self):
  202. s = self.run_main(seconds_per_increment=2.0, switches=['-n35'])
  203. self.assertEqual(s, "35 loops, best of 3: 2 sec per loop\n")
  204. def test_main_setup(self):
  205. s = self.run_main(seconds_per_increment=2.0,
  206. switches=['-n35', '-s', 'print("CustomSetup")'])
  207. self.assertEqual(s, "CustomSetup\n" * 3 +
  208. "35 loops, best of 3: 2 sec per loop\n")
  209. def test_main_fixed_reps(self):
  210. s = self.run_main(seconds_per_increment=60.0, switches=['-r9'])
  211. self.assertEqual(s, "10 loops, best of 9: 60 sec per loop\n")
  212. def test_main_negative_reps(self):
  213. s = self.run_main(seconds_per_increment=60.0, switches=['-r-5'])
  214. self.assertEqual(s, "10 loops, best of 1: 60 sec per loop\n")
  215. @unittest.skipIf(sys.flags.optimize >= 2, "need __doc__")
  216. def test_main_help(self):
  217. s = self.run_main(switches=['-h'])
  218. self.assertEqual(s, timeit.__doc__)
  219. def test_main_using_time(self):
  220. fake_timer = FakeTimer()
  221. s = self.run_main(switches=['-t'], timer=fake_timer)
  222. self.assertEqual(s, self.MAIN_DEFAULT_OUTPUT)
  223. self.assertIs(fake_timer.saved_timer, time.time)
  224. def test_main_using_clock(self):
  225. fake_timer = FakeTimer()
  226. s = self.run_main(switches=['-c'], timer=fake_timer)
  227. self.assertEqual(s, self.MAIN_DEFAULT_OUTPUT)
  228. self.assertIs(fake_timer.saved_timer, time.clock)
  229. def test_main_verbose(self):
  230. s = self.run_main(switches=['-v'])
  231. self.assertEqual(s, dedent("""\
  232. 10 loops -> 10 secs
  233. raw times: 10 10 10
  234. 10 loops, best of 3: 1 sec per loop
  235. """))
  236. def test_main_very_verbose(self):
  237. s = self.run_main(seconds_per_increment=0.000050, switches=['-vv'])
  238. self.assertEqual(s, dedent("""\
  239. 10 loops -> 0.0005 secs
  240. 100 loops -> 0.005 secs
  241. 1000 loops -> 0.05 secs
  242. 10000 loops -> 0.5 secs
  243. raw times: 0.5 0.5 0.5
  244. 10000 loops, best of 3: 50 usec per loop
  245. """))
  246. def test_main_exception(self):
  247. with captured_stderr() as error_stringio:
  248. s = self.run_main(switches=['1.0/0.0'])
  249. self.assert_exc_string(error_stringio.getvalue(), 'ZeroDivisionError')
  250. def test_main_exception_fixed_reps(self):
  251. with captured_stderr() as error_stringio:
  252. s = self.run_main(switches=['-n1', '1.0/0.0'])
  253. self.assert_exc_string(error_stringio.getvalue(), 'ZeroDivisionError')
  254. def test_main():
  255. run_unittest(TestTimeit)
  256. if __name__ == '__main__':
  257. test_main()