Enable check_untyped_defs mypy option for testing/ too

This commit is contained in:
Ran Benita 2020-05-01 14:40:17 +03:00
parent 71dfdca4df
commit 54ad048be7
41 changed files with 598 additions and 443 deletions

View File

@ -91,6 +91,7 @@ formats = sdist.tgz,bdist_wheel
[mypy]
mypy_path = src
check_untyped_defs = True
ignore_missing_imports = True
no_implicit_optional = True
show_error_codes = True
@ -98,6 +99,3 @@ strict_equality = True
warn_redundant_casts = True
warn_return_any = True
warn_unused_configs = True
[mypy-_pytest.*]
check_untyped_defs = True

View File

@ -15,6 +15,7 @@ from typing import Dict
from typing import Generic
from typing import Iterable
from typing import List
from typing import Mapping
from typing import Optional
from typing import Pattern
from typing import Sequence
@ -728,7 +729,7 @@ class FormattedExcinfo:
failindent = indentstr
return lines
def repr_locals(self, locals: Dict[str, object]) -> Optional["ReprLocals"]:
def repr_locals(self, locals: Mapping[str, object]) -> Optional["ReprLocals"]:
if self.showlocals:
lines = []
keys = [loc for loc in locals if loc[0] != "@"]

View File

@ -96,7 +96,7 @@ class PercentStyleMultiline(logging.PercentStyle):
formats the message as if each line were logged separately.
"""
def __init__(self, fmt: str, auto_indent: Union[int, str, bool]) -> None:
def __init__(self, fmt: str, auto_indent: Union[int, str, bool, None]) -> None:
super().__init__(fmt)
self._auto_indent = self._get_auto_indent(auto_indent)
@ -109,7 +109,7 @@ class PercentStyleMultiline(logging.PercentStyle):
return tmp
@staticmethod
def _get_auto_indent(auto_indent_option: Union[int, str, bool]) -> int:
def _get_auto_indent(auto_indent_option: Union[int, str, bool, None]) -> int:
"""Determines the current auto indentation setting
Specify auto indent behavior (on/off/fixed) by passing in
@ -139,7 +139,9 @@ class PercentStyleMultiline(logging.PercentStyle):
>0 (explicitly set indentation position).
"""
if type(auto_indent_option) is int:
if auto_indent_option is None:
return 0
elif type(auto_indent_option) is int:
return int(auto_indent_option)
elif type(auto_indent_option) is str:
try:
@ -732,7 +734,9 @@ class _LiveLoggingStreamHandler(logging.StreamHandler):
stream = None # type: TerminalReporter # type: ignore
def __init__(
self, terminal_reporter: TerminalReporter, capture_manager: CaptureManager
self,
terminal_reporter: TerminalReporter,
capture_manager: Optional[CaptureManager],
) -> None:
"""
:param _pytest.terminal.TerminalReporter terminal_reporter:

View File

@ -401,7 +401,7 @@ def _sys_snapshot():
@pytest.fixture
def _config_for_test():
def _config_for_test() -> Generator[Config, None, None]:
from _pytest.config import get_config
config = get_config()

View File

@ -712,6 +712,7 @@ def raises( # noqa: F811
fail(message)
# This doesn't work with mypy for now. Use fail.Exception instead.
raises.Exception = fail.Exception # type: ignore

View File

@ -4,6 +4,7 @@ import os
import queue
import sys
import textwrap
from typing import Tuple
from typing import Union
import py
@ -14,6 +15,7 @@ from _pytest._code.code import ExceptionChainRepr
from _pytest._code.code import ExceptionInfo
from _pytest._code.code import FormattedExcinfo
from _pytest._io import TerminalWriter
from _pytest.compat import TYPE_CHECKING
from _pytest.pytester import LineMatcher
try:
@ -23,6 +25,9 @@ except ImportError:
else:
invalidate_import_caches = getattr(importlib, "invalidate_caches", None)
if TYPE_CHECKING:
from _pytest._code.code import _TracebackStyle
@pytest.fixture
def limited_recursion_depth():
@ -40,10 +45,11 @@ def test_excinfo_simple() -> None:
assert info.type == ValueError
def test_excinfo_from_exc_info_simple():
def test_excinfo_from_exc_info_simple() -> None:
try:
raise ValueError
except ValueError as e:
assert e.__traceback__ is not None
info = _pytest._code.ExceptionInfo.from_exc_info((type(e), e, e.__traceback__))
assert info.type == ValueError
@ -317,25 +323,25 @@ def test_excinfo_exconly():
assert msg.endswith("world")
def test_excinfo_repr_str():
excinfo = pytest.raises(ValueError, h)
assert repr(excinfo) == "<ExceptionInfo ValueError() tblen=4>"
assert str(excinfo) == "<ExceptionInfo ValueError() tblen=4>"
def test_excinfo_repr_str() -> None:
excinfo1 = pytest.raises(ValueError, h)
assert repr(excinfo1) == "<ExceptionInfo ValueError() tblen=4>"
assert str(excinfo1) == "<ExceptionInfo ValueError() tblen=4>"
class CustomException(Exception):
def __repr__(self):
return "custom_repr"
def raises():
def raises() -> None:
raise CustomException()
excinfo = pytest.raises(CustomException, raises)
assert repr(excinfo) == "<ExceptionInfo custom_repr tblen=2>"
assert str(excinfo) == "<ExceptionInfo custom_repr tblen=2>"
excinfo2 = pytest.raises(CustomException, raises)
assert repr(excinfo2) == "<ExceptionInfo custom_repr tblen=2>"
assert str(excinfo2) == "<ExceptionInfo custom_repr tblen=2>"
def test_excinfo_for_later():
e = ExceptionInfo.for_later()
def test_excinfo_for_later() -> None:
e = ExceptionInfo[BaseException].for_later()
assert "for raises" in repr(e)
assert "for raises" in str(e)
@ -463,7 +469,7 @@ class TestFormattedExcinfo:
assert lines[0] == "| def f(x):"
assert lines[1] == " pass"
def test_repr_source_excinfo(self):
def test_repr_source_excinfo(self) -> None:
""" check if indentation is right """
pr = FormattedExcinfo()
excinfo = self.excinfo_from_exec(
@ -475,6 +481,7 @@ class TestFormattedExcinfo:
)
pr = FormattedExcinfo()
source = pr._getentrysource(excinfo.traceback[-1])
assert source is not None
lines = pr.get_source(source, 1, excinfo)
assert lines == [" def f():", "> assert 0", "E AssertionError"]
@ -522,17 +529,18 @@ raise ValueError()
assert repr.reprtraceback.reprentries[0].lines[0] == "> ???"
assert repr.chain[0][0].reprentries[0].lines[0] == "> ???"
def test_repr_local(self):
def test_repr_local(self) -> None:
p = FormattedExcinfo(showlocals=True)
loc = {"y": 5, "z": 7, "x": 3, "@x": 2, "__builtins__": {}}
reprlocals = p.repr_locals(loc)
assert reprlocals is not None
assert reprlocals.lines
assert reprlocals.lines[0] == "__builtins__ = <builtins>"
assert reprlocals.lines[1] == "x = 3"
assert reprlocals.lines[2] == "y = 5"
assert reprlocals.lines[3] == "z = 7"
def test_repr_local_with_error(self):
def test_repr_local_with_error(self) -> None:
class ObjWithErrorInRepr:
def __repr__(self):
raise NotImplementedError
@ -540,11 +548,12 @@ raise ValueError()
p = FormattedExcinfo(showlocals=True, truncate_locals=False)
loc = {"x": ObjWithErrorInRepr(), "__builtins__": {}}
reprlocals = p.repr_locals(loc)
assert reprlocals is not None
assert reprlocals.lines
assert reprlocals.lines[0] == "__builtins__ = <builtins>"
assert "[NotImplementedError() raised in repr()]" in reprlocals.lines[1]
def test_repr_local_with_exception_in_class_property(self):
def test_repr_local_with_exception_in_class_property(self) -> None:
class ExceptionWithBrokenClass(Exception):
# Type ignored because it's bypassed intentionally.
@property # type: ignore
@ -558,23 +567,26 @@ raise ValueError()
p = FormattedExcinfo(showlocals=True, truncate_locals=False)
loc = {"x": ObjWithErrorInRepr(), "__builtins__": {}}
reprlocals = p.repr_locals(loc)
assert reprlocals is not None
assert reprlocals.lines
assert reprlocals.lines[0] == "__builtins__ = <builtins>"
assert "[ExceptionWithBrokenClass() raised in repr()]" in reprlocals.lines[1]
def test_repr_local_truncated(self):
def test_repr_local_truncated(self) -> None:
loc = {"l": [i for i in range(10)]}
p = FormattedExcinfo(showlocals=True)
truncated_reprlocals = p.repr_locals(loc)
assert truncated_reprlocals is not None
assert truncated_reprlocals.lines
assert truncated_reprlocals.lines[0] == "l = [0, 1, 2, 3, 4, 5, ...]"
q = FormattedExcinfo(showlocals=True, truncate_locals=False)
full_reprlocals = q.repr_locals(loc)
assert full_reprlocals is not None
assert full_reprlocals.lines
assert full_reprlocals.lines[0] == "l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]"
def test_repr_tracebackentry_lines(self, importasmod):
def test_repr_tracebackentry_lines(self, importasmod) -> None:
mod = importasmod(
"""
def func1():
@ -602,11 +614,12 @@ raise ValueError()
assert not lines[4:]
loc = repr_entry.reprfileloc
assert loc is not None
assert loc.path == mod.__file__
assert loc.lineno == 3
# assert loc.message == "ValueError: hello"
def test_repr_tracebackentry_lines2(self, importasmod, tw_mock):
def test_repr_tracebackentry_lines2(self, importasmod, tw_mock) -> None:
mod = importasmod(
"""
def func1(m, x, y, z):
@ -618,6 +631,7 @@ raise ValueError()
entry = excinfo.traceback[-1]
p = FormattedExcinfo(funcargs=True)
reprfuncargs = p.repr_args(entry)
assert reprfuncargs is not None
assert reprfuncargs.args[0] == ("m", repr("m" * 90))
assert reprfuncargs.args[1] == ("x", "5")
assert reprfuncargs.args[2] == ("y", "13")
@ -625,13 +639,14 @@ raise ValueError()
p = FormattedExcinfo(funcargs=True)
repr_entry = p.repr_traceback_entry(entry)
assert repr_entry.reprfuncargs is not None
assert repr_entry.reprfuncargs.args == reprfuncargs.args
repr_entry.toterminal(tw_mock)
assert tw_mock.lines[0] == "m = " + repr("m" * 90)
assert tw_mock.lines[1] == "x = 5, y = 13"
assert tw_mock.lines[2] == "z = " + repr("z" * 120)
def test_repr_tracebackentry_lines_var_kw_args(self, importasmod, tw_mock):
def test_repr_tracebackentry_lines_var_kw_args(self, importasmod, tw_mock) -> None:
mod = importasmod(
"""
def func1(x, *y, **z):
@ -643,17 +658,19 @@ raise ValueError()
entry = excinfo.traceback[-1]
p = FormattedExcinfo(funcargs=True)
reprfuncargs = p.repr_args(entry)
assert reprfuncargs is not None
assert reprfuncargs.args[0] == ("x", repr("a"))
assert reprfuncargs.args[1] == ("y", repr(("b",)))
assert reprfuncargs.args[2] == ("z", repr({"c": "d"}))
p = FormattedExcinfo(funcargs=True)
repr_entry = p.repr_traceback_entry(entry)
assert repr_entry.reprfuncargs
assert repr_entry.reprfuncargs.args == reprfuncargs.args
repr_entry.toterminal(tw_mock)
assert tw_mock.lines[0] == "x = 'a', y = ('b',), z = {'c': 'd'}"
def test_repr_tracebackentry_short(self, importasmod):
def test_repr_tracebackentry_short(self, importasmod) -> None:
mod = importasmod(
"""
def func1():
@ -668,6 +685,7 @@ raise ValueError()
lines = reprtb.lines
basename = py.path.local(mod.__file__).basename
assert lines[0] == " func1()"
assert reprtb.reprfileloc is not None
assert basename in str(reprtb.reprfileloc.path)
assert reprtb.reprfileloc.lineno == 5
@ -677,6 +695,7 @@ raise ValueError()
lines = reprtb.lines
assert lines[0] == ' raise ValueError("hello")'
assert lines[1] == "E ValueError: hello"
assert reprtb.reprfileloc is not None
assert basename in str(reprtb.reprfileloc.path)
assert reprtb.reprfileloc.lineno == 3
@ -716,7 +735,7 @@ raise ValueError()
reprtb = p.repr_traceback(excinfo)
assert len(reprtb.reprentries) == 3
def test_traceback_short_no_source(self, importasmod, monkeypatch):
def test_traceback_short_no_source(self, importasmod, monkeypatch) -> None:
mod = importasmod(
"""
def func1():
@ -729,7 +748,7 @@ raise ValueError()
from _pytest._code.code import Code
monkeypatch.setattr(Code, "path", "bogus")
excinfo.traceback[0].frame.code.path = "bogus"
excinfo.traceback[0].frame.code.path = "bogus" # type: ignore[misc] # noqa: F821
p = FormattedExcinfo(style="short")
reprtb = p.repr_traceback_entry(excinfo.traceback[-2])
lines = reprtb.lines
@ -742,7 +761,7 @@ raise ValueError()
assert last_lines[0] == ' raise ValueError("hello")'
assert last_lines[1] == "E ValueError: hello"
def test_repr_traceback_and_excinfo(self, importasmod):
def test_repr_traceback_and_excinfo(self, importasmod) -> None:
mod = importasmod(
"""
def f(x):
@ -753,7 +772,8 @@ raise ValueError()
)
excinfo = pytest.raises(ValueError, mod.entry)
for style in ("long", "short"):
styles = ("long", "short") # type: Tuple[_TracebackStyle, ...]
for style in styles:
p = FormattedExcinfo(style=style)
reprtb = p.repr_traceback(excinfo)
assert len(reprtb.reprentries) == 2
@ -765,10 +785,11 @@ raise ValueError()
assert repr.chain[0][0]
assert len(repr.chain[0][0].reprentries) == len(reprtb.reprentries)
assert repr.reprcrash is not None
assert repr.reprcrash.path.endswith("mod.py")
assert repr.reprcrash.message == "ValueError: 0"
def test_repr_traceback_with_invalid_cwd(self, importasmod, monkeypatch):
def test_repr_traceback_with_invalid_cwd(self, importasmod, monkeypatch) -> None:
mod = importasmod(
"""
def f(x):
@ -787,7 +808,9 @@ raise ValueError()
def raiseos():
nonlocal raised
if sys._getframe().f_back.f_code.co_name == "checked_call":
upframe = sys._getframe().f_back
assert upframe is not None
if upframe.f_code.co_name == "checked_call":
# Only raise with expected calls, but not via e.g. inspect for
# py38-windows.
raised += 1
@ -831,7 +854,7 @@ raise ValueError()
assert tw_mock.lines[-1] == "content"
assert tw_mock.lines[-2] == ("-", "title")
def test_repr_excinfo_reprcrash(self, importasmod):
def test_repr_excinfo_reprcrash(self, importasmod) -> None:
mod = importasmod(
"""
def entry():
@ -840,6 +863,7 @@ raise ValueError()
)
excinfo = pytest.raises(ValueError, mod.entry)
repr = excinfo.getrepr()
assert repr.reprcrash is not None
assert repr.reprcrash.path.endswith("mod.py")
assert repr.reprcrash.lineno == 3
assert repr.reprcrash.message == "ValueError"
@ -864,7 +888,7 @@ raise ValueError()
assert reprtb.extraline == "!!! Recursion detected (same locals & position)"
assert str(reprtb)
def test_reprexcinfo_getrepr(self, importasmod):
def test_reprexcinfo_getrepr(self, importasmod) -> None:
mod = importasmod(
"""
def f(x):
@ -875,14 +899,15 @@ raise ValueError()
)
excinfo = pytest.raises(ValueError, mod.entry)
for style in ("short", "long", "no"):
styles = ("short", "long", "no") # type: Tuple[_TracebackStyle, ...]
for style in styles:
for showlocals in (True, False):
repr = excinfo.getrepr(style=style, showlocals=showlocals)
assert repr.reprtraceback.style == style
assert isinstance(repr, ExceptionChainRepr)
for repr in repr.chain:
assert repr[0].style == style
for r in repr.chain:
assert r[0].style == style
def test_reprexcinfo_unicode(self):
from _pytest._code.code import TerminalRepr

View File

@ -103,7 +103,7 @@ def test_warn_about_imminent_junit_family_default_change(testdir, junit_family):
result.stdout.fnmatch_lines([warning_msg])
def test_node_direct_ctor_warning():
def test_node_direct_ctor_warning() -> None:
class MockConfig:
pass
@ -112,8 +112,8 @@ def test_node_direct_ctor_warning():
DeprecationWarning,
match="Direct construction of .* has been deprecated, please use .*.from_parent.*",
) as w:
nodes.Node(name="test", config=ms, session=ms, nodeid="None")
assert w[0].lineno == inspect.currentframe().f_lineno - 1
nodes.Node(name="test", config=ms, session=ms, nodeid="None") # type: ignore
assert w[0].lineno == inspect.currentframe().f_lineno - 1 # type: ignore
assert w[0].filename == __file__

View File

@ -2,11 +2,11 @@ from dataclasses import dataclass
from dataclasses import field
def test_dataclasses():
def test_dataclasses() -> None:
@dataclass
class SimpleDataObject:
field_a: int = field()
field_b: int = field()
field_b: str = field()
left = SimpleDataObject(1, "b")
right = SimpleDataObject(1, "c")

View File

@ -2,11 +2,11 @@ from dataclasses import dataclass
from dataclasses import field
def test_dataclasses_with_attribute_comparison_off():
def test_dataclasses_with_attribute_comparison_off() -> None:
@dataclass
class SimpleDataObject:
field_a: int = field()
field_b: int = field(compare=False)
field_b: str = field(compare=False)
left = SimpleDataObject(1, "b")
right = SimpleDataObject(1, "c")

View File

@ -2,11 +2,11 @@ from dataclasses import dataclass
from dataclasses import field
def test_dataclasses_verbose():
def test_dataclasses_verbose() -> None:
@dataclass
class SimpleDataObject:
field_a: int = field()
field_b: int = field()
field_b: str = field()
left = SimpleDataObject(1, "b")
right = SimpleDataObject(1, "c")

View File

@ -2,18 +2,18 @@ from dataclasses import dataclass
from dataclasses import field
def test_comparing_two_different_data_classes():
def test_comparing_two_different_data_classes() -> None:
@dataclass
class SimpleDataObjectOne:
field_a: int = field()
field_b: int = field()
field_b: str = field()
@dataclass
class SimpleDataObjectTwo:
field_a: int = field()
field_b: int = field()
field_b: str = field()
left = SimpleDataObjectOne(1, "b")
right = SimpleDataObjectTwo(1, "c")
assert left != right
assert left != right # type: ignore[comparison-overlap] # noqa: F821

View File

@ -1,4 +1,6 @@
import pprint
from typing import List
from typing import Tuple
import pytest
@ -13,7 +15,7 @@ def pytest_generate_tests(metafunc):
@pytest.fixture(scope="session")
def checked_order():
order = []
order = [] # type: List[Tuple[str, str, str]]
yield order
pprint.pprint(order)

View File

@ -1,7 +1,8 @@
from typing import List
from unittest import IsolatedAsyncioTestCase # type: ignore
teardowns = []
teardowns = [] # type: List[None]
class AsyncArguments(IsolatedAsyncioTestCase):

View File

@ -1,10 +1,11 @@
"""Issue #7110"""
import asyncio
from typing import List
import asynctest
teardowns = []
teardowns = [] # type: List[None]
class Test(asynctest.TestCase):

View File

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

View File

@ -1,10 +1,11 @@
import logging
from typing import Any
from _pytest._io import TerminalWriter
from _pytest.logging import ColoredLevelFormatter
def test_coloredlogformatter():
def test_coloredlogformatter() -> None:
logfmt = "%(filename)-25s %(lineno)4d %(levelname)-8s %(message)s"
record = logging.LogRecord(
@ -14,7 +15,7 @@ def test_coloredlogformatter():
lineno=10,
msg="Test Message",
args=(),
exc_info=False,
exc_info=None,
)
class ColorConfig:
@ -35,7 +36,7 @@ def test_coloredlogformatter():
assert output == ("dummypath 10 INFO Test Message")
def test_multiline_message():
def test_multiline_message() -> None:
from _pytest.logging import PercentStyleMultiline
logfmt = "%(filename)-25s %(lineno)4d %(levelname)-8s %(message)s"
@ -47,8 +48,8 @@ def test_multiline_message():
lineno=10,
msg="Test Message line1\nline2",
args=(),
exc_info=False,
)
exc_info=None,
) # type: Any
# this is called by logging.Formatter.format
record.message = record.getMessage()
@ -124,7 +125,7 @@ def test_multiline_message():
)
def test_colored_short_level():
def test_colored_short_level() -> None:
logfmt = "%(levelname).1s %(message)s"
record = logging.LogRecord(
@ -134,7 +135,7 @@ def test_colored_short_level():
lineno=10,
msg="Test Message",
args=(),
exc_info=False,
exc_info=None,
)
class ColorConfig:

View File

@ -1,9 +1,12 @@
import io
import os
import re
from typing import cast
import pytest
from _pytest.capture import CaptureManager
from _pytest.pytester import Testdir
from _pytest.terminal import TerminalReporter
def test_nothing_logged(testdir):
@ -808,7 +811,7 @@ def test_log_file_unicode(testdir):
@pytest.mark.parametrize("has_capture_manager", [True, False])
def test_live_logging_suspends_capture(has_capture_manager, request):
def test_live_logging_suspends_capture(has_capture_manager: bool, request) -> None:
"""Test that capture manager is suspended when we emitting messages for live logging.
This tests the implementation calls instead of behavior because it is difficult/impossible to do it using
@ -835,8 +838,10 @@ def test_live_logging_suspends_capture(has_capture_manager, request):
def section(self, *args, **kwargs):
pass
out_file = DummyTerminal()
capture_manager = MockCaptureManager() if has_capture_manager else None
out_file = cast(TerminalReporter, DummyTerminal())
capture_manager = (
cast(CaptureManager, MockCaptureManager()) if has_capture_manager else None
)
handler = _LiveLoggingStreamHandler(out_file, capture_manager)
handler.set_when("call")
@ -849,7 +854,7 @@ def test_live_logging_suspends_capture(has_capture_manager, request):
assert MockCaptureManager.calls == ["enter disabled", "exit disabled"]
else:
assert MockCaptureManager.calls == []
assert out_file.getvalue() == "\nsome message\n"
assert cast(io.StringIO, out_file).getvalue() == "\nsome message\n"
def test_collection_live_logging(testdir):

View File

@ -428,10 +428,11 @@ class TestApprox:
assert a12 != approx(a21)
assert a21 != approx(a12)
def test_doctests(self, mocked_doctest_runner):
def test_doctests(self, mocked_doctest_runner) -> None:
import doctest
parser = doctest.DocTestParser()
assert approx.__doc__ is not None
test = parser.get_doctest(
approx.__doc__, {"approx": approx}, approx.__name__, None, None
)

View File

@ -1,6 +1,8 @@
import os
import sys
import textwrap
from typing import Any
from typing import Dict
import _pytest._code
import pytest
@ -698,7 +700,7 @@ class TestFunction:
class TestSorting:
def test_check_equality(self, testdir):
def test_check_equality(self, testdir) -> None:
modcol = testdir.getmodulecol(
"""
def test_pass(): pass
@ -720,10 +722,10 @@ class TestSorting:
assert fn1 != fn3
for fn in fn1, fn2, fn3:
assert fn != 3
assert fn != 3 # type: ignore[comparison-overlap] # noqa: F821
assert fn != modcol
assert fn != [1, 2, 3]
assert [1, 2, 3] != fn
assert fn != [1, 2, 3] # type: ignore[comparison-overlap] # noqa: F821
assert [1, 2, 3] != fn # type: ignore[comparison-overlap] # noqa: F821
assert modcol != fn
def test_allow_sane_sorting_for_decorators(self, testdir):
@ -1006,7 +1008,7 @@ class TestTracebackCutting:
assert "INTERNALERROR>" not in out
result.stdout.fnmatch_lines(["*ValueError: fail me*", "* 1 error in *"])
def test_filter_traceback_generated_code(self):
def test_filter_traceback_generated_code(self) -> None:
"""test that filter_traceback() works with the fact that
_pytest._code.code.Code.path attribute might return an str object.
In this case, one of the entries on the traceback was produced by
@ -1017,17 +1019,18 @@ class TestTracebackCutting:
from _pytest.python import filter_traceback
try:
ns = {}
ns = {} # type: Dict[str, Any]
exec("def foo(): raise ValueError", ns)
ns["foo"]()
except ValueError:
_, _, tb = sys.exc_info()
tb = _pytest._code.Traceback(tb)
assert isinstance(tb[-1].path, str)
assert not filter_traceback(tb[-1])
assert tb is not None
traceback = _pytest._code.Traceback(tb)
assert isinstance(traceback[-1].path, str)
assert not filter_traceback(traceback[-1])
def test_filter_traceback_path_no_longer_valid(self, testdir):
def test_filter_traceback_path_no_longer_valid(self, testdir) -> None:
"""test that filter_traceback() works with the fact that
_pytest._code.code.Code.path attribute might return an str object.
In this case, one of the files in the traceback no longer exists.
@ -1049,10 +1052,11 @@ class TestTracebackCutting:
except ValueError:
_, _, tb = sys.exc_info()
assert tb is not None
testdir.tmpdir.join("filter_traceback_entry_as_str.py").remove()
tb = _pytest._code.Traceback(tb)
assert isinstance(tb[-1].path, str)
assert filter_traceback(tb[-1])
traceback = _pytest._code.Traceback(tb)
assert isinstance(traceback[-1].path, str)
assert filter_traceback(traceback[-1])
class TestReportInfo:

View File

@ -1,10 +1,14 @@
from typing import Any
import pytest
from _pytest import python
from _pytest import runner
class TestOEJSKITSpecials:
def test_funcarg_non_pycollectobj(self, testdir, recwarn): # rough jstests usage
def test_funcarg_non_pycollectobj(
self, testdir, recwarn
) -> None: # rough jstests usage
testdir.makeconftest(
"""
import pytest
@ -28,13 +32,14 @@ class TestOEJSKITSpecials:
)
# this hook finds funcarg factories
rep = runner.collect_one_node(collector=modcol)
clscol = rep.result[0]
# TODO: Don't treat as Any.
clscol = rep.result[0] # type: Any
clscol.obj = lambda arg1: None
clscol.funcargs = {}
pytest._fillfuncargs(clscol)
assert clscol.funcargs["arg1"] == 42
def test_autouse_fixture(self, testdir, recwarn): # rough jstests usage
def test_autouse_fixture(self, testdir, recwarn) -> None: # rough jstests usage
testdir.makeconftest(
"""
import pytest
@ -61,20 +66,21 @@ class TestOEJSKITSpecials:
)
# this hook finds funcarg factories
rep = runner.collect_one_node(modcol)
clscol = rep.result[0]
# TODO: Don't treat as Any.
clscol = rep.result[0] # type: Any
clscol.obj = lambda: None
clscol.funcargs = {}
pytest._fillfuncargs(clscol)
assert not clscol.funcargs
def test_wrapped_getfslineno():
def test_wrapped_getfslineno() -> None:
def func():
pass
def wrap(f):
func.__wrapped__ = f
func.patchings = ["qwe"]
func.__wrapped__ = f # type: ignore
func.patchings = ["qwe"] # type: ignore
return func
@wrap
@ -87,14 +93,14 @@ def test_wrapped_getfslineno():
class TestMockDecoration:
def test_wrapped_getfuncargnames(self):
def test_wrapped_getfuncargnames(self) -> None:
from _pytest.compat import getfuncargnames
def wrap(f):
def func():
pass
func.__wrapped__ = f
func.__wrapped__ = f # type: ignore
return func
@wrap
@ -322,10 +328,11 @@ class TestReRunTests:
)
def test_pytestconfig_is_session_scoped():
def test_pytestconfig_is_session_scoped() -> None:
from _pytest.fixtures import pytestconfig
assert pytestconfig._pytestfixturefunction.scope == "session"
marker = pytestconfig._pytestfixturefunction # type: ignore
assert marker.scope == "session"
class TestNoselikeTestAttribute:

View File

@ -6,9 +6,9 @@ from _pytest.outcomes import Failed
class TestRaises:
def test_check_callable(self):
def test_check_callable(self) -> None:
with pytest.raises(TypeError, match=r".* must be callable"):
pytest.raises(RuntimeError, "int('qwe')")
pytest.raises(RuntimeError, "int('qwe')") # type: ignore[call-overload] # noqa: F821
def test_raises(self):
excinfo = pytest.raises(ValueError, int, "qwe")
@ -18,19 +18,19 @@ class TestRaises:
excinfo = pytest.raises(ValueError, int, "hello")
assert "invalid literal" in str(excinfo.value)
def test_raises_callable_no_exception(self):
def test_raises_callable_no_exception(self) -> None:
class A:
def __call__(self):
pass
try:
pytest.raises(ValueError, A())
except pytest.raises.Exception:
except pytest.fail.Exception:
pass
def test_raises_falsey_type_error(self):
def test_raises_falsey_type_error(self) -> None:
with pytest.raises(TypeError):
with pytest.raises(AssertionError, match=0):
with pytest.raises(AssertionError, match=0): # type: ignore[call-overload] # noqa: F821
raise AssertionError("ohai")
def test_raises_repr_inflight(self):
@ -126,23 +126,23 @@ class TestRaises:
result = testdir.runpytest()
result.stdout.fnmatch_lines(["*2 failed*"])
def test_noclass(self):
def test_noclass(self) -> None:
with pytest.raises(TypeError):
pytest.raises("wrong", lambda: None)
pytest.raises("wrong", lambda: None) # type: ignore[call-overload] # noqa: F821
def test_invalid_arguments_to_raises(self):
def test_invalid_arguments_to_raises(self) -> None:
with pytest.raises(TypeError, match="unknown"):
with pytest.raises(TypeError, unknown="bogus"):
with pytest.raises(TypeError, unknown="bogus"): # type: ignore[call-overload] # noqa: F821
raise ValueError()
def test_tuple(self):
with pytest.raises((KeyError, ValueError)):
raise KeyError("oops")
def test_no_raise_message(self):
def test_no_raise_message(self) -> None:
try:
pytest.raises(ValueError, int, "0")
except pytest.raises.Exception as e:
except pytest.fail.Exception as e:
assert e.msg == "DID NOT RAISE {}".format(repr(ValueError))
else:
assert False, "Expected pytest.raises.Exception"
@ -150,7 +150,7 @@ class TestRaises:
try:
with pytest.raises(ValueError):
pass
except pytest.raises.Exception as e:
except pytest.fail.Exception as e:
assert e.msg == "DID NOT RAISE {}".format(repr(ValueError))
else:
assert False, "Expected pytest.raises.Exception"
@ -252,7 +252,7 @@ class TestRaises:
):
pytest.raises(ClassLooksIterableException, lambda: None)
def test_raises_with_raising_dunder_class(self):
def test_raises_with_raising_dunder_class(self) -> None:
"""Test current behavior with regard to exceptions via __class__ (#4284)."""
class CrappyClass(Exception):
@ -262,12 +262,12 @@ class TestRaises:
assert False, "via __class__"
with pytest.raises(AssertionError) as excinfo:
with pytest.raises(CrappyClass()):
with pytest.raises(CrappyClass()): # type: ignore[call-overload] # noqa: F821
pass
assert "via __class__" in excinfo.value.args[0]
def test_raises_context_manager_with_kwargs(self):
with pytest.raises(TypeError) as excinfo:
with pytest.raises(Exception, foo="bar"):
with pytest.raises(Exception, foo="bar"): # type: ignore[call-overload] # noqa: F821
pass
assert "Unexpected keyword arguments" in str(excinfo.value)

View File

@ -279,9 +279,9 @@ class TestImportHookInstallation:
]
)
def test_register_assert_rewrite_checks_types(self):
def test_register_assert_rewrite_checks_types(self) -> None:
with pytest.raises(TypeError):
pytest.register_assert_rewrite(["pytest_tests_internal_non_existing"])
pytest.register_assert_rewrite(["pytest_tests_internal_non_existing"]) # type: ignore
pytest.register_assert_rewrite(
"pytest_tests_internal_non_existing", "pytest_tests_internal_non_existing2"
)
@ -326,8 +326,10 @@ class TestAssert_reprcompare:
def test_different_types(self):
assert callequal([0, 1], "foo") is None
def test_summary(self):
summary = callequal([0, 1], [0, 2])[0]
def test_summary(self) -> None:
lines = callequal([0, 1], [0, 2])
assert lines is not None
summary = lines[0]
assert len(summary) < 65
def test_text_diff(self):
@ -337,21 +339,24 @@ class TestAssert_reprcompare:
"+ spam",
]
def test_text_skipping(self):
def test_text_skipping(self) -> None:
lines = callequal("a" * 50 + "spam", "a" * 50 + "eggs")
assert lines is not None
assert "Skipping" in lines[1]
for line in lines:
assert "a" * 50 not in line
def test_text_skipping_verbose(self):
def test_text_skipping_verbose(self) -> None:
lines = callequal("a" * 50 + "spam", "a" * 50 + "eggs", verbose=1)
assert lines is not None
assert "- " + "a" * 50 + "eggs" in lines
assert "+ " + "a" * 50 + "spam" in lines
def test_multiline_text_diff(self):
def test_multiline_text_diff(self) -> None:
left = "foo\nspam\nbar"
right = "foo\neggs\nbar"
diff = callequal(left, right)
assert diff is not None
assert "- eggs" in diff
assert "+ spam" in diff
@ -376,8 +381,9 @@ class TestAssert_reprcompare:
"+ b'spam'",
]
def test_list(self):
def test_list(self) -> None:
expl = callequal([0, 1], [0, 2])
assert expl is not None
assert len(expl) > 1
@pytest.mark.parametrize(
@ -421,21 +427,25 @@ class TestAssert_reprcompare:
),
],
)
def test_iterable_full_diff(self, left, right, expected):
def test_iterable_full_diff(self, left, right, expected) -> None:
"""Test the full diff assertion failure explanation.
When verbose is False, then just a -v notice to get the diff is rendered,
when verbose is True, then ndiff of the pprint is returned.
"""
expl = callequal(left, right, verbose=0)
assert expl is not None
assert expl[-1] == "Use -v to get the full diff"
expl = "\n".join(callequal(left, right, verbose=1))
assert expl.endswith(textwrap.dedent(expected).strip())
verbose_expl = callequal(left, right, verbose=1)
assert verbose_expl is not None
assert "\n".join(verbose_expl).endswith(textwrap.dedent(expected).strip())
def test_list_different_lengths(self):
def test_list_different_lengths(self) -> None:
expl = callequal([0, 1], [0, 1, 2])
assert expl is not None
assert len(expl) > 1
expl = callequal([0, 1, 2], [0, 1])
assert expl is not None
assert len(expl) > 1
def test_list_wrap_for_multiple_lines(self):
@ -545,27 +555,31 @@ class TestAssert_reprcompare:
" }",
]
def test_dict(self):
def test_dict(self) -> None:
expl = callequal({"a": 0}, {"a": 1})
assert expl is not None
assert len(expl) > 1
def test_dict_omitting(self):
def test_dict_omitting(self) -> None:
lines = callequal({"a": 0, "b": 1}, {"a": 1, "b": 1})
assert lines is not None
assert lines[1].startswith("Omitting 1 identical item")
assert "Common items" not in lines
for line in lines[1:]:
assert "b" not in line
def test_dict_omitting_with_verbosity_1(self):
def test_dict_omitting_with_verbosity_1(self) -> None:
""" Ensure differing items are visible for verbosity=1 (#1512) """
lines = callequal({"a": 0, "b": 1}, {"a": 1, "b": 1}, verbose=1)
assert lines is not None
assert lines[1].startswith("Omitting 1 identical item")
assert lines[2].startswith("Differing items")
assert lines[3] == "{'a': 0} != {'a': 1}"
assert "Common items" not in lines
def test_dict_omitting_with_verbosity_2(self):
def test_dict_omitting_with_verbosity_2(self) -> None:
lines = callequal({"a": 0, "b": 1}, {"a": 1, "b": 1}, verbose=2)
assert lines is not None
assert lines[1].startswith("Common items:")
assert "Omitting" not in lines[1]
assert lines[2] == "{'b': 1}"
@ -614,15 +628,17 @@ class TestAssert_reprcompare:
"+ (1, 2, 3)",
]
def test_set(self):
def test_set(self) -> None:
expl = callequal({0, 1}, {0, 2})
assert expl is not None
assert len(expl) > 1
def test_frozenzet(self):
def test_frozenzet(self) -> None:
expl = callequal(frozenset([0, 1]), {0, 2})
assert expl is not None
assert len(expl) > 1
def test_Sequence(self):
def test_Sequence(self) -> None:
# Test comparing with a Sequence subclass.
class TestSequence(collections.abc.MutableSequence):
def __init__(self, iterable):
@ -644,15 +660,18 @@ class TestAssert_reprcompare:
pass
expl = callequal(TestSequence([0, 1]), list([0, 2]))
assert expl is not None
assert len(expl) > 1
def test_list_tuples(self):
def test_list_tuples(self) -> None:
expl = callequal([], [(1, 2)])
assert expl is not None
assert len(expl) > 1
expl = callequal([(1, 2)], [])
assert expl is not None
assert len(expl) > 1
def test_repr_verbose(self):
def test_repr_verbose(self) -> None:
class Nums:
def __init__(self, nums):
self.nums = nums
@ -669,21 +688,25 @@ class TestAssert_reprcompare:
assert callequal(nums_x, nums_y) is None
expl = callequal(nums_x, nums_y, verbose=1)
assert expl is not None
assert "+" + repr(nums_x) in expl
assert "-" + repr(nums_y) in expl
expl = callequal(nums_x, nums_y, verbose=2)
assert expl is not None
assert "+" + repr(nums_x) in expl
assert "-" + repr(nums_y) in expl
def test_list_bad_repr(self):
def test_list_bad_repr(self) -> None:
class A:
def __repr__(self):
raise ValueError(42)
expl = callequal([], [A()])
assert expl is not None
assert "ValueError" in "".join(expl)
expl = callequal({}, {"1": A()}, verbose=2)
assert expl is not None
assert expl[0].startswith("{} == <[ValueError")
assert "raised in repr" in expl[0]
assert expl[1:] == [
@ -707,9 +730,10 @@ class TestAssert_reprcompare:
expl = callequal(A(), "")
assert not expl
def test_repr_no_exc(self):
expl = " ".join(callequal("foo", "bar"))
assert "raised in repr()" not in expl
def test_repr_no_exc(self) -> None:
expl = callequal("foo", "bar")
assert expl is not None
assert "raised in repr()" not in " ".join(expl)
def test_unicode(self):
assert callequal("£€", "£") == [
@ -734,11 +758,12 @@ class TestAssert_reprcompare:
def test_format_nonascii_explanation(self):
assert util.format_explanation("λ")
def test_mojibake(self):
def test_mojibake(self) -> None:
# issue 429
left = b"e"
right = b"\xc3\xa9"
expl = callequal(left, right)
assert expl is not None
for line in expl:
assert isinstance(line, str)
msg = "\n".join(expl)
@ -791,7 +816,7 @@ class TestAssert_reprcompare_dataclass:
class TestAssert_reprcompare_attrsclass:
def test_attrs(self):
def test_attrs(self) -> None:
@attr.s
class SimpleDataObject:
field_a = attr.ib()
@ -801,12 +826,13 @@ class TestAssert_reprcompare_attrsclass:
right = SimpleDataObject(1, "c")
lines = callequal(left, right)
assert lines is not None
assert lines[1].startswith("Omitting 1 identical item")
assert "Matching attributes" not in lines
for line in lines[1:]:
assert "field_a" not in line
def test_attrs_verbose(self):
def test_attrs_verbose(self) -> None:
@attr.s
class SimpleDataObject:
field_a = attr.ib()
@ -816,6 +842,7 @@ class TestAssert_reprcompare_attrsclass:
right = SimpleDataObject(1, "c")
lines = callequal(left, right, verbose=2)
assert lines is not None
assert lines[1].startswith("Matching attributes:")
assert "Omitting" not in lines[1]
assert lines[2] == "['field_a']"
@ -824,12 +851,13 @@ class TestAssert_reprcompare_attrsclass:
@attr.s
class SimpleDataObject:
field_a = attr.ib()
field_b = attr.ib(**{ATTRS_EQ_FIELD: False})
field_b = attr.ib(**{ATTRS_EQ_FIELD: False}) # type: ignore
left = SimpleDataObject(1, "b")
right = SimpleDataObject(1, "b")
lines = callequal(left, right, verbose=2)
assert lines is not None
assert lines[1].startswith("Matching attributes:")
assert "Omitting" not in lines[1]
assert lines[2] == "['field_a']"
@ -946,8 +974,8 @@ class TestTruncateExplanation:
# to calculate that results have the expected length.
LINES_IN_TRUNCATION_MSG = 2
def test_doesnt_truncate_when_input_is_empty_list(self):
expl = []
def test_doesnt_truncate_when_input_is_empty_list(self) -> None:
expl = [] # type: List[str]
result = truncate._truncate_explanation(expl, max_lines=8, max_chars=100)
assert result == expl

View File

@ -9,6 +9,13 @@ import sys
import textwrap
import zipfile
from functools import partial
from typing import Dict
from typing import List
from typing import Mapping
from typing import Optional
from typing import Set
import py
import _pytest._code
import pytest
@ -25,24 +32,26 @@ from _pytest.pathlib import Path
from _pytest.pytester import Testdir
def rewrite(src):
def rewrite(src: str) -> ast.Module:
tree = ast.parse(src)
rewrite_asserts(tree, src.encode())
return tree
def getmsg(f, extra_ns=None, must_pass=False):
def getmsg(
f, extra_ns: Optional[Mapping[str, object]] = None, *, must_pass: bool = False
) -> Optional[str]:
"""Rewrite the assertions in f, run it, and get the failure message."""
src = "\n".join(_pytest._code.Code(f).source().lines)
mod = rewrite(src)
code = compile(mod, "<test>", "exec")
ns = {}
ns = {} # type: Dict[str, object]
if extra_ns is not None:
ns.update(extra_ns)
exec(code, ns)
func = ns[f.__name__]
try:
func()
func() # type: ignore[operator] # noqa: F821
except AssertionError:
if must_pass:
pytest.fail("shouldn't have raised")
@ -53,6 +62,7 @@ def getmsg(f, extra_ns=None, must_pass=False):
else:
if not must_pass:
pytest.fail("function didn't raise at all")
return None
class TestAssertionRewrite:
@ -98,10 +108,11 @@ class TestAssertionRewrite:
assert imp.col_offset == 0
assert isinstance(m.body[3], ast.Expr)
def test_dont_rewrite(self):
def test_dont_rewrite(self) -> None:
s = """'PYTEST_DONT_REWRITE'\nassert 14"""
m = rewrite(s)
assert len(m.body) == 2
assert isinstance(m.body[1], ast.Assert)
assert m.body[1].msg is None
def test_dont_rewrite_plugin(self, testdir):
@ -145,28 +156,28 @@ class TestAssertionRewrite:
monkeypatch.syspath_prepend(xdir)
testdir.runpytest().assert_outcomes(passed=1)
def test_name(self, request):
def f():
def test_name(self, request) -> None:
def f1() -> None:
assert False
assert getmsg(f) == "assert False"
assert getmsg(f1) == "assert False"
def f():
def f2() -> None:
f = False
assert f
assert getmsg(f) == "assert False"
assert getmsg(f2) == "assert False"
def f():
assert a_global # noqa
def f3() -> None:
assert a_global # type: ignore[name-defined] # noqa
assert getmsg(f, {"a_global": False}) == "assert False"
assert getmsg(f3, {"a_global": False}) == "assert False"
def f():
assert sys == 42
def f4() -> None:
assert sys == 42 # type: ignore[comparison-overlap] # noqa: F821
verbose = request.config.getoption("verbose")
msg = getmsg(f, {"sys": sys})
msg = getmsg(f4, {"sys": sys})
if verbose > 0:
assert msg == (
"assert <module 'sys' (built-in)> == 42\n"
@ -176,64 +187,74 @@ class TestAssertionRewrite:
else:
assert msg == "assert sys == 42"
def f():
assert cls == 42 # noqa: F821
def f5() -> None:
assert cls == 42 # type: ignore[name-defined] # noqa: F821
class X:
pass
msg = getmsg(f, {"cls": X}).splitlines()
msg = getmsg(f5, {"cls": X})
assert msg is not None
lines = msg.splitlines()
if verbose > 1:
assert msg == ["assert {!r} == 42".format(X), " +{!r}".format(X), " -42"]
assert lines == [
"assert {!r} == 42".format(X),
" +{!r}".format(X),
" -42",
]
elif verbose > 0:
assert msg == [
assert lines == [
"assert <class 'test_...e.<locals>.X'> == 42",
" +{!r}".format(X),
" -42",
]
else:
assert msg == ["assert cls == 42"]
assert lines == ["assert cls == 42"]
def test_assertrepr_compare_same_width(self, request):
def test_assertrepr_compare_same_width(self, request) -> None:
"""Should use same width/truncation with same initial width."""
def f():
def f() -> None:
assert "1234567890" * 5 + "A" == "1234567890" * 5 + "B"
msg = getmsg(f).splitlines()[0]
msg = getmsg(f)
assert msg is not None
line = msg.splitlines()[0]
if request.config.getoption("verbose") > 1:
assert msg == (
assert line == (
"assert '12345678901234567890123456789012345678901234567890A' "
"== '12345678901234567890123456789012345678901234567890B'"
)
else:
assert msg == (
assert line == (
"assert '123456789012...901234567890A' "
"== '123456789012...901234567890B'"
)
def test_dont_rewrite_if_hasattr_fails(self, request):
def test_dont_rewrite_if_hasattr_fails(self, request) -> None:
class Y:
""" A class whos getattr fails, but not with `AttributeError` """
def __getattr__(self, attribute_name):
raise KeyError()
def __repr__(self):
def __repr__(self) -> str:
return "Y"
def __init__(self):
def __init__(self) -> None:
self.foo = 3
def f():
assert cls().foo == 2 # noqa
def f() -> None:
assert cls().foo == 2 # type: ignore[name-defined] # noqa: F821
# XXX: looks like the "where" should also be there in verbose mode?!
message = getmsg(f, {"cls": Y}).splitlines()
msg = getmsg(f, {"cls": Y})
assert msg is not None
lines = msg.splitlines()
if request.config.getoption("verbose") > 0:
assert message == ["assert 3 == 2", " +3", " -2"]
assert lines == ["assert 3 == 2", " +3", " -2"]
else:
assert message == [
assert lines == [
"assert 3 == 2",
" + where 3 = Y.foo",
" + where Y = cls()",
@ -314,145 +335,145 @@ class TestAssertionRewrite:
assert result.ret == 1
result.stdout.fnmatch_lines(["*AssertionError: b'ohai!'", "*assert False"])
def test_boolop(self):
def f():
def test_boolop(self) -> None:
def f1() -> None:
f = g = False
assert f and g
assert getmsg(f) == "assert (False)"
assert getmsg(f1) == "assert (False)"
def f():
def f2() -> None:
f = True
g = False
assert f and g
assert getmsg(f) == "assert (True and False)"
assert getmsg(f2) == "assert (True and False)"
def f():
def f3() -> None:
f = False
g = True
assert f and g
assert getmsg(f) == "assert (False)"
assert getmsg(f3) == "assert (False)"
def f():
def f4() -> None:
f = g = False
assert f or g
assert getmsg(f) == "assert (False or False)"
assert getmsg(f4) == "assert (False or False)"
def f():
def f5() -> None:
f = g = False
assert not f and not g
getmsg(f, must_pass=True)
getmsg(f5, must_pass=True)
def x():
def x() -> bool:
return False
def f():
def f6() -> None:
assert x() and x()
assert (
getmsg(f, {"x": x})
getmsg(f6, {"x": x})
== """assert (False)
+ where False = x()"""
)
def f():
def f7() -> None:
assert False or x()
assert (
getmsg(f, {"x": x})
getmsg(f7, {"x": x})
== """assert (False or False)
+ where False = x()"""
)
def f():
def f8() -> None:
assert 1 in {} and 2 in {}
assert getmsg(f) == "assert (1 in {})"
assert getmsg(f8) == "assert (1 in {})"
def f():
def f9() -> None:
x = 1
y = 2
assert x in {1: None} and y in {}
assert getmsg(f) == "assert (1 in {1: None} and 2 in {})"
assert getmsg(f9) == "assert (1 in {1: None} and 2 in {})"
def f():
def f10() -> None:
f = True
g = False
assert f or g
getmsg(f, must_pass=True)
getmsg(f10, must_pass=True)
def f():
def f11() -> None:
f = g = h = lambda: True
assert f() and g() and h()
getmsg(f, must_pass=True)
getmsg(f11, must_pass=True)
def test_short_circuit_evaluation(self):
def f():
assert True or explode # noqa
def test_short_circuit_evaluation(self) -> None:
def f1() -> None:
assert True or explode # type: ignore[name-defined] # noqa: F821
getmsg(f, must_pass=True)
getmsg(f1, must_pass=True)
def f():
def f2() -> None:
x = 1
assert x == 1 or x == 2
getmsg(f, must_pass=True)
getmsg(f2, must_pass=True)
def test_unary_op(self):
def f():
def test_unary_op(self) -> None:
def f1() -> None:
x = True
assert not x
assert getmsg(f) == "assert not True"
assert getmsg(f1) == "assert not True"
def f():
def f2() -> None:
x = 0
assert ~x + 1
assert getmsg(f) == "assert (~0 + 1)"
assert getmsg(f2) == "assert (~0 + 1)"
def f():
def f3() -> None:
x = 3
assert -x + x
assert getmsg(f) == "assert (-3 + 3)"
assert getmsg(f3) == "assert (-3 + 3)"
def f():
def f4() -> None:
x = 0
assert +x + x
assert getmsg(f) == "assert (+0 + 0)"
assert getmsg(f4) == "assert (+0 + 0)"
def test_binary_op(self):
def f():
def test_binary_op(self) -> None:
def f1() -> None:
x = 1
y = -1
assert x + y
assert getmsg(f) == "assert (1 + -1)"
assert getmsg(f1) == "assert (1 + -1)"
def f():
def f2() -> None:
assert not 5 % 4
assert getmsg(f) == "assert not (5 % 4)"
assert getmsg(f2) == "assert not (5 % 4)"
def test_boolop_percent(self):
def f():
def test_boolop_percent(self) -> None:
def f1() -> None:
assert 3 % 2 and False
assert getmsg(f) == "assert ((3 % 2) and False)"
assert getmsg(f1) == "assert ((3 % 2) and False)"
def f():
def f2() -> None:
assert False or 4 % 2
assert getmsg(f) == "assert (False or (4 % 2))"
assert getmsg(f2) == "assert (False or (4 % 2))"
def test_at_operator_issue1290(self, testdir):
testdir.makepyfile(
@ -480,133 +501,133 @@ class TestAssertionRewrite:
)
testdir.runpytest().assert_outcomes(passed=1)
def test_call(self):
def g(a=42, *args, **kwargs):
def test_call(self) -> None:
def g(a=42, *args, **kwargs) -> bool:
return False
ns = {"g": g}
def f():
def f1() -> None:
assert g()
assert (
getmsg(f, ns)
getmsg(f1, ns)
== """assert False
+ where False = g()"""
)
def f():
def f2() -> None:
assert g(1)
assert (
getmsg(f, ns)
getmsg(f2, ns)
== """assert False
+ where False = g(1)"""
)
def f():
def f3() -> None:
assert g(1, 2)
assert (
getmsg(f, ns)
getmsg(f3, ns)
== """assert False
+ where False = g(1, 2)"""
)
def f():
def f4() -> None:
assert g(1, g=42)
assert (
getmsg(f, ns)
getmsg(f4, ns)
== """assert False
+ where False = g(1, g=42)"""
)
def f():
def f5() -> None:
assert g(1, 3, g=23)
assert (
getmsg(f, ns)
getmsg(f5, ns)
== """assert False
+ where False = g(1, 3, g=23)"""
)
def f():
def f6() -> None:
seq = [1, 2, 3]
assert g(*seq)
assert (
getmsg(f, ns)
getmsg(f6, ns)
== """assert False
+ where False = g(*[1, 2, 3])"""
)
def f():
def f7() -> None:
x = "a"
assert g(**{x: 2})
assert (
getmsg(f, ns)
getmsg(f7, ns)
== """assert False
+ where False = g(**{'a': 2})"""
)
def test_attribute(self):
def test_attribute(self) -> None:
class X:
g = 3
ns = {"x": X}
def f():
assert not x.g # noqa
def f1() -> None:
assert not x.g # type: ignore[name-defined] # noqa: F821
assert (
getmsg(f, ns)
getmsg(f1, ns)
== """assert not 3
+ where 3 = x.g"""
)
def f():
x.a = False # noqa
assert x.a # noqa
def f2() -> None:
x.a = False # type: ignore[name-defined] # noqa: F821
assert x.a # type: ignore[name-defined] # noqa: F821
assert (
getmsg(f, ns)
getmsg(f2, ns)
== """assert False
+ where False = x.a"""
)
def test_comparisons(self):
def f():
def test_comparisons(self) -> None:
def f1() -> None:
a, b = range(2)
assert b < a
assert getmsg(f) == """assert 1 < 0"""
assert getmsg(f1) == """assert 1 < 0"""
def f():
def f2() -> None:
a, b, c = range(3)
assert a > b > c
assert getmsg(f) == """assert 0 > 1"""
assert getmsg(f2) == """assert 0 > 1"""
def f():
def f3() -> None:
a, b, c = range(3)
assert a < b > c
assert getmsg(f) == """assert 1 > 2"""
assert getmsg(f3) == """assert 1 > 2"""
def f():
def f4() -> None:
a, b, c = range(3)
assert a < b <= c
getmsg(f, must_pass=True)
getmsg(f4, must_pass=True)
def f():
def f5() -> None:
a, b, c = range(3)
assert a < b
assert b < c
getmsg(f, must_pass=True)
getmsg(f5, must_pass=True)
def test_len(self, request):
def f():
@ -619,29 +640,29 @@ class TestAssertionRewrite:
else:
assert msg == "assert 10 == 11\n + where 10 = len([0, 1, 2, 3, 4, 5, ...])"
def test_custom_reprcompare(self, monkeypatch):
def my_reprcompare(op, left, right):
def test_custom_reprcompare(self, monkeypatch) -> None:
def my_reprcompare1(op, left, right) -> str:
return "42"
monkeypatch.setattr(util, "_reprcompare", my_reprcompare)
monkeypatch.setattr(util, "_reprcompare", my_reprcompare1)
def f():
def f1() -> None:
assert 42 < 3
assert getmsg(f) == "assert 42"
assert getmsg(f1) == "assert 42"
def my_reprcompare(op, left, right):
def my_reprcompare2(op, left, right) -> str:
return "{} {} {}".format(left, op, right)
monkeypatch.setattr(util, "_reprcompare", my_reprcompare)
monkeypatch.setattr(util, "_reprcompare", my_reprcompare2)
def f():
def f2() -> None:
assert 1 < 3 < 5 <= 4 < 7
assert getmsg(f) == "assert 5 <= 4"
assert getmsg(f2) == "assert 5 <= 4"
def test_assert_raising__bool__in_comparison(self):
def f():
def test_assert_raising__bool__in_comparison(self) -> None:
def f() -> None:
class A:
def __bool__(self):
raise ValueError(42)
@ -652,21 +673,25 @@ class TestAssertionRewrite:
def __repr__(self):
return "<MY42 object>"
def myany(x):
def myany(x) -> bool:
return False
assert myany(A() < 0)
assert "<MY42 object> < 0" in getmsg(f)
msg = getmsg(f)
assert msg is not None
assert "<MY42 object> < 0" in msg
def test_formatchar(self):
def f():
assert "%test" == "test"
def test_formatchar(self) -> None:
def f() -> None:
assert "%test" == "test" # type: ignore[comparison-overlap] # noqa: F821
assert getmsg(f).startswith("assert '%test' == 'test'")
msg = getmsg(f)
assert msg is not None
assert msg.startswith("assert '%test' == 'test'")
def test_custom_repr(self, request):
def f():
def test_custom_repr(self, request) -> None:
def f() -> None:
class Foo:
a = 1
@ -676,14 +701,16 @@ class TestAssertionRewrite:
f = Foo()
assert 0 == f.a
lines = util._format_lines([getmsg(f)])
msg = getmsg(f)
assert msg is not None
lines = util._format_lines([msg])
if request.config.getoption("verbose") > 0:
assert lines == ["assert 0 == 1\n +0\n -1"]
else:
assert lines == ["assert 0 == 1\n + where 1 = \\n{ \\n~ \\n}.a"]
def test_custom_repr_non_ascii(self):
def f():
def test_custom_repr_non_ascii(self) -> None:
def f() -> None:
class A:
name = "ä"
@ -694,6 +721,7 @@ class TestAssertionRewrite:
assert not a.name
msg = getmsg(f)
assert msg is not None
assert "UnicodeDecodeError" not in msg
assert "UnicodeEncodeError" not in msg
@ -895,6 +923,7 @@ def test_rewritten():
hook, "_warn_already_imported", lambda code, msg: warnings.append(msg)
)
spec = hook.find_spec("test_remember_rewritten_modules")
assert spec is not None
module = importlib.util.module_from_spec(spec)
hook.exec_module(module)
hook.mark_rewrite("test_remember_rewritten_modules")
@ -1007,7 +1036,7 @@ class TestAssertionRewriteHookDetails:
result = testdir.runpytest_subprocess()
result.assert_outcomes(passed=1)
def test_read_pyc(self, tmpdir):
def test_read_pyc(self, tmp_path: Path) -> None:
"""
Ensure that the `_read_pyc` can properly deal with corrupted pyc files.
In those circumstances it should just give up instead of generating
@ -1016,18 +1045,18 @@ class TestAssertionRewriteHookDetails:
import py_compile
from _pytest.assertion.rewrite import _read_pyc
source = tmpdir.join("source.py")
pyc = source + "c"
source = tmp_path / "source.py"
pyc = Path(str(source) + "c")
source.write("def test(): pass")
source.write_text("def test(): pass")
py_compile.compile(str(source), str(pyc))
contents = pyc.read(mode="rb")
contents = pyc.read_bytes()
strip_bytes = 20 # header is around 8 bytes, strip a little more
assert len(contents) > strip_bytes
pyc.write(contents[:strip_bytes], mode="wb")
pyc.write_bytes(contents[:strip_bytes])
assert _read_pyc(str(source), str(pyc)) is None # no error
assert _read_pyc(source, pyc) is None # no error
def test_reload_is_same_and_reloads(self, testdir: Testdir) -> None:
"""Reloading a (collected) module after change picks up the change."""
@ -1178,17 +1207,17 @@ def test_source_mtime_long_long(testdir, offset):
assert result.ret == 0
def test_rewrite_infinite_recursion(testdir, pytestconfig, monkeypatch):
def test_rewrite_infinite_recursion(testdir, pytestconfig, monkeypatch) -> None:
"""Fix infinite recursion when writing pyc files: if an import happens to be triggered when writing the pyc
file, this would cause another call to the hook, which would trigger another pyc writing, which could
trigger another import, and so on. (#3506)"""
from _pytest.assertion import rewrite
from _pytest.assertion import rewrite as rewritemod
testdir.syspathinsert()
testdir.makepyfile(test_foo="def test_foo(): pass")
testdir.makepyfile(test_bar="def test_bar(): pass")
original_write_pyc = rewrite._write_pyc
original_write_pyc = rewritemod._write_pyc
write_pyc_called = []
@ -1199,7 +1228,7 @@ def test_rewrite_infinite_recursion(testdir, pytestconfig, monkeypatch):
assert hook.find_spec("test_bar") is None
return original_write_pyc(*args, **kwargs)
monkeypatch.setattr(rewrite, "_write_pyc", spy_write_pyc)
monkeypatch.setattr(rewritemod, "_write_pyc", spy_write_pyc)
monkeypatch.setattr(sys, "dont_write_bytecode", False)
hook = AssertionRewritingHook(pytestconfig)
@ -1212,14 +1241,14 @@ def test_rewrite_infinite_recursion(testdir, pytestconfig, monkeypatch):
class TestEarlyRewriteBailout:
@pytest.fixture
def hook(self, pytestconfig, monkeypatch, testdir):
def hook(self, pytestconfig, monkeypatch, testdir) -> AssertionRewritingHook:
"""Returns a patched AssertionRewritingHook instance so we can configure its initial paths and track
if PathFinder.find_spec has been called.
"""
import importlib.machinery
self.find_spec_calls = []
self.initial_paths = set()
self.find_spec_calls = [] # type: List[str]
self.initial_paths = set() # type: Set[py.path.local]
class StubSession:
_initialpaths = self.initial_paths
@ -1229,17 +1258,17 @@ class TestEarlyRewriteBailout:
def spy_find_spec(name, path):
self.find_spec_calls.append(name)
return importlib.machinery.PathFinder.find_spec(name, path)
return importlib.machinery.PathFinder.find_spec(name, path) # type: ignore
hook = AssertionRewritingHook(pytestconfig)
# use default patterns, otherwise we inherit pytest's testing config
hook.fnpats[:] = ["test_*.py", "*_test.py"]
monkeypatch.setattr(hook, "_find_spec", spy_find_spec)
hook.set_session(StubSession())
hook.set_session(StubSession()) # type: ignore[arg-type] # noqa: F821
testdir.syspathinsert()
return hook
def test_basic(self, testdir, hook):
def test_basic(self, testdir, hook: AssertionRewritingHook) -> None:
"""
Ensure we avoid calling PathFinder.find_spec when we know for sure a certain
module will not be rewritten to optimize assertion rewriting (#3918).
@ -1272,7 +1301,9 @@ class TestEarlyRewriteBailout:
assert hook.find_spec("foobar") is not None
assert self.find_spec_calls == ["conftest", "test_foo", "foobar"]
def test_pattern_contains_subdirectories(self, testdir, hook):
def test_pattern_contains_subdirectories(
self, testdir, hook: AssertionRewritingHook
) -> None:
"""If one of the python_files patterns contain subdirectories ("tests/**.py") we can't bailout early
because we need to match with the full path, which can only be found by calling PathFinder.find_spec
"""
@ -1515,17 +1546,17 @@ def test_get_assertion_exprs(src, expected):
assert _get_assertion_exprs(src) == expected
def test_try_makedirs(monkeypatch, tmp_path):
def test_try_makedirs(monkeypatch, tmp_path: Path) -> None:
from _pytest.assertion.rewrite import try_makedirs
p = tmp_path / "foo"
# create
assert try_makedirs(str(p))
assert try_makedirs(p)
assert p.is_dir()
# already exist
assert try_makedirs(str(p))
assert try_makedirs(p)
# monkeypatch to simulate all error situations
def fake_mkdir(p, exist_ok=False, *, exc):
@ -1533,25 +1564,25 @@ def test_try_makedirs(monkeypatch, tmp_path):
raise exc
monkeypatch.setattr(os, "makedirs", partial(fake_mkdir, exc=FileNotFoundError()))
assert not try_makedirs(str(p))
assert not try_makedirs(p)
monkeypatch.setattr(os, "makedirs", partial(fake_mkdir, exc=NotADirectoryError()))
assert not try_makedirs(str(p))
assert not try_makedirs(p)
monkeypatch.setattr(os, "makedirs", partial(fake_mkdir, exc=PermissionError()))
assert not try_makedirs(str(p))
assert not try_makedirs(p)
err = OSError()
err.errno = errno.EROFS
monkeypatch.setattr(os, "makedirs", partial(fake_mkdir, exc=err))
assert not try_makedirs(str(p))
assert not try_makedirs(p)
# unhandled OSError should raise
err = OSError()
err.errno = errno.ECHILD
monkeypatch.setattr(os, "makedirs", partial(fake_mkdir, exc=err))
with pytest.raises(OSError) as exc_info:
try_makedirs(str(p))
try_makedirs(p)
assert exc_info.value.errno == errno.ECHILD

View File

@ -6,7 +6,9 @@ import sys
import textwrap
from io import UnsupportedOperation
from typing import BinaryIO
from typing import cast
from typing import Generator
from typing import TextIO
import pytest
from _pytest import capture
@ -1351,7 +1353,7 @@ def test_error_attribute_issue555(testdir):
not sys.platform.startswith("win") and sys.version_info[:2] >= (3, 6),
reason="only py3.6+ on windows",
)
def test_py36_windowsconsoleio_workaround_non_standard_streams():
def test_py36_windowsconsoleio_workaround_non_standard_streams() -> None:
"""
Ensure _py36_windowsconsoleio_workaround function works with objects that
do not implement the full ``io``-based stream protocol, for example execnet channels (#2666).
@ -1362,7 +1364,7 @@ def test_py36_windowsconsoleio_workaround_non_standard_streams():
def write(self, s):
pass
stream = DummyStream()
stream = cast(TextIO, DummyStream())
_py36_windowsconsoleio_workaround(stream)

View File

@ -634,13 +634,14 @@ class TestSession:
class Test_getinitialnodes:
def test_global_file(self, testdir, tmpdir):
def test_global_file(self, testdir, tmpdir) -> None:
x = tmpdir.ensure("x.py")
with tmpdir.as_cwd():
config = testdir.parseconfigure(x)
col = testdir.getnode(config, x)
assert isinstance(col, pytest.Module)
assert col.name == "x.py"
assert col.parent is not None
assert col.parent.parent is None
for col in col.listchain():
assert col.config is config

View File

@ -2,6 +2,9 @@ import os
import re
import sys
import textwrap
from typing import Dict
from typing import List
from typing import Sequence
import py.path
@ -264,9 +267,9 @@ class TestConfigCmdlineParsing:
class TestConfigAPI:
def test_config_trace(self, testdir):
def test_config_trace(self, testdir) -> None:
config = testdir.parseconfig()
values = []
values = [] # type: List[str]
config.trace.root.setwriter(values.append)
config.trace("hello")
assert len(values) == 1
@ -519,9 +522,9 @@ class TestConfigFromdictargs:
assert config.option.capture == "no"
assert config.args == args
def test_invocation_params_args(self, _sys_snapshot):
def test_invocation_params_args(self, _sys_snapshot) -> None:
"""Show that fromdictargs can handle args in their "orig" format"""
option_dict = {}
option_dict = {} # type: Dict[str, object]
args = ["-vvvv", "-s", "a", "b"]
config = Config.fromdictargs(option_dict, args)
@ -566,8 +569,8 @@ class TestConfigFromdictargs:
assert config.inicfg.get("should_not_be_set") is None
def test_options_on_small_file_do_not_blow_up(testdir):
def runfiletest(opts):
def test_options_on_small_file_do_not_blow_up(testdir) -> None:
def runfiletest(opts: Sequence[str]) -> None:
reprec = testdir.inline_run(*opts)
passed, skipped, failed = reprec.countoutcomes()
assert failed == 2
@ -580,19 +583,16 @@ def test_options_on_small_file_do_not_blow_up(testdir):
"""
)
for opts in (
[],
["-l"],
["-s"],
["--tb=no"],
["--tb=short"],
["--tb=long"],
["--fulltrace"],
["--traceconfig"],
["-v"],
["-v", "-v"],
):
runfiletest(opts + [path])
runfiletest([path])
runfiletest(["-l", path])
runfiletest(["-s", path])
runfiletest(["--tb=no", path])
runfiletest(["--tb=short", path])
runfiletest(["--tb=long", path])
runfiletest(["--fulltrace", path])
runfiletest(["--traceconfig", path])
runfiletest(["-v", path])
runfiletest(["-v", "-v", path])
def test_preparse_ordering_with_setuptools(testdir, monkeypatch):
@ -1360,7 +1360,7 @@ def test_invocation_args(testdir):
# args cannot be None
with pytest.raises(TypeError):
Config.InvocationParams(args=None, plugins=None, dir=Path())
Config.InvocationParams(args=None, plugins=None, dir=Path()) # type: ignore[arg-type] # noqa: F821
@pytest.mark.parametrize(

View File

@ -50,7 +50,7 @@ def custom_pdb_calls():
def interaction(self, *args):
called.append("interaction")
_pytest._CustomPdb = _CustomPdb
_pytest._CustomPdb = _CustomPdb # type: ignore
return called
@ -73,9 +73,9 @@ def custom_debugger_hook():
print("**CustomDebugger**")
called.append("set_trace")
_pytest._CustomDebugger = _CustomDebugger
_pytest._CustomDebugger = _CustomDebugger # type: ignore
yield called
del _pytest._CustomDebugger
del _pytest._CustomDebugger # type: ignore
class TestPDB:
@ -895,7 +895,7 @@ class TestDebuggingBreakpoints:
if sys.version_info >= (3, 7):
assert SUPPORTS_BREAKPOINT_BUILTIN is True
if sys.version_info.major == 3 and sys.version_info.minor == 5:
assert SUPPORTS_BREAKPOINT_BUILTIN is False
assert SUPPORTS_BREAKPOINT_BUILTIN is False # type: ignore[comparison-overlap]
@pytest.mark.skipif(
not SUPPORTS_BREAKPOINT_BUILTIN, reason="Requires breakpoint() builtin"

View File

@ -1,5 +1,7 @@
import inspect
import textwrap
from typing import Callable
from typing import Optional
import pytest
from _pytest.compat import MODULE_NOT_FOUND_ERROR
@ -1477,7 +1479,9 @@ class Broken:
@pytest.mark.parametrize( # pragma: no branch (lambdas are not called)
"stop", [None, _is_mocked, lambda f: None, lambda f: False, lambda f: True]
)
def test_warning_on_unwrap_of_broken_object(stop):
def test_warning_on_unwrap_of_broken_object(
stop: Optional[Callable[[object], object]]
) -> None:
bad_instance = Broken()
assert inspect.unwrap.__module__ == "inspect"
with _patch_unwrap_mock_aware():
@ -1486,7 +1490,7 @@ def test_warning_on_unwrap_of_broken_object(stop):
pytest.PytestWarning, match="^Got KeyError.* when unwrapping"
):
with pytest.raises(KeyError):
inspect.unwrap(bad_instance, stop=stop)
inspect.unwrap(bad_instance, stop=stop) # type: ignore[arg-type] # noqa: F821
assert inspect.unwrap.__module__ == "inspect"

View File

@ -1,16 +1,22 @@
import os
import platform
from datetime import datetime
from typing import cast
from typing import List
from typing import Tuple
from xml.dom import minidom
import py
import xmlschema
import pytest
from _pytest.compat import TYPE_CHECKING
from _pytest.config import Config
from _pytest.junitxml import bin_xml_escape
from _pytest.junitxml import LogXML
from _pytest.pathlib import Path
from _pytest.reports import BaseReport
from _pytest.reports import TestReport
from _pytest.store import Store
@ -860,10 +866,13 @@ def test_mangle_test_address():
assert newnames == ["a.my.py.thing", "Class", "method", "[a-1-::]"]
def test_dont_configure_on_slaves(tmpdir):
gotten = []
def test_dont_configure_on_slaves(tmpdir) -> None:
gotten = [] # type: List[object]
class FakeConfig:
if TYPE_CHECKING:
slaveinput = None
def __init__(self):
self.pluginmanager = self
self.option = self
@ -877,7 +886,7 @@ def test_dont_configure_on_slaves(tmpdir):
xmlpath = str(tmpdir.join("junix.xml"))
register = gotten.append
fake_config = FakeConfig()
fake_config = cast(Config, FakeConfig())
from _pytest import junitxml
junitxml.pytest_configure(fake_config)
@ -1089,18 +1098,18 @@ def test_double_colon_split_method_issue469(testdir, run_and_parse):
node.assert_attr(name="test_func[double::colon]")
def test_unicode_issue368(testdir):
def test_unicode_issue368(testdir) -> None:
path = testdir.tmpdir.join("test.xml")
log = LogXML(str(path), None)
ustr = "ВНИ!"
class Report(BaseReport):
longrepr = ustr
sections = []
sections = [] # type: List[Tuple[str, str]]
nodeid = "something"
location = "tests/filename.py", 42, "TestClass.method"
test_report = Report()
test_report = cast(TestReport, Report())
# hopefully this is not too brittle ...
log.pytest_sessionstart()
@ -1113,7 +1122,7 @@ def test_unicode_issue368(testdir):
node_reporter.append_skipped(test_report)
test_report.longrepr = "filename", 1, "Skipped: 卡嘣嘣"
node_reporter.append_skipped(test_report)
test_report.wasxfail = ustr
test_report.wasxfail = ustr # type: ignore[attr-defined] # noqa: F821
node_reporter.append_skipped(test_report)
log.pytest_sessionfinish()
@ -1363,17 +1372,17 @@ def test_fancy_items_regression(testdir, run_and_parse):
@parametrize_families
def test_global_properties(testdir, xunit_family):
def test_global_properties(testdir, xunit_family) -> None:
path = testdir.tmpdir.join("test_global_properties.xml")
log = LogXML(str(path), None, family=xunit_family)
class Report(BaseReport):
sections = []
sections = [] # type: List[Tuple[str, str]]
nodeid = "test_node_id"
log.pytest_sessionstart()
log.add_global_property("foo", 1)
log.add_global_property("bar", 2)
log.add_global_property("foo", "1")
log.add_global_property("bar", "2")
log.pytest_sessionfinish()
dom = minidom.parse(str(path))
@ -1397,19 +1406,19 @@ def test_global_properties(testdir, xunit_family):
assert actual == expected
def test_url_property(testdir):
def test_url_property(testdir) -> None:
test_url = "http://www.github.com/pytest-dev"
path = testdir.tmpdir.join("test_url_property.xml")
log = LogXML(str(path), None)
class Report(BaseReport):
longrepr = "FooBarBaz"
sections = []
sections = [] # type: List[Tuple[str, str]]
nodeid = "something"
location = "tests/filename.py", 42, "TestClass.method"
url = test_url
test_report = Report()
test_report = cast(TestReport, Report())
log.pytest_sessionstart()
node_reporter = log._opentestcase(test_report)

View File

@ -13,14 +13,14 @@ from _pytest.nodes import Node
class TestMark:
@pytest.mark.parametrize("attr", ["mark", "param"])
@pytest.mark.parametrize("modulename", ["py.test", "pytest"])
def test_pytest_exists_in_namespace_all(self, attr, modulename):
def test_pytest_exists_in_namespace_all(self, attr: str, modulename: str) -> None:
module = sys.modules[modulename]
assert attr in module.__all__
assert attr in module.__all__ # type: ignore
def test_pytest_mark_notcallable(self):
def test_pytest_mark_notcallable(self) -> None:
mark = Mark()
with pytest.raises(TypeError):
mark()
mark() # type: ignore[operator] # noqa: F821
def test_mark_with_param(self):
def some_function(abc):
@ -30,10 +30,11 @@ class TestMark:
pass
assert pytest.mark.foo(some_function) is some_function
assert pytest.mark.foo.with_args(some_function) is not 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 pytest.mark.foo(SomeClass) is SomeClass
assert pytest.mark.foo.with_args(SomeClass) is not SomeClass
assert pytest.mark.foo.with_args(SomeClass) is not SomeClass # type: ignore[comparison-overlap] # noqa: F821
def test_pytest_mark_name_starts_with_underscore(self):
mark = Mark()
@ -1044,9 +1045,9 @@ def test_markers_from_parametrize(testdir):
result.assert_outcomes(passed=4)
def test_pytest_param_id_requires_string():
def test_pytest_param_id_requires_string() -> None:
with pytest.raises(TypeError) as excinfo:
pytest.param(id=True)
pytest.param(id=True) # type: ignore[arg-type] # noqa: F821
(msg,) = excinfo.value.args
assert msg == "Expected id to be a string, got <class 'bool'>: True"

View File

@ -2,6 +2,8 @@ import os
import re
import sys
import textwrap
from typing import Dict
from typing import Generator
import pytest
from _pytest.compat import TYPE_CHECKING
@ -12,7 +14,7 @@ if TYPE_CHECKING:
@pytest.fixture
def mp():
def mp() -> Generator[MonkeyPatch, None, None]:
cwd = os.getcwd()
sys_path = list(sys.path)
yield MonkeyPatch()
@ -20,14 +22,14 @@ def mp():
os.chdir(cwd)
def test_setattr():
def test_setattr() -> None:
class A:
x = 1
monkeypatch = MonkeyPatch()
pytest.raises(AttributeError, monkeypatch.setattr, A, "notexists", 2)
monkeypatch.setattr(A, "y", 2, raising=False)
assert A.y == 2
assert A.y == 2 # type: ignore
monkeypatch.undo()
assert not hasattr(A, "y")
@ -49,17 +51,17 @@ class TestSetattrWithImportPath:
monkeypatch.setattr("os.path.abspath", lambda x: "hello2")
assert os.path.abspath("123") == "hello2"
def test_string_expression_class(self, monkeypatch):
def test_string_expression_class(self, monkeypatch: MonkeyPatch) -> None:
monkeypatch.setattr("_pytest.config.Config", 42)
import _pytest
assert _pytest.config.Config == 42
assert _pytest.config.Config == 42 # type: ignore
def test_unicode_string(self, monkeypatch):
def test_unicode_string(self, monkeypatch: MonkeyPatch) -> None:
monkeypatch.setattr("_pytest.config.Config", 42)
import _pytest
assert _pytest.config.Config == 42
assert _pytest.config.Config == 42 # type: ignore
monkeypatch.delattr("_pytest.config.Config")
def test_wrong_target(self, monkeypatch):
@ -73,10 +75,10 @@ class TestSetattrWithImportPath:
AttributeError, lambda: monkeypatch.setattr("os.path.qweqwe", None)
)
def test_unknown_attr_non_raising(self, monkeypatch):
def test_unknown_attr_non_raising(self, monkeypatch: MonkeyPatch) -> None:
# https://github.com/pytest-dev/pytest/issues/746
monkeypatch.setattr("os.path.qweqwe", 42, raising=False)
assert os.path.qweqwe == 42
assert os.path.qweqwe == 42 # type: ignore
def test_delattr(self, monkeypatch):
monkeypatch.delattr("os.path.abspath")
@ -123,8 +125,8 @@ def test_setitem():
assert d["x"] == 5
def test_setitem_deleted_meanwhile():
d = {}
def test_setitem_deleted_meanwhile() -> None:
d = {} # type: Dict[str, object]
monkeypatch = MonkeyPatch()
monkeypatch.setitem(d, "x", 2)
del d["x"]
@ -148,8 +150,8 @@ def test_setenv_deleted_meanwhile(before):
assert key not in os.environ
def test_delitem():
d = {"x": 1}
def test_delitem() -> None:
d = {"x": 1} # type: Dict[str, object]
monkeypatch = MonkeyPatch()
monkeypatch.delitem(d, "x")
assert "x" not in d
@ -241,7 +243,7 @@ def test_monkeypatch_plugin(testdir):
assert tuple(res) == (1, 0, 0), res
def test_syspath_prepend(mp):
def test_syspath_prepend(mp: MonkeyPatch):
old = list(sys.path)
mp.syspath_prepend("world")
mp.syspath_prepend("hello")
@ -253,7 +255,7 @@ def test_syspath_prepend(mp):
assert sys.path == old
def test_syspath_prepend_double_undo(mp):
def test_syspath_prepend_double_undo(mp: MonkeyPatch):
old_syspath = sys.path[:]
try:
mp.syspath_prepend("hello world")
@ -265,24 +267,24 @@ def test_syspath_prepend_double_undo(mp):
sys.path[:] = old_syspath
def test_chdir_with_path_local(mp, tmpdir):
def test_chdir_with_path_local(mp: MonkeyPatch, tmpdir):
mp.chdir(tmpdir)
assert os.getcwd() == tmpdir.strpath
def test_chdir_with_str(mp, tmpdir):
def test_chdir_with_str(mp: MonkeyPatch, tmpdir):
mp.chdir(tmpdir.strpath)
assert os.getcwd() == tmpdir.strpath
def test_chdir_undo(mp, tmpdir):
def test_chdir_undo(mp: MonkeyPatch, tmpdir):
cwd = os.getcwd()
mp.chdir(tmpdir)
mp.undo()
assert os.getcwd() == cwd
def test_chdir_double_undo(mp, tmpdir):
def test_chdir_double_undo(mp: MonkeyPatch, tmpdir):
mp.chdir(tmpdir.strpath)
mp.undo()
tmpdir.chdir()

View File

@ -2,6 +2,7 @@ import py
import pytest
from _pytest import nodes
from _pytest.pytester import Testdir
@pytest.mark.parametrize(
@ -17,19 +18,19 @@ from _pytest import nodes
("foo/bar", "foo/bar::TestBop", True),
),
)
def test_ischildnode(baseid, nodeid, expected):
def test_ischildnode(baseid: str, nodeid: str, expected: bool) -> None:
result = nodes.ischildnode(baseid, nodeid)
assert result is expected
def test_node_from_parent_disallowed_arguments():
def test_node_from_parent_disallowed_arguments() -> None:
with pytest.raises(TypeError, match="session is"):
nodes.Node.from_parent(None, session=None)
nodes.Node.from_parent(None, session=None) # type: ignore[arg-type] # noqa: F821
with pytest.raises(TypeError, match="config is"):
nodes.Node.from_parent(None, config=None)
nodes.Node.from_parent(None, config=None) # type: ignore[arg-type] # noqa: F821
def test_std_warn_not_pytestwarning(testdir):
def test_std_warn_not_pytestwarning(testdir: Testdir) -> None:
items = testdir.getitems(
"""
def test():
@ -40,24 +41,24 @@ def test_std_warn_not_pytestwarning(testdir):
items[0].warn(UserWarning("some warning"))
def test__check_initialpaths_for_relpath():
def test__check_initialpaths_for_relpath() -> None:
"""Ensure that it handles dirs, and does not always use dirname."""
cwd = py.path.local()
class FakeSession:
class FakeSession1:
_initialpaths = [cwd]
assert nodes._check_initialpaths_for_relpath(FakeSession, cwd) == ""
assert nodes._check_initialpaths_for_relpath(FakeSession1, cwd) == ""
sub = cwd.join("file")
class FakeSession:
class FakeSession2:
_initialpaths = [cwd]
assert nodes._check_initialpaths_for_relpath(FakeSession, sub) == "file"
assert nodes._check_initialpaths_for_relpath(FakeSession2, sub) == "file"
outside = py.path.local("/outside")
assert nodes._check_initialpaths_for_relpath(FakeSession, outside) is None
assert nodes._check_initialpaths_for_relpath(FakeSession2, outside) is None
def test_failure_with_changed_cwd(testdir):

View File

@ -1,10 +1,13 @@
from typing import List
from typing import Union
import pytest
class TestPasteCapture:
@pytest.fixture
def pastebinlist(self, monkeypatch, request):
pastebinlist = []
def pastebinlist(self, monkeypatch, request) -> List[Union[str, bytes]]:
pastebinlist = [] # type: List[Union[str, bytes]]
plugin = request.config.pluginmanager.getplugin("pastebin")
monkeypatch.setattr(plugin, "create_new_paste", pastebinlist.append)
return pastebinlist

View File

@ -1,6 +1,7 @@
import os
import sys
import types
from typing import List
import pytest
from _pytest.config import ExitCode
@ -10,7 +11,7 @@ from _pytest.main import Session
@pytest.fixture
def pytestpm():
def pytestpm() -> PytestPluginManager:
return PytestPluginManager()
@ -86,7 +87,7 @@ class TestPytestPluginInteractions:
config.pluginmanager.register(A())
assert len(values) == 2
def test_hook_tracing(self, _config_for_test):
def test_hook_tracing(self, _config_for_test) -> None:
pytestpm = _config_for_test.pluginmanager # fully initialized with plugins
saveindent = []
@ -99,7 +100,7 @@ class TestPytestPluginInteractions:
saveindent.append(pytestpm.trace.root.indent)
raise ValueError()
values = []
values = [] # type: List[str]
pytestpm.trace.root.setwriter(values.append)
undo = pytestpm.enable_tracing()
try:
@ -215,20 +216,20 @@ class TestPytestPluginManager:
assert pm.get_plugin("pytest_xyz") == mod
assert pm.is_registered(mod)
def test_consider_module(self, testdir, pytestpm):
def test_consider_module(self, testdir, pytestpm: PytestPluginManager) -> None:
testdir.syspathinsert()
testdir.makepyfile(pytest_p1="#")
testdir.makepyfile(pytest_p2="#")
mod = types.ModuleType("temp")
mod.pytest_plugins = ["pytest_p1", "pytest_p2"]
mod.__dict__["pytest_plugins"] = ["pytest_p1", "pytest_p2"]
pytestpm.consider_module(mod)
assert pytestpm.get_plugin("pytest_p1").__name__ == "pytest_p1"
assert pytestpm.get_plugin("pytest_p2").__name__ == "pytest_p2"
def test_consider_module_import_module(self, testdir, _config_for_test):
def test_consider_module_import_module(self, testdir, _config_for_test) -> None:
pytestpm = _config_for_test.pluginmanager
mod = types.ModuleType("x")
mod.pytest_plugins = "pytest_a"
mod.__dict__["pytest_plugins"] = "pytest_a"
aplugin = testdir.makepyfile(pytest_a="#")
reprec = testdir.make_hook_recorder(pytestpm)
testdir.syspathinsert(aplugin.dirpath())

View File

@ -32,7 +32,7 @@ class TestReportSerialization:
assert test_b_call.outcome == "passed"
assert test_b_call._to_json()["longrepr"] is None
def test_xdist_report_longrepr_reprcrash_130(self, testdir):
def test_xdist_report_longrepr_reprcrash_130(self, testdir) -> None:
"""Regarding issue pytest-xdist#130
This test came originally from test_remote.py in xdist (ca03269).
@ -50,6 +50,7 @@ class TestReportSerialization:
rep.longrepr.sections.append(added_section)
d = rep._to_json()
a = TestReport._from_json(d)
assert a.longrepr is not None
# Check assembled == rep
assert a.__dict__.keys() == rep.__dict__.keys()
for key in rep.__dict__.keys():
@ -67,7 +68,7 @@ class TestReportSerialization:
# Missing section attribute PR171
assert added_section in a.longrepr.sections
def test_reprentries_serialization_170(self, testdir):
def test_reprentries_serialization_170(self, testdir) -> None:
"""Regarding issue pytest-xdist#170
This test came originally from test_remote.py in xdist (ca03269).
@ -87,6 +88,7 @@ class TestReportSerialization:
rep = reports[1]
d = rep._to_json()
a = TestReport._from_json(d)
assert a.longrepr is not None
rep_entries = rep.longrepr.reprtraceback.reprentries
a_entries = a.longrepr.reprtraceback.reprentries
@ -102,7 +104,7 @@ class TestReportSerialization:
assert rep_entries[i].reprlocals.lines == a_entries[i].reprlocals.lines
assert rep_entries[i].style == a_entries[i].style
def test_reprentries_serialization_196(self, testdir):
def test_reprentries_serialization_196(self, testdir) -> None:
"""Regarding issue pytest-xdist#196
This test came originally from test_remote.py in xdist (ca03269).
@ -122,6 +124,7 @@ class TestReportSerialization:
rep = reports[1]
d = rep._to_json()
a = TestReport._from_json(d)
assert a.longrepr is not None
rep_entries = rep.longrepr.reprtraceback.reprentries
a_entries = a.longrepr.reprtraceback.reprentries
@ -157,6 +160,7 @@ class TestReportSerialization:
assert newrep.failed == rep.failed
assert newrep.skipped == rep.skipped
if newrep.skipped and not hasattr(newrep, "wasxfail"):
assert newrep.longrepr is not None
assert len(newrep.longrepr) == 3
assert newrep.outcome == rep.outcome
assert newrep.when == rep.when
@ -316,7 +320,7 @@ class TestReportSerialization:
# elsewhere and we do check the contents of the longrepr object after loading it.
loaded_report.longrepr.toterminal(tw_mock)
def test_chained_exceptions_no_reprcrash(self, testdir, tw_mock):
def test_chained_exceptions_no_reprcrash(self, testdir, tw_mock) -> None:
"""Regression test for tracebacks without a reprcrash (#5971)
This happens notably on exceptions raised by multiprocess.pool: the exception transfer
@ -367,7 +371,7 @@ class TestReportSerialization:
reports = reprec.getreports("pytest_runtest_logreport")
def check_longrepr(longrepr):
def check_longrepr(longrepr) -> None:
assert isinstance(longrepr, ExceptionChainRepr)
assert len(longrepr.chain) == 2
entry1, entry2 = longrepr.chain
@ -378,6 +382,7 @@ class TestReportSerialization:
assert "ValueError: value error" in str(tb2)
assert fileloc1 is None
assert fileloc2 is not None
assert fileloc2.message == "ValueError: value error"
# 3 reports: setup/call/teardown: get the call report
@ -394,6 +399,7 @@ class TestReportSerialization:
check_longrepr(loaded_report.longrepr)
# for same reasons as previous test, ensure we don't blow up here
assert loaded_report.longrepr is not None
loaded_report.longrepr.toterminal(tw_mock)
def test_report_prevent_ConftestImportFailure_hiding_exception(self, testdir):

View File

@ -2,6 +2,8 @@
test correct setup/teardowns at
module, class, and instance level
"""
from typing import List
import pytest
@ -242,12 +244,12 @@ def test_setup_funcarg_setup_when_outer_scope_fails(testdir):
@pytest.mark.parametrize("arg", ["", "arg"])
def test_setup_teardown_function_level_with_optional_argument(
testdir, monkeypatch, arg
):
testdir, monkeypatch, arg: str,
) -> None:
"""parameter to setup/teardown xunit-style functions parameter is now optional (#1728)."""
import sys
trace_setups_teardowns = []
trace_setups_teardowns = [] # type: List[str]
monkeypatch.setattr(
sys, "trace_setups_teardowns", trace_setups_teardowns, raising=False
)

View File

@ -98,7 +98,7 @@ class TestEvaluator:
expl = ev.getexplanation()
assert expl == "condition: not hasattr(os, 'murks')"
def test_marked_skip_with_not_string(self, testdir):
def test_marked_skip_with_not_string(self, testdir) -> None:
item = testdir.getitem(
"""
import pytest
@ -109,6 +109,7 @@ class TestEvaluator:
)
ev = MarkEvaluator(item, "skipif")
exc = pytest.raises(pytest.fail.Exception, ev.istrue)
assert exc.value.msg is not None
assert (
"""Failed: you need to specify reason=STRING when using booleans as conditions."""
in exc.value.msg
@ -869,7 +870,7 @@ def test_reportchars_all_error(testdir):
result.stdout.fnmatch_lines(["ERROR*test_foo*"])
def test_errors_in_xfail_skip_expressions(testdir):
def test_errors_in_xfail_skip_expressions(testdir) -> None:
testdir.makepyfile(
"""
import pytest
@ -886,7 +887,8 @@ def test_errors_in_xfail_skip_expressions(testdir):
)
result = testdir.runpytest()
markline = " ^"
if hasattr(sys, "pypy_version_info") and sys.pypy_version_info < (6,):
pypy_version_info = getattr(sys, "pypy_version_info", None)
if pypy_version_info is not None and pypy_version_info < (6,):
markline = markline[5:]
elif sys.version_info >= (3, 8) or hasattr(sys, "pypy_version_info"):
markline = markline[4:]

View File

@ -6,6 +6,7 @@ import os
import sys
import textwrap
from io import StringIO
from typing import cast
from typing import Dict
from typing import List
from typing import Tuple
@ -17,9 +18,11 @@ import _pytest.config
import _pytest.terminal
import pytest
from _pytest._io.wcwidth import wcswidth
from _pytest.config import Config
from _pytest.config import ExitCode
from _pytest.pytester import Testdir
from _pytest.reports import BaseReport
from _pytest.reports import CollectReport
from _pytest.terminal import _folded_skips
from _pytest.terminal import _get_line_with_reprcrash_message
from _pytest.terminal import _plugin_nameversions
@ -1043,17 +1046,17 @@ def test_color_yes_collection_on_non_atty(testdir, verbose):
assert "collected 10 items" in result.stdout.str()
def test_getreportopt():
def test_getreportopt() -> None:
from _pytest.terminal import _REPORTCHARS_DEFAULT
class Config:
class FakeConfig:
class Option:
reportchars = _REPORTCHARS_DEFAULT
disable_warnings = False
option = Option()
config = Config()
config = cast(Config, FakeConfig())
assert _REPORTCHARS_DEFAULT == "fE"
@ -1994,7 +1997,7 @@ class TestProgressWithTeardown:
output.stdout.re_match_lines([r"[\.E]{40} \s+ \[100%\]"])
def test_skip_reasons_folding():
def test_skip_reasons_folding() -> None:
path = "xyz"
lineno = 3
message = "justso"
@ -2003,28 +2006,28 @@ def test_skip_reasons_folding():
class X:
pass
ev1 = X()
ev1 = cast(CollectReport, X())
ev1.when = "execute"
ev1.skipped = True
ev1.longrepr = longrepr
ev2 = X()
ev2 = cast(CollectReport, X())
ev2.when = "execute"
ev2.longrepr = longrepr
ev2.skipped = True
# ev3 might be a collection report
ev3 = X()
ev3 = cast(CollectReport, X())
ev3.when = "collect"
ev3.longrepr = longrepr
ev3.skipped = True
values = _folded_skips(py.path.local(), [ev1, ev2, ev3])
assert len(values) == 1
num, fspath, lineno, reason = values[0]
num, fspath, lineno_, reason = values[0]
assert num == 3
assert fspath == path
assert lineno == lineno
assert lineno_ == lineno
assert reason == message
@ -2052,8 +2055,8 @@ def test_line_with_reprcrash(monkeypatch):
def check(msg, width, expected):
__tracebackhide__ = True
if msg:
rep.longrepr.reprcrash.message = msg
actual = _get_line_with_reprcrash_message(config, rep(), width)
rep.longrepr.reprcrash.message = msg # type: ignore
actual = _get_line_with_reprcrash_message(config, rep(), width) # type: ignore
assert actual == expected
if actual != "{} {}".format(mocked_verbose_word, mocked_pos):

View File

@ -1,6 +1,8 @@
import os
import stat
import sys
from typing import Callable
from typing import List
import attr
@ -263,10 +265,10 @@ class TestNumberedDir:
lockfile.unlink()
def test_lock_register_cleanup_removal(self, tmp_path):
def test_lock_register_cleanup_removal(self, tmp_path: Path) -> None:
lock = create_cleanup_lock(tmp_path)
registry = []
registry = [] # type: List[Callable[..., None]]
register_cleanup_lock_removal(lock, register=registry.append)
(cleanup_func,) = registry
@ -285,7 +287,7 @@ class TestNumberedDir:
assert not lock.exists()
def _do_cleanup(self, tmp_path):
def _do_cleanup(self, tmp_path: Path) -> None:
self.test_make(tmp_path)
cleanup_numbered_dir(
root=tmp_path,
@ -367,7 +369,7 @@ class TestRmRf:
assert not adir.is_dir()
def test_on_rm_rf_error(self, tmp_path):
def test_on_rm_rf_error(self, tmp_path: Path) -> None:
adir = tmp_path / "dir"
adir.mkdir()
@ -377,32 +379,32 @@ class TestRmRf:
# unknown exception
with pytest.warns(pytest.PytestWarning):
exc_info = (None, RuntimeError(), None)
on_rm_rf_error(os.unlink, str(fn), exc_info, start_path=tmp_path)
exc_info1 = (None, RuntimeError(), None)
on_rm_rf_error(os.unlink, str(fn), exc_info1, start_path=tmp_path)
assert fn.is_file()
# we ignore FileNotFoundError
exc_info = (None, FileNotFoundError(), None)
assert not on_rm_rf_error(None, str(fn), exc_info, start_path=tmp_path)
exc_info2 = (None, FileNotFoundError(), None)
assert not on_rm_rf_error(None, str(fn), exc_info2, start_path=tmp_path)
# unknown function
with pytest.warns(
pytest.PytestWarning,
match=r"^\(rm_rf\) unknown function None when removing .*foo.txt:\nNone: ",
):
exc_info = (None, PermissionError(), None)
on_rm_rf_error(None, str(fn), exc_info, start_path=tmp_path)
exc_info3 = (None, PermissionError(), None)
on_rm_rf_error(None, str(fn), exc_info3, start_path=tmp_path)
assert fn.is_file()
# ignored function
with pytest.warns(None) as warninfo:
exc_info = (None, PermissionError(), None)
on_rm_rf_error(os.open, str(fn), exc_info, start_path=tmp_path)
exc_info4 = (None, PermissionError(), None)
on_rm_rf_error(os.open, str(fn), exc_info4, start_path=tmp_path)
assert fn.is_file()
assert not [x.message for x in warninfo]
exc_info = (None, PermissionError(), None)
on_rm_rf_error(os.unlink, str(fn), exc_info, start_path=tmp_path)
exc_info5 = (None, PermissionError(), None)
on_rm_rf_error(os.unlink, str(fn), exc_info5, start_path=tmp_path)
assert not fn.is_file()

View File

@ -1,4 +1,5 @@
import gc
from typing import List
import pytest
from _pytest.config import ExitCode
@ -1158,13 +1159,13 @@ def test_trace(testdir, monkeypatch):
assert result.ret == 0
def test_pdb_teardown_called(testdir, monkeypatch):
def test_pdb_teardown_called(testdir, monkeypatch) -> None:
"""Ensure tearDown() is always called when --pdb is given in the command-line.
We delay the normal tearDown() calls when --pdb is given, so this ensures we are calling
tearDown() eventually to avoid memory leaks when using --pdb.
"""
teardowns = []
teardowns = [] # type: List[str]
monkeypatch.setattr(
pytest, "test_pdb_teardown_called_teardowns", teardowns, raising=False
)
@ -1194,11 +1195,11 @@ def test_pdb_teardown_called(testdir, monkeypatch):
@pytest.mark.parametrize("mark", ["@unittest.skip", "@pytest.mark.skip"])
def test_pdb_teardown_skipped(testdir, monkeypatch, mark):
def test_pdb_teardown_skipped(testdir, monkeypatch, mark: str) -> None:
"""
With --pdb, setUp and tearDown should not be called for skipped tests.
"""
tracked = []
tracked = [] # type: List[str]
monkeypatch.setattr(pytest, "test_pdb_teardown_skipped", tracked, raising=False)
testdir.makepyfile(

View File

@ -1,5 +1,8 @@
import os
import warnings
from typing import List
from typing import Optional
from typing import Tuple
import pytest
from _pytest.fixtures import FixtureRequest
@ -661,7 +664,9 @@ class TestStackLevel:
@pytest.fixture
def capwarn(self, testdir):
class CapturedWarnings:
captured = []
captured = (
[]
) # type: List[Tuple[warnings.WarningMessage, Optional[Tuple[str, int, str]]]]
@classmethod
def pytest_warning_recorded(cls, warning_message, when, nodeid, location):