1919
2020class TestResult :
2121def __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 :
2727self .name = name
2828self .duration_sec = duration_sec
@@ -39,12 +39,12 @@ def __str__(self) -> str:
3939
4040class Failed (TestResult ):
4141def __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 :
4949super ().__init__ (name ,duration_sec = duration_sec ,xml_data = xml_data )
5050self .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):
158167return 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."""
163172testdir = findtestdir (testdir )
164173names = os .listdir (testdir )
165174tests = []
166175others = set (stdtests )| nottests
167176for name in names :
168177mod ,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 )
171188return stdtests + sorted (tests )
172189
173190
@@ -186,7 +203,7 @@ def _runtest(ns: Namespace, test_name: str) -> TestResult:
186203output_on_failure = ns .verbose3
187204
188205use_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 )
191208if use_timeout :
192209faulthandler .dump_traceback_later (ns .timeout ,exit = True )
@@ -217,7 +234,7 @@ def _runtest(ns: Namespace, test_name: str) -> TestResult:
217234print_warning .orig_stderr = stream
218235
219236result = _runtest_inner (ns ,test_name ,
220- display_failure = False )
237+ display_failure = False )
221238if not isinstance (result ,Passed ):
222239output = stream .getvalue ()
223240finally :
@@ -233,13 +250,13 @@ def _runtest(ns: Namespace, test_name: str) -> TestResult:
233250support .verbose = ns .verbose
234251
235252result = _runtest_inner (ns ,test_name ,
236- display_failure = not ns .verbose )
253+ display_failure = not ns .verbose )
237254
238255if xml_list :
239256import xml .etree .ElementTree as ET
240257result .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
245262result .duration_sec = time .perf_counter ()- start_time
@@ -267,7 +284,7 @@ def runtest(ns: Namespace, test_name: str) -> TestResult:
267284if not ns .pgo :
268285msg = traceback .format_exc ()
269286print (f"test{ test_name } crashed --{ msg } " ,
270- file = sys .stderr ,flush = True )
287+ file = sys .stderr ,flush = True )
271288return Failed (test_name )
272289
273290
@@ -328,7 +345,7 @@ def _runtest_inner2(ns: Namespace, test_name: str) -> bool:
328345if gc .garbage :
329346support .environment_altered = True
330347print_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(
387404if not ns .pgo :
388405msg = traceback .format_exc ()
389406print (f"test{ test_name } crashed --{ msg } " ,
390- file = sys .stderr ,flush = True )
407+ file = sys .stderr ,flush = True )
391408return UncaughtException (test_name )
392409
393410if refleak :
@@ -415,7 +432,7 @@ def cleanup_test_droppings(test_name: str, verbose: int) -> None:
415432kind ,nuker = "file" ,os .unlink
416433else :
417434raise RuntimeError (f"os.path says{ name !r} exists but is neither "
418- f"directory nor file" )
435+ f"directory nor file" )
419436
420437if verbose :
421438print_warning (f"{ test_name } left behind{ kind } { name !r} " )
@@ -428,4 +445,4 @@ def cleanup_test_droppings(test_name: str, verbose: int) -> None:
428445nuker (name )
429446except Exception as exc :
430447print_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 } " )