Use a hack to make typing of pytest.fail.Exception & co work
Mypy currently is unable to handle assigning attributes on function: https://github.com/python/mypy/issues/2087. pytest uses this for the outcome exceptions -- `pytest.fail.Exception`, `pytest.exit.Exception` etc, and this is the canonical name by which they are referred. Initially we started working around this with type: ignores, and later by switching e.g. `pytest.fail.Exception` with the direct exception `Failed`. But this causes a lot of churn and is not as nice. And I also found that some code relies on it, in skipping.py: def pytest_configure(config): if config.option.runxfail: # yay a hack import pytest old = pytest.xfail config._cleanup.append(lambda: setattr(pytest, "xfail", old)) def nop(*args, **kwargs): pass nop.Exception = xfail.Exception setattr(pytest, "xfail", nop) ... So it seems better to support it. Use a hack to make it work. The rest of the commit rolls back all of the workarounds we added up to now. `pytest.raises.Exception` also exists, but it's not used much so I kept it as-is for now. Hopefully in the future mypy supports this and this ugliness can be removed.
This commit is contained in:
@@ -3,7 +3,6 @@ import warnings
|
||||
from typing import Optional
|
||||
|
||||
import pytest
|
||||
from _pytest.outcomes import Failed
|
||||
from _pytest.recwarn import WarningsRecorder
|
||||
|
||||
|
||||
@@ -89,7 +88,7 @@ class TestDeprecatedCall:
|
||||
)
|
||||
|
||||
def test_deprecated_call_raises(self) -> None:
|
||||
with pytest.raises(Failed, match="No warnings of type"):
|
||||
with pytest.raises(pytest.fail.Exception, match="No warnings of type"):
|
||||
pytest.deprecated_call(self.dep, 3, 5)
|
||||
|
||||
def test_deprecated_call(self) -> None:
|
||||
@@ -114,7 +113,7 @@ class TestDeprecatedCall:
|
||||
assert warn_explicit is warnings.warn_explicit
|
||||
|
||||
def test_deprecated_explicit_call_raises(self) -> None:
|
||||
with pytest.raises(Failed):
|
||||
with pytest.raises(pytest.fail.Exception):
|
||||
pytest.deprecated_call(self.dep_explicit, 3)
|
||||
|
||||
def test_deprecated_explicit_call(self) -> None:
|
||||
@@ -131,7 +130,7 @@ class TestDeprecatedCall:
|
||||
pass
|
||||
|
||||
msg = "No warnings of type (.*DeprecationWarning.*, .*PendingDeprecationWarning.*)"
|
||||
with pytest.raises(Failed, match=msg):
|
||||
with pytest.raises(pytest.fail.Exception, match=msg):
|
||||
if mode == "call":
|
||||
pytest.deprecated_call(f)
|
||||
else:
|
||||
@@ -193,9 +192,9 @@ class TestDeprecatedCall:
|
||||
def f():
|
||||
warnings.warn(warning("hi"))
|
||||
|
||||
with pytest.raises(Failed):
|
||||
with pytest.raises(pytest.fail.Exception):
|
||||
pytest.deprecated_call(f)
|
||||
with pytest.raises(Failed):
|
||||
with pytest.raises(pytest.fail.Exception):
|
||||
with pytest.deprecated_call():
|
||||
f()
|
||||
|
||||
@@ -203,7 +202,7 @@ class TestDeprecatedCall:
|
||||
with pytest.deprecated_call(match=r"must be \d+$"):
|
||||
warnings.warn("value must be 42", DeprecationWarning)
|
||||
|
||||
with pytest.raises(Failed):
|
||||
with pytest.raises(pytest.fail.Exception):
|
||||
with pytest.deprecated_call(match=r"must be \d+$"):
|
||||
warnings.warn("this is not here", DeprecationWarning)
|
||||
|
||||
@@ -217,7 +216,7 @@ class TestWarns:
|
||||
def test_several_messages(self) -> None:
|
||||
# different messages, b/c Python suppresses multiple identical warnings
|
||||
pytest.warns(RuntimeWarning, lambda: warnings.warn("w1", RuntimeWarning))
|
||||
with pytest.raises(Failed):
|
||||
with pytest.raises(pytest.fail.Exception):
|
||||
pytest.warns(UserWarning, lambda: warnings.warn("w2", RuntimeWarning))
|
||||
pytest.warns(RuntimeWarning, lambda: warnings.warn("w3", RuntimeWarning))
|
||||
|
||||
@@ -234,7 +233,7 @@ class TestWarns:
|
||||
(RuntimeWarning, SyntaxWarning), lambda: warnings.warn("w2", SyntaxWarning)
|
||||
)
|
||||
pytest.raises(
|
||||
Failed,
|
||||
pytest.fail.Exception,
|
||||
lambda: pytest.warns(
|
||||
(RuntimeWarning, SyntaxWarning),
|
||||
lambda: warnings.warn("w3", UserWarning),
|
||||
@@ -248,7 +247,7 @@ class TestWarns:
|
||||
with pytest.warns(UserWarning):
|
||||
warnings.warn("user", UserWarning)
|
||||
|
||||
with pytest.raises(Failed) as excinfo:
|
||||
with pytest.raises(pytest.fail.Exception) as excinfo:
|
||||
with pytest.warns(RuntimeWarning):
|
||||
warnings.warn("user", UserWarning)
|
||||
excinfo.match(
|
||||
@@ -256,7 +255,7 @@ class TestWarns:
|
||||
r"The list of emitted warnings is: \[UserWarning\('user',?\)\]."
|
||||
)
|
||||
|
||||
with pytest.raises(Failed) as excinfo:
|
||||
with pytest.raises(pytest.fail.Exception) as excinfo:
|
||||
with pytest.warns(UserWarning):
|
||||
warnings.warn("runtime", RuntimeWarning)
|
||||
excinfo.match(
|
||||
@@ -264,7 +263,7 @@ class TestWarns:
|
||||
r"The list of emitted warnings is: \[RuntimeWarning\('runtime',?\)\]."
|
||||
)
|
||||
|
||||
with pytest.raises(Failed) as excinfo:
|
||||
with pytest.raises(pytest.fail.Exception) as excinfo:
|
||||
with pytest.warns(UserWarning):
|
||||
pass
|
||||
excinfo.match(
|
||||
@@ -273,7 +272,7 @@ class TestWarns:
|
||||
)
|
||||
|
||||
warning_classes = (UserWarning, FutureWarning)
|
||||
with pytest.raises(Failed) as excinfo:
|
||||
with pytest.raises(pytest.fail.Exception) as excinfo:
|
||||
with pytest.warns(warning_classes) as warninfo:
|
||||
warnings.warn("runtime", RuntimeWarning)
|
||||
warnings.warn("import", ImportWarning)
|
||||
@@ -349,11 +348,11 @@ class TestWarns:
|
||||
with pytest.warns(UserWarning, match=r"must be \d+$"):
|
||||
warnings.warn("value must be 42", UserWarning)
|
||||
|
||||
with pytest.raises(Failed):
|
||||
with pytest.raises(pytest.fail.Exception):
|
||||
with pytest.warns(UserWarning, match=r"must be \d+$"):
|
||||
warnings.warn("this is not here", UserWarning)
|
||||
|
||||
with pytest.raises(Failed):
|
||||
with pytest.raises(pytest.fail.Exception):
|
||||
with pytest.warns(FutureWarning, match=r"must be \d+$"):
|
||||
warnings.warn("value must be 42", UserWarning)
|
||||
|
||||
@@ -364,7 +363,7 @@ class TestWarns:
|
||||
warnings.warn("aaaaaaaaaa", UserWarning)
|
||||
|
||||
def test_none_of_multiple_warns(self) -> None:
|
||||
with pytest.raises(Failed):
|
||||
with pytest.raises(pytest.fail.Exception):
|
||||
with pytest.warns(UserWarning, match=r"aaa"):
|
||||
warnings.warn("bbbbbbbbbb", UserWarning)
|
||||
warnings.warn("cccccccccc", UserWarning)
|
||||
|
||||
Reference in New Issue
Block a user