Type annotate more of _pytest.terminal
This commit is contained in:
parent
2833884688
commit
c0af19d8ad
|
@ -16,7 +16,9 @@ from typing import Generator
|
||||||
from typing import List
|
from typing import List
|
||||||
from typing import Mapping
|
from typing import Mapping
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
from typing import Sequence
|
||||||
from typing import Set
|
from typing import Set
|
||||||
|
from typing import TextIO
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
|
@ -37,11 +39,15 @@ from _pytest.config import Config
|
||||||
from _pytest.config import ExitCode
|
from _pytest.config import ExitCode
|
||||||
from _pytest.config.argparsing import Parser
|
from _pytest.config.argparsing import Parser
|
||||||
from _pytest.deprecated import TERMINALWRITER_WRITER
|
from _pytest.deprecated import TERMINALWRITER_WRITER
|
||||||
|
from _pytest.nodes import Item
|
||||||
|
from _pytest.nodes import Node
|
||||||
from _pytest.reports import BaseReport
|
from _pytest.reports import BaseReport
|
||||||
from _pytest.reports import CollectReport
|
from _pytest.reports import CollectReport
|
||||||
from _pytest.reports import TestReport
|
from _pytest.reports import TestReport
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
from typing_extensions import Literal
|
||||||
|
|
||||||
from _pytest.main import Session
|
from _pytest.main import Session
|
||||||
|
|
||||||
|
|
||||||
|
@ -69,7 +75,14 @@ class MoreQuietAction(argparse.Action):
|
||||||
used to unify verbosity handling
|
used to unify verbosity handling
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, option_strings, dest, default=None, required=False, help=None):
|
def __init__(
|
||||||
|
self,
|
||||||
|
option_strings: Sequence[str],
|
||||||
|
dest: str,
|
||||||
|
default: object = None,
|
||||||
|
required: bool = False,
|
||||||
|
help: Optional[str] = None,
|
||||||
|
) -> None:
|
||||||
super().__init__(
|
super().__init__(
|
||||||
option_strings=option_strings,
|
option_strings=option_strings,
|
||||||
dest=dest,
|
dest=dest,
|
||||||
|
@ -79,7 +92,13 @@ class MoreQuietAction(argparse.Action):
|
||||||
help=help,
|
help=help,
|
||||||
)
|
)
|
||||||
|
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
def __call__(
|
||||||
|
self,
|
||||||
|
parser: argparse.ArgumentParser,
|
||||||
|
namespace: argparse.Namespace,
|
||||||
|
values: Union[str, Sequence[object], None],
|
||||||
|
option_string: Optional[str] = None,
|
||||||
|
) -> None:
|
||||||
new_count = getattr(namespace, self.dest, 0) - 1
|
new_count = getattr(namespace, self.dest, 0) - 1
|
||||||
setattr(namespace, self.dest, new_count)
|
setattr(namespace, self.dest, new_count)
|
||||||
# todo Deprecate config.quiet
|
# todo Deprecate config.quiet
|
||||||
|
@ -194,7 +213,7 @@ def pytest_configure(config: Config) -> None:
|
||||||
|
|
||||||
|
|
||||||
def getreportopt(config: Config) -> str:
|
def getreportopt(config: Config) -> str:
|
||||||
reportchars = config.option.reportchars
|
reportchars = config.option.reportchars # type: str
|
||||||
|
|
||||||
old_aliases = {"F", "S"}
|
old_aliases = {"F", "S"}
|
||||||
reportopts = ""
|
reportopts = ""
|
||||||
|
@ -247,10 +266,12 @@ class WarningReport:
|
||||||
|
|
||||||
message = attr.ib(type=str)
|
message = attr.ib(type=str)
|
||||||
nodeid = attr.ib(type=Optional[str], default=None)
|
nodeid = attr.ib(type=Optional[str], default=None)
|
||||||
fslocation = attr.ib(default=None)
|
fslocation = attr.ib(
|
||||||
|
type=Optional[Union[Tuple[str, int], py.path.local]], default=None
|
||||||
|
)
|
||||||
count_towards_summary = True
|
count_towards_summary = True
|
||||||
|
|
||||||
def get_location(self, config):
|
def get_location(self, config: Config) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
Returns the more user-friendly information about the location
|
Returns the more user-friendly information about the location
|
||||||
of a warning, or None.
|
of a warning, or None.
|
||||||
|
@ -270,13 +291,13 @@ class WarningReport:
|
||||||
|
|
||||||
|
|
||||||
class TerminalReporter:
|
class TerminalReporter:
|
||||||
def __init__(self, config: Config, file=None) -> None:
|
def __init__(self, config: Config, file: Optional[TextIO] = None) -> None:
|
||||||
import _pytest.config
|
import _pytest.config
|
||||||
|
|
||||||
self.config = config
|
self.config = config
|
||||||
self._numcollected = 0
|
self._numcollected = 0
|
||||||
self._session = None # type: Optional[Session]
|
self._session = None # type: Optional[Session]
|
||||||
self._showfspath = None
|
self._showfspath = None # type: Optional[bool]
|
||||||
|
|
||||||
self.stats = {} # type: Dict[str, List[Any]]
|
self.stats = {} # type: Dict[str, List[Any]]
|
||||||
self._main_color = None # type: Optional[str]
|
self._main_color = None # type: Optional[str]
|
||||||
|
@ -293,6 +314,7 @@ class TerminalReporter:
|
||||||
self._progress_nodeids_reported = set() # type: Set[str]
|
self._progress_nodeids_reported = set() # type: Set[str]
|
||||||
self._show_progress_info = self._determine_show_progress_info()
|
self._show_progress_info = self._determine_show_progress_info()
|
||||||
self._collect_report_last_write = None # type: Optional[float]
|
self._collect_report_last_write = None # type: Optional[float]
|
||||||
|
self._already_displayed_warnings = None # type: Optional[int]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def writer(self) -> TerminalWriter:
|
def writer(self) -> TerminalWriter:
|
||||||
|
@ -300,11 +322,11 @@ class TerminalReporter:
|
||||||
return self._tw
|
return self._tw
|
||||||
|
|
||||||
@writer.setter
|
@writer.setter
|
||||||
def writer(self, value: TerminalWriter):
|
def writer(self, value: TerminalWriter) -> None:
|
||||||
warnings.warn(TERMINALWRITER_WRITER, stacklevel=2)
|
warnings.warn(TERMINALWRITER_WRITER, stacklevel=2)
|
||||||
self._tw = value
|
self._tw = value
|
||||||
|
|
||||||
def _determine_show_progress_info(self):
|
def _determine_show_progress_info(self) -> "Literal['progress', 'count', False]":
|
||||||
"""Return True if we should display progress information based on the current config"""
|
"""Return True if we should display progress information based on the current config"""
|
||||||
# do not show progress if we are not capturing output (#3038)
|
# do not show progress if we are not capturing output (#3038)
|
||||||
if self.config.getoption("capture", "no") == "no":
|
if self.config.getoption("capture", "no") == "no":
|
||||||
|
@ -312,38 +334,42 @@ class TerminalReporter:
|
||||||
# do not show progress if we are showing fixture setup/teardown
|
# do not show progress if we are showing fixture setup/teardown
|
||||||
if self.config.getoption("setupshow", False):
|
if self.config.getoption("setupshow", False):
|
||||||
return False
|
return False
|
||||||
cfg = self.config.getini("console_output_style")
|
cfg = self.config.getini("console_output_style") # type: str
|
||||||
if cfg in ("progress", "count"):
|
if cfg == "progress":
|
||||||
return cfg
|
return "progress"
|
||||||
return False
|
elif cfg == "count":
|
||||||
|
return "count"
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def verbosity(self):
|
def verbosity(self) -> int:
|
||||||
return self.config.option.verbose
|
verbosity = self.config.option.verbose # type: int
|
||||||
|
return verbosity
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def showheader(self):
|
def showheader(self) -> bool:
|
||||||
return self.verbosity >= 0
|
return self.verbosity >= 0
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def showfspath(self):
|
def showfspath(self) -> bool:
|
||||||
if self._showfspath is None:
|
if self._showfspath is None:
|
||||||
return self.verbosity >= 0
|
return self.verbosity >= 0
|
||||||
return self._showfspath
|
return self._showfspath
|
||||||
|
|
||||||
@showfspath.setter
|
@showfspath.setter
|
||||||
def showfspath(self, value):
|
def showfspath(self, value: Optional[bool]) -> None:
|
||||||
self._showfspath = value
|
self._showfspath = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def showlongtestinfo(self):
|
def showlongtestinfo(self) -> bool:
|
||||||
return self.verbosity > 0
|
return self.verbosity > 0
|
||||||
|
|
||||||
def hasopt(self, char):
|
def hasopt(self, char: str) -> bool:
|
||||||
char = {"xfailed": "x", "skipped": "s"}.get(char, char)
|
char = {"xfailed": "x", "skipped": "s"}.get(char, char)
|
||||||
return char in self.reportchars
|
return char in self.reportchars
|
||||||
|
|
||||||
def write_fspath_result(self, nodeid, res, **markup):
|
def write_fspath_result(self, nodeid: str, res, **markup: bool) -> None:
|
||||||
fspath = self.config.rootdir.join(nodeid.split("::")[0])
|
fspath = self.config.rootdir.join(nodeid.split("::")[0])
|
||||||
# NOTE: explicitly check for None to work around py bug, and for less
|
# NOTE: explicitly check for None to work around py bug, and for less
|
||||||
# overhead in general (https://github.com/pytest-dev/py/pull/207).
|
# overhead in general (https://github.com/pytest-dev/py/pull/207).
|
||||||
|
@ -356,7 +382,7 @@ class TerminalReporter:
|
||||||
self._tw.write(fspath + " ")
|
self._tw.write(fspath + " ")
|
||||||
self._tw.write(res, flush=True, **markup)
|
self._tw.write(res, flush=True, **markup)
|
||||||
|
|
||||||
def write_ensure_prefix(self, prefix, extra="", **kwargs):
|
def write_ensure_prefix(self, prefix, extra: str = "", **kwargs) -> None:
|
||||||
if self.currentfspath != prefix:
|
if self.currentfspath != prefix:
|
||||||
self._tw.line()
|
self._tw.line()
|
||||||
self.currentfspath = prefix
|
self.currentfspath = prefix
|
||||||
|
@ -376,13 +402,13 @@ class TerminalReporter:
|
||||||
def flush(self) -> None:
|
def flush(self) -> None:
|
||||||
self._tw.flush()
|
self._tw.flush()
|
||||||
|
|
||||||
def write_line(self, line: Union[str, bytes], **markup) -> None:
|
def write_line(self, line: Union[str, bytes], **markup: bool) -> None:
|
||||||
if not isinstance(line, str):
|
if not isinstance(line, str):
|
||||||
line = str(line, errors="replace")
|
line = str(line, errors="replace")
|
||||||
self.ensure_newline()
|
self.ensure_newline()
|
||||||
self._tw.line(line, **markup)
|
self._tw.line(line, **markup)
|
||||||
|
|
||||||
def rewrite(self, line, **markup):
|
def rewrite(self, line: str, **markup: bool) -> None:
|
||||||
"""
|
"""
|
||||||
Rewinds the terminal cursor to the beginning and writes the given line.
|
Rewinds the terminal cursor to the beginning and writes the given line.
|
||||||
|
|
||||||
|
@ -400,14 +426,20 @@ class TerminalReporter:
|
||||||
line = str(line)
|
line = str(line)
|
||||||
self._tw.write("\r" + line + fill, **markup)
|
self._tw.write("\r" + line + fill, **markup)
|
||||||
|
|
||||||
def write_sep(self, sep, title=None, **markup):
|
def write_sep(
|
||||||
|
self,
|
||||||
|
sep: str,
|
||||||
|
title: Optional[str] = None,
|
||||||
|
fullwidth: Optional[int] = None,
|
||||||
|
**markup: bool
|
||||||
|
) -> None:
|
||||||
self.ensure_newline()
|
self.ensure_newline()
|
||||||
self._tw.sep(sep, title, **markup)
|
self._tw.sep(sep, title, fullwidth, **markup)
|
||||||
|
|
||||||
def section(self, title, sep="=", **kw):
|
def section(self, title: str, sep: str = "=", **kw: bool) -> None:
|
||||||
self._tw.sep(sep, title, **kw)
|
self._tw.sep(sep, title, **kw)
|
||||||
|
|
||||||
def line(self, msg, **kw):
|
def line(self, msg: str, **kw: bool) -> None:
|
||||||
self._tw.line(msg, **kw)
|
self._tw.line(msg, **kw)
|
||||||
|
|
||||||
def _add_stats(self, category: str, items: List) -> None:
|
def _add_stats(self, category: str, items: List) -> None:
|
||||||
|
@ -421,7 +453,9 @@ class TerminalReporter:
|
||||||
self.write_line("INTERNALERROR> " + line)
|
self.write_line("INTERNALERROR> " + line)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def pytest_warning_recorded(self, warning_message, nodeid):
|
def pytest_warning_recorded(
|
||||||
|
self, warning_message: warnings.WarningMessage, nodeid: str,
|
||||||
|
) -> None:
|
||||||
from _pytest.warnings import warning_record_to_str
|
from _pytest.warnings import warning_record_to_str
|
||||||
|
|
||||||
fslocation = warning_message.filename, warning_message.lineno
|
fslocation = warning_message.filename, warning_message.lineno
|
||||||
|
@ -440,10 +474,10 @@ class TerminalReporter:
|
||||||
# which garbles our output if we use self.write_line
|
# which garbles our output if we use self.write_line
|
||||||
self.write_line(msg)
|
self.write_line(msg)
|
||||||
|
|
||||||
def pytest_deselected(self, items):
|
def pytest_deselected(self, items) -> None:
|
||||||
self._add_stats("deselected", items)
|
self._add_stats("deselected", items)
|
||||||
|
|
||||||
def pytest_runtest_logstart(self, nodeid, location):
|
def pytest_runtest_logstart(self, nodeid, location) -> None:
|
||||||
# ensure that the path is printed before the
|
# ensure that the path is printed before the
|
||||||
# 1st test of a module starts running
|
# 1st test of a module starts running
|
||||||
if self.showlongtestinfo:
|
if self.showlongtestinfo:
|
||||||
|
@ -457,7 +491,9 @@ class TerminalReporter:
|
||||||
def pytest_runtest_logreport(self, report: TestReport) -> None:
|
def pytest_runtest_logreport(self, report: TestReport) -> None:
|
||||||
self._tests_ran = True
|
self._tests_ran = True
|
||||||
rep = report
|
rep = report
|
||||||
res = self.config.hook.pytest_report_teststatus(report=rep, config=self.config)
|
res = self.config.hook.pytest_report_teststatus(
|
||||||
|
report=rep, config=self.config
|
||||||
|
) # type: Tuple[str, str, str]
|
||||||
category, letter, word = res
|
category, letter, word = res
|
||||||
if isinstance(word, tuple):
|
if isinstance(word, tuple):
|
||||||
word, markup = word
|
word, markup = word
|
||||||
|
@ -504,10 +540,11 @@ class TerminalReporter:
|
||||||
self.flush()
|
self.flush()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _is_last_item(self):
|
def _is_last_item(self) -> bool:
|
||||||
|
assert self._session is not None
|
||||||
return len(self._progress_nodeids_reported) == self._session.testscollected
|
return len(self._progress_nodeids_reported) == self._session.testscollected
|
||||||
|
|
||||||
def pytest_runtest_logfinish(self, nodeid):
|
def pytest_runtest_logfinish(self, nodeid) -> None:
|
||||||
assert self._session
|
assert self._session
|
||||||
if self.verbosity <= 0 and self._show_progress_info:
|
if self.verbosity <= 0 and self._show_progress_info:
|
||||||
if self._show_progress_info == "count":
|
if self._show_progress_info == "count":
|
||||||
|
@ -545,7 +582,7 @@ class TerminalReporter:
|
||||||
)
|
)
|
||||||
return " [100%]"
|
return " [100%]"
|
||||||
|
|
||||||
def _write_progress_information_filling_space(self):
|
def _write_progress_information_filling_space(self) -> None:
|
||||||
color, _ = self._get_main_color()
|
color, _ = self._get_main_color()
|
||||||
msg = self._get_progress_information_message()
|
msg = self._get_progress_information_message()
|
||||||
w = self._width_of_current_line
|
w = self._width_of_current_line
|
||||||
|
@ -553,7 +590,7 @@ class TerminalReporter:
|
||||||
self.write(msg.rjust(fill), flush=True, **{color: True})
|
self.write(msg.rjust(fill), flush=True, **{color: True})
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _width_of_current_line(self):
|
def _width_of_current_line(self) -> int:
|
||||||
"""Return the width of current line, using the superior implementation of py-1.6 when available"""
|
"""Return the width of current line, using the superior implementation of py-1.6 when available"""
|
||||||
return self._tw.width_of_current_line
|
return self._tw.width_of_current_line
|
||||||
|
|
||||||
|
@ -575,7 +612,7 @@ class TerminalReporter:
|
||||||
if self.isatty:
|
if self.isatty:
|
||||||
self.report_collect()
|
self.report_collect()
|
||||||
|
|
||||||
def report_collect(self, final=False):
|
def report_collect(self, final: bool = False) -> None:
|
||||||
if self.config.option.verbose < 0:
|
if self.config.option.verbose < 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -643,7 +680,9 @@ class TerminalReporter:
|
||||||
)
|
)
|
||||||
self._write_report_lines_from_hooks(lines)
|
self._write_report_lines_from_hooks(lines)
|
||||||
|
|
||||||
def _write_report_lines_from_hooks(self, lines) -> None:
|
def _write_report_lines_from_hooks(
|
||||||
|
self, lines: List[Union[str, List[str]]]
|
||||||
|
) -> None:
|
||||||
lines.reverse()
|
lines.reverse()
|
||||||
for line in collapse(lines):
|
for line in collapse(lines):
|
||||||
self.write_line(line)
|
self.write_line(line)
|
||||||
|
@ -685,7 +724,7 @@ class TerminalReporter:
|
||||||
for rep in failed:
|
for rep in failed:
|
||||||
rep.toterminal(self._tw)
|
rep.toterminal(self._tw)
|
||||||
|
|
||||||
def _printcollecteditems(self, items):
|
def _printcollecteditems(self, items: Sequence[Item]) -> None:
|
||||||
# to print out items and their parent collectors
|
# to print out items and their parent collectors
|
||||||
# we take care to leave out Instances aka ()
|
# we take care to leave out Instances aka ()
|
||||||
# because later versions are going to get rid of them anyway
|
# because later versions are going to get rid of them anyway
|
||||||
|
@ -701,7 +740,7 @@ class TerminalReporter:
|
||||||
for item in items:
|
for item in items:
|
||||||
self._tw.line(item.nodeid)
|
self._tw.line(item.nodeid)
|
||||||
return
|
return
|
||||||
stack = []
|
stack = [] # type: List[Node]
|
||||||
indent = ""
|
indent = ""
|
||||||
for item in items:
|
for item in items:
|
||||||
needed_collectors = item.listchain()[1:] # strip root node
|
needed_collectors = item.listchain()[1:] # strip root node
|
||||||
|
@ -716,11 +755,8 @@ class TerminalReporter:
|
||||||
indent = (len(stack) - 1) * " "
|
indent = (len(stack) - 1) * " "
|
||||||
self._tw.line("{}{}".format(indent, col))
|
self._tw.line("{}{}".format(indent, col))
|
||||||
if self.config.option.verbose >= 1:
|
if self.config.option.verbose >= 1:
|
||||||
try:
|
obj = getattr(col, "obj", None)
|
||||||
obj = col.obj # type: ignore
|
doc = inspect.getdoc(obj) if obj else None
|
||||||
except AttributeError:
|
|
||||||
continue
|
|
||||||
doc = inspect.getdoc(obj)
|
|
||||||
if doc:
|
if doc:
|
||||||
for line in doc.splitlines():
|
for line in doc.splitlines():
|
||||||
self._tw.line("{}{}".format(indent + " ", line))
|
self._tw.line("{}{}".format(indent + " ", line))
|
||||||
|
@ -744,12 +780,12 @@ class TerminalReporter:
|
||||||
terminalreporter=self, exitstatus=exitstatus, config=self.config
|
terminalreporter=self, exitstatus=exitstatus, config=self.config
|
||||||
)
|
)
|
||||||
if session.shouldfail:
|
if session.shouldfail:
|
||||||
self.write_sep("!", session.shouldfail, red=True)
|
self.write_sep("!", str(session.shouldfail), red=True)
|
||||||
if exitstatus == ExitCode.INTERRUPTED:
|
if exitstatus == ExitCode.INTERRUPTED:
|
||||||
self._report_keyboardinterrupt()
|
self._report_keyboardinterrupt()
|
||||||
del self._keyboardinterrupt_memo
|
del self._keyboardinterrupt_memo
|
||||||
elif session.shouldstop:
|
elif session.shouldstop:
|
||||||
self.write_sep("!", session.shouldstop, red=True)
|
self.write_sep("!", str(session.shouldstop), red=True)
|
||||||
self.summary_stats()
|
self.summary_stats()
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True)
|
@pytest.hookimpl(hookwrapper=True)
|
||||||
|
@ -770,7 +806,7 @@ class TerminalReporter:
|
||||||
if hasattr(self, "_keyboardinterrupt_memo"):
|
if hasattr(self, "_keyboardinterrupt_memo"):
|
||||||
self._report_keyboardinterrupt()
|
self._report_keyboardinterrupt()
|
||||||
|
|
||||||
def _report_keyboardinterrupt(self):
|
def _report_keyboardinterrupt(self) -> None:
|
||||||
excrepr = self._keyboardinterrupt_memo
|
excrepr = self._keyboardinterrupt_memo
|
||||||
msg = excrepr.reprcrash.message
|
msg = excrepr.reprcrash.message
|
||||||
self.write_sep("!", msg)
|
self.write_sep("!", msg)
|
||||||
|
@ -824,14 +860,14 @@ class TerminalReporter:
|
||||||
#
|
#
|
||||||
# summaries for sessionfinish
|
# summaries for sessionfinish
|
||||||
#
|
#
|
||||||
def getreports(self, name):
|
def getreports(self, name: str):
|
||||||
values = []
|
values = []
|
||||||
for x in self.stats.get(name, []):
|
for x in self.stats.get(name, []):
|
||||||
if not hasattr(x, "_pdbshown"):
|
if not hasattr(x, "_pdbshown"):
|
||||||
values.append(x)
|
values.append(x)
|
||||||
return values
|
return values
|
||||||
|
|
||||||
def summary_warnings(self):
|
def summary_warnings(self) -> None:
|
||||||
if self.hasopt("w"):
|
if self.hasopt("w"):
|
||||||
all_warnings = self.stats.get(
|
all_warnings = self.stats.get(
|
||||||
"warnings"
|
"warnings"
|
||||||
|
@ -839,7 +875,7 @@ class TerminalReporter:
|
||||||
if not all_warnings:
|
if not all_warnings:
|
||||||
return
|
return
|
||||||
|
|
||||||
final = hasattr(self, "_already_displayed_warnings")
|
final = self._already_displayed_warnings is not None
|
||||||
if final:
|
if final:
|
||||||
warning_reports = all_warnings[self._already_displayed_warnings :]
|
warning_reports = all_warnings[self._already_displayed_warnings :]
|
||||||
else:
|
else:
|
||||||
|
@ -854,7 +890,7 @@ class TerminalReporter:
|
||||||
for wr in warning_reports:
|
for wr in warning_reports:
|
||||||
reports_grouped_by_message.setdefault(wr.message, []).append(wr)
|
reports_grouped_by_message.setdefault(wr.message, []).append(wr)
|
||||||
|
|
||||||
def collapsed_location_report(reports: List[WarningReport]):
|
def collapsed_location_report(reports: List[WarningReport]) -> str:
|
||||||
locations = []
|
locations = []
|
||||||
for w in reports:
|
for w in reports:
|
||||||
location = w.get_location(self.config)
|
location = w.get_location(self.config)
|
||||||
|
@ -888,10 +924,10 @@ class TerminalReporter:
|
||||||
self._tw.line()
|
self._tw.line()
|
||||||
self._tw.line("-- Docs: https://docs.pytest.org/en/latest/warnings.html")
|
self._tw.line("-- Docs: https://docs.pytest.org/en/latest/warnings.html")
|
||||||
|
|
||||||
def summary_passes(self):
|
def summary_passes(self) -> None:
|
||||||
if self.config.option.tbstyle != "no":
|
if self.config.option.tbstyle != "no":
|
||||||
if self.hasopt("P"):
|
if self.hasopt("P"):
|
||||||
reports = self.getreports("passed")
|
reports = self.getreports("passed") # type: List[TestReport]
|
||||||
if not reports:
|
if not reports:
|
||||||
return
|
return
|
||||||
self.write_sep("=", "PASSES")
|
self.write_sep("=", "PASSES")
|
||||||
|
@ -903,9 +939,10 @@ class TerminalReporter:
|
||||||
self._handle_teardown_sections(rep.nodeid)
|
self._handle_teardown_sections(rep.nodeid)
|
||||||
|
|
||||||
def _get_teardown_reports(self, nodeid: str) -> List[TestReport]:
|
def _get_teardown_reports(self, nodeid: str) -> List[TestReport]:
|
||||||
|
reports = self.getreports("")
|
||||||
return [
|
return [
|
||||||
report
|
report
|
||||||
for report in self.getreports("")
|
for report in reports
|
||||||
if report.when == "teardown" and report.nodeid == nodeid
|
if report.when == "teardown" and report.nodeid == nodeid
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -926,9 +963,9 @@ class TerminalReporter:
|
||||||
content = content[:-1]
|
content = content[:-1]
|
||||||
self._tw.line(content)
|
self._tw.line(content)
|
||||||
|
|
||||||
def summary_failures(self):
|
def summary_failures(self) -> None:
|
||||||
if self.config.option.tbstyle != "no":
|
if self.config.option.tbstyle != "no":
|
||||||
reports = self.getreports("failed")
|
reports = self.getreports("failed") # type: List[BaseReport]
|
||||||
if not reports:
|
if not reports:
|
||||||
return
|
return
|
||||||
self.write_sep("=", "FAILURES")
|
self.write_sep("=", "FAILURES")
|
||||||
|
@ -943,9 +980,9 @@ class TerminalReporter:
|
||||||
self._outrep_summary(rep)
|
self._outrep_summary(rep)
|
||||||
self._handle_teardown_sections(rep.nodeid)
|
self._handle_teardown_sections(rep.nodeid)
|
||||||
|
|
||||||
def summary_errors(self):
|
def summary_errors(self) -> None:
|
||||||
if self.config.option.tbstyle != "no":
|
if self.config.option.tbstyle != "no":
|
||||||
reports = self.getreports("error")
|
reports = self.getreports("error") # type: List[BaseReport]
|
||||||
if not reports:
|
if not reports:
|
||||||
return
|
return
|
||||||
self.write_sep("=", "ERRORS")
|
self.write_sep("=", "ERRORS")
|
||||||
|
@ -958,7 +995,7 @@ class TerminalReporter:
|
||||||
self.write_sep("_", msg, red=True, bold=True)
|
self.write_sep("_", msg, red=True, bold=True)
|
||||||
self._outrep_summary(rep)
|
self._outrep_summary(rep)
|
||||||
|
|
||||||
def _outrep_summary(self, rep):
|
def _outrep_summary(self, rep: BaseReport) -> None:
|
||||||
rep.toterminal(self._tw)
|
rep.toterminal(self._tw)
|
||||||
showcapture = self.config.option.showcapture
|
showcapture = self.config.option.showcapture
|
||||||
if showcapture == "no":
|
if showcapture == "no":
|
||||||
|
@ -971,7 +1008,7 @@ class TerminalReporter:
|
||||||
content = content[:-1]
|
content = content[:-1]
|
||||||
self._tw.line(content)
|
self._tw.line(content)
|
||||||
|
|
||||||
def summary_stats(self):
|
def summary_stats(self) -> None:
|
||||||
if self.verbosity < -1:
|
if self.verbosity < -1:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -1041,7 +1078,7 @@ class TerminalReporter:
|
||||||
lines.append("{} {} {}".format(verbose_word, pos, reason))
|
lines.append("{} {} {}".format(verbose_word, pos, reason))
|
||||||
|
|
||||||
def show_skipped(lines: List[str]) -> None:
|
def show_skipped(lines: List[str]) -> None:
|
||||||
skipped = self.stats.get("skipped", [])
|
skipped = self.stats.get("skipped", []) # type: List[CollectReport]
|
||||||
fskips = _folded_skips(self.startdir, skipped) if skipped else []
|
fskips = _folded_skips(self.startdir, skipped) if skipped else []
|
||||||
if not fskips:
|
if not fskips:
|
||||||
return
|
return
|
||||||
|
@ -1125,12 +1162,14 @@ class TerminalReporter:
|
||||||
return parts, main_color
|
return parts, main_color
|
||||||
|
|
||||||
|
|
||||||
def _get_pos(config, rep):
|
def _get_pos(config: Config, rep: BaseReport):
|
||||||
nodeid = config.cwd_relative_nodeid(rep.nodeid)
|
nodeid = config.cwd_relative_nodeid(rep.nodeid)
|
||||||
return nodeid
|
return nodeid
|
||||||
|
|
||||||
|
|
||||||
def _get_line_with_reprcrash_message(config, rep, termwidth):
|
def _get_line_with_reprcrash_message(
|
||||||
|
config: Config, rep: BaseReport, termwidth: int
|
||||||
|
) -> str:
|
||||||
"""Get summary line for a report, trying to add reprcrash message."""
|
"""Get summary line for a report, trying to add reprcrash message."""
|
||||||
verbose_word = rep._get_verbose_word(config)
|
verbose_word = rep._get_verbose_word(config)
|
||||||
pos = _get_pos(config, rep)
|
pos = _get_pos(config, rep)
|
||||||
|
@ -1143,7 +1182,8 @@ def _get_line_with_reprcrash_message(config, rep, termwidth):
|
||||||
return line
|
return line
|
||||||
|
|
||||||
try:
|
try:
|
||||||
msg = rep.longrepr.reprcrash.message
|
# Type ignored intentionally -- possible AttributeError expected.
|
||||||
|
msg = rep.longrepr.reprcrash.message # type: ignore[union-attr] # noqa: F821
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
|
@ -1166,9 +1206,12 @@ def _get_line_with_reprcrash_message(config, rep, termwidth):
|
||||||
return line
|
return line
|
||||||
|
|
||||||
|
|
||||||
def _folded_skips(startdir, skipped):
|
def _folded_skips(
|
||||||
d = {}
|
startdir: py.path.local, skipped: Sequence[CollectReport],
|
||||||
|
) -> List[Tuple[int, str, Optional[int], str]]:
|
||||||
|
d = {} # type: Dict[Tuple[str, Optional[int], str], List[CollectReport]]
|
||||||
for event in skipped:
|
for event in skipped:
|
||||||
|
assert event.longrepr is not None
|
||||||
assert len(event.longrepr) == 3, (event, event.longrepr)
|
assert len(event.longrepr) == 3, (event, event.longrepr)
|
||||||
fspath, lineno, reason = event.longrepr
|
fspath, lineno, reason = event.longrepr
|
||||||
# For consistency, report all fspaths in relative form.
|
# For consistency, report all fspaths in relative form.
|
||||||
|
@ -1182,13 +1225,13 @@ def _folded_skips(startdir, skipped):
|
||||||
and "skip" in keywords
|
and "skip" in keywords
|
||||||
and "pytestmark" not in keywords
|
and "pytestmark" not in keywords
|
||||||
):
|
):
|
||||||
key = (fspath, None, reason)
|
key = (fspath, None, reason) # type: Tuple[str, Optional[int], str]
|
||||||
else:
|
else:
|
||||||
key = (fspath, lineno, reason)
|
key = (fspath, lineno, reason)
|
||||||
d.setdefault(key, []).append(event)
|
d.setdefault(key, []).append(event)
|
||||||
values = []
|
values = [] # type: List[Tuple[int, str, Optional[int], str]]
|
||||||
for key, events in d.items():
|
for key, events in d.items():
|
||||||
values.append((len(events),) + key)
|
values.append((len(events), *key))
|
||||||
return values
|
return values
|
||||||
|
|
||||||
|
|
||||||
|
@ -1201,7 +1244,7 @@ _color_for_type = {
|
||||||
_color_for_type_default = "yellow"
|
_color_for_type_default = "yellow"
|
||||||
|
|
||||||
|
|
||||||
def _make_plural(count, noun):
|
def _make_plural(count: int, noun: str) -> Tuple[int, str]:
|
||||||
# No need to pluralize words such as `failed` or `passed`.
|
# No need to pluralize words such as `failed` or `passed`.
|
||||||
if noun not in ["error", "warnings"]:
|
if noun not in ["error", "warnings"]:
|
||||||
return count, noun
|
return count, noun
|
||||||
|
|
Loading…
Reference in New Issue