19
19
20
20
class TestResult :
21
21
def __init__ (
22
- self ,
23
- name : str ,
24
- duration_sec : float = 0.0 ,
25
- xml_data : list [str ] | None = None ,
22
+ self ,
23
+ name : str ,
24
+ duration_sec : float = 0.0 ,
25
+ xml_data : list [str ] | None = None ,
26
26
) -> None :
27
27
self .name = name
28
28
self .duration_sec = duration_sec
@@ -39,12 +39,12 @@ def __str__(self) -> str:
39
39
40
40
class Failed (TestResult ):
41
41
def __init__ (
42
- self ,
43
- name : str ,
44
- duration_sec : float = 0.0 ,
45
- xml_data : list [str ] | None = None ,
46
- errors : list [tuple [str , str ]] | None = None ,
47
- failures : list [tuple [str , str ]] | None = None ,
42
+ self ,
43
+ name : str ,
44
+ duration_sec : float = 0.0 ,
45
+ xml_data : list [str ] | None = None ,
46
+ errors : list [tuple [str , str ]] | None = None ,
47
+ failures : list [tuple [str , str ]] | None = None ,
48
48
) -> None :
49
49
super ().__init__ (name , duration_sec = duration_sec , xml_data = xml_data )
50
50
self .errors = errors
@@ -128,21 +128,30 @@ def __str__(self) -> str:
128
128
# small set of tests to determine if we have a basically functioning interpreter
129
129
# (i.e. if any of these fail, then anything else is likely to follow)
130
130
STDTESTS = [
131
- 'test_grammar' ,
132
- 'test_opcodes' ,
133
- 'test_dict' ,
134
- 'test_builtin' ,
135
- 'test_exceptions' ,
136
- 'test_types' ,
137
- 'test_unittest' ,
138
- 'test_doctest' ,
139
- 'test_doctest2' ,
140
- 'test_support'
131
+ 'test_grammar' ,
132
+ 'test_opcodes' ,
133
+ 'test_dict' ,
134
+ 'test_builtin' ,
135
+ 'test_exceptions' ,
136
+ 'test_types' ,
137
+ 'test_unittest' ,
138
+ 'test_doctest' ,
139
+ 'test_doctest2' ,
140
+ 'test_support'
141
141
]
142
142
143
143
# set of tests that we don't want to be executed when using regrtest
144
144
NOTTESTS = set ()
145
145
146
+ #If these test directories are encountered recurse into them and treat each
147
+ # test_ .py or dir as a separate test module. This can increase parallelism.
148
+ # Beware this can't generally be done for any directory with sub-tests as the
149
+ # __init__.py may do things which alter what tests are to be run.
150
+
151
+ SPLITTESTDIRS = {
152
+ "test_asyncio" ,
153
+ "test_compiler" ,
154
+ }
146
155
147
156
# Storage of uncollectable objects
148
157
FOUND_GARBAGE = []
@@ -158,16 +167,24 @@ def findtestdir(path=None):
158
167
return path or os .path .dirname (os .path .dirname (__file__ )) or os .curdir
159
168
160
169
161
- def findtests (testdir = None , stdtests = STDTESTS , nottests = NOTTESTS ):
170
+ def findtests (testdir = None , stdtests = STDTESTS , nottests = NOTTESTS , splittestdirs = SPLITTESTDIRS , base_mod = "" ):
162
171
"""Return a list of all applicable test modules."""
163
172
testdir = findtestdir (testdir )
164
173
names = os .listdir (testdir )
165
174
tests = []
166
175
others = set (stdtests ) | nottests
167
176
for name in names :
168
177
mod , ext = os .path .splitext (name )
169
- if mod [:5 ] == "test_" and ext in (".py" , "" ) and mod not in others :
170
- tests .append (mod )
178
+ if mod [:5 ] == "test_" and mod not in others :
179
+ if mod in splittestdirs :
180
+ subdir = os .path .join (testdir , mod )
181
+ if len (base_mod ):
182
+ mod = f"{ base_mod } .{ mod } "
183
+ else :
184
+ mod = f"test.{ mod } "
185
+ tests .extend (findtests (subdir , [], nottests , splittestdirs , mod ))
186
+ elif ext in (".py" , "" ):
187
+ tests .append (f"{ base_mod } .{ mod } " if len (base_mod ) else mod )
171
188
return stdtests + sorted (tests )
172
189
173
190
@@ -186,7 +203,7 @@ def _runtest(ns: Namespace, test_name: str) -> TestResult:
186
203
output_on_failure = ns .verbose3
187
204
188
205
use_timeout = (
189
- ns .timeout is not None and threading_helper .can_start_thread
206
+ ns .timeout is not None and threading_helper .can_start_thread
190
207
)
191
208
if use_timeout :
192
209
faulthandler .dump_traceback_later (ns .timeout , exit = True )
@@ -217,7 +234,7 @@ def _runtest(ns: Namespace, test_name: str) -> TestResult:
217
234
print_warning .orig_stderr = stream
218
235
219
236
result = _runtest_inner (ns , test_name ,
220
- display_failure = False )
237
+ display_failure = False )
221
238
if not isinstance (result , Passed ):
222
239
output = stream .getvalue ()
223
240
finally :
@@ -233,13 +250,13 @@ def _runtest(ns: Namespace, test_name: str) -> TestResult:
233
250
support .verbose = ns .verbose
234
251
235
252
result = _runtest_inner (ns , test_name ,
236
- display_failure = not ns .verbose )
253
+ display_failure = not ns .verbose )
237
254
238
255
if xml_list :
239
256
import xml .etree .ElementTree as ET
240
257
result .xml_data = [
241
- ET .tostring (x ).decode ('us-ascii' )
242
- for x in xml_list
258
+ ET .tostring (x ).decode ('us-ascii' )
259
+ for x in xml_list
243
260
]
244
261
245
262
result .duration_sec = time .perf_counter () - start_time
@@ -267,7 +284,7 @@ def runtest(ns: Namespace, test_name: str) -> TestResult:
267
284
if not ns .pgo :
268
285
msg = traceback .format_exc ()
269
286
print (f"test { test_name } crashed -- { msg } " ,
270
- file = sys .stderr , flush = True )
287
+ file = sys .stderr , flush = True )
271
288
return Failed (test_name )
272
289
273
290
@@ -328,7 +345,7 @@ def _runtest_inner2(ns: Namespace, test_name: str) -> bool:
328
345
if gc .garbage :
329
346
support .environment_altered = True
330
347
print_warning (f"{ test_name } created { len (gc .garbage )} "
331
- f"uncollectable object(s)." )
348
+ f"uncollectable object(s)." )
332
349
333
350
# move the uncollectable objects somewhere,
334
351
# so we don't see them again
@@ -341,7 +358,7 @@ def _runtest_inner2(ns: Namespace, test_name: str) -> bool:
341
358
342
359
343
360
def _runtest_inner (
344
- ns : Namespace , test_name : str , display_failure : bool = True
361
+ ns : Namespace , test_name : str , display_failure : bool = True
345
362
) -> TestResult :
346
363
# Detect environment changes, handle exceptions.
347
364
@@ -387,7 +404,7 @@ def _runtest_inner(
387
404
if not ns .pgo :
388
405
msg = traceback .format_exc ()
389
406
print (f"test { test_name } crashed -- { msg } " ,
390
- file = sys .stderr , flush = True )
407
+ file = sys .stderr , flush = True )
391
408
return UncaughtException (test_name )
392
409
393
410
if refleak :
@@ -415,7 +432,7 @@ def cleanup_test_droppings(test_name: str, verbose: int) -> None:
415
432
kind , nuker = "file" , os .unlink
416
433
else :
417
434
raise RuntimeError (f"os.path says { name !r} exists but is neither "
418
- f"directory nor file" )
435
+ f"directory nor file" )
419
436
420
437
if verbose :
421
438
print_warning (f"{ test_name } left behind { kind } { name !r} " )
@@ -428,4 +445,4 @@ def cleanup_test_droppings(test_name: str, verbose: int) -> None:
428
445
nuker (name )
429
446
except Exception as exc :
430
447
print_warning (f"{ test_name } left behind { kind } { name !r} "
431
- f"and it couldn't be removed: { exc } " )
448
+ f"and it couldn't be removed: { exc } " )
0 commit comments