1919
2020class TestResult :
2121 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 ,
2626 ) -> None :
2727 self .name = name
2828 self .duration_sec = duration_sec
@@ -39,12 +39,12 @@ def __str__(self) -> str:
3939
4040class Failed (TestResult ):
4141 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 ,
4848 ) -> None :
4949 super ().__init__ (name , duration_sec = duration_sec , xml_data = xml_data )
5050 self .errors = errors
@@ -128,21 +128,30 @@ def __str__(self) -> str:
128128# small set of tests to determine if we have a basically functioning interpreter
129129# (i.e. if any of these fail, then anything else is likely to follow)
130130STDTESTS = [
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'
141141]
142142
143143# set of tests that we don't want to be executed when using regrtest
144144NOTTESTS = set ()
145145
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+ }
146155
147156# Storage of uncollectable objects
148157FOUND_GARBAGE = []
@@ -158,16 +167,24 @@ def findtestdir(path=None):
158167 return path or os .path .dirname (os .path .dirname (__file__ )) or os .curdir
159168
160169
161- def findtests (testdir = None , stdtests = STDTESTS , nottests = NOTTESTS ):
170+ def findtests (testdir = None , stdtests = STDTESTS , nottests = NOTTESTS , splittestdirs = SPLITTESTDIRS , base_mod = "" ):
162171 """Return a list of all applicable test modules."""
163172 testdir = findtestdir (testdir )
164173 names = os .listdir (testdir )
165174 tests = []
166175 others = set (stdtests ) | nottests
167176 for name in names :
168177 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 )
171188 return stdtests + sorted (tests )
172189
173190
@@ -186,7 +203,7 @@ def _runtest(ns: Namespace, test_name: str) -> TestResult:
186203 output_on_failure = ns .verbose3
187204
188205 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
190207 )
191208 if use_timeout :
192209 faulthandler .dump_traceback_later (ns .timeout , exit = True )
@@ -217,7 +234,7 @@ def _runtest(ns: Namespace, test_name: str) -> TestResult:
217234 print_warning .orig_stderr = stream
218235
219236 result = _runtest_inner (ns , test_name ,
220- display_failure = False )
237+ display_failure = False )
221238 if not isinstance (result , Passed ):
222239 output = stream .getvalue ()
223240 finally :
@@ -233,13 +250,13 @@ def _runtest(ns: Namespace, test_name: str) -> TestResult:
233250 support .verbose = ns .verbose
234251
235252 result = _runtest_inner (ns , test_name ,
236- display_failure = not ns .verbose )
253+ display_failure = not ns .verbose )
237254
238255 if xml_list :
239256 import xml .etree .ElementTree as ET
240257 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
243260 ]
244261
245262 result .duration_sec = time .perf_counter () - start_time
@@ -267,7 +284,7 @@ def runtest(ns: Namespace, test_name: str) -> TestResult:
267284 if not ns .pgo :
268285 msg = traceback .format_exc ()
269286 print (f"test { test_name } crashed -- { msg } " ,
270- file = sys .stderr , flush = True )
287+ file = sys .stderr , flush = True )
271288 return Failed (test_name )
272289
273290
@@ -328,7 +345,7 @@ def _runtest_inner2(ns: Namespace, test_name: str) -> bool:
328345 if gc .garbage :
329346 support .environment_altered = True
330347 print_warning (f"{ test_name } created { len (gc .garbage )} "
331- f"uncollectable object(s)." )
348+ f"uncollectable object(s)." )
332349
333350 # move the uncollectable objects somewhere,
334351 # so we don't see them again
@@ -341,7 +358,7 @@ def _runtest_inner2(ns: Namespace, test_name: str) -> bool:
341358
342359
343360def _runtest_inner (
344- ns : Namespace , test_name : str , display_failure : bool = True
361+ ns : Namespace , test_name : str , display_failure : bool = True
345362) -> TestResult :
346363 # Detect environment changes, handle exceptions.
347364
@@ -387,7 +404,7 @@ def _runtest_inner(
387404 if not ns .pgo :
388405 msg = traceback .format_exc ()
389406 print (f"test { test_name } crashed -- { msg } " ,
390- file = sys .stderr , flush = True )
407+ file = sys .stderr , flush = True )
391408 return UncaughtException (test_name )
392409
393410 if refleak :
@@ -415,7 +432,7 @@ def cleanup_test_droppings(test_name: str, verbose: int) -> None:
415432 kind , nuker = "file" , os .unlink
416433 else :
417434 raise RuntimeError (f"os.path says { name !r} exists but is neither "
418- f"directory nor file" )
435+ f"directory nor file" )
419436
420437 if verbose :
421438 print_warning (f"{ test_name } left behind { kind } { name !r} " )
@@ -428,4 +445,4 @@ def cleanup_test_droppings(test_name: str, verbose: int) -> None:
428445 nuker (name )
429446 except Exception as exc :
430447 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