Merge pull request #7472 from bluetech/cleanups-4

Some minor fixes & type annotations
This commit is contained in:
Ran Benita 2020-07-11 19:05:07 +03:00 committed by GitHub
commit 7b65b2337b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 360 additions and 349 deletions

View File

@ -0,0 +1 @@
The ``exec_()`` and ``is_true()`` methods of ``_pytest._code.Frame`` have been removed.

View File

@ -51,7 +51,7 @@ if TYPE_CHECKING:
class Code: class Code:
""" wrapper around Python code objects """ """Wrapper around Python code objects."""
def __init__(self, rawcode) -> None: def __init__(self, rawcode) -> None:
if not hasattr(rawcode, "co_filename"): if not hasattr(rawcode, "co_filename"):
@ -69,12 +69,9 @@ class Code:
# Ignore type because of https://github.com/python/mypy/issues/4266. # Ignore type because of https://github.com/python/mypy/issues/4266.
__hash__ = None # type: ignore __hash__ = None # type: ignore
def __ne__(self, other):
return not self == other
@property @property
def path(self) -> Union[py.path.local, str]: def path(self) -> Union[py.path.local, str]:
""" return a path object pointing to source code (or a str in case """Return a path object pointing to source code (or a str in case
of OSError / non-existing file). of OSError / non-existing file).
""" """
if not self.raw.co_filename: if not self.raw.co_filename:
@ -92,24 +89,22 @@ class Code:
@property @property
def fullsource(self) -> Optional["Source"]: def fullsource(self) -> Optional["Source"]:
""" return a _pytest._code.Source object for the full source file of the code """Return a _pytest._code.Source object for the full source file of the code."""
"""
full, _ = findsource(self.raw) full, _ = findsource(self.raw)
return full return full
def source(self) -> "Source": def source(self) -> "Source":
""" return a _pytest._code.Source object for the code object's source only """Return a _pytest._code.Source object for the code object's source only."""
"""
# return source only for that part of code # return source only for that part of code
return Source(self.raw) return Source(self.raw)
def getargs(self, var: bool = False) -> Tuple[str, ...]: def getargs(self, var: bool = False) -> Tuple[str, ...]:
""" return a tuple with the argument names for the code object """Return a tuple with the argument names for the code object.
if 'var' is set True also return the names of the variable and If 'var' is set True also return the names of the variable and
keyword arguments when present keyword arguments when present.
""" """
# handfull shortcut for getting args # Handy shortcut for getting args.
raw = self.raw raw = self.raw
argcount = raw.co_argcount argcount = raw.co_argcount
if var: if var:
@ -131,44 +126,31 @@ class Frame:
@property @property
def statement(self) -> "Source": def statement(self) -> "Source":
""" statement this frame is at """ """Statement this frame is at."""
if self.code.fullsource is None: if self.code.fullsource is None:
return Source("") return Source("")
return self.code.fullsource.getstatement(self.lineno) return self.code.fullsource.getstatement(self.lineno)
def eval(self, code, **vars): def eval(self, code, **vars):
""" evaluate 'code' in the frame """Evaluate 'code' in the frame.
'vars' are optional additional local variables 'vars' are optional additional local variables.
returns the result of the evaluation Returns the result of the evaluation.
""" """
f_locals = self.f_locals.copy() f_locals = self.f_locals.copy()
f_locals.update(vars) f_locals.update(vars)
return eval(code, self.f_globals, f_locals) return eval(code, self.f_globals, f_locals)
def exec_(self, code, **vars) -> None:
""" exec 'code' in the frame
'vars' are optional; additional local variables
"""
f_locals = self.f_locals.copy()
f_locals.update(vars)
exec(code, self.f_globals, f_locals)
def repr(self, object: object) -> str: def repr(self, object: object) -> str:
""" return a 'safe' (non-recursive, one-line) string repr for 'object' """Return a 'safe' (non-recursive, one-line) string repr for 'object'."""
"""
return saferepr(object) return saferepr(object)
def is_true(self, object):
return object
def getargs(self, var: bool = False): def getargs(self, var: bool = False):
""" return a list of tuples (name, value) for all arguments """Return a list of tuples (name, value) for all arguments.
if 'var' is set True also include the variable and keyword If 'var' is set True, also include the variable and keyword arguments
arguments when present when present.
""" """
retval = [] retval = []
for arg in self.code.getargs(var): for arg in self.code.getargs(var):
@ -180,12 +162,16 @@ class Frame:
class TracebackEntry: class TracebackEntry:
""" a single entry in a traceback """ """A single entry in a Traceback."""
_repr_style = None # type: Optional[Literal["short", "long"]] _repr_style = None # type: Optional[Literal["short", "long"]]
exprinfo = None exprinfo = None
def __init__(self, rawentry: TracebackType, excinfo=None) -> None: def __init__(
self,
rawentry: TracebackType,
excinfo: Optional["ReferenceType[ExceptionInfo[BaseException]]"] = None,
) -> None:
self._excinfo = excinfo self._excinfo = excinfo
self._rawentry = rawentry self._rawentry = rawentry
self.lineno = rawentry.tb_lineno - 1 self.lineno = rawentry.tb_lineno - 1
@ -207,26 +193,26 @@ class TracebackEntry:
@property @property
def statement(self) -> "Source": def statement(self) -> "Source":
""" _pytest._code.Source object for the current statement """ """_pytest._code.Source object for the current statement."""
source = self.frame.code.fullsource source = self.frame.code.fullsource
assert source is not None assert source is not None
return source.getstatement(self.lineno) return source.getstatement(self.lineno)
@property @property
def path(self) -> Union[py.path.local, str]: def path(self) -> Union[py.path.local, str]:
""" path to the source code """ """Path to the source code."""
return self.frame.code.path return self.frame.code.path
@property @property
def locals(self) -> Dict[str, Any]: def locals(self) -> Dict[str, Any]:
""" locals of underlying frame """ """Locals of underlying frame."""
return self.frame.f_locals return self.frame.f_locals
def getfirstlinesource(self) -> int: def getfirstlinesource(self) -> int:
return self.frame.code.firstlineno return self.frame.code.firstlineno
def getsource(self, astcache=None) -> Optional["Source"]: def getsource(self, astcache=None) -> Optional["Source"]:
""" return failing source code. """ """Return failing source code."""
# we use the passed in astcache to not reparse asttrees # we use the passed in astcache to not reparse asttrees
# within exception info printing # within exception info printing
source = self.frame.code.fullsource source = self.frame.code.fullsource
@ -251,19 +237,19 @@ class TracebackEntry:
source = property(getsource) source = property(getsource)
def ishidden(self): def ishidden(self) -> bool:
""" return True if the current frame has a var __tracebackhide__ """Return True if the current frame has a var __tracebackhide__
resolving to True. resolving to True.
If __tracebackhide__ is a callable, it gets called with the If __tracebackhide__ is a callable, it gets called with the
ExceptionInfo instance and can decide whether to hide the traceback. ExceptionInfo instance and can decide whether to hide the traceback.
mostly for internal use Mostly for internal use.
""" """
f = self.frame f = self.frame
tbh = f.f_locals.get( tbh = f.f_locals.get(
"__tracebackhide__", f.f_globals.get("__tracebackhide__", False) "__tracebackhide__", f.f_globals.get("__tracebackhide__", False)
) ) # type: Union[bool, Callable[[Optional[ExceptionInfo[BaseException]]], bool]]
if tbh and callable(tbh): if tbh and callable(tbh):
return tbh(None if self._excinfo is None else self._excinfo()) return tbh(None if self._excinfo is None else self._excinfo())
return tbh return tbh
@ -280,21 +266,19 @@ class TracebackEntry:
@property @property
def name(self) -> str: def name(self) -> str:
""" co_name of underlying code """ """co_name of underlying code."""
return self.frame.code.raw.co_name return self.frame.code.raw.co_name
class Traceback(List[TracebackEntry]): class Traceback(List[TracebackEntry]):
""" Traceback objects encapsulate and offer higher level """Traceback objects encapsulate and offer higher level access to Traceback entries."""
access to Traceback entries.
"""
def __init__( def __init__(
self, self,
tb: Union[TracebackType, Iterable[TracebackEntry]], tb: Union[TracebackType, Iterable[TracebackEntry]],
excinfo: Optional["ReferenceType[ExceptionInfo]"] = None, excinfo: Optional["ReferenceType[ExceptionInfo[BaseException]]"] = None,
) -> None: ) -> None:
""" initialize from given python traceback object and ExceptionInfo """ """Initialize from given python traceback object and ExceptionInfo."""
self._excinfo = excinfo self._excinfo = excinfo
if isinstance(tb, TracebackType): if isinstance(tb, TracebackType):
@ -313,16 +297,16 @@ class Traceback(List[TracebackEntry]):
path=None, path=None,
lineno: Optional[int] = None, lineno: Optional[int] = None,
firstlineno: Optional[int] = None, firstlineno: Optional[int] = None,
excludepath=None, excludepath: Optional[py.path.local] = None,
) -> "Traceback": ) -> "Traceback":
""" return a Traceback instance wrapping part of this Traceback """Return a Traceback instance wrapping part of this Traceback.
by providing any combination of path, lineno and firstlineno, the By providing any combination of path, lineno and firstlineno, the
first frame to start the to-be-returned traceback is determined first frame to start the to-be-returned traceback is determined.
this allows cutting the first part of a Traceback instance e.g. This allows cutting the first part of a Traceback instance e.g.
for formatting reasons (removing some uninteresting bits that deal for formatting reasons (removing some uninteresting bits that deal
with handling of the exception/traceback) with handling of the exception/traceback).
""" """
for x in self: for x in self:
code = x.frame.code code = x.frame.code
@ -359,21 +343,19 @@ class Traceback(List[TracebackEntry]):
def filter( def filter(
self, fn: Callable[[TracebackEntry], bool] = lambda x: not x.ishidden() self, fn: Callable[[TracebackEntry], bool] = lambda x: not x.ishidden()
) -> "Traceback": ) -> "Traceback":
""" return a Traceback instance with certain items removed """Return a Traceback instance with certain items removed
fn is a function that gets a single argument, a TracebackEntry fn is a function that gets a single argument, a TracebackEntry
instance, and should return True when the item should be added instance, and should return True when the item should be added
to the Traceback, False when not to the Traceback, False when not.
by default this removes all the TracebackEntries which are hidden By default this removes all the TracebackEntries which are hidden
(see ishidden() above) (see ishidden() above).
""" """
return Traceback(filter(fn, self), self._excinfo) return Traceback(filter(fn, self), self._excinfo)
def getcrashentry(self) -> TracebackEntry: def getcrashentry(self) -> TracebackEntry:
""" return last non-hidden traceback entry that lead """Return last non-hidden traceback entry that lead to the exception of a traceback."""
to the exception of a traceback.
"""
for i in range(-1, -len(self) - 1, -1): for i in range(-1, -len(self) - 1, -1):
entry = self[i] entry = self[i]
if not entry.ishidden(): if not entry.ishidden():
@ -381,9 +363,8 @@ class Traceback(List[TracebackEntry]):
return self[-1] return self[-1]
def recursionindex(self) -> Optional[int]: def recursionindex(self) -> Optional[int]:
""" return the index of the frame/TracebackEntry where recursion """Return the index of the frame/TracebackEntry where recursion originates if
originates if appropriate, None if no recursion occurred appropriate, None if no recursion occurred."""
"""
cache = {} # type: Dict[Tuple[Any, int, int], List[Dict[str, Any]]] cache = {} # type: Dict[Tuple[Any, int, int], List[Dict[str, Any]]]
for i, entry in enumerate(self): for i, entry in enumerate(self):
# id for the code.raw is needed to work around # id for the code.raw is needed to work around
@ -397,12 +378,10 @@ class Traceback(List[TracebackEntry]):
f = entry.frame f = entry.frame
loc = f.f_locals loc = f.f_locals
for otherloc in values: for otherloc in values:
if f.is_true( if f.eval(
f.eval( co_equal,
co_equal, __recursioncache_locals_1=loc,
__recursioncache_locals_1=loc, __recursioncache_locals_2=otherloc,
__recursioncache_locals_2=otherloc,
)
): ):
return i return i
values.append(entry.frame.f_locals) values.append(entry.frame.f_locals)
@ -414,14 +393,12 @@ co_equal = compile(
) )
_E = TypeVar("_E", bound=BaseException) _E = TypeVar("_E", bound=BaseException, covariant=True)
@attr.s(repr=False) @attr.s(repr=False)
class ExceptionInfo(Generic[_E]): class ExceptionInfo(Generic[_E]):
""" wraps sys.exc_info() objects and offers """Wraps sys.exc_info() objects and offers help for navigating the traceback."""
help for navigating the traceback.
"""
_assert_start_repr = "AssertionError('assert " _assert_start_repr = "AssertionError('assert "
@ -435,13 +412,12 @@ class ExceptionInfo(Generic[_E]):
exc_info: Tuple["Type[_E]", "_E", TracebackType], exc_info: Tuple["Type[_E]", "_E", TracebackType],
exprinfo: Optional[str] = None, exprinfo: Optional[str] = None,
) -> "ExceptionInfo[_E]": ) -> "ExceptionInfo[_E]":
"""returns an ExceptionInfo for an existing exc_info tuple. """Returns an ExceptionInfo for an existing exc_info tuple.
.. warning:: .. warning::
Experimental API Experimental API
:param exprinfo: a text string helping to determine if we should :param exprinfo: a text string helping to determine if we should
strip ``AssertionError`` from the output, defaults strip ``AssertionError`` from the output, defaults
to the exception message/``__str__()`` to the exception message/``__str__()``
@ -460,13 +436,12 @@ class ExceptionInfo(Generic[_E]):
def from_current( def from_current(
cls, exprinfo: Optional[str] = None cls, exprinfo: Optional[str] = None
) -> "ExceptionInfo[BaseException]": ) -> "ExceptionInfo[BaseException]":
"""returns an ExceptionInfo matching the current traceback """Returns an ExceptionInfo matching the current traceback.
.. warning:: .. warning::
Experimental API Experimental API
:param exprinfo: a text string helping to determine if we should :param exprinfo: a text string helping to determine if we should
strip ``AssertionError`` from the output, defaults strip ``AssertionError`` from the output, defaults
to the exception message/``__str__()`` to the exception message/``__str__()``
@ -480,8 +455,7 @@ class ExceptionInfo(Generic[_E]):
@classmethod @classmethod
def for_later(cls) -> "ExceptionInfo[_E]": def for_later(cls) -> "ExceptionInfo[_E]":
"""return an unfilled ExceptionInfo """Return an unfilled ExceptionInfo."""
"""
return cls(None) return cls(None)
def fill_unfilled(self, exc_info: Tuple["Type[_E]", _E, TracebackType]) -> None: def fill_unfilled(self, exc_info: Tuple["Type[_E]", _E, TracebackType]) -> None:
@ -491,7 +465,7 @@ class ExceptionInfo(Generic[_E]):
@property @property
def type(self) -> "Type[_E]": def type(self) -> "Type[_E]":
"""the exception class""" """The exception class."""
assert ( assert (
self._excinfo is not None self._excinfo is not None
), ".type can only be used after the context manager exits" ), ".type can only be used after the context manager exits"
@ -499,7 +473,7 @@ class ExceptionInfo(Generic[_E]):
@property @property
def value(self) -> _E: def value(self) -> _E:
"""the exception value""" """The exception value."""
assert ( assert (
self._excinfo is not None self._excinfo is not None
), ".value can only be used after the context manager exits" ), ".value can only be used after the context manager exits"
@ -507,7 +481,7 @@ class ExceptionInfo(Generic[_E]):
@property @property
def tb(self) -> TracebackType: def tb(self) -> TracebackType:
"""the exception raw traceback""" """The exception raw traceback."""
assert ( assert (
self._excinfo is not None self._excinfo is not None
), ".tb can only be used after the context manager exits" ), ".tb can only be used after the context manager exits"
@ -515,7 +489,7 @@ class ExceptionInfo(Generic[_E]):
@property @property
def typename(self) -> str: def typename(self) -> str:
"""the type name of the exception""" """The type name of the exception."""
assert ( assert (
self._excinfo is not None self._excinfo is not None
), ".typename can only be used after the context manager exits" ), ".typename can only be used after the context manager exits"
@ -523,7 +497,7 @@ class ExceptionInfo(Generic[_E]):
@property @property
def traceback(self) -> Traceback: def traceback(self) -> Traceback:
"""the traceback""" """The traceback."""
if self._traceback is None: if self._traceback is None:
self._traceback = Traceback(self.tb, excinfo=ref(self)) self._traceback = Traceback(self.tb, excinfo=ref(self))
return self._traceback return self._traceback
@ -540,12 +514,12 @@ class ExceptionInfo(Generic[_E]):
) )
def exconly(self, tryshort: bool = False) -> str: def exconly(self, tryshort: bool = False) -> str:
""" return the exception as a string """Return the exception as a string.
when 'tryshort' resolves to True, and the exception is a When 'tryshort' resolves to True, and the exception is a
_pytest._code._AssertionError, only the actual exception part of _pytest._code._AssertionError, only the actual exception part of
the exception representation is returned (so 'AssertionError: ' is the exception representation is returned (so 'AssertionError: ' is
removed from the beginning) removed from the beginning).
""" """
lines = format_exception_only(self.type, self.value) lines = format_exception_only(self.type, self.value)
text = "".join(lines) text = "".join(lines)
@ -558,7 +532,10 @@ class ExceptionInfo(Generic[_E]):
def errisinstance( def errisinstance(
self, exc: Union["Type[BaseException]", Tuple["Type[BaseException]", ...]] self, exc: Union["Type[BaseException]", Tuple["Type[BaseException]", ...]]
) -> bool: ) -> bool:
""" return True if the exception is an instance of exc """ """Return True if the exception is an instance of exc.
Consider using ``isinstance(excinfo.value, exc)`` instead.
"""
return isinstance(self.value, exc) return isinstance(self.value, exc)
def _getreprcrash(self) -> "ReprFileLocation": def _getreprcrash(self) -> "ReprFileLocation":
@ -577,8 +554,7 @@ class ExceptionInfo(Generic[_E]):
truncate_locals: bool = True, truncate_locals: bool = True,
chain: bool = True, chain: bool = True,
) -> Union["ReprExceptionInfo", "ExceptionChainRepr"]: ) -> Union["ReprExceptionInfo", "ExceptionChainRepr"]:
""" """Return str()able representation of this exception info.
Return str()able representation of this exception info.
:param bool showlocals: :param bool showlocals:
Show locals per traceback entry. Show locals per traceback entry.
@ -627,11 +603,10 @@ 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]") -> "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`.
If it matches `True` is returned.
If it doesn't match an `AssertionError` is raised. If it matches `True` is returned, otherwise an `AssertionError` is raised.
""" """
__tracebackhide__ = True __tracebackhide__ = True
assert re.search( assert re.search(
@ -643,7 +618,7 @@ class ExceptionInfo(Generic[_E]):
@attr.s @attr.s
class FormattedExcinfo: class FormattedExcinfo:
""" presenting information about failing Functions and Generators. """ """Presenting information about failing Functions and Generators."""
# for traceback entries # for traceback entries
flow_marker = ">" flow_marker = ">"
@ -694,7 +669,7 @@ class FormattedExcinfo:
excinfo: Optional[ExceptionInfo] = None, excinfo: Optional[ExceptionInfo] = 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."""
lines = [] lines = []
if source is None or line_index >= len(source.lines): if source is None or line_index >= len(source.lines):
source = Source("???") source = Source("???")
@ -804,7 +779,7 @@ class FormattedExcinfo:
if self.tbfilter: if self.tbfilter:
traceback = traceback.filter() traceback = traceback.filter()
if excinfo.errisinstance(RecursionError): if isinstance(excinfo.value, RecursionError):
traceback, extraline = self._truncate_recursive_traceback(traceback) traceback, extraline = self._truncate_recursive_traceback(traceback)
else: else:
extraline = None extraline = None
@ -935,7 +910,7 @@ class ExceptionRepr(TerminalRepr):
reprcrash = None # type: Optional[ReprFileLocation] reprcrash = None # type: Optional[ReprFileLocation]
reprtraceback = None # type: ReprTraceback reprtraceback = None # type: ReprTraceback
def __attrs_post_init__(self): def __attrs_post_init__(self) -> None:
self.sections = [] # type: List[Tuple[str, str, str]] self.sections = [] # type: List[Tuple[str, str, str]]
def addsection(self, name: str, content: str, sep: str = "-") -> None: def addsection(self, name: str, content: str, sep: str = "-") -> None:
@ -955,7 +930,7 @@ class ExceptionChainRepr(ExceptionRepr):
] ]
) )
def __attrs_post_init__(self): def __attrs_post_init__(self) -> None:
super().__attrs_post_init__() super().__attrs_post_init__()
# reprcrash and reprtraceback of the outermost (the newest) exception # reprcrash and reprtraceback of the outermost (the newest) exception
# in the chain # in the chain
@ -1157,8 +1132,9 @@ class ReprFuncArgs(TerminalRepr):
tw.line("") tw.line("")
def getfslineno(obj: Any) -> Tuple[Union[str, py.path.local], int]: def getfslineno(obj: object) -> Tuple[Union[str, py.path.local], int]:
""" Return source location (path, lineno) for the given object. """Return source location (path, lineno) for the given object.
If the source cannot be determined return ("", -1). If the source cannot be determined return ("", -1).
The line number is 0-based. The line number is 0-based.
@ -1168,13 +1144,13 @@ def getfslineno(obj: Any) -> Tuple[Union[str, py.path.local], int]:
# in 6ec13a2b9. It ("place_as") appears to be something very custom. # in 6ec13a2b9. It ("place_as") appears to be something very custom.
obj = get_real_func(obj) obj = get_real_func(obj)
if hasattr(obj, "place_as"): if hasattr(obj, "place_as"):
obj = obj.place_as obj = obj.place_as # type: ignore[attr-defined]
try: try:
code = Code(obj) code = Code(obj)
except TypeError: except TypeError:
try: try:
fn = inspect.getsourcefile(obj) or inspect.getfile(obj) fn = inspect.getsourcefile(obj) or inspect.getfile(obj) # type: ignore[arg-type]
except TypeError: except TypeError:
return "", -1 return "", -1
@ -1186,8 +1162,8 @@ def getfslineno(obj: Any) -> Tuple[Union[str, py.path.local], int]:
except OSError: except OSError:
pass pass
return fspath, lineno return fspath, lineno
else:
return code.path, code.firstlineno return code.path, code.firstlineno
# relative paths that we use to filter traceback entries from appearing to the user; # relative paths that we use to filter traceback entries from appearing to the user;

View File

@ -98,12 +98,12 @@ class AlwaysDispatchingPrettyPrinter(pprint.PrettyPrinter):
level: int, level: int,
) -> None: ) -> None:
# Type ignored because _dispatch is private. # Type ignored because _dispatch is private.
p = self._dispatch.get(type(object).__repr__, None) # type: ignore[attr-defined] # noqa: F821 p = self._dispatch.get(type(object).__repr__, None) # type: ignore[attr-defined]
objid = id(object) objid = id(object)
if objid in context or p is None: if objid in context or p is None:
# Type ignored because _format is private. # Type ignored because _format is private.
super()._format( # type: ignore[misc] # noqa: F821 super()._format( # type: ignore[misc]
object, stream, indent, allowance, context, level, object, stream, indent, allowance, context, level,
) )
return return

View File

@ -80,7 +80,7 @@ class Cache:
rm_rf(d) rm_rf(d)
@staticmethod @staticmethod
def cache_dir_from_config(config: Config): def cache_dir_from_config(config: Config) -> Path:
return resolve_from_str(config.getini("cache_dir"), config.rootdir) return resolve_from_str(config.getini("cache_dir"), config.rootdir)
def warn(self, fmt: str, **args: object) -> None: def warn(self, fmt: str, **args: object) -> None:
@ -113,7 +113,7 @@ class Cache:
def _getvaluepath(self, key: str) -> Path: def _getvaluepath(self, key: str) -> Path:
return self._cachedir.joinpath(self._CACHE_PREFIX_VALUES, Path(key)) return self._cachedir.joinpath(self._CACHE_PREFIX_VALUES, Path(key))
def get(self, key, default): def get(self, key: str, default):
""" return cached value for the given key. If no value """ return cached value for the given key. If no value
was yet cached or the value cannot be read, the specified was yet cached or the value cannot be read, the specified
default is returned. default is returned.
@ -131,7 +131,7 @@ class Cache:
except (ValueError, OSError): except (ValueError, OSError):
return default return default
def set(self, key, value) -> None: def set(self, key: str, value: object) -> None:
""" save value for the given key. """ save value for the given key.
:param key: must be a ``/`` separated value. Usually the first :param key: must be a ``/`` separated value. Usually the first
@ -522,7 +522,7 @@ def cacheshow(config: Config, session: Session) -> int:
vdir = basedir / Cache._CACHE_PREFIX_VALUES vdir = basedir / Cache._CACHE_PREFIX_VALUES
tw.sep("-", "cache values for %r" % glob) tw.sep("-", "cache values for %r" % glob)
for valpath in sorted(x for x in vdir.rglob(glob) if x.is_file()): for valpath in sorted(x for x in vdir.rglob(glob) if x.is_file()):
key = valpath.relative_to(vdir) key = str(valpath.relative_to(vdir))
val = config.cache.get(key, dummy) val = config.cache.get(key, dummy)
if val is dummy: if val is dummy:
tw.line("%s contains unreadable content, will be ignored" % key) tw.line("%s contains unreadable content, will be ignored" % key)
@ -539,6 +539,6 @@ def cacheshow(config: Config, session: Session) -> int:
# if p.check(dir=1): # if p.check(dir=1):
# print("%s/" % p.relto(basedir)) # print("%s/" % p.relto(basedir))
if p.is_file(): if p.is_file():
key = p.relative_to(basedir) key = str(p.relative_to(basedir))
tw.line("{} is a file of length {:d}".format(key, p.stat().st_size)) tw.line("{} is a file of length {:d}".format(key, p.stat().st_size))
return 0 return 0

View File

@ -821,7 +821,7 @@ class CaptureFixture:
@pytest.fixture @pytest.fixture
def capsys(request: SubRequest): def capsys(request: SubRequest) -> Generator[CaptureFixture, None, None]:
"""Enable text capturing of writes to ``sys.stdout`` and ``sys.stderr``. """Enable text capturing of writes to ``sys.stdout`` and ``sys.stderr``.
The captured output is made available via ``capsys.readouterr()`` method The captured output is made available via ``capsys.readouterr()`` method
@ -838,7 +838,7 @@ def capsys(request: SubRequest):
@pytest.fixture @pytest.fixture
def capsysbinary(request: SubRequest): def capsysbinary(request: SubRequest) -> Generator[CaptureFixture, None, None]:
"""Enable bytes capturing of writes to ``sys.stdout`` and ``sys.stderr``. """Enable bytes capturing of writes to ``sys.stdout`` and ``sys.stderr``.
The captured output is made available via ``capsysbinary.readouterr()`` The captured output is made available via ``capsysbinary.readouterr()``
@ -855,7 +855,7 @@ def capsysbinary(request: SubRequest):
@pytest.fixture @pytest.fixture
def capfd(request: SubRequest): def capfd(request: SubRequest) -> Generator[CaptureFixture, None, None]:
"""Enable text capturing of writes to file descriptors ``1`` and ``2``. """Enable text capturing of writes to file descriptors ``1`` and ``2``.
The captured output is made available via ``capfd.readouterr()`` method The captured output is made available via ``capfd.readouterr()`` method
@ -872,7 +872,7 @@ def capfd(request: SubRequest):
@pytest.fixture @pytest.fixture
def capfdbinary(request: SubRequest): def capfdbinary(request: SubRequest) -> Generator[CaptureFixture, None, None]:
"""Enable bytes capturing of writes to file descriptors ``1`` and ``2``. """Enable bytes capturing of writes to file descriptors ``1`` and ``2``.
The captured output is made available via ``capfd.readouterr()`` method The captured output is made available via ``capfd.readouterr()`` method

View File

@ -146,7 +146,7 @@ class pytestPDB:
# Type ignored because mypy doesn't support "dynamic" # Type ignored because mypy doesn't support "dynamic"
# inheritance like this. # inheritance like this.
class PytestPdbWrapper(pdb_cls): # type: ignore[valid-type,misc] # noqa: F821 class PytestPdbWrapper(pdb_cls): # type: ignore[valid-type,misc]
_pytest_capman = capman _pytest_capman = capman
_continued = False _continued = False
@ -349,7 +349,7 @@ def _enter_pdb(
rep.toterminal(tw) rep.toterminal(tw)
tw.sep(">", "entering PDB") tw.sep(">", "entering PDB")
tb = _postmortem_traceback(excinfo) tb = _postmortem_traceback(excinfo)
rep._pdbshown = True # type: ignore[attr-defined] # noqa: F821 rep._pdbshown = True # type: ignore[attr-defined]
post_mortem(tb) post_mortem(tb)
return rep return rep

View File

@ -284,7 +284,7 @@ class DoctestItem(pytest.Item):
failures = [] # type: List[doctest.DocTestFailure] failures = [] # type: List[doctest.DocTestFailure]
# Type ignored because we change the type of `out` from what # Type ignored because we change the type of `out` from what
# doctest expects. # doctest expects.
self.runner.run(self.dtest, out=failures) # type: ignore[arg-type] # noqa: F821 self.runner.run(self.dtest, out=failures) # type: ignore[arg-type]
if failures: if failures:
raise MultipleDoctestFailures(failures) raise MultipleDoctestFailures(failures)
@ -302,7 +302,7 @@ class DoctestItem(pytest.Item):
sys.stderr.write(err) sys.stderr.write(err)
# TODO: Type ignored -- breaks Liskov Substitution. # TODO: Type ignored -- breaks Liskov Substitution.
def repr_failure( # type: ignore[override] # noqa: F821 def repr_failure( # type: ignore[override]
self, excinfo: ExceptionInfo[BaseException], self, excinfo: ExceptionInfo[BaseException],
) -> Union[str, TerminalRepr]: ) -> Union[str, TerminalRepr]:
import doctest import doctest
@ -329,7 +329,7 @@ class DoctestItem(pytest.Item):
lineno = test.lineno + example.lineno + 1 lineno = test.lineno + example.lineno + 1
message = type(failure).__name__ message = type(failure).__name__
# TODO: ReprFileLocation doesn't expect a None lineno. # TODO: ReprFileLocation doesn't expect a None lineno.
reprlocation = ReprFileLocation(filename, lineno, message) # type: ignore[arg-type] # noqa: F821 reprlocation = ReprFileLocation(filename, lineno, message) # type: ignore[arg-type]
checker = _get_checker() checker = _get_checker()
report_choice = _get_report_choice( report_choice = _get_report_choice(
self.config.getoption("doctestreport") self.config.getoption("doctestreport")
@ -567,9 +567,9 @@ def _setup_fixtures(doctest_item: DoctestItem) -> FixtureRequest:
def func() -> None: def func() -> None:
pass pass
doctest_item.funcargs = {} # type: ignore[attr-defined] # noqa: F821 doctest_item.funcargs = {} # type: ignore[attr-defined]
fm = doctest_item.session._fixturemanager fm = doctest_item.session._fixturemanager
doctest_item._fixtureinfo = fm.getfixtureinfo( # type: ignore[attr-defined] # noqa: F821 doctest_item._fixtureinfo = fm.getfixtureinfo( # type: ignore[attr-defined]
node=doctest_item, func=func, cls=None, funcargs=False node=doctest_item, func=func, cls=None, funcargs=False
) )
fixture_request = FixtureRequest(doctest_item) fixture_request = FixtureRequest(doctest_item)

View File

@ -248,7 +248,7 @@ def get_parametrized_fixture_keys(item: "nodes.Item", scopenum: int) -> Iterator
the specified scope. """ the specified scope. """
assert scopenum < scopenum_function # function assert scopenum < scopenum_function # function
try: try:
callspec = item.callspec # type: ignore[attr-defined] # noqa: F821 callspec = item.callspec # type: ignore[attr-defined]
except AttributeError: except AttributeError:
pass pass
else: else:
@ -266,7 +266,7 @@ def get_parametrized_fixture_keys(item: "nodes.Item", scopenum: int) -> Iterator
elif scopenum == 2: # module elif scopenum == 2: # module
key = (argname, param_index, item.fspath) key = (argname, param_index, item.fspath)
elif scopenum == 3: # class elif scopenum == 3: # class
item_cls = item.cls # type: ignore[attr-defined] # noqa: F821 item_cls = item.cls # type: ignore[attr-defined]
key = (argname, param_index, item.fspath, item_cls) key = (argname, param_index, item.fspath, item_cls)
yield key yield key
@ -477,7 +477,7 @@ class FixtureRequest:
fixturedefs = self._fixturemanager.getfixturedefs(argname, parentid) fixturedefs = self._fixturemanager.getfixturedefs(argname, parentid)
# TODO: Fix this type ignore. Either add assert or adjust types. # TODO: Fix this type ignore. Either add assert or adjust types.
# Can this be None here? # Can this be None here?
self._arg2fixturedefs[argname] = fixturedefs # type: ignore[assignment] # noqa: F821 self._arg2fixturedefs[argname] = fixturedefs # type: ignore[assignment]
# fixturedefs list is immutable so we maintain a decreasing index # fixturedefs list is immutable so we maintain a decreasing index
index = self._arg2index.get(argname, 0) - 1 index = self._arg2index.get(argname, 0) - 1
if fixturedefs is None or (-index > len(fixturedefs)): if fixturedefs is None or (-index > len(fixturedefs)):
@ -723,7 +723,7 @@ class FixtureRequest:
if scope == "package": if scope == "package":
# FIXME: _fixturedef is not defined on FixtureRequest (this class), # FIXME: _fixturedef is not defined on FixtureRequest (this class),
# but on FixtureRequest (a subclass). # but on FixtureRequest (a subclass).
node = get_scope_package(self._pyfuncitem, self._fixturedef) # type: ignore[attr-defined] # noqa: F821 node = get_scope_package(self._pyfuncitem, self._fixturedef) # type: ignore[attr-defined]
else: else:
node = get_scope_node(self._pyfuncitem, scope) node = get_scope_node(self._pyfuncitem, scope)
if node is None and scope == "class": if node is None and scope == "class":
@ -809,7 +809,9 @@ def scope2index(scope: str, descr: str, where: Optional[str] = None) -> int:
class FixtureLookupError(LookupError): class FixtureLookupError(LookupError):
""" could not return a requested Fixture (missing or invalid). """ """ could not return a requested Fixture (missing or invalid). """
def __init__(self, argname, request, msg: Optional[str] = None) -> None: def __init__(
self, argname: Optional[str], request: FixtureRequest, msg: Optional[str] = None
) -> None:
self.argname = argname self.argname = argname
self.request = request self.request = request
self.fixturestack = request._get_fixturestack() self.fixturestack = request._get_fixturestack()
@ -861,7 +863,14 @@ class FixtureLookupError(LookupError):
class FixtureLookupErrorRepr(TerminalRepr): class FixtureLookupErrorRepr(TerminalRepr):
def __init__(self, filename, firstlineno, tblines, errorstring, argname): def __init__(
self,
filename: Union[str, py.path.local],
firstlineno: int,
tblines: Sequence[str],
errorstring: str,
argname: Optional[str],
) -> None:
self.tblines = tblines self.tblines = tblines
self.errorstring = errorstring self.errorstring = errorstring
self.filename = filename self.filename = filename
@ -935,7 +944,7 @@ def _eval_scope_callable(
try: try:
# Type ignored because there is no typing mechanism to specify # Type ignored because there is no typing mechanism to specify
# keyword arguments, currently. # keyword arguments, currently.
result = scope_callable(fixture_name=fixture_name, config=config) # type: ignore[call-arg] # noqa: F821 result = scope_callable(fixture_name=fixture_name, config=config) # type: ignore[call-arg]
except Exception as e: except Exception as e:
raise TypeError( raise TypeError(
"Error evaluating {} while defining fixture '{}'.\n" "Error evaluating {} while defining fixture '{}'.\n"
@ -1072,7 +1081,7 @@ def resolve_fixture_function(
if fixturedef.unittest: if fixturedef.unittest:
if request.instance is not None: if request.instance is not None:
# bind the unbound method to the TestCase instance # bind the unbound method to the TestCase instance
fixturefunc = fixturedef.func.__get__(request.instance) # type: ignore[union-attr] # noqa: F821 fixturefunc = fixturedef.func.__get__(request.instance) # type: ignore[union-attr]
else: else:
# the fixture function needs to be bound to the actual # the fixture function needs to be bound to the actual
# request.instance so that code working with "fixturedef" behaves # request.instance so that code working with "fixturedef" behaves
@ -1081,12 +1090,12 @@ def resolve_fixture_function(
# handle the case where fixture is defined not in a test class, but some other class # handle the case where fixture is defined not in a test class, but some other class
# (for example a plugin class with a fixture), see #2270 # (for example a plugin class with a fixture), see #2270
if hasattr(fixturefunc, "__self__") and not isinstance( if hasattr(fixturefunc, "__self__") and not isinstance(
request.instance, fixturefunc.__self__.__class__ # type: ignore[union-attr] # noqa: F821 request.instance, fixturefunc.__self__.__class__ # type: ignore[union-attr]
): ):
return fixturefunc return fixturefunc
fixturefunc = getimfunc(fixturedef.func) fixturefunc = getimfunc(fixturedef.func)
if fixturefunc != fixturedef.func: if fixturefunc != fixturedef.func:
fixturefunc = fixturefunc.__get__(request.instance) # type: ignore[union-attr] # noqa: F821 fixturefunc = fixturefunc.__get__(request.instance) # type: ignore[union-attr]
return fixturefunc return fixturefunc
@ -1158,7 +1167,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 # 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) # further than this point and lose useful wrappings like @mock.patch (#3774)
result.__pytest_wrapped__ = _PytestWrapper(function) # type: ignore[attr-defined] # noqa: F821 result.__pytest_wrapped__ = _PytestWrapper(function) # type: ignore[attr-defined]
return result return result
@ -1200,7 +1209,7 @@ class FixtureFunctionMarker:
) )
# Type ignored because https://github.com/python/mypy/issues/2087. # Type ignored because https://github.com/python/mypy/issues/2087.
function._pytestfixturefunction = self # type: ignore[attr-defined] # noqa: F821 function._pytestfixturefunction = self # type: ignore[attr-defined]
return function return function
@ -1493,7 +1502,7 @@ class FixtureManager:
def pytest_plugin_registered(self, plugin: _PluggyPlugin) -> None: def pytest_plugin_registered(self, plugin: _PluggyPlugin) -> None:
nodeid = None nodeid = None
try: try:
p = py.path.local(plugin.__file__) # type: ignore[attr-defined] # noqa: F821 p = py.path.local(plugin.__file__) # type: ignore[attr-defined]
except AttributeError: except AttributeError:
pass pass
else: else:

View File

@ -32,7 +32,6 @@ if TYPE_CHECKING:
from _pytest.main import Session from _pytest.main import Session
from _pytest.nodes import Collector from _pytest.nodes import Collector
from _pytest.nodes import Item from _pytest.nodes import Item
from _pytest.nodes import Node
from _pytest.outcomes import Exit from _pytest.outcomes import Exit
from _pytest.python import Function from _pytest.python import Function
from _pytest.python import Metafunc from _pytest.python import Metafunc
@ -827,7 +826,7 @@ def pytest_keyboard_interrupt(
def pytest_exception_interact( def pytest_exception_interact(
node: "Node", node: Union["Item", "Collector"],
call: "CallInfo[object]", call: "CallInfo[object]",
report: Union["CollectReport", "TestReport"], report: Union["CollectReport", "TestReport"],
) -> None: ) -> None:

View File

@ -14,6 +14,7 @@ import platform
import re import re
import sys import sys
from datetime import datetime from datetime import datetime
from typing import Callable
from typing import Dict from typing import Dict
from typing import List from typing import List
from typing import Match from typing import Match
@ -70,7 +71,7 @@ del _legal_xml_re
_py_ext_re = re.compile(r"\.py$") _py_ext_re = re.compile(r"\.py$")
def bin_xml_escape(arg: str) -> py.xml.raw: def bin_xml_escape(arg: object) -> py.xml.raw:
def repl(matchobj: Match[str]) -> str: def repl(matchobj: Match[str]) -> str:
i = ord(matchobj.group()) i = ord(matchobj.group())
if i <= 0xFF: if i <= 0xFF:
@ -78,7 +79,7 @@ def bin_xml_escape(arg: str) -> py.xml.raw:
else: else:
return "#x%04X" % i return "#x%04X" % i
return py.xml.raw(illegal_xml_re.sub(repl, py.xml.escape(arg))) return py.xml.raw(illegal_xml_re.sub(repl, py.xml.escape(str(arg))))
def merge_family(left, right) -> None: def merge_family(left, right) -> None:
@ -118,10 +119,10 @@ class _NodeReporter:
self.xml.add_stats(type(node).__name__) self.xml.add_stats(type(node).__name__)
self.nodes.append(node) self.nodes.append(node)
def add_property(self, name: str, value: str) -> None: def add_property(self, name: str, value: object) -> None:
self.properties.append((str(name), bin_xml_escape(value))) self.properties.append((str(name), bin_xml_escape(value)))
def add_attribute(self, name: str, value: str) -> None: def add_attribute(self, name: str, value: object) -> None:
self.attrs[str(name)] = bin_xml_escape(value) self.attrs[str(name)] = bin_xml_escape(value)
def make_properties_node(self) -> Union[py.xml.Tag, str]: def make_properties_node(self) -> Union[py.xml.Tag, str]:
@ -280,7 +281,7 @@ class _NodeReporter:
self.__dict__.clear() self.__dict__.clear()
# Type ignored becuase mypy doesn't like overriding a method. # Type ignored becuase mypy doesn't like overriding a method.
# Also the return value doesn't match... # Also the return value doesn't match...
self.to_xml = lambda: py.xml.raw(data) # type: ignore # noqa: F821 self.to_xml = lambda: py.xml.raw(data) # type: ignore
def _warn_incompatibility_with_xunit2( def _warn_incompatibility_with_xunit2(
@ -301,12 +302,14 @@ def _warn_incompatibility_with_xunit2(
@pytest.fixture @pytest.fixture
def record_property(request: FixtureRequest): def record_property(request: FixtureRequest) -> Callable[[str, object], None]:
"""Add an extra properties the calling test. """Add extra properties to the calling test.
User properties become part of the test report and are available to the User properties become part of the test report and are available to the
configured reporters, like JUnit XML. configured reporters, like JUnit XML.
The fixture is callable with ``(name, value)``, with value being automatically
xml-encoded. The fixture is callable with ``name, value``. The value is automatically
XML-encoded.
Example:: Example::
@ -322,10 +325,11 @@ def record_property(request: FixtureRequest):
@pytest.fixture @pytest.fixture
def record_xml_attribute(request: FixtureRequest): def record_xml_attribute(request: FixtureRequest) -> Callable[[str, object], None]:
"""Add extra xml attributes to the tag for the calling test. """Add extra xml attributes to the tag for the calling test.
The fixture is callable with ``(name, value)``, with value being
automatically xml-encoded The fixture is callable with ``name, value``. The value is
automatically XML-encoded.
""" """
from _pytest.warning_types import PytestExperimentalApiWarning from _pytest.warning_types import PytestExperimentalApiWarning
@ -336,7 +340,7 @@ def record_xml_attribute(request: FixtureRequest):
_warn_incompatibility_with_xunit2(request, "record_xml_attribute") _warn_incompatibility_with_xunit2(request, "record_xml_attribute")
# Declare noop # Declare noop
def add_attr_noop(name: str, value: str) -> None: def add_attr_noop(name: str, value: object) -> None:
pass pass
attr_func = add_attr_noop attr_func = add_attr_noop
@ -359,7 +363,7 @@ def _check_record_param_type(param: str, v: str) -> None:
@pytest.fixture(scope="session") @pytest.fixture(scope="session")
def record_testsuite_property(request: FixtureRequest): def record_testsuite_property(request: FixtureRequest) -> Callable[[str, object], None]:
""" """
Records a new ``<property>`` tag as child of the root ``<testsuite>``. This is suitable to Records a new ``<property>`` tag as child of the root ``<testsuite>``. This is suitable to
writing global information regarding the entire test suite, and is compatible with ``xunit2`` JUnit family. writing global information regarding the entire test suite, and is compatible with ``xunit2`` JUnit family.
@ -377,7 +381,7 @@ def record_testsuite_property(request: FixtureRequest):
__tracebackhide__ = True __tracebackhide__ = True
def record_func(name: str, value: str): def record_func(name: str, value: object) -> None:
"""noop function in case --junitxml was not passed in the command-line""" """noop function in case --junitxml was not passed in the command-line"""
__tracebackhide__ = True __tracebackhide__ = True
_check_record_param_type("name", name) _check_record_param_type("name", name)
@ -693,7 +697,7 @@ class LogXML:
def pytest_terminal_summary(self, terminalreporter: TerminalReporter) -> None: def pytest_terminal_summary(self, terminalreporter: TerminalReporter) -> None:
terminalreporter.write_sep("-", "generated xml file: {}".format(self.logfile)) terminalreporter.write_sep("-", "generated xml file: {}".format(self.logfile))
def add_global_property(self, name: str, value: str) -> None: def add_global_property(self, name: str, value: object) -> None:
__tracebackhide__ = True __tracebackhide__ = True
_check_record_param_type("name", name) _check_record_param_type("name", name)
self.global_properties.append((name, bin_xml_escape(value))) self.global_properties.append((name, bin_xml_escape(value)))

View File

@ -165,7 +165,7 @@ class PercentStyleMultiline(logging.PercentStyle):
if "\n" in record.message: if "\n" in record.message:
if hasattr(record, "auto_indent"): if hasattr(record, "auto_indent"):
# passed in from the "extra={}" kwarg on the call to logging.log() # passed in from the "extra={}" kwarg on the call to logging.log()
auto_indent = self._get_auto_indent(record.auto_indent) # type: ignore[attr-defined] # noqa: F821 auto_indent = self._get_auto_indent(record.auto_indent) # type: ignore[attr-defined]
else: else:
auto_indent = self._auto_indent auto_indent = self._auto_indent
@ -755,7 +755,7 @@ class _LiveLoggingStreamHandler(logging.StreamHandler):
:param _pytest.terminal.TerminalReporter terminal_reporter: :param _pytest.terminal.TerminalReporter terminal_reporter:
:param _pytest.capture.CaptureManager capture_manager: :param _pytest.capture.CaptureManager capture_manager:
""" """
logging.StreamHandler.__init__(self, stream=terminal_reporter) # type: ignore[arg-type] # noqa: F821 logging.StreamHandler.__init__(self, stream=terminal_reporter) # type: ignore[arg-type]
self.capture_manager = capture_manager self.capture_manager = capture_manager
self.reset() self.reset()
self.set_when(None) self.set_when(None)

View File

@ -265,7 +265,7 @@ def wrap_session(
session.exitstatus = exc.returncode session.exitstatus = exc.returncode
sys.stderr.write("{}: {}\n".format(type(exc).__name__, exc)) sys.stderr.write("{}: {}\n".format(type(exc).__name__, exc))
else: else:
if excinfo.errisinstance(SystemExit): if isinstance(excinfo.value, SystemExit):
sys.stderr.write("mainloop: caught unexpected SystemExit!\n") sys.stderr.write("mainloop: caught unexpected SystemExit!\n")
finally: finally:

View File

@ -125,7 +125,7 @@ class ParameterSet(
# #
# @pytest.mark.parametrize(('x', 'y'), [1, 2]) # @pytest.mark.parametrize(('x', 'y'), [1, 2])
# def test_foo(x, y): pass # def test_foo(x, y): pass
return cls(parameterset, marks=[], id=None) # type: ignore[arg-type] # noqa: F821 return cls(parameterset, marks=[], id=None) # type: ignore[arg-type]
@staticmethod @staticmethod
def _parse_parametrize_args( def _parse_parametrize_args(
@ -321,7 +321,7 @@ class MarkDecorator:
# return type. Not much we can do about that. Thankfully mypy picks # return type. Not much we can do about that. Thankfully mypy picks
# the first match so it works out even if we break the rules. # the first match so it works out even if we break the rules.
@overload @overload
def __call__(self, arg: _Markable) -> _Markable: # type: ignore[misc] # noqa: F821 def __call__(self, arg: _Markable) -> _Markable: # type: ignore[misc]
raise NotImplementedError() raise NotImplementedError()
@overload # noqa: F811 @overload # noqa: F811

View File

@ -457,7 +457,7 @@ class Collector(Node):
raise NotImplementedError("abstract") raise NotImplementedError("abstract")
# TODO: This omits the style= parameter which breaks Liskov Substitution. # TODO: This omits the style= parameter which breaks Liskov Substitution.
def repr_failure( # type: ignore[override] # noqa: F821 def repr_failure( # type: ignore[override]
self, excinfo: ExceptionInfo[BaseException] self, excinfo: ExceptionInfo[BaseException]
) -> Union[str, TerminalRepr]: ) -> Union[str, TerminalRepr]:
""" """
@ -600,7 +600,7 @@ class FSCollector(Collector):
else: else:
duplicate_paths.add(path) duplicate_paths.add(path)
return ihook.pytest_collect_file(path=path, parent=self) # type: ignore[no-any-return] # noqa: F723 return ihook.pytest_collect_file(path=path, parent=self) # type: ignore[no-any-return]
class File(FSCollector): class File(FSCollector):

View File

@ -363,15 +363,15 @@ def make_numbered_dir_with_cleanup(
raise e raise e
def resolve_from_str(input: str, root): def resolve_from_str(input: str, root: py.path.local) -> Path:
assert not isinstance(input, Path), "would break on py2" assert not isinstance(input, Path), "would break on py2"
root = Path(root) rootpath = Path(root)
input = expanduser(input) input = expanduser(input)
input = expandvars(input) input = expandvars(input)
if isabs(input): if isabs(input):
return Path(input) return Path(input)
else: else:
return root.joinpath(input) return rootpath.joinpath(input)
def fnmatch_ex(pattern: str, path) -> bool: def fnmatch_ex(pattern: str, path) -> bool:

View File

@ -32,6 +32,7 @@ from _pytest.compat import TYPE_CHECKING
from _pytest.config import _PluggyPlugin from _pytest.config import _PluggyPlugin
from _pytest.config import Config from _pytest.config import Config
from _pytest.config import ExitCode from _pytest.config import ExitCode
from _pytest.config import PytestPluginManager
from _pytest.config.argparsing import Parser from _pytest.config.argparsing import Parser
from _pytest.fixtures import FixtureRequest from _pytest.fixtures import FixtureRequest
from _pytest.main import Session from _pytest.main import Session
@ -210,7 +211,7 @@ class HookRecorder:
""" """
def __init__(self, pluginmanager) -> None: def __init__(self, pluginmanager: PytestPluginManager) -> None:
self._pluginmanager = pluginmanager self._pluginmanager = pluginmanager
self.calls = [] # type: List[ParsedCall] self.calls = [] # type: List[ParsedCall]
@ -376,7 +377,7 @@ def LineMatcher_fixture(request: FixtureRequest) -> "Type[LineMatcher]":
@pytest.fixture @pytest.fixture
def testdir(request: FixtureRequest, tmpdir_factory) -> "Testdir": def testdir(request: FixtureRequest, tmpdir_factory: TempdirFactory) -> "Testdir":
""" """
A :class: `TestDir` instance, that can be used to run and test pytest itself. A :class: `TestDir` instance, that can be used to run and test pytest itself.
@ -388,7 +389,7 @@ def testdir(request: FixtureRequest, tmpdir_factory) -> "Testdir":
@pytest.fixture @pytest.fixture
def _sys_snapshot(): def _sys_snapshot() -> Generator[None, None, None]:
snappaths = SysPathsSnapshot() snappaths = SysPathsSnapshot()
snapmods = SysModulesSnapshot() snapmods = SysModulesSnapshot()
yield yield
@ -526,7 +527,7 @@ class CwdSnapshot:
class SysModulesSnapshot: class SysModulesSnapshot:
def __init__(self, preserve: Optional[Callable[[str], bool]] = None): def __init__(self, preserve: Optional[Callable[[str], bool]] = None) -> None:
self.__preserve = preserve self.__preserve = preserve
self.__saved = dict(sys.modules) self.__saved = dict(sys.modules)
@ -605,13 +606,13 @@ class Testdir:
# Do not use colors for inner runs by default. # Do not use colors for inner runs by default.
mp.setenv("PY_COLORS", "0") mp.setenv("PY_COLORS", "0")
def __repr__(self): def __repr__(self) -> str:
return "<Testdir {!r}>".format(self.tmpdir) return "<Testdir {!r}>".format(self.tmpdir)
def __str__(self): def __str__(self) -> str:
return str(self.tmpdir) return str(self.tmpdir)
def finalize(self): def finalize(self) -> None:
"""Clean up global state artifacts. """Clean up global state artifacts.
Some methods modify the global interpreter state and this tries to Some methods modify the global interpreter state and this tries to
@ -624,7 +625,7 @@ class Testdir:
self._cwd_snapshot.restore() self._cwd_snapshot.restore()
self.monkeypatch.undo() self.monkeypatch.undo()
def __take_sys_modules_snapshot(self): def __take_sys_modules_snapshot(self) -> SysModulesSnapshot:
# some zope modules used by twisted-related tests keep internal state # some zope modules used by twisted-related tests keep internal state
# and can't be deleted; we had some trouble in the past with # and can't be deleted; we had some trouble in the past with
# `zope.interface` for example # `zope.interface` for example
@ -633,13 +634,13 @@ class Testdir:
return SysModulesSnapshot(preserve=preserve_module) return SysModulesSnapshot(preserve=preserve_module)
def make_hook_recorder(self, pluginmanager): def make_hook_recorder(self, pluginmanager: PytestPluginManager) -> HookRecorder:
"""Create a new :py:class:`HookRecorder` for a PluginManager.""" """Create a new :py:class:`HookRecorder` for a PluginManager."""
pluginmanager.reprec = reprec = HookRecorder(pluginmanager) pluginmanager.reprec = reprec = HookRecorder(pluginmanager)
self.request.addfinalizer(reprec.finish_recording) self.request.addfinalizer(reprec.finish_recording)
return reprec return reprec
def chdir(self): def chdir(self) -> None:
"""Cd into the temporary directory. """Cd into the temporary directory.
This is done automatically upon instantiation. This is done automatically upon instantiation.
@ -647,7 +648,7 @@ class Testdir:
""" """
self.tmpdir.chdir() self.tmpdir.chdir()
def _makefile(self, ext, lines, files, encoding="utf-8"): def _makefile(self, ext: str, lines, files, encoding: str = "utf-8"):
items = list(files.items()) items = list(files.items())
def to_text(s): def to_text(s):
@ -669,7 +670,7 @@ class Testdir:
ret = p ret = p
return ret return ret
def makefile(self, ext, *args, **kwargs): def makefile(self, ext: str, *args: str, **kwargs):
r"""Create new file(s) in the testdir. r"""Create new file(s) in the testdir.
:param str ext: The extension the file(s) should use, including the dot, e.g. `.py`. :param str ext: The extension the file(s) should use, including the dot, e.g. `.py`.
@ -698,7 +699,7 @@ class Testdir:
"""Write a tox.ini file with 'source' as contents.""" """Write a tox.ini file with 'source' as contents."""
return self.makefile(".ini", tox=source) return self.makefile(".ini", tox=source)
def getinicfg(self, source): def getinicfg(self, source) -> IniConfig:
"""Return the pytest section from the tox.ini config file.""" """Return the pytest section from the tox.ini config file."""
p = self.makeini(source) p = self.makeini(source)
return IniConfig(p)["pytest"] return IniConfig(p)["pytest"]
@ -748,7 +749,7 @@ class Testdir:
""" """
return self._makefile(".txt", args, kwargs) return self._makefile(".txt", args, kwargs)
def syspathinsert(self, path=None): def syspathinsert(self, path=None) -> None:
"""Prepend a directory to sys.path, defaults to :py:attr:`tmpdir`. """Prepend a directory to sys.path, defaults to :py:attr:`tmpdir`.
This is undone automatically when this object dies at the end of each This is undone automatically when this object dies at the end of each
@ -759,11 +760,11 @@ class Testdir:
self.monkeypatch.syspath_prepend(str(path)) self.monkeypatch.syspath_prepend(str(path))
def mkdir(self, name): def mkdir(self, name) -> py.path.local:
"""Create a new (sub)directory.""" """Create a new (sub)directory."""
return self.tmpdir.mkdir(name) return self.tmpdir.mkdir(name)
def mkpydir(self, name): def mkpydir(self, name) -> py.path.local:
"""Create a new python package. """Create a new python package.
This creates a (sub)directory with an empty ``__init__.py`` file so it This creates a (sub)directory with an empty ``__init__.py`` file so it
@ -774,7 +775,7 @@ class Testdir:
p.ensure("__init__.py") p.ensure("__init__.py")
return p return p
def copy_example(self, name=None): def copy_example(self, name=None) -> py.path.local:
"""Copy file from project's directory into the testdir. """Copy file from project's directory into the testdir.
:param str name: The name of the file to copy. :param str name: The name of the file to copy.
@ -826,7 +827,7 @@ class Testdir:
Session = Session Session = Session
def getnode(self, config, arg): def getnode(self, config: Config, arg):
"""Return the collection node of a file. """Return the collection node of a file.
:param config: :py:class:`_pytest.config.Config` instance, see :param config: :py:class:`_pytest.config.Config` instance, see
@ -861,7 +862,7 @@ class Testdir:
config.hook.pytest_sessionfinish(session=session, exitstatus=ExitCode.OK) config.hook.pytest_sessionfinish(session=session, exitstatus=ExitCode.OK)
return res return res
def genitems(self, colitems: List[Union[Item, Collector]]) -> List[Item]: def genitems(self, colitems: Sequence[Union[Item, Collector]]) -> List[Item]:
"""Generate all test items from a collection node. """Generate all test items from a collection node.
This recurses into the collection node and returns a list of all the This recurses into the collection node and returns a list of all the
@ -974,7 +975,7 @@ class Testdir:
class reprec: # type: ignore class reprec: # type: ignore
pass pass
reprec.ret = ret reprec.ret = ret # type: ignore[attr-defined]
# typically we reraise keyboard interrupts from the child run # typically we reraise keyboard interrupts from the child run
# because it's our user requesting interruption of the testing # because it's our user requesting interruption of the testing
@ -1083,7 +1084,7 @@ class Testdir:
config._do_configure() config._do_configure()
return config return config
def getitem(self, source, funcname="test_func"): def getitem(self, source, funcname: str = "test_func") -> Item:
"""Return the test item for a test function. """Return the test item for a test function.
This writes the source to a python file and runs pytest's collection on This writes the source to a python file and runs pytest's collection on
@ -1104,7 +1105,7 @@ class Testdir:
funcname, source, items funcname, source, items
) )
def getitems(self, source): def getitems(self, source) -> List[Item]:
"""Return all test items collected from the module. """Return all test items collected from the module.
This writes the source to a python file and runs pytest's collection on This writes the source to a python file and runs pytest's collection on
@ -1114,7 +1115,7 @@ class Testdir:
modcol = self.getmodulecol(source) modcol = self.getmodulecol(source)
return self.genitems([modcol]) return self.genitems([modcol])
def getmodulecol(self, source, configargs=(), withinit=False): def getmodulecol(self, source, configargs=(), withinit: bool = False):
"""Return the module collection node for ``source``. """Return the module collection node for ``source``.
This writes ``source`` to a file using :py:meth:`makepyfile` and then This writes ``source`` to a file using :py:meth:`makepyfile` and then
@ -1199,7 +1200,9 @@ class Testdir:
return popen return popen
def run(self, *cmdargs, timeout=None, stdin=CLOSE_STDIN) -> RunResult: def run(
self, *cmdargs, timeout: Optional[float] = None, stdin=CLOSE_STDIN
) -> RunResult:
"""Run a command with arguments. """Run a command with arguments.
Run a process using subprocess.Popen saving the stdout and stderr. Run a process using subprocess.Popen saving the stdout and stderr.
@ -1238,7 +1241,7 @@ class Testdir:
if isinstance(stdin, bytes): if isinstance(stdin, bytes):
popen.stdin.close() popen.stdin.close()
def handle_timeout(): def handle_timeout() -> None:
__tracebackhide__ = True __tracebackhide__ = True
timeout_message = ( timeout_message = (
@ -1283,7 +1286,7 @@ class Testdir:
except UnicodeEncodeError: except UnicodeEncodeError:
print("couldn't print to {} because of encoding".format(fp)) print("couldn't print to {} because of encoding".format(fp))
def _getpytestargs(self): def _getpytestargs(self) -> Tuple[str, ...]:
return sys.executable, "-mpytest" return sys.executable, "-mpytest"
def runpython(self, script) -> RunResult: def runpython(self, script) -> RunResult:
@ -1298,7 +1301,7 @@ class Testdir:
"""Run python -c "command", return a :py:class:`RunResult`.""" """Run python -c "command", return a :py:class:`RunResult`."""
return self.run(sys.executable, "-c", command) return self.run(sys.executable, "-c", command)
def runpytest_subprocess(self, *args, timeout=None) -> RunResult: def runpytest_subprocess(self, *args, timeout: Optional[float] = None) -> RunResult:
"""Run pytest as a subprocess with given arguments. """Run pytest as a subprocess with given arguments.
Any plugins added to the :py:attr:`plugins` list will be added using the Any plugins added to the :py:attr:`plugins` list will be added using the

View File

@ -13,7 +13,9 @@ from collections.abc import Sequence
from functools import partial from functools import partial
from typing import Callable from typing import Callable
from typing import Dict from typing import Dict
from typing import Generator
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 Optional from typing import Optional
@ -196,8 +198,8 @@ def pytest_collect_file(path: py.path.local, parent) -> Optional["Module"]:
return None return None
def path_matches_patterns(path, patterns): def path_matches_patterns(path: py.path.local, patterns: Iterable[str]) -> bool:
"""Returns True if the given py.path.local matches one of the patterns in the list of globs given""" """Returns True if path matches any of the patterns in the list of globs given."""
return any(path.fnmatch(pattern) for pattern in patterns) return any(path.fnmatch(pattern) for pattern in patterns)
@ -297,10 +299,10 @@ class PyobjMixin:
"""Gets the underlying Python object. May be overwritten by subclasses.""" """Gets the underlying Python object. May be overwritten by subclasses."""
# TODO: Improve the type of `parent` such that assert/ignore aren't needed. # TODO: Improve the type of `parent` such that assert/ignore aren't needed.
assert self.parent is not None assert self.parent is not None
obj = self.parent.obj # type: ignore[attr-defined] # noqa: F821 obj = self.parent.obj # type: ignore[attr-defined]
return getattr(obj, self.name) return getattr(obj, self.name)
def getmodpath(self, stopatmodule=True, includemodule=False): def getmodpath(self, stopatmodule: bool = True, includemodule: bool = False) -> str:
""" return python path relative to the containing module. """ """ return python path relative to the containing module. """
chain = self.listchain() chain = self.listchain()
chain.reverse() chain.reverse()
@ -338,10 +340,10 @@ class PyobjMixin:
class PyCollector(PyobjMixin, nodes.Collector): class PyCollector(PyobjMixin, nodes.Collector):
def funcnamefilter(self, name): def funcnamefilter(self, name: str) -> bool:
return self._matches_prefix_or_glob_option("python_functions", name) return self._matches_prefix_or_glob_option("python_functions", name)
def isnosetest(self, obj): def isnosetest(self, obj: object) -> bool:
""" Look for the __test__ attribute, which is applied by the """ Look for the __test__ attribute, which is applied by the
@nose.tools.istest decorator @nose.tools.istest decorator
""" """
@ -350,10 +352,10 @@ class PyCollector(PyobjMixin, nodes.Collector):
# function) as test classes. # function) as test classes.
return safe_getattr(obj, "__test__", False) is True return safe_getattr(obj, "__test__", False) is True
def classnamefilter(self, name): def classnamefilter(self, name: str) -> bool:
return self._matches_prefix_or_glob_option("python_classes", name) return self._matches_prefix_or_glob_option("python_classes", name)
def istestfunction(self, obj, name): def istestfunction(self, obj: object, name: str) -> bool:
if self.funcnamefilter(name) or self.isnosetest(obj): if self.funcnamefilter(name) or self.isnosetest(obj):
if isinstance(obj, staticmethod): if isinstance(obj, staticmethod):
# static methods need to be unwrapped # static methods need to be unwrapped
@ -365,10 +367,10 @@ class PyCollector(PyobjMixin, nodes.Collector):
else: else:
return False return False
def istestclass(self, obj, name): def istestclass(self, obj: object, name: str) -> bool:
return self.classnamefilter(name) or self.isnosetest(obj) return self.classnamefilter(name) or self.isnosetest(obj)
def _matches_prefix_or_glob_option(self, option_name, name): def _matches_prefix_or_glob_option(self, option_name: str, name: str) -> bool:
""" """
checks if the given name matches the prefix or glob-pattern defined checks if the given name matches the prefix or glob-pattern defined
in ini configuration. in ini configuration.
@ -428,7 +430,7 @@ class PyCollector(PyobjMixin, nodes.Collector):
) # type: Union[None, nodes.Item, nodes.Collector, List[Union[nodes.Item, nodes.Collector]]] ) # type: Union[None, nodes.Item, nodes.Collector, List[Union[nodes.Item, nodes.Collector]]]
return item return item
def _genfunctions(self, name, funcobj): def _genfunctions(self, name: str, funcobj) -> Iterator["Function"]:
modulecol = self.getparent(Module) modulecol = self.getparent(Module)
assert modulecol is not None assert modulecol is not None
module = modulecol.obj module = modulecol.obj
@ -486,7 +488,7 @@ class Module(nodes.File, PyCollector):
self.session._fixturemanager.parsefactories(self) self.session._fixturemanager.parsefactories(self)
return super().collect() return super().collect()
def _inject_setup_module_fixture(self): def _inject_setup_module_fixture(self) -> None:
"""Injects a hidden autouse, module scoped fixture into the collected module object """Injects a hidden autouse, module scoped fixture into the collected module object
that invokes setUpModule/tearDownModule if either or both are available. that invokes setUpModule/tearDownModule if either or both are available.
@ -504,7 +506,7 @@ class Module(nodes.File, PyCollector):
return return
@fixtures.fixture(autouse=True, scope="module") @fixtures.fixture(autouse=True, scope="module")
def xunit_setup_module_fixture(request): def xunit_setup_module_fixture(request) -> Generator[None, None, None]:
if setup_module is not None: if setup_module is not None:
_call_with_optional_argument(setup_module, request.module) _call_with_optional_argument(setup_module, request.module)
yield yield
@ -513,7 +515,7 @@ class Module(nodes.File, PyCollector):
self.obj.__pytest_setup_module = xunit_setup_module_fixture self.obj.__pytest_setup_module = xunit_setup_module_fixture
def _inject_setup_function_fixture(self): def _inject_setup_function_fixture(self) -> None:
"""Injects a hidden autouse, function scoped fixture into the collected module object """Injects a hidden autouse, function scoped fixture into the collected module object
that invokes setup_function/teardown_function if either or both are available. that invokes setup_function/teardown_function if either or both are available.
@ -528,7 +530,7 @@ class Module(nodes.File, PyCollector):
return return
@fixtures.fixture(autouse=True, scope="function") @fixtures.fixture(autouse=True, scope="function")
def xunit_setup_function_fixture(request): def xunit_setup_function_fixture(request) -> Generator[None, None, None]:
if request.instance is not None: if request.instance is not None:
# in this case we are bound to an instance, so we need to let # in this case we are bound to an instance, so we need to let
# setup_method handle this # setup_method handle this
@ -608,7 +610,7 @@ class Package(Module):
) )
self.name = os.path.basename(str(fspath.dirname)) self.name = os.path.basename(str(fspath.dirname))
def setup(self): def setup(self) -> None:
# not using fixtures to call setup_module here because autouse fixtures # not using fixtures to call setup_module here because autouse fixtures
# from packages are not called automatically (#4085) # from packages are not called automatically (#4085)
setup_module = _get_first_non_fixture_func( setup_module = _get_first_non_fixture_func(
@ -661,7 +663,7 @@ class Package(Module):
pkg_prefixes.add(path) pkg_prefixes.add(path)
def _call_with_optional_argument(func, arg): def _call_with_optional_argument(func, arg) -> None:
"""Call the given function with the given argument if func accepts one argument, otherwise """Call the given function with the given argument if func accepts one argument, otherwise
calls func without arguments""" calls func without arguments"""
arg_count = func.__code__.co_argcount arg_count = func.__code__.co_argcount
@ -673,7 +675,7 @@ def _call_with_optional_argument(func, arg):
func() func()
def _get_first_non_fixture_func(obj, names): def _get_first_non_fixture_func(obj: object, names: Iterable[str]):
"""Return the attribute from the given object to be used as a setup/teardown """Return the attribute from the given object to be used as a setup/teardown
xunit-style function, but only if not marked as a fixture to xunit-style function, but only if not marked as a fixture to
avoid calling it twice. avoid calling it twice.
@ -723,7 +725,7 @@ class Class(PyCollector):
return [Instance.from_parent(self, name="()")] return [Instance.from_parent(self, name="()")]
def _inject_setup_class_fixture(self): def _inject_setup_class_fixture(self) -> None:
"""Injects a hidden autouse, class scoped fixture into the collected class object """Injects a hidden autouse, class scoped fixture into the collected class object
that invokes setup_class/teardown_class if either or both are available. that invokes setup_class/teardown_class if either or both are available.
@ -736,7 +738,7 @@ class Class(PyCollector):
return return
@fixtures.fixture(autouse=True, scope="class") @fixtures.fixture(autouse=True, scope="class")
def xunit_setup_class_fixture(cls): def xunit_setup_class_fixture(cls) -> Generator[None, None, None]:
if setup_class is not None: if setup_class is not None:
func = getimfunc(setup_class) func = getimfunc(setup_class)
_call_with_optional_argument(func, self.obj) _call_with_optional_argument(func, self.obj)
@ -747,7 +749,7 @@ class Class(PyCollector):
self.obj.__pytest_setup_class = xunit_setup_class_fixture self.obj.__pytest_setup_class = xunit_setup_class_fixture
def _inject_setup_method_fixture(self): def _inject_setup_method_fixture(self) -> None:
"""Injects a hidden autouse, function scoped fixture into the collected class object """Injects a hidden autouse, function scoped fixture into the collected class object
that invokes setup_method/teardown_method if either or both are available. that invokes setup_method/teardown_method if either or both are available.
@ -760,7 +762,7 @@ class Class(PyCollector):
return return
@fixtures.fixture(autouse=True, scope="function") @fixtures.fixture(autouse=True, scope="function")
def xunit_setup_method_fixture(self, request): def xunit_setup_method_fixture(self, request) -> Generator[None, None, None]:
method = request.function method = request.function
if setup_method is not None: if setup_method is not None:
func = getattr(self, "setup_method") func = getattr(self, "setup_method")
@ -782,7 +784,7 @@ class Instance(PyCollector):
def _getobj(self): def _getobj(self):
# TODO: Improve the type of `parent` such that assert/ignore aren't needed. # TODO: Improve the type of `parent` such that assert/ignore aren't needed.
assert self.parent is not None assert self.parent is not None
obj = self.parent.obj # type: ignore[attr-defined] # noqa: F821 obj = self.parent.obj # type: ignore[attr-defined]
return obj() return obj()
def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]: def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]:
@ -794,16 +796,18 @@ class Instance(PyCollector):
return self.obj return self.obj
def hasinit(obj): def hasinit(obj: object) -> bool:
init = getattr(obj, "__init__", None) init = getattr(obj, "__init__", None) # type: object
if init: if init:
return init != object.__init__ return init != object.__init__
return False
def hasnew(obj): def hasnew(obj: object) -> bool:
new = getattr(obj, "__new__", None) new = getattr(obj, "__new__", None) # type: object
if new: if new:
return new != object.__new__ return new != object.__new__
return False
class CallSpec2: class CallSpec2:
@ -843,7 +847,7 @@ class CallSpec2:
def setmulti2( def setmulti2(
self, self,
valtypes: "Mapping[str, Literal['params', 'funcargs']]", valtypes: Mapping[str, "Literal['params', 'funcargs']"],
argnames: typing.Sequence[str], argnames: typing.Sequence[str],
valset: Iterable[object], valset: Iterable[object],
id: str, id: str,
@ -903,7 +907,7 @@ class Metafunc:
self._arg2fixturedefs = fixtureinfo.name2fixturedefs self._arg2fixturedefs = fixtureinfo.name2fixturedefs
@property @property
def funcargnames(self): def funcargnames(self) -> List[str]:
""" alias attribute for ``fixturenames`` for pre-2.3 compatibility""" """ alias attribute for ``fixturenames`` for pre-2.3 compatibility"""
warnings.warn(FUNCARGNAMES, stacklevel=2) warnings.warn(FUNCARGNAMES, stacklevel=2)
return self.fixturenames return self.fixturenames
@ -1170,7 +1174,11 @@ class Metafunc:
) )
def _find_parametrized_scope(argnames, arg2fixturedefs, indirect): def _find_parametrized_scope(
argnames: typing.Sequence[str],
arg2fixturedefs: Mapping[str, typing.Sequence[fixtures.FixtureDef]],
indirect: Union[bool, typing.Sequence[str]],
) -> "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.
When there's at least one direct argument, always use "function" scope. When there's at least one direct argument, always use "function" scope.
@ -1180,9 +1188,7 @@ def _find_parametrized_scope(argnames, arg2fixturedefs, indirect):
Related to issue #1832, based on code posted by @Kingdread. Related to issue #1832, based on code posted by @Kingdread.
""" """
from _pytest.fixtures import scopes if isinstance(indirect, Sequence):
if isinstance(indirect, (list, tuple)):
all_arguments_are_fixtures = len(indirect) == len(argnames) all_arguments_are_fixtures = len(indirect) == len(argnames)
else: else:
all_arguments_are_fixtures = bool(indirect) all_arguments_are_fixtures = bool(indirect)
@ -1196,7 +1202,7 @@ def _find_parametrized_scope(argnames, arg2fixturedefs, indirect):
] ]
if used_scopes: if used_scopes:
# Takes the most narrow scope from used fixtures # Takes the most narrow scope from used fixtures
for scope in reversed(scopes): for scope in reversed(fixtures.scopes):
if scope in used_scopes: if scope in used_scopes:
return scope return scope
@ -1264,7 +1270,7 @@ def _idvalset(
ids: Optional[List[Union[None, str]]], ids: Optional[List[Union[None, str]]],
nodeid: Optional[str], nodeid: Optional[str],
config: Optional[Config], config: Optional[Config],
): ) -> str:
if parameterset.id is not None: if parameterset.id is not None:
return parameterset.id return parameterset.id
id = None if ids is None or idx >= len(ids) else ids[idx] id = None if ids is None or idx >= len(ids) else ids[idx]
@ -1318,7 +1324,7 @@ def show_fixtures_per_test(config):
return wrap_session(config, _show_fixtures_per_test) return wrap_session(config, _show_fixtures_per_test)
def _show_fixtures_per_test(config, session): def _show_fixtures_per_test(config: Config, session: Session) -> None:
import _pytest.config import _pytest.config
session.perform_collect() session.perform_collect()
@ -1330,7 +1336,7 @@ def _show_fixtures_per_test(config, session):
loc = getlocation(func, curdir) loc = getlocation(func, curdir)
return curdir.bestrelpath(py.path.local(loc)) return curdir.bestrelpath(py.path.local(loc))
def write_fixture(fixture_def): def write_fixture(fixture_def: fixtures.FixtureDef[object]) -> None:
argname = fixture_def.argname argname = fixture_def.argname
if verbose <= 0 and argname.startswith("_"): if verbose <= 0 and argname.startswith("_"):
return return
@ -1346,18 +1352,16 @@ def _show_fixtures_per_test(config, session):
else: else:
tw.line(" no docstring available", red=True) tw.line(" no docstring available", red=True)
def write_item(item): def write_item(item: nodes.Item) -> None:
try: # Not all items have _fixtureinfo attribute.
info = item._fixtureinfo info = getattr(item, "_fixtureinfo", None) # type: Optional[FuncFixtureInfo]
except AttributeError: if info is None or not info.name2fixturedefs:
# doctests items have no _fixtureinfo attribute # This test item does not use any fixtures.
return
if not info.name2fixturedefs:
# this test item does not use any fixtures
return return
tw.line() tw.line()
tw.sep("-", "fixtures used by {}".format(item.name)) tw.sep("-", "fixtures used by {}".format(item.name))
tw.sep("-", "({})".format(get_best_relpath(item.function))) # TODO: Fix this type ignore.
tw.sep("-", "({})".format(get_best_relpath(item.function))) # type: ignore[attr-defined]
# dict key not used in loop but needed for sorting # dict key not used in loop but needed for sorting
for _, fixturedefs in sorted(info.name2fixturedefs.items()): for _, fixturedefs in sorted(info.name2fixturedefs.items()):
assert fixturedefs is not None assert fixturedefs is not None
@ -1448,15 +1452,15 @@ class Function(PyobjMixin, nodes.Item):
def __init__( def __init__(
self, self,
name, name: str,
parent, parent,
config=None, config: Optional[Config] = None,
callspec: Optional[CallSpec2] = None, callspec: Optional[CallSpec2] = None,
callobj=NOTSET, callobj=NOTSET,
keywords=None, keywords=None,
session=None, session: Optional[Session] = None,
fixtureinfo: Optional[FuncFixtureInfo] = None, fixtureinfo: Optional[FuncFixtureInfo] = None,
originalname=None, originalname: Optional[str] = None,
) -> None: ) -> None:
""" """
param name: the full function name, including any decorations like those param name: the full function name, including any decorations like those
@ -1533,8 +1537,8 @@ class Function(PyobjMixin, nodes.Item):
""" """
return super().from_parent(parent=parent, **kw) return super().from_parent(parent=parent, **kw)
def _initrequest(self): def _initrequest(self) -> None:
self.funcargs = {} self.funcargs = {} # type: Dict[str, object]
self._request = fixtures.FixtureRequest(self) self._request = fixtures.FixtureRequest(self)
@property @property
@ -1552,7 +1556,7 @@ class Function(PyobjMixin, nodes.Item):
return self return self
@property @property
def funcargnames(self): def funcargnames(self) -> List[str]:
""" alias attribute for ``fixturenames`` for pre-2.3 compatibility""" """ alias attribute for ``fixturenames`` for pre-2.3 compatibility"""
warnings.warn(FUNCARGNAMES, stacklevel=2) warnings.warn(FUNCARGNAMES, stacklevel=2)
return self.fixturenames return self.fixturenames
@ -1589,7 +1593,7 @@ class Function(PyobjMixin, nodes.Item):
entry.set_repr_style("short") entry.set_repr_style("short")
# TODO: Type ignored -- breaks Liskov Substitution. # TODO: Type ignored -- breaks Liskov Substitution.
def repr_failure( # type: ignore[override] # noqa: F821 def repr_failure( # type: ignore[override]
self, excinfo: ExceptionInfo[BaseException], self, excinfo: ExceptionInfo[BaseException],
) -> Union[str, TerminalRepr]: ) -> Union[str, TerminalRepr]:
style = self.config.getoption("tbstyle", "auto") style = self.config.getoption("tbstyle", "auto")

View File

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

View File

@ -308,7 +308,7 @@ class TestReport(BaseReport):
if not isinstance(excinfo, ExceptionInfo): if not isinstance(excinfo, ExceptionInfo):
outcome = "failed" outcome = "failed"
longrepr = excinfo longrepr = excinfo
elif excinfo.errisinstance(skip.Exception): elif isinstance(excinfo.value, skip.Exception):
outcome = "skipped" outcome = "skipped"
r = excinfo._getreprcrash() r = excinfo._getreprcrash()
longrepr = (str(r.path), r.lineno, r.message) longrepr = (str(r.path), r.lineno, r.message)

View File

@ -106,8 +106,8 @@ def runtestprotocol(
item: Item, log: bool = True, nextitem: Optional[Item] = None item: Item, log: bool = True, nextitem: Optional[Item] = None
) -> List[TestReport]: ) -> List[TestReport]:
hasrequest = hasattr(item, "_request") hasrequest = hasattr(item, "_request")
if hasrequest and not item._request: # type: ignore[attr-defined] # noqa: F821 if hasrequest and not item._request: # type: ignore[attr-defined]
item._initrequest() # type: ignore[attr-defined] # noqa: F821 item._initrequest() # type: ignore[attr-defined]
rep = call_and_report(item, "setup", log) rep = call_and_report(item, "setup", log)
reports = [rep] reports = [rep]
if rep.passed: if rep.passed:
@ -119,8 +119,8 @@ def runtestprotocol(
# after all teardown hooks have been called # after all teardown hooks have been called
# want funcargs and request info to go away # want funcargs and request info to go away
if hasrequest: if hasrequest:
item._request = False # type: ignore[attr-defined] # noqa: F821 item._request = False # type: ignore[attr-defined]
item.funcargs = None # type: ignore[attr-defined] # noqa: F821 item.funcargs = None # type: ignore[attr-defined]
return reports return reports
@ -215,11 +215,18 @@ def call_and_report(
def check_interactive_exception(call: "CallInfo", report: BaseReport) -> bool: def check_interactive_exception(call: "CallInfo", report: BaseReport) -> bool:
return call.excinfo is not None and not ( """Check whether the call raised an exception that should be reported as
hasattr(report, "wasxfail") interactive."""
or call.excinfo.errisinstance(Skipped) if call.excinfo is None:
or call.excinfo.errisinstance(bdb.BdbQuit) # Didn't raise.
) return False
if hasattr(report, "wasxfail"):
# Exception was expected.
return False
if isinstance(call.excinfo.value, (Skipped, bdb.BdbQuit)):
# Special control flow exception.
return False
return True
def call_runtest_hook( def call_runtest_hook(
@ -287,7 +294,7 @@ class CallInfo(Generic[_T]):
result = func() # type: Optional[_T] result = func() # type: Optional[_T]
except BaseException: except BaseException:
excinfo = ExceptionInfo.from_current() excinfo = ExceptionInfo.from_current()
if reraise is not None and excinfo.errisinstance(reraise): if reraise is not None and isinstance(excinfo.value, reraise):
raise raise
result = None result = None
# use the perf counter # use the perf counter
@ -325,7 +332,7 @@ def pytest_make_collect_report(collector: Collector) -> CollectReport:
if unittest is not None: if unittest is not None:
# Type ignored because unittest is loaded dynamically. # Type ignored because unittest is loaded dynamically.
skip_exceptions.append(unittest.SkipTest) # type: ignore skip_exceptions.append(unittest.SkipTest) # type: ignore
if call.excinfo.errisinstance(tuple(skip_exceptions)): if isinstance(call.excinfo.value, tuple(skip_exceptions)):
outcome = "skipped" outcome = "skipped"
r_ = collector._repr_failure_py(call.excinfo, "line") r_ = collector._repr_failure_py(call.excinfo, "line")
assert isinstance(r_, ExceptionChainRepr), repr(r_) assert isinstance(r_, ExceptionChainRepr), repr(r_)
@ -415,7 +422,7 @@ class SetupState:
# check if the last collection node has raised an error # check if the last collection node has raised an error
for col in self.stack: for col in self.stack:
if hasattr(col, "_prepare_exc"): if hasattr(col, "_prepare_exc"):
exc = col._prepare_exc # type: ignore[attr-defined] # noqa: F821 exc = col._prepare_exc # type: ignore[attr-defined]
raise exc raise exc
needed_collectors = colitem.listchain() needed_collectors = colitem.listchain()
@ -424,7 +431,7 @@ class SetupState:
try: try:
col.setup() col.setup()
except TEST_OUTCOME as e: except TEST_OUTCOME as e:
col._prepare_exc = e # type: ignore[attr-defined] # noqa: F821 col._prepare_exc = e # type: ignore[attr-defined]
raise e raise e

View File

@ -43,7 +43,7 @@ def pytest_fixture_setup(
param = fixturedef.ids[request.param_index] param = fixturedef.ids[request.param_index]
else: else:
param = request.param param = request.param
fixturedef.cached_param = param # type: ignore[attr-defined] # noqa: F821 fixturedef.cached_param = param # type: ignore[attr-defined]
_show_fixture_action(fixturedef, "SETUP") _show_fixture_action(fixturedef, "SETUP")
@ -53,7 +53,7 @@ def pytest_fixture_post_finalizer(fixturedef: FixtureDef) -> None:
if config.option.setupshow: if config.option.setupshow:
_show_fixture_action(fixturedef, "TEARDOWN") _show_fixture_action(fixturedef, "TEARDOWN")
if hasattr(fixturedef, "cached_param"): if hasattr(fixturedef, "cached_param"):
del fixturedef.cached_param # type: ignore[attr-defined] # noqa: F821 del fixturedef.cached_param # type: ignore[attr-defined]
def _show_fixture_action(fixturedef: FixtureDef, msg: str) -> None: def _show_fixture_action(fixturedef: FixtureDef, msg: str) -> None:

View File

@ -56,7 +56,7 @@ def pytest_configure(config: Config) -> None:
def nop(*args, **kwargs): def nop(*args, **kwargs):
pass pass
nop.Exception = xfail.Exception # type: ignore[attr-defined] # noqa: F821 nop.Exception = xfail.Exception # type: ignore[attr-defined]
setattr(pytest, "xfail", nop) setattr(pytest, "xfail", nop)
config.addinivalue_line( config.addinivalue_line(

View File

@ -1219,7 +1219,7 @@ def _get_line_with_reprcrash_message(
try: try:
# Type ignored intentionally -- possible AttributeError expected. # Type ignored intentionally -- possible AttributeError expected.
msg = rep.longrepr.reprcrash.message # type: ignore[union-attr] # noqa: F821 msg = rep.longrepr.reprcrash.message # type: ignore[union-attr]
except AttributeError: except AttributeError:
pass pass
else: else:

View File

@ -46,7 +46,7 @@ class TempPathFactory:
given_basetemp=config.option.basetemp, trace=config.trace.get("tmpdir") given_basetemp=config.option.basetemp, trace=config.trace.get("tmpdir")
) )
def _ensure_relative_to_basetemp(self, basename: str): def _ensure_relative_to_basetemp(self, basename: str) -> str:
basename = os.path.normpath(basename) basename = os.path.normpath(basename)
if (self.getbasetemp() / basename).resolve().parent != self.getbasetemp(): if (self.getbasetemp() / basename).resolve().parent != self.getbasetemp():
raise ValueError( raise ValueError(
@ -119,7 +119,7 @@ class TempdirFactory:
""" """
return py.path.local(self._tmppath_factory.mktemp(basename, numbered).resolve()) return py.path.local(self._tmppath_factory.mktemp(basename, numbered).resolve())
def getbasetemp(self): def getbasetemp(self) -> py.path.local:
"""backward compat wrapper for ``_tmppath_factory.getbasetemp``""" """backward compat wrapper for ``_tmppath_factory.getbasetemp``"""
return py.path.local(self._tmppath_factory.getbasetemp().resolve()) return py.path.local(self._tmppath_factory.getbasetemp().resolve())
@ -176,7 +176,7 @@ def _mk_tmp(request: FixtureRequest, factory: TempPathFactory) -> Path:
@pytest.fixture @pytest.fixture
def tmpdir(tmp_path): def tmpdir(tmp_path: Path) -> py.path.local:
"""Return a temporary directory path object """Return a temporary directory path object
which is unique to each test function invocation, which is unique to each test function invocation,
created as a sub directory of the base temporary created as a sub directory of the base temporary

View File

@ -102,13 +102,13 @@ class UnitTestCase(Class):
cls, "setUpClass", "tearDownClass", scope="class", pass_self=False cls, "setUpClass", "tearDownClass", scope="class", pass_self=False
) )
if class_fixture: if class_fixture:
cls.__pytest_class_setup = class_fixture # type: ignore[attr-defined] # noqa: F821 cls.__pytest_class_setup = class_fixture # type: ignore[attr-defined]
method_fixture = _make_xunit_fixture( method_fixture = _make_xunit_fixture(
cls, "setup_method", "teardown_method", scope="function", pass_self=True cls, "setup_method", "teardown_method", scope="function", pass_self=True
) )
if method_fixture: if method_fixture:
cls.__pytest_method_setup = method_fixture # type: ignore[attr-defined] # noqa: F821 cls.__pytest_method_setup = method_fixture # type: ignore[attr-defined]
def _make_xunit_fixture( def _make_xunit_fixture(
@ -148,7 +148,7 @@ class TestCaseFunction(Function):
# a bound method to be called during teardown() if set (see 'runtest()') # a bound method to be called during teardown() if set (see 'runtest()')
self._explicit_tearDown = None # type: Optional[Callable[[], None]] self._explicit_tearDown = None # type: Optional[Callable[[], None]]
assert self.parent is not None assert self.parent is not None
self._testcase = self.parent.obj(self.name) # type: ignore[attr-defined] # noqa: F821 self._testcase = self.parent.obj(self.name) # type: ignore[attr-defined]
self._obj = getattr(self._testcase, self.name) self._obj = getattr(self._testcase, self.name)
if hasattr(self, "_request"): if hasattr(self, "_request"):
self._request._fillfixtures() self._request._fillfixtures()
@ -167,7 +167,7 @@ class TestCaseFunction(Function):
# unwrap potential exception info (see twisted trial support below) # unwrap potential exception info (see twisted trial support below)
rawexcinfo = getattr(rawexcinfo, "_rawexcinfo", rawexcinfo) rawexcinfo = getattr(rawexcinfo, "_rawexcinfo", rawexcinfo)
try: try:
excinfo = _pytest._code.ExceptionInfo(rawexcinfo) # type: ignore[arg-type] # noqa: F821 excinfo = _pytest._code.ExceptionInfo(rawexcinfo) # type: ignore[arg-type]
# invoke the attributes to trigger storing the traceback # invoke the attributes to trigger storing the traceback
# trial causes some issue there # trial causes some issue there
excinfo.value excinfo.value
@ -259,7 +259,7 @@ class TestCaseFunction(Function):
# let the unittest framework handle async functions # let the unittest framework handle async functions
if is_async_function(self.obj): if is_async_function(self.obj):
# Type ignored because self acts as the TestResult, but is not actually one. # Type ignored because self acts as the TestResult, but is not actually one.
self._testcase(result=self) # type: ignore[arg-type] # noqa: F821 self._testcase(result=self) # type: ignore[arg-type]
else: else:
# when --pdb is given, we want to postpone calling tearDown() otherwise # when --pdb is given, we want to postpone calling tearDown() otherwise
# when entering the pdb prompt, tearDown() would have probably cleaned up # when entering the pdb prompt, tearDown() would have probably cleaned up
@ -275,7 +275,7 @@ class TestCaseFunction(Function):
# wrap_pytest_function_for_tracing replaces self.obj by a wrapper # wrap_pytest_function_for_tracing replaces self.obj by a wrapper
setattr(self._testcase, self.name, self.obj) setattr(self._testcase, self.name, self.obj)
try: try:
self._testcase(result=self) # type: ignore[arg-type] # noqa: F821 self._testcase(result=self) # type: ignore[arg-type]
finally: finally:
delattr(self._testcase, self.name) delattr(self._testcase, self.name)
@ -302,9 +302,7 @@ def pytest_runtest_makereport(item: Item, call: CallInfo[None]) -> None:
if ( if (
unittest unittest
and call.excinfo and call.excinfo
and call.excinfo.errisinstance( and isinstance(call.excinfo.value, unittest.SkipTest) # type: ignore[attr-defined]
unittest.SkipTest # type: ignore[attr-defined] # noqa: F821
)
): ):
excinfo = call.excinfo excinfo = call.excinfo
# let's substitute the excinfo with a pytest.skip one # let's substitute the excinfo with a pytest.skip one

View File

@ -752,7 +752,7 @@ raise ValueError()
from _pytest._code.code import Code from _pytest._code.code import Code
monkeypatch.setattr(Code, "path", "bogus") monkeypatch.setattr(Code, "path", "bogus")
excinfo.traceback[0].frame.code.path = "bogus" # type: ignore[misc] # noqa: F821 excinfo.traceback[0].frame.code.path = "bogus" # type: ignore[misc]
p = FormattedExcinfo(style="short") p = FormattedExcinfo(style="short")
reprtb = p.repr_traceback_entry(excinfo.traceback[-2]) reprtb = p.repr_traceback_entry(excinfo.traceback[-2])
lines = reprtb.lines lines = reprtb.lines

View File

@ -16,4 +16,4 @@ def test_comparing_two_different_data_classes() -> None:
left = SimpleDataObjectOne(1, "b") left = SimpleDataObjectOne(1, "b")
right = SimpleDataObjectTwo(1, "c") right = SimpleDataObjectTwo(1, "c")
assert left != right # type: ignore[comparison-overlap] # noqa: F821 assert left != right # type: ignore[comparison-overlap]

View File

@ -34,8 +34,8 @@ def test_exceptions() -> None:
raise self.ex raise self.ex
class BrokenReprException(Exception): class BrokenReprException(Exception):
__str__ = None # type: ignore[assignment] # noqa: F821 __str__ = None # type: ignore[assignment]
__repr__ = None # type: ignore[assignment] # noqa: F821 __repr__ = None # type: ignore[assignment]
assert "Exception" in saferepr(BrokenRepr(Exception("broken"))) assert "Exception" in saferepr(BrokenRepr(Exception("broken")))
s = saferepr(BrokenReprException("really broken")) s = saferepr(BrokenReprException("really broken"))
@ -44,7 +44,7 @@ def test_exceptions() -> None:
none = None none = None
try: try:
none() # type: ignore[misc] # noqa: F821 none() # type: ignore[misc]
except BaseException as exc: except BaseException as exc:
exp_exc = repr(exc) exp_exc = repr(exc)
obj = BrokenRepr(BrokenReprException("omg even worse")) obj = BrokenRepr(BrokenReprException("omg even worse"))
@ -139,7 +139,7 @@ def test_big_repr():
def test_repr_on_newstyle() -> None: def test_repr_on_newstyle() -> None:
class Function: class Function:
def __repr__(self): def __repr__(self):
return "<%s>" % (self.name) # type: ignore[attr-defined] # noqa: F821 return "<%s>" % (self.name) # type: ignore[attr-defined]
assert saferepr(Function()) assert saferepr(Function())

View File

@ -675,7 +675,11 @@ class TestFunction:
pass pass
""" """
) )
assert [x.originalname for x in items] == [ originalnames = []
for x in items:
assert isinstance(x, pytest.Function)
originalnames.append(x.originalname)
assert originalnames == [
"test_func", "test_func",
"test_func", "test_func",
"test_no_param", "test_no_param",
@ -720,10 +724,10 @@ class TestSorting:
assert fn1 != fn3 assert fn1 != fn3
for fn in fn1, fn2, fn3: for fn in fn1, fn2, fn3:
assert fn != 3 # type: ignore[comparison-overlap] # noqa: F821 assert fn != 3 # type: ignore[comparison-overlap]
assert fn != modcol assert fn != modcol
assert fn != [1, 2, 3] # type: ignore[comparison-overlap] # noqa: F821 assert fn != [1, 2, 3] # type: ignore[comparison-overlap]
assert [1, 2, 3] != fn # type: ignore[comparison-overlap] # noqa: F821 assert [1, 2, 3] != fn # type: ignore[comparison-overlap]
assert modcol != fn assert modcol != fn
def test_allow_sane_sorting_for_decorators(self, testdir): def test_allow_sane_sorting_for_decorators(self, testdir):

View File

@ -3850,7 +3850,7 @@ class TestScopeOrdering:
) )
testdir.runpytest() testdir.runpytest()
# actual fixture execution differs: dependent fixtures must be created first ("my_tmpdir") # actual fixture execution differs: dependent fixtures must be created first ("my_tmpdir")
FIXTURE_ORDER = pytest.FIXTURE_ORDER # type: ignore[attr-defined] # noqa: F821 FIXTURE_ORDER = pytest.FIXTURE_ORDER # type: ignore[attr-defined]
assert FIXTURE_ORDER == "s1 my_tmpdir_factory p1 m1 my_tmpdir f1 f2".split() assert FIXTURE_ORDER == "s1 my_tmpdir_factory p1 m1 my_tmpdir f1 f2".split()
def test_func_closure_module(self, testdir): def test_func_closure_module(self, testdir):
@ -4159,7 +4159,7 @@ def test_fixture_duplicated_arguments() -> None:
"""Raise error if there are positional and keyword arguments for the same parameter (#1682).""" """Raise error if there are positional and keyword arguments for the same parameter (#1682)."""
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
@pytest.fixture("session", scope="session") # type: ignore[call-overload] # noqa: F821 @pytest.fixture("session", scope="session") # type: ignore[call-overload]
def arg(arg): def arg(arg):
pass pass
@ -4171,7 +4171,7 @@ def test_fixture_duplicated_arguments() -> None:
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
@pytest.fixture( # type: ignore[call-overload] # noqa: F821 @pytest.fixture( # type: ignore[call-overload]
"function", "function",
["p1"], ["p1"],
True, True,
@ -4199,7 +4199,7 @@ def test_fixture_with_positionals() -> None:
with pytest.warns(pytest.PytestDeprecationWarning) as warnings: with pytest.warns(pytest.PytestDeprecationWarning) as warnings:
@pytest.fixture("function", [0], True) # type: ignore[call-overload] # noqa: F821 @pytest.fixture("function", [0], True) # type: ignore[call-overload]
def fixture_with_positionals(): def fixture_with_positionals():
pass pass
@ -4213,7 +4213,7 @@ def test_fixture_with_positionals() -> None:
def test_fixture_with_too_many_positionals() -> None: def test_fixture_with_too_many_positionals() -> None:
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
@pytest.fixture("function", [0], True, ["id"], "name", "extra") # type: ignore[call-overload] # noqa: F821 @pytest.fixture("function", [0], True, ["id"], "name", "extra") # type: ignore[call-overload]
def fixture_with_positionals(): def fixture_with_positionals():
pass pass

View File

@ -3,9 +3,12 @@ import re
import sys import sys
import textwrap import textwrap
from typing import Any from typing import Any
from typing import cast
from typing import Dict
from typing import Iterator from typing import Iterator
from typing import List from typing import List
from typing import Optional from typing import Optional
from typing import Sequence
from typing import Tuple from typing import Tuple
from typing import Union from typing import Union
@ -74,7 +77,7 @@ class TestMetafunc:
pytest.raises(ValueError, lambda: metafunc.parametrize("y", [5, 6])) pytest.raises(ValueError, lambda: metafunc.parametrize("y", [5, 6]))
with pytest.raises(TypeError, match="^ids must be a callable or an iterable$"): with pytest.raises(TypeError, match="^ids must be a callable or an iterable$"):
metafunc.parametrize("y", [5, 6], ids=42) # type: ignore[arg-type] # noqa: F821 metafunc.parametrize("y", [5, 6], ids=42) # type: ignore[arg-type]
def test_parametrize_error_iterator(self) -> None: def test_parametrize_error_iterator(self) -> None:
def func(x): def func(x):
@ -92,7 +95,7 @@ class TestMetafunc:
metafunc = self.Metafunc(func) metafunc = self.Metafunc(func)
# When the input is an iterator, only len(args) are taken, # When the input is an iterator, only len(args) are taken,
# so the bad Exc isn't reached. # so the bad Exc isn't reached.
metafunc.parametrize("x", [1, 2], ids=gen()) # type: ignore[arg-type] # noqa: F821 metafunc.parametrize("x", [1, 2], ids=gen()) # type: ignore[arg-type]
assert [(x.funcargs, x.id) for x in metafunc._calls] == [ assert [(x.funcargs, x.id) for x in metafunc._calls] == [
({"x": 1}, "0"), ({"x": 1}, "0"),
({"x": 2}, "2"), ({"x": 2}, "2"),
@ -104,7 +107,7 @@ class TestMetafunc:
r" Exc\(from_gen\) \(type: <class .*Exc'>\) at index 2" r" Exc\(from_gen\) \(type: <class .*Exc'>\) at index 2"
), ),
): ):
metafunc.parametrize("x", [1, 2, 3], ids=gen()) # type: ignore[arg-type] # noqa: F821 metafunc.parametrize("x", [1, 2, 3], ids=gen()) # type: ignore[arg-type]
def test_parametrize_bad_scope(self) -> None: def test_parametrize_bad_scope(self) -> None:
def func(x): def func(x):
@ -115,7 +118,7 @@ class TestMetafunc:
fail.Exception, fail.Exception,
match=r"parametrize\(\) call in func got an unexpected scope value 'doggy'", match=r"parametrize\(\) call in func got an unexpected scope value 'doggy'",
): ):
metafunc.parametrize("x", [1], scope="doggy") # type: ignore[arg-type] # noqa: F821 metafunc.parametrize("x", [1], scope="doggy") # type: ignore[arg-type]
def test_parametrize_request_name(self, testdir: Testdir) -> None: def test_parametrize_request_name(self, testdir: Testdir) -> None:
"""Show proper error when 'request' is used as a parameter name in parametrize (#6183)""" """Show proper error when 'request' is used as a parameter name in parametrize (#6183)"""
@ -138,12 +141,15 @@ class TestMetafunc:
class DummyFixtureDef: class DummyFixtureDef:
scope = attr.ib() scope = attr.ib()
fixtures_defs = dict( fixtures_defs = cast(
session_fix=[DummyFixtureDef("session")], Dict[str, Sequence[fixtures.FixtureDef]],
package_fix=[DummyFixtureDef("package")], dict(
module_fix=[DummyFixtureDef("module")], session_fix=[DummyFixtureDef("session")],
class_fix=[DummyFixtureDef("class")], package_fix=[DummyFixtureDef("package")],
func_fix=[DummyFixtureDef("function")], module_fix=[DummyFixtureDef("module")],
class_fix=[DummyFixtureDef("class")],
func_fix=[DummyFixtureDef("function")],
),
) )
# use arguments to determine narrow scope; the cause of the bug is that it would look on all # use arguments to determine narrow scope; the cause of the bug is that it would look on all
@ -669,7 +675,7 @@ class TestMetafunc:
fail.Exception, fail.Exception,
match="In func: expected Sequence or boolean for indirect, got dict", match="In func: expected Sequence or boolean for indirect, got dict",
): ):
metafunc.parametrize("x, y", [("a", "b")], indirect={}) # type: ignore[arg-type] # noqa: F821 metafunc.parametrize("x, y", [("a", "b")], indirect={}) # type: ignore[arg-type]
def test_parametrize_indirect_list_functional(self, testdir: Testdir) -> None: def test_parametrize_indirect_list_functional(self, testdir: Testdir) -> None:
""" """

View File

@ -8,7 +8,7 @@ from _pytest.outcomes import Failed
class TestRaises: class TestRaises:
def test_check_callable(self) -> None: def test_check_callable(self) -> None:
with pytest.raises(TypeError, match=r".* must be callable"): with pytest.raises(TypeError, match=r".* must be callable"):
pytest.raises(RuntimeError, "int('qwe')") # type: ignore[call-overload] # noqa: F821 pytest.raises(RuntimeError, "int('qwe')") # type: ignore[call-overload]
def test_raises(self): def test_raises(self):
excinfo = pytest.raises(ValueError, int, "qwe") excinfo = pytest.raises(ValueError, int, "qwe")
@ -30,7 +30,7 @@ class TestRaises:
def test_raises_falsey_type_error(self) -> None: def test_raises_falsey_type_error(self) -> None:
with pytest.raises(TypeError): with pytest.raises(TypeError):
with pytest.raises(AssertionError, match=0): # type: ignore[call-overload] # noqa: F821 with pytest.raises(AssertionError, match=0): # type: ignore[call-overload]
raise AssertionError("ohai") raise AssertionError("ohai")
def test_raises_repr_inflight(self): def test_raises_repr_inflight(self):
@ -128,11 +128,11 @@ class TestRaises:
def test_noclass(self) -> None: def test_noclass(self) -> None:
with pytest.raises(TypeError): with pytest.raises(TypeError):
pytest.raises("wrong", lambda: None) # type: ignore[call-overload] # noqa: F821 pytest.raises("wrong", lambda: None) # type: ignore[call-overload]
def test_invalid_arguments_to_raises(self) -> None: def test_invalid_arguments_to_raises(self) -> None:
with pytest.raises(TypeError, match="unknown"): with pytest.raises(TypeError, match="unknown"):
with pytest.raises(TypeError, unknown="bogus"): # type: ignore[call-overload] # noqa: F821 with pytest.raises(TypeError, unknown="bogus"): # type: ignore[call-overload]
raise ValueError() raise ValueError()
def test_tuple(self): def test_tuple(self):
@ -262,12 +262,12 @@ class TestRaises:
assert False, "via __class__" assert False, "via __class__"
with pytest.raises(AssertionError) as excinfo: with pytest.raises(AssertionError) as excinfo:
with pytest.raises(CrappyClass()): # type: ignore[call-overload] # noqa: F821 with pytest.raises(CrappyClass()): # type: ignore[call-overload]
pass pass
assert "via __class__" in excinfo.value.args[0] assert "via __class__" in excinfo.value.args[0]
def test_raises_context_manager_with_kwargs(self): def test_raises_context_manager_with_kwargs(self):
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
with pytest.raises(Exception, foo="bar"): # type: ignore[call-overload] # noqa: F821 with pytest.raises(Exception, foo="bar"): # type: ignore[call-overload]
pass pass
assert "Unexpected keyword arguments" in str(excinfo.value) assert "Unexpected keyword arguments" in str(excinfo.value)

View File

@ -51,7 +51,7 @@ def getmsg(
exec(code, ns) exec(code, ns)
func = ns[f.__name__] func = ns[f.__name__]
try: try:
func() # type: ignore[operator] # noqa: F821 func() # type: ignore[operator]
except AssertionError: except AssertionError:
if must_pass: if must_pass:
pytest.fail("shouldn't have raised") pytest.fail("shouldn't have raised")
@ -174,7 +174,7 @@ class TestAssertionRewrite:
assert getmsg(f3, {"a_global": False}) == "assert False" assert getmsg(f3, {"a_global": False}) == "assert False"
def f4() -> None: def f4() -> None:
assert sys == 42 # type: ignore[comparison-overlap] # noqa: F821 assert sys == 42 # type: ignore[comparison-overlap]
verbose = request.config.getoption("verbose") verbose = request.config.getoption("verbose")
msg = getmsg(f4, {"sys": sys}) msg = getmsg(f4, {"sys": sys})
@ -188,7 +188,7 @@ class TestAssertionRewrite:
assert msg == "assert sys == 42" assert msg == "assert sys == 42"
def f5() -> None: def f5() -> None:
assert cls == 42 # type: ignore[name-defined] # noqa: F821 assert cls == 42 # type: ignore[name-defined] # noqa: F821
class X: class X:
pass pass
@ -684,7 +684,7 @@ class TestAssertionRewrite:
def test_formatchar(self) -> None: def test_formatchar(self) -> None:
def f() -> None: def f() -> None:
assert "%test" == "test" # type: ignore[comparison-overlap] # noqa: F821 assert "%test" == "test" # type: ignore[comparison-overlap]
msg = getmsg(f) msg = getmsg(f)
assert msg is not None assert msg is not None
@ -1264,7 +1264,7 @@ class TestEarlyRewriteBailout:
# use default patterns, otherwise we inherit pytest's testing config # use default patterns, otherwise we inherit pytest's testing config
hook.fnpats[:] = ["test_*.py", "*_test.py"] hook.fnpats[:] = ["test_*.py", "*_test.py"]
monkeypatch.setattr(hook, "_find_spec", spy_find_spec) monkeypatch.setattr(hook, "_find_spec", spy_find_spec)
hook.set_session(StubSession()) # type: ignore[arg-type] # noqa: F821 hook.set_session(StubSession()) # type: ignore[arg-type]
testdir.syspathinsert() testdir.syspathinsert()
return hook return hook

View File

@ -1537,7 +1537,7 @@ def test_encodedfile_writelines(tmpfile: BinaryIO) -> None:
ef = capture.EncodedFile(tmpfile, encoding="utf-8") ef = capture.EncodedFile(tmpfile, encoding="utf-8")
with pytest.raises(TypeError): with pytest.raises(TypeError):
ef.writelines([b"line1", b"line2"]) ef.writelines([b"line1", b"line2"])
assert ef.writelines(["line3", "line4"]) is None # type: ignore[func-returns-value] # noqa: F821 assert ef.writelines(["line3", "line4"]) is None # type: ignore[func-returns-value]
ef.flush() ef.flush()
tmpfile.seek(0) tmpfile.seek(0)
assert tmpfile.read() == b"line3line4" assert tmpfile.read() == b"line3line4"

View File

@ -41,10 +41,10 @@ class TestCollector:
for fn in fn1, fn2, fn3: for fn in fn1, fn2, fn3:
assert isinstance(fn, pytest.Function) assert isinstance(fn, pytest.Function)
assert fn != 3 # type: ignore[comparison-overlap] # noqa: F821 assert fn != 3 # type: ignore[comparison-overlap]
assert fn != modcol assert fn != modcol
assert fn != [1, 2, 3] # type: ignore[comparison-overlap] # noqa: F821 assert fn != [1, 2, 3] # type: ignore[comparison-overlap]
assert [1, 2, 3] != fn # type: ignore[comparison-overlap] # noqa: F821 assert [1, 2, 3] != fn # type: ignore[comparison-overlap]
assert modcol != fn assert modcol != fn
assert testdir.collect_by_name(modcol, "doesnotexist") is None assert testdir.collect_by_name(modcol, "doesnotexist") is None

View File

@ -1602,7 +1602,7 @@ def test_invocation_args(testdir):
# args cannot be None # args cannot be None
with pytest.raises(TypeError): with pytest.raises(TypeError):
Config.InvocationParams(args=None, plugins=None, dir=Path()) # type: ignore[arg-type] # noqa: F821 Config.InvocationParams(args=None, plugins=None, dir=Path()) # type: ignore[arg-type]
@pytest.mark.parametrize( @pytest.mark.parametrize(

View File

@ -1490,7 +1490,7 @@ def test_warning_on_unwrap_of_broken_object(
pytest.PytestWarning, match="^Got KeyError.* when unwrapping" pytest.PytestWarning, match="^Got KeyError.* when unwrapping"
): ):
with pytest.raises(KeyError): with pytest.raises(KeyError):
inspect.unwrap(bad_instance, stop=stop) # type: ignore[arg-type] # noqa: F821 inspect.unwrap(bad_instance, stop=stop) # type: ignore[arg-type]
assert inspect.unwrap.__module__ == "inspect" assert inspect.unwrap.__module__ == "inspect"

View File

@ -1124,7 +1124,7 @@ def test_unicode_issue368(testdir) -> None:
node_reporter.append_skipped(test_report) node_reporter.append_skipped(test_report)
test_report.longrepr = "filename", 1, "Skipped: 卡嘣嘣" test_report.longrepr = "filename", 1, "Skipped: 卡嘣嘣"
node_reporter.append_skipped(test_report) node_reporter.append_skipped(test_report)
test_report.wasxfail = ustr # type: ignore[attr-defined] # noqa: F821 test_report.wasxfail = ustr # type: ignore[attr-defined]
node_reporter.append_skipped(test_report) node_reporter.append_skipped(test_report)
log.pytest_sessionfinish() log.pytest_sessionfinish()

View File

@ -20,7 +20,7 @@ class TestMark:
def test_pytest_mark_notcallable(self) -> None: def test_pytest_mark_notcallable(self) -> None:
mark = Mark() mark = Mark()
with pytest.raises(TypeError): with pytest.raises(TypeError):
mark() # type: ignore[operator] # noqa: F821 mark() # type: ignore[operator]
def test_mark_with_param(self): def test_mark_with_param(self):
def some_function(abc): def some_function(abc):
@ -31,10 +31,10 @@ class TestMark:
assert pytest.mark.foo(some_function) is some_function assert pytest.mark.foo(some_function) is some_function
marked_with_args = pytest.mark.foo.with_args(some_function) marked_with_args = pytest.mark.foo.with_args(some_function)
assert marked_with_args is not some_function # type: ignore[comparison-overlap] # noqa: F821 assert marked_with_args is not some_function # type: ignore[comparison-overlap]
assert pytest.mark.foo(SomeClass) is SomeClass assert pytest.mark.foo(SomeClass) is SomeClass
assert pytest.mark.foo.with_args(SomeClass) is not SomeClass # type: ignore[comparison-overlap] # noqa: F821 assert pytest.mark.foo.with_args(SomeClass) is not SomeClass # type: ignore[comparison-overlap]
def test_pytest_mark_name_starts_with_underscore(self): def test_pytest_mark_name_starts_with_underscore(self):
mark = Mark() mark = Mark()
@ -1077,7 +1077,7 @@ def test_markers_from_parametrize(testdir):
def test_pytest_param_id_requires_string() -> None: def test_pytest_param_id_requires_string() -> None:
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
pytest.param(id=True) # type: ignore[arg-type] # noqa: F821 pytest.param(id=True) # type: ignore[arg-type]
(msg,) = excinfo.value.args (msg,) = excinfo.value.args
assert msg == "Expected id to be a string, got <class 'bool'>: True" assert msg == "Expected id to be a string, got <class 'bool'>: True"

View File

@ -25,9 +25,9 @@ def test_ischildnode(baseid: str, nodeid: str, expected: bool) -> None:
def test_node_from_parent_disallowed_arguments() -> None: def test_node_from_parent_disallowed_arguments() -> None:
with pytest.raises(TypeError, match="session is"): with pytest.raises(TypeError, match="session is"):
nodes.Node.from_parent(None, session=None) # type: ignore[arg-type] # noqa: F821 nodes.Node.from_parent(None, session=None) # type: ignore[arg-type]
with pytest.raises(TypeError, match="config is"): with pytest.raises(TypeError, match="config is"):
nodes.Node.from_parent(None, config=None) # type: ignore[arg-type] # noqa: F821 nodes.Node.from_parent(None, config=None) # type: ignore[arg-type]
def test_std_warn_not_pytestwarning(testdir: Testdir) -> None: def test_std_warn_not_pytestwarning(testdir: Testdir) -> None:
@ -38,7 +38,7 @@ def test_std_warn_not_pytestwarning(testdir: Testdir) -> None:
""" """
) )
with pytest.raises(ValueError, match=".*instance of PytestWarning.*"): with pytest.raises(ValueError, match=".*instance of PytestWarning.*"):
items[0].warn(UserWarning("some warning")) items[0].warn(UserWarning("some warning")) # type: ignore[arg-type]
def test__check_initialpaths_for_relpath() -> None: def test__check_initialpaths_for_relpath() -> None:

View File

@ -484,20 +484,20 @@ def test_linematcher_with_nonlist() -> None:
lm = LineMatcher([]) lm = LineMatcher([])
with pytest.raises(TypeError, match="invalid type for lines2: set"): with pytest.raises(TypeError, match="invalid type for lines2: set"):
lm.fnmatch_lines(set()) # type: ignore[arg-type] # noqa: F821 lm.fnmatch_lines(set()) # type: ignore[arg-type]
with pytest.raises(TypeError, match="invalid type for lines2: dict"): with pytest.raises(TypeError, match="invalid type for lines2: dict"):
lm.fnmatch_lines({}) # type: ignore[arg-type] # noqa: F821 lm.fnmatch_lines({}) # type: ignore[arg-type]
with pytest.raises(TypeError, match="invalid type for lines2: set"): with pytest.raises(TypeError, match="invalid type for lines2: set"):
lm.re_match_lines(set()) # type: ignore[arg-type] # noqa: F821 lm.re_match_lines(set()) # type: ignore[arg-type]
with pytest.raises(TypeError, match="invalid type for lines2: dict"): with pytest.raises(TypeError, match="invalid type for lines2: dict"):
lm.re_match_lines({}) # type: ignore[arg-type] # noqa: F821 lm.re_match_lines({}) # type: ignore[arg-type]
with pytest.raises(TypeError, match="invalid type for lines2: Source"): with pytest.raises(TypeError, match="invalid type for lines2: Source"):
lm.fnmatch_lines(Source()) # type: ignore[arg-type] # noqa: F821 lm.fnmatch_lines(Source()) # type: ignore[arg-type]
lm.fnmatch_lines([]) lm.fnmatch_lines([])
lm.fnmatch_lines(()) lm.fnmatch_lines(())
lm.fnmatch_lines("") lm.fnmatch_lines("")
assert lm._getlines({}) == {} # type: ignore[arg-type,comparison-overlap] # noqa: F821 assert lm._getlines({}) == {} # type: ignore[arg-type,comparison-overlap]
assert lm._getlines(set()) == set() # type: ignore[arg-type,comparison-overlap] # noqa: F821 assert lm._getlines(set()) == set() # type: ignore[arg-type,comparison-overlap]
assert lm._getlines(Source()) == [] assert lm._getlines(Source()) == []
assert lm._getlines(Source("pass\npass")) == ["pass", "pass"] assert lm._getlines(Source("pass\npass")) == ["pass", "pass"]

View File

@ -884,7 +884,7 @@ def test_store_except_info_on_error() -> None:
raise IndexError("TEST") raise IndexError("TEST")
try: try:
runner.pytest_runtest_call(ItemMightRaise()) # type: ignore[arg-type] # noqa: F821 runner.pytest_runtest_call(ItemMightRaise()) # type: ignore[arg-type]
except IndexError: except IndexError:
pass pass
# Check that exception info is stored on sys # Check that exception info is stored on sys
@ -895,7 +895,7 @@ def test_store_except_info_on_error() -> None:
# The next run should clear the exception info stored by the previous run # The next run should clear the exception info stored by the previous run
ItemMightRaise.raise_error = False ItemMightRaise.raise_error = False
runner.pytest_runtest_call(ItemMightRaise()) # type: ignore[arg-type] # noqa: F821 runner.pytest_runtest_call(ItemMightRaise()) # type: ignore[arg-type]
assert not hasattr(sys, "last_type") assert not hasattr(sys, "last_type")
assert not hasattr(sys, "last_value") assert not hasattr(sys, "last_value")
assert not hasattr(sys, "last_traceback") assert not hasattr(sys, "last_traceback")

View File

@ -47,7 +47,7 @@ def test_store() -> None:
# Can't accidentally add attributes to store object itself. # Can't accidentally add attributes to store object itself.
with pytest.raises(AttributeError): with pytest.raises(AttributeError):
store.foo = "nope" # type: ignore[attr-defined] # noqa: F821 store.foo = "nope" # type: ignore[attr-defined]
# No interaction with anoter store. # No interaction with anoter store.
store2 = Store() store2 = Store()

View File

@ -1699,7 +1699,7 @@ def test_summary_stats(
class fake_session: class fake_session:
testscollected = 0 testscollected = 0
tr._session = fake_session # type: ignore[assignment] # noqa: F821 tr._session = fake_session # type: ignore[assignment]
assert tr._is_last_item assert tr._is_last_item
# Reset cache. # Reset cache.