diff --git a/src/_pytest/logging.py b/src/_pytest/logging.py index df0da3daa..3fccee005 100644 --- a/src/_pytest/logging.py +++ b/src/_pytest/logging.py @@ -10,6 +10,7 @@ from typing import List from typing import Mapping import pytest +from _pytest import nodes from _pytest.compat import nullcontext from _pytest.config import _strtobool from _pytest.config import create_terminal_writer @@ -326,13 +327,13 @@ class LogCaptureFixture: logger.setLevel(level) @property - def handler(self): + def handler(self) -> LogCaptureHandler: """ :rtype: LogCaptureHandler """ - return self._item.catch_log_handler + return self._item.catch_log_handler # type: ignore[no-any-return] # noqa: F723 - def get_records(self, when): + def get_records(self, when: str) -> List[logging.LogRecord]: """ Get the logging records for one of the possible test phases. @@ -346,7 +347,7 @@ class LogCaptureFixture: """ handler = self._item.catch_log_handlers.get(when) if handler: - return handler.records + return handler.records # type: ignore[no-any-return] # noqa: F723 else: return [] @@ -613,7 +614,9 @@ class LoggingPlugin: yield @contextmanager - def _runtest_for_main(self, item, when): + def _runtest_for_main( + self, item: nodes.Item, when: str + ) -> Generator[None, None, None]: """Implements the internals of pytest_runtest_xxx() hook.""" with catching_logs( LogCaptureHandler(), formatter=self.formatter, level=self.log_level @@ -626,15 +629,15 @@ class LoggingPlugin: return if not hasattr(item, "catch_log_handlers"): - item.catch_log_handlers = {} - item.catch_log_handlers[when] = log_handler - item.catch_log_handler = log_handler + item.catch_log_handlers = {} # type: ignore[attr-defined] # noqa: F821 + item.catch_log_handlers[when] = log_handler # type: ignore[attr-defined] # noqa: F821 + item.catch_log_handler = log_handler # type: ignore[attr-defined] # noqa: F821 try: yield # run test finally: if when == "teardown": - del item.catch_log_handler - del item.catch_log_handlers + del item.catch_log_handler # type: ignore[attr-defined] # noqa: F821 + del item.catch_log_handlers # type: ignore[attr-defined] # noqa: F821 if self.print_logs: # Add a captured log section to the report. diff --git a/src/_pytest/mark/structures.py b/src/_pytest/mark/structures.py index de4333a62..161f623ee 100644 --- a/src/_pytest/mark/structures.py +++ b/src/_pytest/mark/structures.py @@ -2,7 +2,10 @@ import inspect import warnings from collections import namedtuple from collections.abc import MutableMapping +from typing import Iterable +from typing import List from typing import Set +from typing import Union import attr @@ -144,7 +147,7 @@ class Mark: #: keyword arguments of the mark decorator kwargs = attr.ib() # Dict[str, object] - def combined_with(self, other): + def combined_with(self, other: "Mark") -> "Mark": """ :param other: the mark to combine with :type other: Mark @@ -249,7 +252,7 @@ def get_unpacked_marks(obj): return normalize_mark_list(mark_list) -def normalize_mark_list(mark_list): +def normalize_mark_list(mark_list: Iterable[Union[Mark, MarkDecorator]]) -> List[Mark]: """ normalizes marker decorating helpers to mark objects diff --git a/src/_pytest/nodes.py b/src/_pytest/nodes.py index 218684e14..641f889fe 100644 --- a/src/_pytest/nodes.py +++ b/src/_pytest/nodes.py @@ -333,7 +333,9 @@ class Node: return self._repr_failure_py(excinfo, style) -def get_fslocation_from_item(item): +def get_fslocation_from_item( + item: "Item", +) -> Tuple[Union[str, py.path.local], Optional[int]]: """Tries to extract the actual location from an item, depending on available attributes: * "fslocation": a pair (path, lineno) @@ -342,9 +344,10 @@ def get_fslocation_from_item(item): :rtype: a tuple of (str|LocalPath, int) with filename and line number. """ - result = getattr(item, "location", None) - if result is not None: - return result[:2] + try: + return item.location[:2] + except AttributeError: + pass obj = getattr(item, "obj", None) if obj is not None: return getfslineno(obj) diff --git a/src/_pytest/python.py b/src/_pytest/python.py index 525498de2..5309c8dd0 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -10,6 +10,7 @@ from collections import defaultdict from collections.abc import Sequence from functools import partial from textwrap import dedent +from typing import Dict from typing import List from typing import Tuple from typing import Union @@ -36,6 +37,7 @@ from _pytest.compat import STRING_TYPES from _pytest.config import hookimpl from _pytest.deprecated import FUNCARGNAMES from _pytest.mark import MARK_GEN +from _pytest.mark import ParameterSet from _pytest.mark.structures import get_unpacked_marks from _pytest.mark.structures import normalize_mark_list from _pytest.outcomes import fail @@ -947,7 +949,6 @@ class Metafunc: to set a dynamic scope using test context or configuration. """ from _pytest.fixtures import scope2index - from _pytest.mark import ParameterSet argnames, parameters = ParameterSet._for_parametrize( argnames, @@ -996,7 +997,9 @@ class Metafunc: newcalls.append(newcallspec) self._calls = newcalls - def _resolve_arg_ids(self, argnames, ids, parameters, item): + def _resolve_arg_ids( + self, argnames: List[str], ids, parameters: List[ParameterSet], item: nodes.Item + ): """Resolves the actual ids for the given argnames, based on the ``ids`` parameter given to ``parametrize``. @@ -1028,7 +1031,7 @@ class Metafunc: ids = idmaker(argnames, parameters, idfn, ids, self.config, item=item) return ids - def _resolve_arg_value_types(self, argnames, indirect): + def _resolve_arg_value_types(self, argnames: List[str], indirect) -> Dict[str, str]: """Resolves if each parametrized argument must be considered a parameter to a fixture or a "funcarg" to the function, based on the ``indirect`` parameter of the parametrized() call.