77import time
88import trace
99
10- from test import support
1110from test .support import os_helper , MS_WINDOWS
1211
1312from .cmdline import _parse_args , Namespace
@@ -73,6 +72,7 @@ def __init__(self, ns: Namespace, _add_python_opts: bool = False):
7372 self .want_cleanup : bool = ns .cleanup
7473 self .want_rerun : bool = ns .rerun
7574 self .want_run_leaks : bool = ns .runleaks
75+ self .want_bisect : bool = ns .bisect
7676
7777 self .ci_mode : bool = (ns .fast_ci or ns .slow_ci )
7878 self .want_add_python_opts : bool = (_add_python_opts
@@ -273,6 +273,47 @@ def rerun_failed_tests(self, runtests: RunTests):
273273
274274 self .display_result (rerun_runtests )
275275
276+ def _run_bisect (self , runtests : RunTests , test : str , progress : str ) -> bool :
277+ print ()
278+ title = f"Bisect { test } "
279+ if progress :
280+ title = f"{ title } ({ progress } )"
281+ print (title )
282+ print ("#" * len (title ))
283+ print ()
284+
285+ cmd = runtests .create_python_cmd ()
286+ cmd .extend ([
287+ "-u" , "-m" , "test.bisect_cmd" ,
288+ # Limit to 25 iterations (instead of 100) to not abuse CI resources
289+ "--max-iter" , "25" ,
290+ "-v" ,
291+ # runtests.match_tests is not used (yet) for bisect_cmd -i arg
292+ ])
293+ cmd .extend (runtests .bisect_cmd_args ())
294+ cmd .append (test )
295+ print ("+" , shlex .join (cmd ), flush = True )
296+
297+ import subprocess
298+ proc = subprocess .run (cmd , timeout = runtests .timeout )
299+ exitcode = proc .returncode
300+ if exitcode :
301+ print (f"Bisect failed with exit code { exitcode } " )
302+ return False
303+
304+ return True
305+
306+ def run_bisect (self , runtests : RunTests ) -> None :
307+ tests , _ = self .results .prepare_rerun (clear = False )
308+
309+ for index , name in enumerate (tests , 1 ):
310+ if len (tests ) > 1 :
311+ progress = f"{ index } /{ len (tests )} "
312+ else :
313+ progress = ""
314+ if not self ._run_bisect (runtests , name , progress ):
315+ return
316+
276317 def display_result (self , runtests ):
277318 # If running the test suite for PGO then no one cares about results.
278319 if runtests .pgo :
@@ -466,7 +507,7 @@ def _run_tests(self, selected: TestTuple, tests: TestList | None) -> int:
466507
467508 setup_process ()
468509
469- if self .hunt_refleak and not self .num_workers :
510+ if ( runtests .hunt_refleak is not None ) and ( not self .num_workers ) :
470511 # gh-109739: WindowsLoadTracker thread interfers with refleak check
471512 use_load_tracker = False
472513 else :
@@ -486,6 +527,9 @@ def _run_tests(self, selected: TestTuple, tests: TestList | None) -> int:
486527
487528 if self .want_rerun and self .results .need_rerun ():
488529 self .rerun_failed_tests (runtests )
530+
531+ if self .want_bisect and self .results .need_rerun ():
532+ self .run_bisect (runtests )
489533 finally :
490534 if use_load_tracker :
491535 self .logger .stop_load_tracker ()
0 commit comments