1+ import itertools
12import timeit
23import unittest
34import sys
@@ -23,8 +24,9 @@ class FakeTimer:
2324 BASE_TIME = 42.0
2425 def __init__ (self , seconds_per_increment = 1.0 ):
2526 self .count = 0
27+ self .global_setup_calls = 0
2628 self .setup_calls = 0
27- self .seconds_per_increment = seconds_per_increment
29+ self .seconds_per_increment = seconds_per_increment
2830 timeit ._fake_timer = self
2931
3032 def __call__ (self ):
@@ -33,6 +35,9 @@ def __call__(self):
3335 def inc (self ):
3436 self .count += 1
3537
38+ def global_setup (self ):
39+ self .global_setup_calls += 1
40+
3641 def setup (self ):
3742 self .setup_calls += 1
3843
@@ -81,6 +86,15 @@ def test_timer_invalid_stmt(self):
8186 self .assertRaises (SyntaxError , timeit .Timer ,
8287 setup = 'while False:\n pass' , stmt = ' break' )
8388
89+ def test_timer_invalid_global_setup (self ):
90+ self .assertRaises (ValueError , timeit .Timer , global_setup = None )
91+ self .assertRaises (SyntaxError , timeit .Timer , global_setup = 'return' )
92+ self .assertRaises (SyntaxError , timeit .Timer , global_setup = 'yield' )
93+ self .assertRaises (SyntaxError , timeit .Timer , global_setup = 'yield from ()' )
94+ self .assertRaises (SyntaxError , timeit .Timer , global_setup = 'break' )
95+ self .assertRaises (SyntaxError , timeit .Timer , global_setup = 'continue' )
96+ self .assertRaises (SyntaxError , timeit .Timer , global_setup = ' pass' )
97+
8498 def test_timer_invalid_setup (self ):
8599 self .assertRaises (ValueError , timeit .Timer , setup = None )
86100 self .assertRaises (SyntaxError , timeit .Timer , setup = 'return' )
@@ -91,30 +105,62 @@ def test_timer_invalid_setup(self):
91105 self .assertRaises (SyntaxError , timeit .Timer , setup = 'from timeit import *' )
92106 self .assertRaises (SyntaxError , timeit .Timer , setup = ' pass' )
93107
108+ def test_timer_empty_global_setup (self ):
109+ timeit .Timer (global_setup = '' )
110+ timeit .Timer (global_setup = ' \n \t \f ' )
111+ timeit .Timer (global_setup = '# comment' )
112+
94113 def test_timer_empty_stmt (self ):
95114 timeit .Timer (stmt = '' )
96115 timeit .Timer (stmt = ' \n \t \f ' )
97116 timeit .Timer (stmt = '# comment' )
98117
118+ def test_timer_global_setup_future (self ):
119+ timer = timeit .Timer (stmt = 'print(f.__annotations__)' ,
120+ setup = 'def f(x: int): pass' ,
121+ global_setup = 'from __future__ import annotations' )
122+ with captured_stdout () as stdout :
123+ timer .timeit (1 )
124+ self .assertEqual (stdout .getvalue ().strip (), str ({'x' : 'int' }))
125+
126+ def test_timer_global_setup_side_effect (self ):
127+ timer = timeit .Timer (stmt = 'print(s)' , global_setup = 's = 1' )
128+ with captured_stdout () as stdout :
129+ timer .timeit (5 )
130+ self .assertEqual (stdout .getvalue (), '1\n ' * 5 )
131+
132+ def test_timer_callable_global_setup_side_effect (self ):
133+ self .fake_timer = FakeTimer ()
134+ timer = timeit .Timer (global_setup = self .fake_callable_global_setup )
135+ timer .timeit (5 )
136+ self .assertEqual (self .fake_timer .count , 0 )
137+ self .assertEqual (self .fake_timer .setup_calls , 0 )
138+ self .assertEqual (self .fake_timer .global_setup_calls , 1 )
139+
140+ fake_global_setup = "import timeit\n timeit._fake_timer.global_setup()"
99141 fake_setup = "import timeit\n timeit._fake_timer.setup()"
100142 fake_stmt = "import timeit\n timeit._fake_timer.inc()"
101143
144+ def fake_callable_global_setup (self ):
145+ self .fake_timer .global_setup ()
146+
102147 def fake_callable_setup (self ):
103148 self .fake_timer .setup ()
104149
105150 def fake_callable_stmt (self ):
106151 self .fake_timer .inc ()
107152
108- def timeit (self , stmt , setup , number = None , globals = None ):
153+ def timeit (self , stmt , setup , global_setup , number = None , globals = None ):
109154 self .fake_timer = FakeTimer ()
110155 t = timeit .Timer (stmt = stmt , setup = setup , timer = self .fake_timer ,
111- globals = globals )
156+ globals = globals , global_setup = global_setup )
112157 kwargs = {}
113158 if number is None :
114159 number = DEFAULT_NUMBER
115160 else :
116161 kwargs ['number' ] = number
117162 delta_time = t .timeit (** kwargs )
163+ self .assertEqual (self .fake_timer .global_setup_calls , 1 )
118164 self .assertEqual (self .fake_timer .setup_calls , 1 )
119165 self .assertEqual (self .fake_timer .count , number )
120166 self .assertEqual (delta_time , number )
@@ -123,21 +169,20 @@ def timeit(self, stmt, setup, number=None, globals=None):
123169 #def test_timeit_default_iters(self):
124170 # self.timeit(self.fake_stmt, self.fake_setup)
125171
126- def test_timeit_zero_iters (self ):
127- self .timeit (self .fake_stmt , self .fake_setup , number = 0 )
128-
129- def test_timeit_few_iters (self ):
130- self .timeit (self .fake_stmt , self .fake_setup , number = 3 )
131-
132- def test_timeit_callable_stmt (self ):
133- self .timeit (self .fake_callable_stmt , self .fake_setup , number = 3 )
134-
135- def test_timeit_callable_setup (self ):
136- self .timeit (self .fake_stmt , self .fake_callable_setup , number = 3 )
137-
138- def test_timeit_callable_stmt_and_setup (self ):
139- self .timeit (self .fake_callable_stmt ,
140- self .fake_callable_setup , number = 3 )
172+ def test_timeit_simple (self ):
173+ for number , (callable_stmt , callable_setup , callable_global_setup ) in (
174+ itertools .product ([0 , 3 ], itertools .product ([True , False ], repeat = 3 ))
175+ ):
176+ with self .subTest (
177+ number = number ,
178+ callable_stmt = callable_stmt ,
179+ callable_setup = callable_setup ,
180+ callable_global_setup = callable_global_setup ,
181+ ):
182+ stmt = self .fake_stmt if callable_stmt else self .fake_callable_stmt
183+ setup = self .fake_setup if callable_setup else self .fake_callable_setup
184+ global_setup = self .fake_global_setup if callable_global_setup else self .fake_callable_global_setup
185+ self .timeit (stmt , setup , global_setup , number = number )
141186
142187 # Takes too long to run in debug build.
143188 #def test_timeit_function(self):
@@ -161,9 +206,10 @@ def test_timeit_globals_args(self):
161206 timeit .timeit (stmt = 'local_timer.inc()' , timer = local_timer ,
162207 globals = locals (), number = 3 )
163208
164- def repeat (self , stmt , setup , repeat = None , number = None ):
209+ def repeat (self , stmt , setup , global_setup , repeat = None , number = None ):
165210 self .fake_timer = FakeTimer ()
166- t = timeit .Timer (stmt = stmt , setup = setup , timer = self .fake_timer )
211+ t = timeit .Timer (stmt = stmt , setup = setup , timer = self .fake_timer ,
212+ global_setup = global_setup )
167213 kwargs = {}
168214 if repeat is None :
169215 repeat = DEFAULT_REPEAT
@@ -174,6 +220,7 @@ def repeat(self, stmt, setup, repeat=None, number=None):
174220 else :
175221 kwargs ['number' ] = number
176222 delta_times = t .repeat (** kwargs )
223+ self .assertEqual (self .fake_timer .global_setup_calls , 1 )
177224 self .assertEqual (self .fake_timer .setup_calls , repeat )
178225 self .assertEqual (self .fake_timer .count , repeat * number )
179226 self .assertEqual (delta_times , repeat * [float (number )])
@@ -182,26 +229,23 @@ def repeat(self, stmt, setup, repeat=None, number=None):
182229 #def test_repeat_default(self):
183230 # self.repeat(self.fake_stmt, self.fake_setup)
184231
185- def test_repeat_zero_reps (self ):
186- self .repeat (self .fake_stmt , self .fake_setup , repeat = 0 )
187-
188- def test_repeat_zero_iters (self ):
189- self .repeat (self .fake_stmt , self .fake_setup , number = 0 )
190-
191- def test_repeat_few_reps_and_iters (self ):
192- self .repeat (self .fake_stmt , self .fake_setup , repeat = 3 , number = 5 )
193-
194- def test_repeat_callable_stmt (self ):
195- self .repeat (self .fake_callable_stmt , self .fake_setup ,
196- repeat = 3 , number = 5 )
197-
198- def test_repeat_callable_setup (self ):
199- self .repeat (self .fake_stmt , self .fake_callable_setup ,
200- repeat = 3 , number = 5 )
201-
202- def test_repeat_callable_stmt_and_setup (self ):
203- self .repeat (self .fake_callable_stmt , self .fake_callable_setup ,
204- repeat = 3 , number = 5 )
232+ def test_repeat_simple (self ):
233+ for repeat , (callable_stmt , callable_setup , callable_global_setup ) in (
234+ itertools .product ([0 , 3 ], itertools .product ([True , False ], repeat = 3 ))
235+ ):
236+ # do not use number = None for repeat > 0 as it would be too large
237+ number = 5 if repeat > 0 else None
238+ with self .subTest (
239+ repeat = repeat ,
240+ number = number ,
241+ callable_stmt = callable_stmt ,
242+ callable_setup = callable_setup ,
243+ callable_global_setup = callable_global_setup ,
244+ ):
245+ stmt = self .fake_stmt if callable_stmt else self .fake_callable_stmt
246+ setup = self .fake_setup if callable_setup else self .fake_callable_setup
247+ global_setup = self .fake_global_setup if callable_global_setup else self .fake_callable_global_setup
248+ self .repeat (stmt , setup , global_setup , repeat = repeat , number = number )
205249
206250 # Takes too long to run in debug build.
207251 #def test_repeat_function(self):
@@ -274,6 +318,18 @@ def test_main_fixed_iters(self):
274318 s = self .run_main (seconds_per_increment = 2.0 , switches = ['-n35' ])
275319 self .assertEqual (s , "35 loops, best of 5: 2 sec per loop\n " )
276320
321+ def test_main_global_setup (self ):
322+ s = self .run_main (seconds_per_increment = 2.0 ,
323+ switches = ['-n35' , '-g' , 'print("CustomSetup")' ])
324+ self .assertEqual (s , "CustomSetup\n " +
325+ "35 loops, best of 5: 2 sec per loop\n " )
326+
327+ def test_main_multiple_global_setups (self ):
328+ s = self .run_main (seconds_per_increment = 2.0 ,
329+ switches = ['-n35' , '-g' , 'a = "CustomSetup"' , '-g' , 'print(a)' ])
330+ self .assertEqual (s , "CustomSetup\n " +
331+ "35 loops, best of 5: 2 sec per loop\n " )
332+
277333 def test_main_setup (self ):
278334 s = self .run_main (seconds_per_increment = 2.0 ,
279335 switches = ['-n35' , '-s' , 'print("CustomSetup")' ])
0 commit comments