@@ -70,7 +70,6 @@ def stop(self):
7070 with self .lock :
7171 self .tests_iter = None
7272
73-
7473@dataclasses .dataclass (slots = True , frozen = True )
7574class MultiprocessResult :
7675 result : TestResult
@@ -269,16 +268,22 @@ def create_json_file(self, stack: contextlib.ExitStack) -> tuple[JsonFile, TextI
269268 json_file = JsonFile (json_fd , JsonFileType .UNIX_FD )
270269 return (json_file , json_tmpfile )
271270
272- def create_worker_runtests (self , test_name : TestName , json_file : JsonFile ) -> WorkerRunTests :
273- tests = (test_name ,)
274- if self .runtests .rerun :
275- match_tests = self .runtests .get_match_tests (test_name )
271+ def create_worker_runtests (self , test_name : TestName ,
272+ json_file : JsonFile ,
273+ module_name : TestName | None = None ,
274+ ) -> WorkerRunTests :
275+ kwargs : dict [str , Any ] = {}
276+
277+ if module_name is not None and test_name != module_name :
278+ tests = (module_name ,)
279+ kwargs ['match_tests' ] = [(test_name , True )]
276280 else :
277- match_tests = None
281+ tests = (test_name ,)
282+ if self .runtests .rerun :
283+ match_tests = self .runtests .get_match_tests (test_name )
284+ if match_tests :
285+ kwargs ['match_tests' ] = [(test , True ) for test in match_tests ]
278286
279- kwargs : dict [str , Any ] = {}
280- if match_tests :
281- kwargs ['match_tests' ] = [(test , True ) for test in match_tests ]
282287 if self .runtests .output_on_failure :
283288 kwargs ['verbose' ] = True
284289 kwargs ['output_on_failure' ] = False
@@ -356,11 +361,13 @@ def read_json(self, json_file: JsonFile, json_tmpfile: TextIO | None,
356361
357362 return (result , stdout )
358363
359- def _runtest (self , test_name : TestName ) -> MultiprocessResult :
364+ def _runtest (self , test_name : TestName ,
365+ module_name : TestName | None = None ) -> MultiprocessResult :
360366 with contextlib .ExitStack () as stack :
361367 stdout_file = self .create_stdout (stack )
362368 json_file , json_tmpfile = self .create_json_file (stack )
363- worker_runtests = self .create_worker_runtests (test_name , json_file )
369+ worker_runtests = self .create_worker_runtests (
370+ test_name , json_file , module_name = module_name )
364371
365372 retcode : str | int | None
366373 retcode , tmp_files = self .run_tmp_files (worker_runtests ,
@@ -393,26 +400,38 @@ def _runtest(self, test_name: TestName) -> MultiprocessResult:
393400 def run (self ) -> None :
394401 fail_fast = self .runtests .fail_fast
395402 fail_env_changed = self .runtests .fail_env_changed
403+ single_process_per_case = self .runtests .single_process_per_case
396404 try :
397- while not self ._stopped :
405+ stop = False
406+ while not self ._stopped and not stop :
398407 try :
399- test_name = next (self .pending )
408+ module_name , case_ids = next (self .pending )
400409 except StopIteration :
401410 break
402411
403- self .start_time = time .monotonic ()
404- self .test_name = test_name
405- try :
406- mp_result = self ._runtest (test_name )
407- except WorkerError as exc :
408- mp_result = exc .mp_result
409- finally :
410- self .test_name = _NOT_RUNNING
411- mp_result .result .duration = time .monotonic () - self .start_time
412- self .output .put ((False , mp_result ))
413-
414- if mp_result .result .must_stop (fail_fast , fail_env_changed ):
415- break
412+ # All cases of a group run sequentially on this thread
413+ for test_name in case_ids :
414+ if self ._stopped :
415+ break
416+ self .start_time = time .monotonic ()
417+ self .test_name = test_name
418+ try :
419+ mp_result = self ._runtest (
420+ test_name ,
421+ module_name if single_process_per_case else None )
422+ except WorkerError as exc :
423+ mp_result = exc .mp_result
424+ finally :
425+ self .test_name = _NOT_RUNNING
426+ mp_result .result .duration = time .monotonic () - self .start_time
427+ if single_process_per_case :
428+ # Report the test case, not the test module
429+ mp_result .result .test_name = test_name
430+ self .output .put ((False , mp_result ))
431+
432+ if mp_result .result .must_stop (fail_fast , fail_env_changed ):
433+ stop = True
434+ break
416435 except ExitThread :
417436 pass
418437 except BaseException :
@@ -489,8 +508,7 @@ def __init__(self, num_workers: int, runtests: RunTests,
489508 self .live_worker_count = 0
490509
491510 self .output : queue .Queue [QueueContent ] = queue .Queue ()
492- tests_iter = runtests .iter_tests ()
493- self .pending = MultiprocessIterator (tests_iter )
511+ self .pending = MultiprocessIterator (runtests .iter_case_groups ())
494512 self .timeout = runtests .timeout
495513 if self .timeout is not None :
496514 # Rely on faulthandler to kill a worker process. This timouet is
0 commit comments