[pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci
This commit is contained in:
pre-commit-ci[bot] 2024-04-13 00:00:18 +00:00
parent 72ad6dc953
commit f4cd1ba0d6
813 changed files with 66015 additions and 58839 deletions

View file

@ -1,5 +1,7 @@
# mypy: allow-untyped-defs
"""Basic collect and runtest protocol implementations."""
from __future__ import annotations
import bdb
import dataclasses
import os
@ -18,10 +20,6 @@ from typing import TYPE_CHECKING
from typing import TypeVar
from typing import Union
from .reports import BaseReport
from .reports import CollectErrorRepr
from .reports import CollectReport
from .reports import TestReport
from _pytest import timing
from _pytest._code.code import ExceptionChainRepr
from _pytest._code.code import ExceptionInfo
@ -37,6 +35,11 @@ from _pytest.outcomes import OutcomeException
from _pytest.outcomes import Skipped
from _pytest.outcomes import TEST_OUTCOME
from .reports import BaseReport
from .reports import CollectErrorRepr
from .reports import CollectReport
from .reports import TestReport
if sys.version_info[:2] < (3, 11):
from exceptiongroup import BaseExceptionGroup
@ -50,66 +53,66 @@ if TYPE_CHECKING:
def pytest_addoption(parser: Parser) -> None:
group = parser.getgroup("terminal reporting", "Reporting", after="general")
group = parser.getgroup('terminal reporting', 'Reporting', after='general')
group.addoption(
"--durations",
action="store",
'--durations',
action='store',
type=int,
default=None,
metavar="N",
help="Show N slowest setup/test durations (N=0 for all)",
metavar='N',
help='Show N slowest setup/test durations (N=0 for all)',
)
group.addoption(
"--durations-min",
action="store",
'--durations-min',
action='store',
type=float,
default=0.005,
metavar="N",
help="Minimal duration in seconds for inclusion in slowest list. "
"Default: 0.005.",
metavar='N',
help='Minimal duration in seconds for inclusion in slowest list. '
'Default: 0.005.',
)
def pytest_terminal_summary(terminalreporter: "TerminalReporter") -> None:
def pytest_terminal_summary(terminalreporter: TerminalReporter) -> None:
durations = terminalreporter.config.option.durations
durations_min = terminalreporter.config.option.durations_min
verbose = terminalreporter.config.getvalue("verbose")
verbose = terminalreporter.config.getvalue('verbose')
if durations is None:
return
tr = terminalreporter
dlist = []
for replist in tr.stats.values():
for rep in replist:
if hasattr(rep, "duration"):
if hasattr(rep, 'duration'):
dlist.append(rep)
if not dlist:
return
dlist.sort(key=lambda x: x.duration, reverse=True) # type: ignore[no-any-return]
if not durations:
tr.write_sep("=", "slowest durations")
tr.write_sep('=', 'slowest durations')
else:
tr.write_sep("=", "slowest %s durations" % durations)
tr.write_sep('=', 'slowest %s durations' % durations)
dlist = dlist[:durations]
for i, rep in enumerate(dlist):
if verbose < 2 and rep.duration < durations_min:
tr.write_line("")
tr.write_line('')
tr.write_line(
f"({len(dlist) - i} durations < {durations_min:g}s hidden. Use -vv to show these durations.)"
f'({len(dlist) - i} durations < {durations_min:g}s hidden. Use -vv to show these durations.)',
)
break
tr.write_line(f"{rep.duration:02.2f}s {rep.when:<8} {rep.nodeid}")
tr.write_line(f'{rep.duration:02.2f}s {rep.when:<8} {rep.nodeid}')
def pytest_sessionstart(session: "Session") -> None:
def pytest_sessionstart(session: Session) -> None:
session._setupstate = SetupState()
def pytest_sessionfinish(session: "Session") -> None:
def pytest_sessionfinish(session: Session) -> None:
session._setupstate.teardown_exact(None)
def pytest_runtest_protocol(item: Item, nextitem: Optional[Item]) -> bool:
def pytest_runtest_protocol(item: Item, nextitem: Item | None) -> bool:
ihook = item.ihook
ihook.pytest_runtest_logstart(nodeid=item.nodeid, location=item.location)
runtestprotocol(item, nextitem=nextitem)
@ -118,21 +121,21 @@ def pytest_runtest_protocol(item: Item, nextitem: Optional[Item]) -> bool:
def runtestprotocol(
item: Item, log: bool = True, nextitem: Optional[Item] = None
) -> List[TestReport]:
hasrequest = hasattr(item, "_request")
item: Item, log: bool = True, nextitem: Item | None = None,
) -> list[TestReport]:
hasrequest = hasattr(item, '_request')
if hasrequest and not item._request: # type: ignore[attr-defined]
# This only happens if the item is re-run, as is done by
# pytest-rerunfailures.
item._initrequest() # type: ignore[attr-defined]
rep = call_and_report(item, "setup", log)
rep = call_and_report(item, 'setup', log)
reports = [rep]
if rep.passed:
if item.config.getoption("setupshow", False):
if item.config.getoption('setupshow', False):
show_test_item(item)
if not item.config.getoption("setuponly", False):
reports.append(call_and_report(item, "call", log))
reports.append(call_and_report(item, "teardown", log, nextitem=nextitem))
if not item.config.getoption('setuponly', False):
reports.append(call_and_report(item, 'call', log))
reports.append(call_and_report(item, 'teardown', log, nextitem=nextitem))
# After all teardown hooks have been called
# want funcargs and request info to go away.
if hasrequest:
@ -145,21 +148,21 @@ def show_test_item(item: Item) -> None:
"""Show test function, parameters and the fixtures of the test item."""
tw = item.config.get_terminal_writer()
tw.line()
tw.write(" " * 8)
tw.write(' ' * 8)
tw.write(item.nodeid)
used_fixtures = sorted(getattr(item, "fixturenames", []))
used_fixtures = sorted(getattr(item, 'fixturenames', []))
if used_fixtures:
tw.write(" (fixtures used: {})".format(", ".join(used_fixtures)))
tw.write(' (fixtures used: {})'.format(', '.join(used_fixtures)))
tw.flush()
def pytest_runtest_setup(item: Item) -> None:
_update_current_test_var(item, "setup")
_update_current_test_var(item, 'setup')
item.session._setupstate.setup(item)
def pytest_runtest_call(item: Item) -> None:
_update_current_test_var(item, "call")
_update_current_test_var(item, 'call')
try:
del sys.last_type
del sys.last_value
@ -182,38 +185,38 @@ def pytest_runtest_call(item: Item) -> None:
raise e
def pytest_runtest_teardown(item: Item, nextitem: Optional[Item]) -> None:
_update_current_test_var(item, "teardown")
def pytest_runtest_teardown(item: Item, nextitem: Item | None) -> None:
_update_current_test_var(item, 'teardown')
item.session._setupstate.teardown_exact(nextitem)
_update_current_test_var(item, None)
def _update_current_test_var(
item: Item, when: Optional[Literal["setup", "call", "teardown"]]
item: Item, when: Literal['setup', 'call', 'teardown'] | None,
) -> None:
"""Update :envvar:`PYTEST_CURRENT_TEST` to reflect the current item and stage.
If ``when`` is None, delete ``PYTEST_CURRENT_TEST`` from the environment.
"""
var_name = "PYTEST_CURRENT_TEST"
var_name = 'PYTEST_CURRENT_TEST'
if when:
value = f"{item.nodeid} ({when})"
value = f'{item.nodeid} ({when})'
# don't allow null bytes on environment variables (see #2644, #2957)
value = value.replace("\x00", "(null)")
value = value.replace('\x00', '(null)')
os.environ[var_name] = value
else:
os.environ.pop(var_name)
def pytest_report_teststatus(report: BaseReport) -> Optional[Tuple[str, str, str]]:
if report.when in ("setup", "teardown"):
def pytest_report_teststatus(report: BaseReport) -> tuple[str, str, str] | None:
if report.when in ('setup', 'teardown'):
if report.failed:
# category, shortletter, verbose-word
return "error", "E", "ERROR"
return 'error', 'E', 'ERROR'
elif report.skipped:
return "skipped", "s", "SKIPPED"
return 'skipped', 's', 'SKIPPED'
else:
return "", "", ""
return '', '', ''
return None
@ -222,22 +225,22 @@ def pytest_report_teststatus(report: BaseReport) -> Optional[Tuple[str, str, str
def call_and_report(
item: Item, when: Literal["setup", "call", "teardown"], log: bool = True, **kwds
item: Item, when: Literal['setup', 'call', 'teardown'], log: bool = True, **kwds,
) -> TestReport:
ihook = item.ihook
if when == "setup":
if when == 'setup':
runtest_hook: Callable[..., None] = ihook.pytest_runtest_setup
elif when == "call":
elif when == 'call':
runtest_hook = ihook.pytest_runtest_call
elif when == "teardown":
elif when == 'teardown':
runtest_hook = ihook.pytest_runtest_teardown
else:
assert False, f"Unhandled runtest hook case: {when}"
reraise: Tuple[Type[BaseException], ...] = (Exit,)
if not item.config.getoption("usepdb", False):
assert False, f'Unhandled runtest hook case: {when}'
reraise: tuple[type[BaseException], ...] = (Exit,)
if not item.config.getoption('usepdb', False):
reraise += (KeyboardInterrupt,)
call = CallInfo.from_call(
lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise
lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise,
)
report: TestReport = ihook.pytest_runtest_makereport(item=item, call=call)
if log:
@ -247,13 +250,13 @@ def call_and_report(
return report
def check_interactive_exception(call: "CallInfo[object]", report: BaseReport) -> bool:
def check_interactive_exception(call: CallInfo[object], report: BaseReport) -> bool:
"""Check whether the call raised an exception that should be reported as
interactive."""
if call.excinfo is None:
# Didn't raise.
return False
if hasattr(report, "wasxfail"):
if hasattr(report, 'wasxfail'):
# Exception was expected.
return False
if isinstance(call.excinfo.value, (Skipped, bdb.BdbQuit)):
@ -262,7 +265,7 @@ def check_interactive_exception(call: "CallInfo[object]", report: BaseReport) ->
return True
TResult = TypeVar("TResult", covariant=True)
TResult = TypeVar('TResult', covariant=True)
@final
@ -270,9 +273,9 @@ TResult = TypeVar("TResult", covariant=True)
class CallInfo(Generic[TResult]):
"""Result/Exception info of a function invocation."""
_result: Optional[TResult]
_result: TResult | None
#: The captured exception of the call, if it raised.
excinfo: Optional[ExceptionInfo[BaseException]]
excinfo: ExceptionInfo[BaseException] | None
#: The system time when the call started, in seconds since the epoch.
start: float
#: The system time when the call ended, in seconds since the epoch.
@ -280,16 +283,16 @@ class CallInfo(Generic[TResult]):
#: The call duration, in seconds.
duration: float
#: The context of invocation: "collect", "setup", "call" or "teardown".
when: Literal["collect", "setup", "call", "teardown"]
when: Literal['collect', 'setup', 'call', 'teardown']
def __init__(
self,
result: Optional[TResult],
excinfo: Optional[ExceptionInfo[BaseException]],
result: TResult | None,
excinfo: ExceptionInfo[BaseException] | None,
start: float,
stop: float,
duration: float,
when: Literal["collect", "setup", "call", "teardown"],
when: Literal['collect', 'setup', 'call', 'teardown'],
*,
_ispytest: bool = False,
) -> None:
@ -308,7 +311,7 @@ class CallInfo(Generic[TResult]):
Can only be accessed if excinfo is None.
"""
if self.excinfo is not None:
raise AttributeError(f"{self!r} has no valid result")
raise AttributeError(f'{self!r} has no valid result')
# The cast is safe because an exception wasn't raised, hence
# _result has the expected function return type (which may be
# None, that's why a cast and not an assert).
@ -318,11 +321,11 @@ class CallInfo(Generic[TResult]):
def from_call(
cls,
func: Callable[[], TResult],
when: Literal["collect", "setup", "call", "teardown"],
reraise: Optional[
Union[Type[BaseException], Tuple[Type[BaseException], ...]]
] = None,
) -> "CallInfo[TResult]":
when: Literal['collect', 'setup', 'call', 'teardown'],
reraise: None | (
type[BaseException] | tuple[type[BaseException], ...]
) = None,
) -> CallInfo[TResult]:
"""Call func, wrapping the result in a CallInfo.
:param func:
@ -337,7 +340,7 @@ class CallInfo(Generic[TResult]):
start = timing.time()
precise_start = timing.perf_counter()
try:
result: Optional[TResult] = func()
result: TResult | None = func()
except BaseException:
excinfo = ExceptionInfo.from_current()
if reraise is not None and isinstance(excinfo.value, reraise):
@ -359,8 +362,8 @@ class CallInfo(Generic[TResult]):
def __repr__(self) -> str:
if self.excinfo is None:
return f"<CallInfo when={self.when!r} result: {self._result!r}>"
return f"<CallInfo when={self.when!r} excinfo={self.excinfo!r}>"
return f'<CallInfo when={self.when!r} result: {self._result!r}>'
return f'<CallInfo when={self.when!r} excinfo={self.excinfo!r}>'
def pytest_runtest_makereport(item: Item, call: CallInfo[None]) -> TestReport:
@ -368,7 +371,7 @@ def pytest_runtest_makereport(item: Item, call: CallInfo[None]) -> TestReport:
def pytest_make_collect_report(collector: Collector) -> CollectReport:
def collect() -> List[Union[Item, Collector]]:
def collect() -> list[Item | Collector]:
# Before collecting, if this is a Directory, load the conftests.
# If a conftest import fails to load, it is considered a collection
# error of the Directory collector. This is why it's done inside of the
@ -378,36 +381,36 @@ def pytest_make_collect_report(collector: Collector) -> CollectReport:
if isinstance(collector, Directory):
collector.config.pluginmanager._loadconftestmodules(
collector.path,
collector.config.getoption("importmode"),
collector.config.getoption('importmode'),
rootpath=collector.config.rootpath,
consider_namespace_packages=collector.config.getini(
"consider_namespace_packages"
'consider_namespace_packages',
),
)
return list(collector.collect())
call = CallInfo.from_call(collect, "collect")
longrepr: Union[None, Tuple[str, int, str], str, TerminalRepr] = None
call = CallInfo.from_call(collect, 'collect')
longrepr: None | tuple[str, int, str] | str | TerminalRepr = None
if not call.excinfo:
outcome: Literal["passed", "skipped", "failed"] = "passed"
outcome: Literal['passed', 'skipped', 'failed'] = 'passed'
else:
skip_exceptions = [Skipped]
unittest = sys.modules.get("unittest")
unittest = sys.modules.get('unittest')
if unittest is not None:
# Type ignored because unittest is loaded dynamically.
skip_exceptions.append(unittest.SkipTest) # type: ignore
if isinstance(call.excinfo.value, tuple(skip_exceptions)):
outcome = "skipped"
r_ = collector._repr_failure_py(call.excinfo, "line")
outcome = 'skipped'
r_ = collector._repr_failure_py(call.excinfo, 'line')
assert isinstance(r_, ExceptionChainRepr), repr(r_)
r = r_.reprcrash
assert r
longrepr = (str(r.path), r.lineno, r.message)
else:
outcome = "failed"
outcome = 'failed'
errorinfo = collector.repr_failure(call.excinfo)
if not hasattr(errorinfo, "toterminal"):
if not hasattr(errorinfo, 'toterminal'):
assert isinstance(errorinfo, str)
errorinfo = CollectErrorRepr(errorinfo)
longrepr = errorinfo
@ -483,13 +486,13 @@ class SetupState:
def __init__(self) -> None:
# The stack is in the dict insertion order.
self.stack: Dict[
self.stack: dict[
Node,
Tuple[
tuple[
# Node's finalizers.
List[Callable[[], object]],
list[Callable[[], object]],
# Node's exception, if its setup raised.
Optional[Union[OutcomeException, Exception]],
OutcomeException | Exception | None,
],
] = {}
@ -500,11 +503,11 @@ class SetupState:
# If a collector fails its setup, fail its entire subtree of items.
# The setup is not retried for each item - the same exception is used.
for col, (finalizers, exc) in self.stack.items():
assert col in needed_collectors, "previous item was not torn down properly"
assert col in needed_collectors, 'previous item was not torn down properly'
if exc:
raise exc
for col in needed_collectors[len(self.stack) :]:
for col in needed_collectors[len(self.stack):]:
assert col not in self.stack
# Push onto the stack.
self.stack[col] = ([col.teardown], None)
@ -524,7 +527,7 @@ class SetupState:
assert node in self.stack, (node, self.stack)
self.stack[node][0].append(finalizer)
def teardown_exact(self, nextitem: Optional[Item]) -> None:
def teardown_exact(self, nextitem: Item | None) -> None:
"""Teardown the current stack up until reaching nodes that nextitem
also descends from.
@ -532,7 +535,7 @@ class SetupState:
stack is torn down.
"""
needed_collectors = nextitem and nextitem.listchain() or []
exceptions: List[BaseException] = []
exceptions: list[BaseException] = []
while self.stack:
if list(self.stack.keys()) == needed_collectors[: len(self.stack)]:
break
@ -548,13 +551,13 @@ class SetupState:
if len(these_exceptions) == 1:
exceptions.extend(these_exceptions)
elif these_exceptions:
msg = f"errors while tearing down {node!r}"
msg = f'errors while tearing down {node!r}'
exceptions.append(BaseExceptionGroup(msg, these_exceptions[::-1]))
if len(exceptions) == 1:
raise exceptions[0]
elif exceptions:
raise BaseExceptionGroup("errors during test teardown", exceptions[::-1])
raise BaseExceptionGroup('errors during test teardown', exceptions[::-1])
if nextitem is None:
assert not self.stack
@ -563,7 +566,7 @@ def collect_one_node(collector: Collector) -> CollectReport:
ihook = collector.ihook
ihook.pytest_collectstart(collector=collector)
rep: CollectReport = ihook.pytest_make_collect_report(collector=collector)
call = rep.__dict__.pop("call", None)
call = rep.__dict__.pop('call', None)
if call and check_interactive_exception(call, rep):
ihook.pytest_exception_interact(node=collector, call=call, report=rep)
return rep