Enable check_untyped_defs mypy option for src/

This option checks even functions which are not annotated. It's a good
step to ensure that existing type annotation are correct.

In a Pareto fashion, the last few holdouts are always the ugliest,
beware.
This commit is contained in:
Ran Benita 2020-05-01 14:40:16 +03:00
parent 848ab00663
commit 71dfdca4df
9 changed files with 65 additions and 31 deletions

View File

@ -98,3 +98,6 @@ strict_equality = True
warn_redundant_casts = True
warn_return_any = True
warn_unused_configs = True
[mypy-_pytest.*]
check_untyped_defs = True

View File

@ -519,10 +519,11 @@ class MultiCapture:
def pop_outerr_to_orig(self):
""" pop current snapshot out/err capture and flush to orig streams. """
out, err = self.readouterr()
# TODO: Fix type ignores.
if out:
self.out.writeorg(out)
self.out.writeorg(out) # type: ignore[union-attr] # noqa: F821
if err:
self.err.writeorg(err)
self.err.writeorg(err) # type: ignore[union-attr] # noqa: F821
return out, err
def suspend_capturing(self, in_: bool = False) -> None:
@ -542,7 +543,8 @@ class MultiCapture:
if self.err:
self.err.resume()
if self._in_suspended:
self.in_.resume()
# TODO: Fix type ignore.
self.in_.resume() # type: ignore[union-attr] # noqa: F821
self._in_suspended = False
def stop_capturing(self) -> None:

View File

@ -974,7 +974,7 @@ class Config:
self._mark_plugins_for_rewrite(hook)
_warn_about_missing_assertion(mode)
def _mark_plugins_for_rewrite(self, hook):
def _mark_plugins_for_rewrite(self, hook) -> None:
"""
Given an importhook, mark for rewrite any top-level
modules or packages in the distribution package for
@ -989,7 +989,9 @@ class Config:
package_files = (
str(file)
for dist in importlib_metadata.distributions()
if any(ep.group == "pytest11" for ep in dist.entry_points)
# Type ignored due to missing stub:
# https://github.com/python/typeshed/pull/3795
if any(ep.group == "pytest11" for ep in dist.entry_points) # type: ignore
for file in dist.files or []
)

View File

@ -721,7 +721,9 @@ class FixtureRequest:
# this might also be a non-function Item despite its attribute name
return self._pyfuncitem
if scope == "package":
node = get_scope_package(self._pyfuncitem, self._fixturedef)
# FIXME: _fixturedef is not defined on FixtureRequest (this class),
# but on FixtureRequest (a subclass).
node = get_scope_package(self._pyfuncitem, self._fixturedef) # type: ignore[attr-defined] # noqa: F821
else:
node = get_scope_node(self._pyfuncitem, scope)
if node is None and scope == "class":
@ -1158,7 +1160,7 @@ def wrap_function_to_error_out_if_called_directly(function, fixture_marker):
# keep reference to the original function in our own custom attribute so we don't unwrap
# further than this point and lose useful wrappings like @mock.patch (#3774)
result.__pytest_wrapped__ = _PytestWrapper(function)
result.__pytest_wrapped__ = _PytestWrapper(function) # type: ignore[attr-defined] # noqa: F821
return result

View File

@ -42,6 +42,8 @@ if TYPE_CHECKING:
# Imported here due to circular import.
from _pytest.main import Session
from _pytest.warning_types import PytestWarning
SEP = "/"
@ -118,9 +120,9 @@ class Node(metaclass=NodeMeta):
def __init__(
self,
name: str,
parent: Optional["Node"] = None,
parent: "Optional[Node]" = None,
config: Optional[Config] = None,
session: Optional["Session"] = None,
session: "Optional[Session]" = None,
fspath: Optional[py.path.local] = None,
nodeid: Optional[str] = None,
) -> None:
@ -201,7 +203,7 @@ class Node(metaclass=NodeMeta):
def __repr__(self) -> str:
return "<{} {}>".format(self.__class__.__name__, getattr(self, "name", None))
def warn(self, warning):
def warn(self, warning: "PytestWarning") -> None:
"""Issue a warning for this item.
Warnings will be displayed after the test session, unless explicitly suppressed
@ -226,11 +228,9 @@ class Node(metaclass=NodeMeta):
)
)
path, lineno = get_fslocation_from_item(self)
assert lineno is not None
warnings.warn_explicit(
warning,
category=None,
filename=str(path),
lineno=lineno + 1 if lineno is not None else None,
warning, category=None, filename=str(path), lineno=lineno + 1,
)
# methods for ordering nodes
@ -417,24 +417,26 @@ class Node(metaclass=NodeMeta):
def get_fslocation_from_item(
item: "Item",
node: "Node",
) -> Tuple[Union[str, py.path.local], Optional[int]]:
"""Tries to extract the actual location from an item, depending on available attributes:
"""Tries to extract the actual location from a node, depending on available attributes:
* "fslocation": a pair (path, lineno)
* "obj": a Python object that the item wraps.
* "location": a pair (path, lineno)
* "obj": a Python object that the node wraps.
* "fspath": just a path
:rtype: a tuple of (str|LocalPath, int) with filename and line number.
"""
try:
return item.location[:2]
except AttributeError:
pass
obj = getattr(item, "obj", None)
# See Item.location.
location = getattr(
node, "location", None
) # type: Optional[Tuple[str, Optional[int], str]]
if location is not None:
return location[:2]
obj = getattr(node, "obj", None)
if obj is not None:
return getfslineno(obj)
return getattr(item, "fspath", "unknown location"), -1
return getattr(node, "fspath", "unknown location"), -1
class Collector(Node):

View File

@ -1169,8 +1169,10 @@ class Testdir:
popen = subprocess.Popen(cmdargs, stdout=stdout, stderr=stderr, **kw)
if stdin is Testdir.CLOSE_STDIN:
assert popen.stdin is not None
popen.stdin.close()
elif isinstance(stdin, bytes):
assert popen.stdin is not None
popen.stdin.write(stdin)
return popen

View File

@ -64,6 +64,7 @@ from _pytest.warning_types import PytestCollectionWarning
from _pytest.warning_types import PytestUnhandledCoroutineWarning
if TYPE_CHECKING:
from typing import Type
from typing_extensions import Literal
from _pytest.fixtures import _Scope
@ -256,6 +257,18 @@ def pytest_pycollect_makeitem(collector: "PyCollector", name: str, obj):
class PyobjMixin:
_ALLOW_MARKERS = True
# Function and attributes that the mixin needs (for type-checking only).
if TYPE_CHECKING:
name = "" # type: str
parent = None # type: Optional[nodes.Node]
own_markers = [] # type: List[Mark]
def getparent(self, cls: Type[nodes._NodeType]) -> Optional[nodes._NodeType]:
...
def listchain(self) -> List[nodes.Node]:
...
@property
def module(self):
"""Python module object this node was collected from (can be None)."""
@ -292,7 +305,10 @@ class PyobjMixin:
def _getobj(self):
"""Gets the underlying Python object. May be overwritten by subclasses."""
return getattr(self.parent.obj, self.name)
# TODO: Improve the type of `parent` such that assert/ignore aren't needed.
assert self.parent is not None
obj = self.parent.obj # type: ignore[attr-defined] # noqa: F821
return getattr(obj, self.name)
def getmodpath(self, stopatmodule=True, includemodule=False):
""" return python path relative to the containing module. """
@ -772,7 +788,10 @@ class Instance(PyCollector):
# can be removed at node structure reorganization time
def _getobj(self):
return self.parent.obj()
# TODO: Improve the type of `parent` such that assert/ignore aren't needed.
assert self.parent is not None
obj = self.parent.obj # type: ignore[attr-defined] # noqa: F821
return obj()
def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]:
self.session._fixturemanager.parsefactories(self)
@ -1527,7 +1546,8 @@ class Function(PyobjMixin, nodes.Item):
return getimfunc(self.obj)
def _getobj(self):
return getattr(self.parent.obj, self.originalname)
assert self.parent is not None
return getattr(self.parent.obj, self.originalname) # type: ignore[attr-defined]
@property
def _pyfuncitem(self):

View File

@ -508,7 +508,7 @@ def approx(expected, rel=None, abs=None, nan_ok=False):
__tracebackhide__ = True
if isinstance(expected, Decimal):
cls = ApproxDecimal
cls = ApproxDecimal # type: Type[ApproxBase]
elif isinstance(expected, Number):
cls = ApproxScalar
elif isinstance(expected, Mapping):
@ -534,7 +534,7 @@ def _is_numpy_array(obj):
"""
import sys
np = sys.modules.get("numpy")
np = sys.modules.get("numpy") # type: Any
if np is not None:
return isinstance(obj, np.ndarray)
return False

View File

@ -136,8 +136,9 @@ class WarningsRecorder(warnings.catch_warnings):
Adapted from `warnings.catch_warnings`.
"""
def __init__(self):
super().__init__(record=True)
def __init__(self) -> None:
# Type ignored due to the way typeshed handles warnings.catch_warnings.
super().__init__(record=True) # type: ignore[call-arg] # noqa: F821
self._entered = False
self._list = [] # type: List[warnings.WarningMessage]