typing: set disallow_any_generics

This prevents referring to a generic type without filling in its generic
type parameters.

The FixtureDef typing might need some more refining in the future.
This commit is contained in:
Ran Benita 2020-08-01 13:06:13 +03:00
parent 49827adcb9
commit be656dd4e4
23 changed files with 123 additions and 104 deletions

View File

@ -96,6 +96,7 @@ formats = sdist.tgz,bdist_wheel
[mypy] [mypy]
mypy_path = src mypy_path = src
check_untyped_defs = True check_untyped_defs = True
disallow_any_generics = True
ignore_missing_imports = True ignore_missing_imports = True
no_implicit_optional = True no_implicit_optional = True
show_error_codes = True show_error_codes = True

View File

@ -613,7 +613,7 @@ class ExceptionInfo(Generic[_E]):
) )
return fmt.repr_excinfo(self) return fmt.repr_excinfo(self)
def match(self, regexp: "Union[str, Pattern]") -> "Literal[True]": def match(self, regexp: "Union[str, Pattern[str]]") -> "Literal[True]":
"""Check whether the regular expression `regexp` matches the string """Check whether the regular expression `regexp` matches the string
representation of the exception using :func:`python:re.search`. representation of the exception using :func:`python:re.search`.
@ -678,7 +678,7 @@ class FormattedExcinfo:
self, self,
source: "Source", source: "Source",
line_index: int = -1, line_index: int = -1,
excinfo: Optional[ExceptionInfo] = None, excinfo: Optional[ExceptionInfo[BaseException]] = None,
short: bool = False, short: bool = False,
) -> List[str]: ) -> List[str]:
"""Return formatted and marked up source lines.""" """Return formatted and marked up source lines."""
@ -703,7 +703,10 @@ class FormattedExcinfo:
return lines return lines
def get_exconly( def get_exconly(
self, excinfo: ExceptionInfo, indent: int = 4, markall: bool = False self,
excinfo: ExceptionInfo[BaseException],
indent: int = 4,
markall: bool = False,
) -> List[str]: ) -> List[str]:
lines = [] lines = []
indentstr = " " * indent indentstr = " " * indent
@ -743,7 +746,9 @@ class FormattedExcinfo:
return None return None
def repr_traceback_entry( def repr_traceback_entry(
self, entry: TracebackEntry, excinfo: Optional[ExceptionInfo] = None self,
entry: TracebackEntry,
excinfo: Optional[ExceptionInfo[BaseException]] = None,
) -> "ReprEntry": ) -> "ReprEntry":
lines = [] # type: List[str] lines = [] # type: List[str]
style = entry._repr_style if entry._repr_style is not None else self.style style = entry._repr_style if entry._repr_style is not None else self.style
@ -785,7 +790,7 @@ class FormattedExcinfo:
path = np path = np
return path return path
def repr_traceback(self, excinfo: ExceptionInfo) -> "ReprTraceback": def repr_traceback(self, excinfo: ExceptionInfo[BaseException]) -> "ReprTraceback":
traceback = excinfo.traceback traceback = excinfo.traceback
if self.tbfilter: if self.tbfilter:
traceback = traceback.filter() traceback = traceback.filter()
@ -850,12 +855,14 @@ class FormattedExcinfo:
return traceback, extraline return traceback, extraline
def repr_excinfo(self, excinfo: ExceptionInfo) -> "ExceptionChainRepr": def repr_excinfo(
self, excinfo: ExceptionInfo[BaseException]
) -> "ExceptionChainRepr":
repr_chain = ( repr_chain = (
[] []
) # type: List[Tuple[ReprTraceback, Optional[ReprFileLocation], Optional[str]]] ) # type: List[Tuple[ReprTraceback, Optional[ReprFileLocation], Optional[str]]]
e = excinfo.value e = excinfo.value # type: Optional[BaseException]
excinfo_ = excinfo # type: Optional[ExceptionInfo] excinfo_ = excinfo # type: Optional[ExceptionInfo[BaseException]]
descr = None descr = None
seen = set() # type: Set[int] seen = set() # type: Set[int]
while e is not None and id(e) not in seen: while e is not None and id(e) not in seen:

View File

@ -710,7 +710,7 @@ class AssertionRewriter(ast.NodeVisitor):
node = nodes.pop() node = nodes.pop()
for name, field in ast.iter_fields(node): for name, field in ast.iter_fields(node):
if isinstance(field, list): if isinstance(field, list):
new = [] # type: List new = [] # type: List[ast.AST]
for i, child in enumerate(field): for i, child in enumerate(field):
if isinstance(child, ast.Assert): if isinstance(child, ast.Assert):
# Transform assert. # Transform assert.

View File

@ -181,7 +181,7 @@ class LFPluginCollWrapper:
self._collected_at_least_one_failure = False self._collected_at_least_one_failure = False
@pytest.hookimpl(hookwrapper=True) @pytest.hookimpl(hookwrapper=True)
def pytest_make_collect_report(self, collector: nodes.Collector) -> Generator: def pytest_make_collect_report(self, collector: nodes.Collector):
if isinstance(collector, Session): if isinstance(collector, Session):
out = yield out = yield
res = out.get_result() # type: CollectReport res = out.get_result() # type: CollectReport

View File

@ -3,7 +3,10 @@ import argparse
import functools import functools
import sys import sys
import types import types
from typing import Any
from typing import Callable
from typing import Generator from typing import Generator
from typing import List
from typing import Tuple from typing import Tuple
from typing import Union from typing import Union
@ -91,7 +94,7 @@ class pytestPDB:
_pluginmanager = None # type: PytestPluginManager _pluginmanager = None # type: PytestPluginManager
_config = None # type: Config _config = None # type: Config
_saved = [] # type: list _saved = [] # type: List[Tuple[Callable[..., None], PytestPluginManager, Config]]
_recursive_debug = 0 _recursive_debug = 0
_wrapped_pdb_cls = None _wrapped_pdb_cls = None
@ -274,7 +277,7 @@ class pytestPDB:
class PdbInvoke: class PdbInvoke:
def pytest_exception_interact( def pytest_exception_interact(
self, node: Node, call: "CallInfo", report: BaseReport self, node: Node, call: "CallInfo[Any]", report: BaseReport
) -> None: ) -> None:
capman = node.config.pluginmanager.getplugin("capturemanager") capman = node.config.pluginmanager.getplugin("capturemanager")
if capman: if capman:

View File

@ -94,8 +94,8 @@ _FixtureCachedResult = Union[
@attr.s(frozen=True) @attr.s(frozen=True)
class PseudoFixtureDef: class PseudoFixtureDef(Generic[_FixtureValue]):
cached_result = attr.ib(type="_FixtureCachedResult") cached_result = attr.ib(type="_FixtureCachedResult[_FixtureValue]")
scope = attr.ib(type="_Scope") scope = attr.ib(type="_Scope")
@ -141,7 +141,7 @@ def scopeproperty(name=None, doc=None):
return decoratescope return decoratescope
def get_scope_package(node, fixturedef: "FixtureDef"): def get_scope_package(node, fixturedef: "FixtureDef[object]"):
import pytest import pytest
cls = pytest.Package cls = pytest.Package
@ -397,7 +397,7 @@ class FuncFixtureInfo:
# definitions. # definitions.
initialnames = attr.ib(type=Tuple[str, ...]) initialnames = attr.ib(type=Tuple[str, ...])
names_closure = attr.ib(type=List[str]) names_closure = attr.ib(type=List[str])
name2fixturedefs = attr.ib(type=Dict[str, Sequence["FixtureDef"]]) name2fixturedefs = attr.ib(type=Dict[str, Sequence["FixtureDef[Any]"]])
def prune_dependency_tree(self) -> None: def prune_dependency_tree(self) -> None:
"""Recompute names_closure from initialnames and name2fixturedefs. """Recompute names_closure from initialnames and name2fixturedefs.
@ -441,7 +441,7 @@ class FixtureRequest:
self.fixturename = None # type: Optional[str] self.fixturename = None # type: Optional[str]
#: Scope string, one of "function", "class", "module", "session". #: Scope string, one of "function", "class", "module", "session".
self.scope = "function" # type: _Scope self.scope = "function" # type: _Scope
self._fixture_defs = {} # type: Dict[str, FixtureDef] self._fixture_defs = {} # type: Dict[str, FixtureDef[Any]]
fixtureinfo = pyfuncitem._fixtureinfo # type: FuncFixtureInfo fixtureinfo = pyfuncitem._fixtureinfo # type: FuncFixtureInfo
self._arg2fixturedefs = fixtureinfo.name2fixturedefs.copy() self._arg2fixturedefs = fixtureinfo.name2fixturedefs.copy()
self._arg2index = {} # type: Dict[str, int] self._arg2index = {} # type: Dict[str, int]
@ -467,7 +467,7 @@ class FixtureRequest:
"""Underlying collection node (depends on current request scope).""" """Underlying collection node (depends on current request scope)."""
return self._getscopeitem(self.scope) return self._getscopeitem(self.scope)
def _getnextfixturedef(self, argname: str) -> "FixtureDef": def _getnextfixturedef(self, argname: str) -> "FixtureDef[Any]":
fixturedefs = self._arg2fixturedefs.get(argname, None) fixturedefs = self._arg2fixturedefs.get(argname, None)
if fixturedefs is None: if fixturedefs is None:
# We arrive here because of a dynamic call to # We arrive here because of a dynamic call to
@ -586,7 +586,7 @@ class FixtureRequest:
def _get_active_fixturedef( def _get_active_fixturedef(
self, argname: str self, argname: str
) -> Union["FixtureDef", PseudoFixtureDef]: ) -> Union["FixtureDef[object]", PseudoFixtureDef[object]]:
try: try:
return self._fixture_defs[argname] return self._fixture_defs[argname]
except KeyError: except KeyError:
@ -604,9 +604,9 @@ class FixtureRequest:
self._fixture_defs[argname] = fixturedef self._fixture_defs[argname] = fixturedef
return fixturedef return fixturedef
def _get_fixturestack(self) -> List["FixtureDef"]: def _get_fixturestack(self) -> List["FixtureDef[Any]"]:
current = self current = self
values = [] # type: List[FixtureDef] values = [] # type: List[FixtureDef[Any]]
while 1: while 1:
fixturedef = getattr(current, "_fixturedef", None) fixturedef = getattr(current, "_fixturedef", None)
if fixturedef is None: if fixturedef is None:
@ -616,7 +616,7 @@ class FixtureRequest:
assert isinstance(current, SubRequest) assert isinstance(current, SubRequest)
current = current._parent_request current = current._parent_request
def _compute_fixture_value(self, fixturedef: "FixtureDef") -> None: def _compute_fixture_value(self, fixturedef: "FixtureDef[object]") -> None:
"""Create a SubRequest based on "self" and call the execute method """Create a SubRequest based on "self" and call the execute method
of the given FixtureDef object. of the given FixtureDef object.
@ -689,7 +689,7 @@ class FixtureRequest:
self._schedule_finalizers(fixturedef, subrequest) self._schedule_finalizers(fixturedef, subrequest)
def _schedule_finalizers( def _schedule_finalizers(
self, fixturedef: "FixtureDef", subrequest: "SubRequest" self, fixturedef: "FixtureDef[object]", subrequest: "SubRequest"
) -> None: ) -> None:
# If fixture function failed it might have registered finalizers. # If fixture function failed it might have registered finalizers.
self.session._setupstate.addfinalizer( self.session._setupstate.addfinalizer(
@ -751,7 +751,7 @@ class SubRequest(FixtureRequest):
scope: "_Scope", scope: "_Scope",
param, param,
param_index: int, param_index: int,
fixturedef: "FixtureDef", fixturedef: "FixtureDef[object]",
) -> None: ) -> None:
self._parent_request = request self._parent_request = request
self.fixturename = fixturedef.argname self.fixturename = fixturedef.argname
@ -773,7 +773,7 @@ class SubRequest(FixtureRequest):
self._fixturedef.addfinalizer(finalizer) self._fixturedef.addfinalizer(finalizer)
def _schedule_finalizers( def _schedule_finalizers(
self, fixturedef: "FixtureDef", subrequest: "SubRequest" self, fixturedef: "FixtureDef[object]", subrequest: "SubRequest"
) -> None: ) -> None:
# If the executing fixturedef was not explicitly requested in the argument list (via # If the executing fixturedef was not explicitly requested in the argument list (via
# getfixturevalue inside the fixture call) then ensure this fixture def will be finished # getfixturevalue inside the fixture call) then ensure this fixture def will be finished
@ -1456,8 +1456,8 @@ class FixtureManager:
def __init__(self, session: "Session") -> None: def __init__(self, session: "Session") -> None:
self.session = session self.session = session
self.config = session.config # type: Config self.config = session.config # type: Config
self._arg2fixturedefs = {} # type: Dict[str, List[FixtureDef]] self._arg2fixturedefs = {} # type: Dict[str, List[FixtureDef[Any]]]
self._holderobjseen = set() # type: Set self._holderobjseen = set() # type: Set[object]
self._nodeid_and_autousenames = [ self._nodeid_and_autousenames = [
("", self.config.getini("usefixtures")) ("", self.config.getini("usefixtures"))
] # type: List[Tuple[str, List[str]]] ] # type: List[Tuple[str, List[str]]]
@ -1534,7 +1534,7 @@ class FixtureManager:
def getfixtureclosure( def getfixtureclosure(
self, fixturenames: Tuple[str, ...], parentnode, ignore_args: Sequence[str] = () self, fixturenames: Tuple[str, ...], parentnode, ignore_args: Sequence[str] = ()
) -> Tuple[Tuple[str, ...], List[str], Dict[str, Sequence[FixtureDef]]]: ) -> Tuple[Tuple[str, ...], List[str], Dict[str, Sequence[FixtureDef[Any]]]]:
# Collect the closure of all fixtures, starting with the given # Collect the closure of all fixtures, starting with the given
# fixturenames as the initial set. As we have to visit all # fixturenames as the initial set. As we have to visit all
# factory definitions anyway, we also return an arg2fixturedefs # factory definitions anyway, we also return an arg2fixturedefs
@ -1557,7 +1557,7 @@ class FixtureManager:
# need to return it as well, so save this. # need to return it as well, so save this.
initialnames = tuple(fixturenames_closure) initialnames = tuple(fixturenames_closure)
arg2fixturedefs = {} # type: Dict[str, Sequence[FixtureDef]] arg2fixturedefs = {} # type: Dict[str, Sequence[FixtureDef[Any]]]
lastlen = -1 lastlen = -1
while lastlen != len(fixturenames_closure): while lastlen != len(fixturenames_closure):
lastlen = len(fixturenames_closure) lastlen = len(fixturenames_closure)
@ -1677,7 +1677,7 @@ class FixtureManager:
def getfixturedefs( def getfixturedefs(
self, argname: str, nodeid: str self, argname: str, nodeid: str
) -> Optional[Sequence[FixtureDef]]: ) -> Optional[Sequence[FixtureDef[Any]]]:
"""Get a list of fixtures which are applicable to the given node id. """Get a list of fixtures which are applicable to the given node id.
:param str argname: Name of the fixture to search for. :param str argname: Name of the fixture to search for.
@ -1691,8 +1691,8 @@ class FixtureManager:
return tuple(self._matchfactories(fixturedefs, nodeid)) return tuple(self._matchfactories(fixturedefs, nodeid))
def _matchfactories( def _matchfactories(
self, fixturedefs: Iterable[FixtureDef], nodeid: str self, fixturedefs: Iterable[FixtureDef[Any]], nodeid: str
) -> Iterator[FixtureDef]: ) -> Iterator[FixtureDef[Any]]:
from _pytest import nodes from _pytest import nodes
for fixturedef in fixturedefs: for fixturedef in fixturedefs:

View File

@ -533,7 +533,7 @@ def pytest_report_from_serializable(
@hookspec(firstresult=True) @hookspec(firstresult=True)
def pytest_fixture_setup( def pytest_fixture_setup(
fixturedef: "FixtureDef", request: "SubRequest" fixturedef: "FixtureDef[Any]", request: "SubRequest"
) -> Optional[object]: ) -> Optional[object]:
"""Perform fixture setup execution. """Perform fixture setup execution.
@ -549,7 +549,7 @@ def pytest_fixture_setup(
def pytest_fixture_post_finalizer( def pytest_fixture_post_finalizer(
fixturedef: "FixtureDef", request: "SubRequest" fixturedef: "FixtureDef[Any]", request: "SubRequest"
) -> None: ) -> None:
"""Called after fixture teardown, but before the cache is cleared, so """Called after fixture teardown, but before the cache is cleared, so
the fixture result ``fixturedef.cached_result`` is still available (not the fixture result ``fixturedef.cached_result`` is still available (not
@ -826,7 +826,7 @@ def pytest_keyboard_interrupt(
def pytest_exception_interact( def pytest_exception_interact(
node: Union["Item", "Collector"], node: Union["Item", "Collector"],
call: "CallInfo[object]", call: "CallInfo[Any]",
report: Union["CollectReport", "TestReport"], report: Union["CollectReport", "TestReport"],
) -> None: ) -> None:
"""Called when an exception was raised which can potentially be """Called when an exception was raised which can potentially be

View File

@ -404,7 +404,7 @@ class Failed(Exception):
@attr.s @attr.s
class _bestrelpath_cache(dict): class _bestrelpath_cache(Dict[py.path.local, str]):
path = attr.ib(type=py.path.local) path = attr.ib(type=py.path.local)
def __missing__(self, path: py.path.local) -> str: def __missing__(self, path: py.path.local) -> str:

View File

@ -5,6 +5,7 @@ import warnings
from typing import Any from typing import Any
from typing import Callable from typing import Callable
from typing import Iterable from typing import Iterable
from typing import Iterator
from typing import List from typing import List
from typing import Mapping from typing import Mapping
from typing import NamedTuple from typing import NamedTuple
@ -30,6 +31,8 @@ from _pytest.warning_types import PytestUnknownMarkWarning
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Type from typing import Type
from ..nodes import Node
EMPTY_PARAMETERSET_OPTION = "empty_parameter_set_mark" EMPTY_PARAMETERSET_OPTION = "empty_parameter_set_mark"
@ -521,13 +524,14 @@ class MarkGenerator:
MARK_GEN = MarkGenerator() MARK_GEN = MarkGenerator()
class NodeKeywords(collections.abc.MutableMapping): # TODO(py36): inherit from typing.MutableMapping[str, Any].
def __init__(self, node): class NodeKeywords(collections.abc.MutableMapping): # type: ignore[type-arg]
def __init__(self, node: "Node") -> None:
self.node = node self.node = node
self.parent = node.parent self.parent = node.parent
self._markers = {node.name: True} self._markers = {node.name: True}
def __getitem__(self, key): def __getitem__(self, key: str) -> Any:
try: try:
return self._markers[key] return self._markers[key]
except KeyError: except KeyError:
@ -535,17 +539,17 @@ class NodeKeywords(collections.abc.MutableMapping):
raise raise
return self.parent.keywords[key] return self.parent.keywords[key]
def __setitem__(self, key, value): def __setitem__(self, key: str, value: Any) -> None:
self._markers[key] = value self._markers[key] = value
def __delitem__(self, key): def __delitem__(self, key: str) -> None:
raise ValueError("cannot delete key in keywords dict") raise ValueError("cannot delete key in keywords dict")
def __iter__(self): def __iter__(self) -> Iterator[str]:
seen = self._seen() seen = self._seen()
return iter(seen) return iter(seen)
def _seen(self): def _seen(self) -> Set[str]:
seen = set(self._markers) seen = set(self._markers)
if self.parent is not None: if self.parent is not None:
seen.update(self.parent.keywords) seen.update(self.parent.keywords)

View File

@ -1,6 +1,7 @@
import os import os
import warnings import warnings
from functools import lru_cache from functools import lru_cache
from typing import Any
from typing import Callable from typing import Callable
from typing import Dict from typing import Dict
from typing import Iterable from typing import Iterable
@ -167,7 +168,7 @@ class Node(metaclass=NodeMeta):
self.extra_keyword_matches = set() # type: Set[str] self.extra_keyword_matches = set() # type: Set[str]
# Used for storing artificial fixturedefs for direct parametrization. # Used for storing artificial fixturedefs for direct parametrization.
self._name2pseudofixturedef = {} # type: Dict[str, FixtureDef] self._name2pseudofixturedef = {} # type: Dict[str, FixtureDef[Any]]
if nodeid is not None: if nodeid is not None:
assert "::()" not in nodeid assert "::()" not in nodeid
@ -354,7 +355,7 @@ class Node(metaclass=NodeMeta):
assert current is None or isinstance(current, cls) assert current is None or isinstance(current, cls)
return current return current
def _prunetraceback(self, excinfo): def _prunetraceback(self, excinfo: ExceptionInfo[BaseException]) -> None:
pass pass
def _repr_failure_py( def _repr_failure_py(
@ -479,7 +480,7 @@ class Collector(Node):
return self._repr_failure_py(excinfo, style=tbstyle) return self._repr_failure_py(excinfo, style=tbstyle)
def _prunetraceback(self, excinfo): def _prunetraceback(self, excinfo: ExceptionInfo[BaseException]) -> None:
if hasattr(self, "fspath"): if hasattr(self, "fspath"):
traceback = excinfo.traceback traceback = excinfo.traceback
ntraceback = traceback.cut(path=self.fspath) ntraceback = traceback.cut(path=self.fspath)

View File

@ -83,7 +83,7 @@ class Exit(Exception):
# Elaborate hack to work around https://github.com/python/mypy/issues/2087. # Elaborate hack to work around https://github.com/python/mypy/issues/2087.
# Ideally would just be `exit.Exception = Exit` etc. # Ideally would just be `exit.Exception = Exit` etc.
_F = TypeVar("_F", bound=Callable) _F = TypeVar("_F", bound=Callable[..., object])
_ET = TypeVar("_ET", bound="Type[BaseException]") _ET = TypeVar("_ET", bound="Type[BaseException]")

View File

@ -1179,7 +1179,7 @@ class Metafunc:
def _find_parametrized_scope( def _find_parametrized_scope(
argnames: typing.Sequence[str], argnames: typing.Sequence[str],
arg2fixturedefs: Mapping[str, typing.Sequence[fixtures.FixtureDef]], arg2fixturedefs: Mapping[str, typing.Sequence[fixtures.FixtureDef[object]]],
indirect: Union[bool, typing.Sequence[str]], indirect: Union[bool, typing.Sequence[str]],
) -> "fixtures._Scope": ) -> "fixtures._Scope":
"""Find the most appropriate scope for a parametrized call based on its arguments. """Find the most appropriate scope for a parametrized call based on its arguments.
@ -1578,7 +1578,7 @@ class Function(PyobjMixin, nodes.Item):
self.obj = self._getobj() self.obj = self._getobj()
self._request._fillfixtures() self._request._fillfixtures()
def _prunetraceback(self, excinfo: ExceptionInfo) -> None: def _prunetraceback(self, excinfo: ExceptionInfo[BaseException]) -> None:
if hasattr(self, "_obj") and not self.config.getoption("fulltrace", False): if hasattr(self, "_obj") and not self.config.getoption("fulltrace", False):
code = _pytest._code.Code(get_real_func(self.obj)) code = _pytest._code.Code(get_real_func(self.obj))
path, firstlineno = code.path, code.firstlineno path, firstlineno = code.path, code.firstlineno

View File

@ -526,7 +526,7 @@ _E = TypeVar("_E", bound=BaseException)
def raises( def raises(
expected_exception: Union["Type[_E]", Tuple["Type[_E]", ...]], expected_exception: Union["Type[_E]", Tuple["Type[_E]", ...]],
*, *,
match: "Optional[Union[str, Pattern]]" = ... match: "Optional[Union[str, Pattern[str]]]" = ...
) -> "RaisesContext[_E]": ) -> "RaisesContext[_E]":
... # pragma: no cover ... # pragma: no cover
@ -534,7 +534,7 @@ def raises(
@overload # noqa: F811 @overload # noqa: F811
def raises( # noqa: F811 def raises( # noqa: F811
expected_exception: Union["Type[_E]", Tuple["Type[_E]", ...]], expected_exception: Union["Type[_E]", Tuple["Type[_E]", ...]],
func: Callable, func: Callable[..., Any],
*args: Any, *args: Any,
**kwargs: Any **kwargs: Any
) -> _pytest._code.ExceptionInfo[_E]: ) -> _pytest._code.ExceptionInfo[_E]:
@ -670,7 +670,7 @@ def raises( # noqa: F811
message = "DID NOT RAISE {}".format(expected_exception) message = "DID NOT RAISE {}".format(expected_exception)
if not args: if not args:
match = kwargs.pop("match", None) match = kwargs.pop("match", None) # type: Optional[Union[str, Pattern[str]]]
if kwargs: if kwargs:
msg = "Unexpected keyword arguments passed to pytest.raises: " msg = "Unexpected keyword arguments passed to pytest.raises: "
msg += ", ".join(sorted(kwargs)) msg += ", ".join(sorted(kwargs))
@ -703,7 +703,7 @@ class RaisesContext(Generic[_E]):
self, self,
expected_exception: Union["Type[_E]", Tuple["Type[_E]", ...]], expected_exception: Union["Type[_E]", Tuple["Type[_E]", ...]],
message: str, message: str,
match_expr: Optional[Union[str, "Pattern"]] = None, match_expr: Optional[Union[str, "Pattern[str]"]] = None,
) -> None: ) -> None:
self.expected_exception = expected_exception self.expected_exception = expected_exception
self.message = message self.message = message

View File

@ -40,7 +40,7 @@ def recwarn() -> Generator["WarningsRecorder", None, None]:
@overload @overload
def deprecated_call( def deprecated_call(
*, match: Optional[Union[str, "Pattern"]] = ... *, match: Optional[Union[str, "Pattern[str]"]] = ...
) -> "WarningsRecorder": ) -> "WarningsRecorder":
raise NotImplementedError() raise NotImplementedError()
@ -53,7 +53,7 @@ def deprecated_call( # noqa: F811
def deprecated_call( # noqa: F811 def deprecated_call( # noqa: F811
func: Optional[Callable] = None, *args: Any, **kwargs: Any func: Optional[Callable[..., Any]] = None, *args: Any, **kwargs: Any
) -> Union["WarningsRecorder", Any]: ) -> Union["WarningsRecorder", Any]:
"""Assert that code produces a ``DeprecationWarning`` or ``PendingDeprecationWarning``. """Assert that code produces a ``DeprecationWarning`` or ``PendingDeprecationWarning``.
@ -87,7 +87,7 @@ def deprecated_call( # noqa: F811
def warns( def warns(
expected_warning: Optional[Union["Type[Warning]", Tuple["Type[Warning]", ...]]], expected_warning: Optional[Union["Type[Warning]", Tuple["Type[Warning]", ...]]],
*, *,
match: "Optional[Union[str, Pattern]]" = ... match: "Optional[Union[str, Pattern[str]]]" = ...
) -> "WarningsChecker": ) -> "WarningsChecker":
raise NotImplementedError() raise NotImplementedError()
@ -105,7 +105,7 @@ def warns( # noqa: F811
def warns( # noqa: F811 def warns( # noqa: F811
expected_warning: Optional[Union["Type[Warning]", Tuple["Type[Warning]", ...]]], expected_warning: Optional[Union["Type[Warning]", Tuple["Type[Warning]", ...]]],
*args: Any, *args: Any,
match: Optional[Union[str, "Pattern"]] = None, match: Optional[Union[str, "Pattern[str]"]] = None,
**kwargs: Any **kwargs: Any
) -> Union["WarningsChecker", Any]: ) -> Union["WarningsChecker", Any]:
r"""Assert that code raises a particular class of warning. r"""Assert that code raises a particular class of warning.
@ -234,7 +234,7 @@ class WarningsChecker(WarningsRecorder):
expected_warning: Optional[ expected_warning: Optional[
Union["Type[Warning]", Tuple["Type[Warning]", ...]] Union["Type[Warning]", Tuple["Type[Warning]", ...]]
] = None, ] = None,
match_expr: Optional[Union[str, "Pattern"]] = None, match_expr: Optional[Union[str, "Pattern[str]"]] = None,
) -> None: ) -> None:
super().__init__() super().__init__()

View File

@ -514,7 +514,7 @@ def _report_kwargs_from_json(reportdict: Dict[str, Any]) -> Dict[str, Any]:
] ]
return ReprTraceback(**repr_traceback_dict) return ReprTraceback(**repr_traceback_dict)
def deserialize_repr_crash(repr_crash_dict: Optional[dict]): def deserialize_repr_crash(repr_crash_dict: Optional[Dict[str, Any]]):
if repr_crash_dict is not None: if repr_crash_dict is not None:
return ReprFileLocation(**repr_crash_dict) return ReprFileLocation(**repr_crash_dict)
else: else:

View File

@ -213,7 +213,7 @@ def call_and_report(
return report return report
def check_interactive_exception(call: "CallInfo", 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 """Check whether the call raised an exception that should be reported as
interactive.""" interactive."""
if call.excinfo is None: if call.excinfo is None:
@ -247,11 +247,11 @@ def call_runtest_hook(
) )
_T = TypeVar("_T") TResult = TypeVar("TResult", covariant=True)
@attr.s(repr=False) @attr.s(repr=False)
class CallInfo(Generic[_T]): class CallInfo(Generic[TResult]):
"""Result/Exception info a function invocation. """Result/Exception info a function invocation.
:param T result: :param T result:
@ -269,7 +269,7 @@ class CallInfo(Generic[_T]):
The context of invocation: "setup", "call", "teardown", ... The context of invocation: "setup", "call", "teardown", ...
""" """
_result = attr.ib(type="Optional[_T]") _result = attr.ib(type="Optional[TResult]")
excinfo = attr.ib(type=Optional[ExceptionInfo[BaseException]]) excinfo = attr.ib(type=Optional[ExceptionInfo[BaseException]])
start = attr.ib(type=float) start = attr.ib(type=float)
stop = attr.ib(type=float) stop = attr.ib(type=float)
@ -277,26 +277,26 @@ class CallInfo(Generic[_T]):
when = attr.ib(type="Literal['collect', 'setup', 'call', 'teardown']") when = attr.ib(type="Literal['collect', 'setup', 'call', 'teardown']")
@property @property
def result(self) -> _T: def result(self) -> TResult:
if self.excinfo is not None: if self.excinfo is not None:
raise AttributeError("{!r} has no valid result".format(self)) raise AttributeError("{!r} has no valid result".format(self))
# The cast is safe because an exception wasn't raised, hence # The cast is safe because an exception wasn't raised, hence
# _result has the expected function return type (which may be # _result has the expected function return type (which may be
# None, that's why a cast and not an assert). # None, that's why a cast and not an assert).
return cast(_T, self._result) return cast(TResult, self._result)
@classmethod @classmethod
def from_call( def from_call(
cls, cls,
func: "Callable[[], _T]", func: "Callable[[], TResult]",
when: "Literal['collect', 'setup', 'call', 'teardown']", when: "Literal['collect', 'setup', 'call', 'teardown']",
reraise: "Optional[Union[Type[BaseException], Tuple[Type[BaseException], ...]]]" = None, reraise: "Optional[Union[Type[BaseException], Tuple[Type[BaseException], ...]]]" = None,
) -> "CallInfo[_T]": ) -> "CallInfo[TResult]":
excinfo = None excinfo = None
start = timing.time() start = timing.time()
precise_start = timing.perf_counter() precise_start = timing.perf_counter()
try: try:
result = func() # type: Optional[_T] result = func() # type: Optional[TResult]
except BaseException: except BaseException:
excinfo = ExceptionInfo.from_current() excinfo = ExceptionInfo.from_current()
if reraise is not None and isinstance(excinfo.value, reraise): if reraise is not None and isinstance(excinfo.value, reraise):

View File

@ -29,7 +29,7 @@ def pytest_addoption(parser: Parser) -> None:
@pytest.hookimpl(hookwrapper=True) @pytest.hookimpl(hookwrapper=True)
def pytest_fixture_setup( def pytest_fixture_setup(
fixturedef: FixtureDef, request: SubRequest fixturedef: FixtureDef[object], request: SubRequest
) -> Generator[None, None, None]: ) -> Generator[None, None, None]:
yield yield
if request.config.option.setupshow: if request.config.option.setupshow:
@ -47,7 +47,7 @@ def pytest_fixture_setup(
_show_fixture_action(fixturedef, "SETUP") _show_fixture_action(fixturedef, "SETUP")
def pytest_fixture_post_finalizer(fixturedef: FixtureDef) -> None: def pytest_fixture_post_finalizer(fixturedef: FixtureDef[object]) -> None:
if fixturedef.cached_result is not None: if fixturedef.cached_result is not None:
config = fixturedef._fixturemanager.config config = fixturedef._fixturemanager.config
if config.option.setupshow: if config.option.setupshow:
@ -56,7 +56,7 @@ def pytest_fixture_post_finalizer(fixturedef: FixtureDef) -> None:
del fixturedef.cached_param # type: ignore[attr-defined] del fixturedef.cached_param # type: ignore[attr-defined]
def _show_fixture_action(fixturedef: FixtureDef, msg: str) -> None: def _show_fixture_action(fixturedef: FixtureDef[object], msg: str) -> None:
config = fixturedef._fixturemanager.config config = fixturedef._fixturemanager.config
capman = config.pluginmanager.getplugin("capturemanager") capman = config.pluginmanager.getplugin("capturemanager")
if capman: if capman:

View File

@ -22,7 +22,7 @@ def pytest_addoption(parser: Parser) -> None:
@pytest.hookimpl(tryfirst=True) @pytest.hookimpl(tryfirst=True)
def pytest_fixture_setup( def pytest_fixture_setup(
fixturedef: FixtureDef, request: SubRequest fixturedef: FixtureDef[object], request: SubRequest
) -> Optional[object]: ) -> Optional[object]:
# Will return a dummy fixture if the setuponly option is provided. # Will return a dummy fixture if the setuponly option is provided.
if request.config.option.setupplan: if request.config.option.setupplan:

View File

@ -319,7 +319,7 @@ class TerminalReporter:
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]
self._known_types = None # type: Optional[List] self._known_types = None # type: Optional[List[str]]
self.startdir = config.invocation_dir self.startdir = config.invocation_dir
if file is None: if file is None:
file = sys.stdout file = sys.stdout
@ -469,7 +469,7 @@ class TerminalReporter:
def line(self, msg: str, **kw: bool) -> None: 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: Sequence) -> None: def _add_stats(self, category: str, items: Sequence[Any]) -> None:
set_main_color = category not in self.stats set_main_color = category not in self.stats
self.stats.setdefault(category, []).extend(items) self.stats.setdefault(category, []).extend(items)
if set_main_color: if set_main_color:

View File

@ -141,7 +141,7 @@ def _make_xunit_fixture(
class TestCaseFunction(Function): class TestCaseFunction(Function):
nofuncargs = True nofuncargs = True
_excinfo = None # type: Optional[List[_pytest._code.ExceptionInfo]] _excinfo = None # type: Optional[List[_pytest._code.ExceptionInfo[BaseException]]]
_testcase = None # type: Optional[unittest.TestCase] _testcase = None # type: Optional[unittest.TestCase]
def setup(self) -> None: def setup(self) -> None:
@ -279,7 +279,9 @@ class TestCaseFunction(Function):
finally: finally:
delattr(self._testcase, self.name) delattr(self._testcase, self.name)
def _prunetraceback(self, excinfo: _pytest._code.ExceptionInfo) -> None: def _prunetraceback(
self, excinfo: _pytest._code.ExceptionInfo[BaseException]
) -> None:
Function._prunetraceback(self, excinfo) Function._prunetraceback(self, excinfo)
traceback = excinfo.traceback.filter( traceback = excinfo.traceback.filter(
lambda x: not x.frame.f_globals.get("__unittest") lambda x: not x.frame.f_globals.get("__unittest")

View File

@ -144,7 +144,7 @@ class TestMetafunc:
scope = attr.ib() scope = attr.ib()
fixtures_defs = cast( fixtures_defs = cast(
Dict[str, Sequence[fixtures.FixtureDef]], Dict[str, Sequence[fixtures.FixtureDef[object]]],
dict( dict(
session_fix=[DummyFixtureDef("session")], session_fix=[DummyFixtureDef("session")],
package_fix=[DummyFixtureDef("package")], package_fix=[DummyFixtureDef("package")],

View File

@ -640,7 +640,8 @@ class TestAssert_reprcompare:
def test_Sequence(self) -> None: def test_Sequence(self) -> None:
# Test comparing with a Sequence subclass. # Test comparing with a Sequence subclass.
class TestSequence(collections.abc.MutableSequence): # TODO(py36): Inherit from typing.MutableSequence[int].
class TestSequence(collections.abc.MutableSequence): # type: ignore[type-arg]
def __init__(self, iterable): def __init__(self, iterable):
self.elements = list(iterable) self.elements = list(iterable)

View File

@ -1564,66 +1564,66 @@ def tr() -> TerminalReporter:
# dict value, not the actual contents, so tuples of anything # dict value, not the actual contents, so tuples of anything
# suffice # suffice
# Important statuses -- the highest priority of these always wins # Important statuses -- the highest priority of these always wins
("red", [("1 failed", {"bold": True, "red": True})], {"failed": (1,)}), ("red", [("1 failed", {"bold": True, "red": True})], {"failed": [1]}),
( (
"red", "red",
[ [
("1 failed", {"bold": True, "red": True}), ("1 failed", {"bold": True, "red": True}),
("1 passed", {"bold": False, "green": True}), ("1 passed", {"bold": False, "green": True}),
], ],
{"failed": (1,), "passed": (1,)}, {"failed": [1], "passed": [1]},
), ),
("red", [("1 error", {"bold": True, "red": True})], {"error": (1,)}), ("red", [("1 error", {"bold": True, "red": True})], {"error": [1]}),
("red", [("2 errors", {"bold": True, "red": True})], {"error": (1, 2)}), ("red", [("2 errors", {"bold": True, "red": True})], {"error": [1, 2]}),
( (
"red", "red",
[ [
("1 passed", {"bold": False, "green": True}), ("1 passed", {"bold": False, "green": True}),
("1 error", {"bold": True, "red": True}), ("1 error", {"bold": True, "red": True}),
], ],
{"error": (1,), "passed": (1,)}, {"error": [1], "passed": [1]},
), ),
# (a status that's not known to the code) # (a status that's not known to the code)
("yellow", [("1 weird", {"bold": True, "yellow": True})], {"weird": (1,)}), ("yellow", [("1 weird", {"bold": True, "yellow": True})], {"weird": [1]}),
( (
"yellow", "yellow",
[ [
("1 passed", {"bold": False, "green": True}), ("1 passed", {"bold": False, "green": True}),
("1 weird", {"bold": True, "yellow": True}), ("1 weird", {"bold": True, "yellow": True}),
], ],
{"weird": (1,), "passed": (1,)}, {"weird": [1], "passed": [1]},
), ),
("yellow", [("1 warning", {"bold": True, "yellow": True})], {"warnings": (1,)}), ("yellow", [("1 warning", {"bold": True, "yellow": True})], {"warnings": [1]}),
( (
"yellow", "yellow",
[ [
("1 passed", {"bold": False, "green": True}), ("1 passed", {"bold": False, "green": True}),
("1 warning", {"bold": True, "yellow": True}), ("1 warning", {"bold": True, "yellow": True}),
], ],
{"warnings": (1,), "passed": (1,)}, {"warnings": [1], "passed": [1]},
), ),
( (
"green", "green",
[("5 passed", {"bold": True, "green": True})], [("5 passed", {"bold": True, "green": True})],
{"passed": (1, 2, 3, 4, 5)}, {"passed": [1, 2, 3, 4, 5]},
), ),
# "Boring" statuses. These have no effect on the color of the summary # "Boring" statuses. These have no effect on the color of the summary
# line. Thus, if *every* test has a boring status, the summary line stays # line. Thus, if *every* test has a boring status, the summary line stays
# at its default color, i.e. yellow, to warn the user that the test run # at its default color, i.e. yellow, to warn the user that the test run
# produced no useful information # produced no useful information
("yellow", [("1 skipped", {"bold": True, "yellow": True})], {"skipped": (1,)}), ("yellow", [("1 skipped", {"bold": True, "yellow": True})], {"skipped": [1]}),
( (
"green", "green",
[ [
("1 passed", {"bold": True, "green": True}), ("1 passed", {"bold": True, "green": True}),
("1 skipped", {"bold": False, "yellow": True}), ("1 skipped", {"bold": False, "yellow": True}),
], ],
{"skipped": (1,), "passed": (1,)}, {"skipped": [1], "passed": [1]},
), ),
( (
"yellow", "yellow",
[("1 deselected", {"bold": True, "yellow": True})], [("1 deselected", {"bold": True, "yellow": True})],
{"deselected": (1,)}, {"deselected": [1]},
), ),
( (
"green", "green",
@ -1631,34 +1631,34 @@ def tr() -> TerminalReporter:
("1 passed", {"bold": True, "green": True}), ("1 passed", {"bold": True, "green": True}),
("1 deselected", {"bold": False, "yellow": True}), ("1 deselected", {"bold": False, "yellow": True}),
], ],
{"deselected": (1,), "passed": (1,)}, {"deselected": [1], "passed": [1]},
), ),
("yellow", [("1 xfailed", {"bold": True, "yellow": True})], {"xfailed": (1,)}), ("yellow", [("1 xfailed", {"bold": True, "yellow": True})], {"xfailed": [1]}),
( (
"green", "green",
[ [
("1 passed", {"bold": True, "green": True}), ("1 passed", {"bold": True, "green": True}),
("1 xfailed", {"bold": False, "yellow": True}), ("1 xfailed", {"bold": False, "yellow": True}),
], ],
{"xfailed": (1,), "passed": (1,)}, {"xfailed": [1], "passed": [1]},
), ),
("yellow", [("1 xpassed", {"bold": True, "yellow": True})], {"xpassed": (1,)}), ("yellow", [("1 xpassed", {"bold": True, "yellow": True})], {"xpassed": [1]}),
( (
"yellow", "yellow",
[ [
("1 passed", {"bold": False, "green": True}), ("1 passed", {"bold": False, "green": True}),
("1 xpassed", {"bold": True, "yellow": True}), ("1 xpassed", {"bold": True, "yellow": True}),
], ],
{"xpassed": (1,), "passed": (1,)}, {"xpassed": [1], "passed": [1]},
), ),
# Likewise if no tests were found at all # Likewise if no tests were found at all
("yellow", [("no tests ran", {"yellow": True})], {}), ("yellow", [("no tests ran", {"yellow": True})], {}),
# Test the empty-key special case # Test the empty-key special case
("yellow", [("no tests ran", {"yellow": True})], {"": (1,)}), ("yellow", [("no tests ran", {"yellow": True})], {"": [1]}),
( (
"green", "green",
[("1 passed", {"bold": True, "green": True})], [("1 passed", {"bold": True, "green": True})],
{"": (1,), "passed": (1,)}, {"": [1], "passed": [1]},
), ),
# A couple more complex combinations # A couple more complex combinations
( (
@ -1668,7 +1668,7 @@ def tr() -> TerminalReporter:
("2 passed", {"bold": False, "green": True}), ("2 passed", {"bold": False, "green": True}),
("3 xfailed", {"bold": False, "yellow": True}), ("3 xfailed", {"bold": False, "yellow": True}),
], ],
{"passed": (1, 2), "failed": (1,), "xfailed": (1, 2, 3)}, {"passed": [1, 2], "failed": [1], "xfailed": [1, 2, 3]},
), ),
( (
"green", "green",
@ -1679,10 +1679,10 @@ def tr() -> TerminalReporter:
("2 xfailed", {"bold": False, "yellow": True}), ("2 xfailed", {"bold": False, "yellow": True}),
], ],
{ {
"passed": (1,), "passed": [1],
"skipped": (1, 2), "skipped": [1, 2],
"deselected": (1, 2, 3), "deselected": [1, 2, 3],
"xfailed": (1, 2), "xfailed": [1, 2],
}, },
), ),
], ],
@ -1691,7 +1691,7 @@ def test_summary_stats(
tr: TerminalReporter, tr: TerminalReporter,
exp_line: List[Tuple[str, Dict[str, bool]]], exp_line: List[Tuple[str, Dict[str, bool]]],
exp_color: str, exp_color: str,
stats_arg: Dict[str, List], stats_arg: Dict[str, List[object]],
) -> None: ) -> None:
tr.stats = stats_arg tr.stats = stats_arg