Enable check_untyped_defs mypy option for testing/ too
This commit is contained in:
parent
71dfdca4df
commit
54ad048be7
|
@ -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
|
||||
|
|
|
@ -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] != "@"]
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__
|
||||
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
from typing import List
|
||||
from unittest import IsolatedAsyncioTestCase # type: ignore
|
||||
|
||||
|
||||
teardowns = []
|
||||
teardowns = [] # type: List[None]
|
||||
|
||||
|
||||
class AsyncArguments(IsolatedAsyncioTestCase):
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
"""Issue #7110"""
|
||||
import asyncio
|
||||
from typing import List
|
||||
|
||||
import asynctest
|
||||
|
||||
|
||||
teardowns = []
|
||||
teardowns = [] # type: List[None]
|
||||
|
||||
|
||||
class Test(asynctest.TestCase):
|
||||
|
|
|
@ -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())
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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:]
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue