@@ -432,7 +432,7 @@ def hasopt(self, char: str) -> bool:
432
432
char = {"xfailed" : "x" , "skipped" : "s" }.get (char , char )
433
433
return char in self .reportchars
434
434
435
- def write_fspath_result (self , nodeid : str , res , ** markup : bool ) -> None :
435
+ def write_fspath_result (self , nodeid : str , res : str , ** markup : bool ) -> None :
436
436
fspath = self .config .rootpath / nodeid .split ("::" )[0 ]
437
437
if self .currentfspath is None or fspath != self .currentfspath :
438
438
if self .currentfspath is not None and self ._show_progress_info :
@@ -565,10 +565,11 @@ def pytest_deselected(self, items: Sequence[Item]) -> None:
565
565
def pytest_runtest_logstart (
566
566
self , nodeid : str , location : Tuple [str , Optional [int ], str ]
567
567
) -> None :
568
+ fspath , lineno , domain = location
568
569
# Ensure that the path is printed before the
569
570
# 1st test of a module starts running.
570
571
if self .showlongtestinfo :
571
- line = self ._locationline (nodeid , * location )
572
+ line = self ._locationline (nodeid , fspath , lineno , domain )
572
573
self .write_ensure_prefix (line , "" )
573
574
self .flush ()
574
575
elif self .showfspath :
@@ -591,7 +592,6 @@ def pytest_runtest_logreport(self, report: TestReport) -> None:
591
592
if not letter and not word :
592
593
# Probably passed setup/teardown.
593
594
return
594
- running_xdist = hasattr (rep , "node" )
595
595
if markup is None :
596
596
was_xfail = hasattr (report , "wasxfail" )
597
597
if rep .passed and not was_xfail :
@@ -604,11 +604,20 @@ def pytest_runtest_logreport(self, report: TestReport) -> None:
604
604
markup = {"yellow" : True }
605
605
else :
606
606
markup = {}
607
+ self ._progress_nodeids_reported .add (rep .nodeid )
607
608
if self .config .get_verbosity (Config .VERBOSITY_TEST_CASES ) <= 0 :
608
609
self ._tw .write (letter , ** markup )
610
+ # When running in xdist, the logreport and logfinish of multiple
611
+ # items are interspersed, e.g. `logreport`, `logreport`,
612
+ # `logfinish`, `logfinish`. To avoid the "past edge" calculation
613
+ # from getting confused and overflowing (#7166), do the past edge
614
+ # printing here and not in logfinish, except for the 100% which
615
+ # should only be printed after all teardowns are finished.
616
+ if self ._show_progress_info and not self ._is_last_item :
617
+ self ._write_progress_information_if_past_edge ()
609
618
else :
610
- self ._progress_nodeids_reported .add (rep .nodeid )
611
619
line = self ._locationline (rep .nodeid , * rep .location )
620
+ running_xdist = hasattr (rep , "node" )
612
621
if not running_xdist :
613
622
self .write_ensure_prefix (line , word , ** markup )
614
623
if rep .skipped or hasattr (report , "wasxfail" ):
@@ -648,39 +657,29 @@ def _is_last_item(self) -> bool:
648
657
assert self ._session is not None
649
658
return len (self ._progress_nodeids_reported ) == self ._session .testscollected
650
659
651
- def pytest_runtest_logfinish (self , nodeid : str ) -> None :
652
- assert self ._session
660
+ @hookimpl (wrapper = True )
661
+ def pytest_runtestloop (self ) -> Generator [None , object , object ]:
662
+ result = yield
663
+
664
+ # Write the final/100% progress -- deferred until the loop is complete.
653
665
if (
654
666
self .config .get_verbosity (Config .VERBOSITY_TEST_CASES ) <= 0
655
667
and self ._show_progress_info
668
+ and self ._progress_nodeids_reported
656
669
):
657
- if self ._show_progress_info == "count" :
658
- num_tests = self ._session .testscollected
659
- progress_length = len (f" [{ num_tests } /{ num_tests } ]" )
660
- else :
661
- progress_length = len (" [100%]" )
662
-
663
- self ._progress_nodeids_reported .add (nodeid )
670
+ self ._write_progress_information_filling_space ()
664
671
665
- if self ._is_last_item :
666
- self ._write_progress_information_filling_space ()
667
- else :
668
- main_color , _ = self ._get_main_color ()
669
- w = self ._width_of_current_line
670
- past_edge = w + progress_length + 1 >= self ._screen_width
671
- if past_edge :
672
- msg = self ._get_progress_information_message ()
673
- self ._tw .write (msg + "\n " , ** {main_color : True })
672
+ return result
674
673
675
674
def _get_progress_information_message (self ) -> str :
676
675
assert self ._session
677
676
collected = self ._session .testscollected
678
677
if self ._show_progress_info == "count" :
679
678
if collected :
680
- progress = self ._progress_nodeids_reported
679
+ progress = len ( self ._progress_nodeids_reported )
681
680
counter_format = f"{{:{ len (str (collected ))} d}}"
682
681
format_string = f" [{ counter_format } /{{}}]"
683
- return format_string .format (len ( progress ) , collected )
682
+ return format_string .format (progress , collected )
684
683
return f" [ { collected } / { collected } ]"
685
684
else :
686
685
if collected :
@@ -689,6 +688,20 @@ def _get_progress_information_message(self) -> str:
689
688
)
690
689
return " [100%]"
691
690
691
+ def _write_progress_information_if_past_edge (self ) -> None :
692
+ w = self ._width_of_current_line
693
+ if self ._show_progress_info == "count" :
694
+ assert self ._session
695
+ num_tests = self ._session .testscollected
696
+ progress_length = len (f" [{ num_tests } /{ num_tests } ]" )
697
+ else :
698
+ progress_length = len (" [100%]" )
699
+ past_edge = w + progress_length + 1 >= self ._screen_width
700
+ if past_edge :
701
+ main_color , _ = self ._get_main_color ()
702
+ msg = self ._get_progress_information_message ()
703
+ self ._tw .write (msg + "\n " , ** {main_color : True })
704
+
692
705
def _write_progress_information_filling_space (self ) -> None :
693
706
color , _ = self ._get_main_color ()
694
707
msg = self ._get_progress_information_message ()
@@ -937,7 +950,7 @@ def mkrel(nodeid: str) -> str:
937
950
line += "[" .join (values )
938
951
return line
939
952
940
- # collect_fspath comes from testid which has a "/"-normalized path.
953
+ # fspath comes from testid which has a "/"-normalized path.
941
954
if fspath :
942
955
res = mkrel (nodeid )
943
956
if self .verbosity >= 2 and nodeid .split ("::" )[0 ] != fspath .replace (
0 commit comments