2017-03-17 09:21:30 +08:00
|
|
|
from __future__ import absolute_import, division, print_function
|
2015-07-29 07:01:11 +08:00
|
|
|
import warnings
|
2016-12-20 20:36:57 +08:00
|
|
|
import re
|
2017-05-30 05:59:34 +08:00
|
|
|
|
2015-07-29 07:01:11 +08:00
|
|
|
import pytest
|
2015-08-05 06:27:13 +08:00
|
|
|
from _pytest.recwarn import WarningsRecorder
|
2015-07-29 07:01:11 +08:00
|
|
|
|
2009-09-06 22:59:39 +08:00
|
|
|
|
|
|
|
def test_recwarn_functional(testdir):
|
2018-05-23 22:48:46 +08:00
|
|
|
reprec = testdir.inline_runsource(
|
|
|
|
"""
|
2009-09-06 22:59:39 +08:00
|
|
|
import warnings
|
|
|
|
def test_method(recwarn):
|
|
|
|
warnings.warn("hello")
|
|
|
|
warn = recwarn.pop()
|
|
|
|
assert isinstance(warn.message, UserWarning)
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
2009-09-06 22:59:39 +08:00
|
|
|
res = reprec.countoutcomes()
|
2017-03-14 06:52:35 +08:00
|
|
|
assert tuple(res) == (1, 0, 0), res
|
2010-07-27 03:15:15 +08:00
|
|
|
|
2015-07-29 07:01:11 +08:00
|
|
|
|
|
|
|
class TestWarningsRecorderChecker(object):
|
2018-05-23 22:48:46 +08:00
|
|
|
|
2017-03-14 06:52:35 +08:00
|
|
|
def test_recording(self):
|
2015-07-29 07:01:11 +08:00
|
|
|
rec = WarningsRecorder()
|
|
|
|
with rec:
|
|
|
|
assert not rec.list
|
2017-12-27 11:47:26 +08:00
|
|
|
warnings.warn_explicit("hello", UserWarning, "xyz", 13)
|
2015-07-29 07:01:11 +08:00
|
|
|
assert len(rec.list) == 1
|
2017-12-27 11:47:26 +08:00
|
|
|
warnings.warn(DeprecationWarning("hello"))
|
2015-07-29 07:01:11 +08:00
|
|
|
assert len(rec.list) == 2
|
|
|
|
warn = rec.pop()
|
|
|
|
assert str(warn.message) == "hello"
|
2017-11-04 23:17:20 +08:00
|
|
|
values = rec.list
|
2015-07-29 07:01:11 +08:00
|
|
|
rec.clear()
|
|
|
|
assert len(rec.list) == 0
|
2017-11-04 23:17:20 +08:00
|
|
|
assert values is rec.list
|
2015-07-29 07:01:11 +08:00
|
|
|
pytest.raises(AssertionError, "rec.pop()")
|
|
|
|
|
|
|
|
def test_typechecking(self):
|
2015-08-05 06:27:13 +08:00
|
|
|
from _pytest.recwarn import WarningsChecker
|
2018-05-23 22:48:46 +08:00
|
|
|
|
2015-07-29 07:01:11 +08:00
|
|
|
with pytest.raises(TypeError):
|
|
|
|
WarningsChecker(5)
|
|
|
|
with pytest.raises(TypeError):
|
2018-05-23 22:48:46 +08:00
|
|
|
WarningsChecker(("hi", RuntimeWarning))
|
2015-07-29 07:01:11 +08:00
|
|
|
with pytest.raises(TypeError):
|
|
|
|
WarningsChecker([DeprecationWarning, RuntimeWarning])
|
|
|
|
|
|
|
|
def test_invalid_enter_exit(self):
|
|
|
|
# wrap this test in WarningsRecorder to ensure warning state gets reset
|
|
|
|
with WarningsRecorder():
|
|
|
|
with pytest.raises(RuntimeError):
|
|
|
|
rec = WarningsRecorder()
|
|
|
|
rec.__exit__(None, None, None) # can't exit before entering
|
|
|
|
|
|
|
|
with pytest.raises(RuntimeError):
|
|
|
|
rec = WarningsRecorder()
|
|
|
|
with rec:
|
|
|
|
with rec:
|
|
|
|
pass # can't enter twice
|
|
|
|
|
2009-09-06 22:59:39 +08:00
|
|
|
|
2015-11-27 02:27:20 +08:00
|
|
|
class TestDeprecatedCall(object):
|
|
|
|
"""test pytest.deprecated_call()"""
|
2009-09-06 22:59:39 +08:00
|
|
|
|
2015-12-09 08:40:05 +08:00
|
|
|
def dep(self, i, j=None):
|
2015-11-27 02:27:20 +08:00
|
|
|
if i == 0:
|
2018-05-23 22:48:46 +08:00
|
|
|
warnings.warn("is deprecated", DeprecationWarning, stacklevel=1)
|
2015-11-27 02:27:20 +08:00
|
|
|
return 42
|
2009-09-06 22:59:39 +08:00
|
|
|
|
2015-11-27 02:27:20 +08:00
|
|
|
def dep_explicit(self, i):
|
|
|
|
if i == 0:
|
2018-05-23 22:48:46 +08:00
|
|
|
warnings.warn_explicit(
|
|
|
|
"dep_explicit", category=DeprecationWarning, filename="hello", lineno=3
|
|
|
|
)
|
2015-09-21 21:18:29 +08:00
|
|
|
|
2015-07-29 07:01:11 +08:00
|
|
|
def test_deprecated_call_raises(self):
|
2015-11-27 02:27:20 +08:00
|
|
|
with pytest.raises(AssertionError) as excinfo:
|
2015-12-09 08:40:05 +08:00
|
|
|
pytest.deprecated_call(self.dep, 3, 5)
|
2018-05-23 22:48:46 +08:00
|
|
|
assert "Did not produce" in str(excinfo)
|
2015-07-29 07:01:11 +08:00
|
|
|
|
|
|
|
def test_deprecated_call(self):
|
2015-12-09 08:40:05 +08:00
|
|
|
pytest.deprecated_call(self.dep, 0, 5)
|
2015-07-29 07:01:11 +08:00
|
|
|
|
|
|
|
def test_deprecated_call_ret(self):
|
2015-11-27 02:27:20 +08:00
|
|
|
ret = pytest.deprecated_call(self.dep, 0)
|
2015-07-29 07:01:11 +08:00
|
|
|
assert ret == 42
|
|
|
|
|
|
|
|
def test_deprecated_call_preserves(self):
|
2017-12-27 11:47:26 +08:00
|
|
|
onceregistry = warnings.onceregistry.copy()
|
|
|
|
filters = warnings.filters[:]
|
|
|
|
warn = warnings.warn
|
|
|
|
warn_explicit = warnings.warn_explicit
|
2015-07-29 07:01:11 +08:00
|
|
|
self.test_deprecated_call_raises()
|
|
|
|
self.test_deprecated_call()
|
2017-12-27 11:47:26 +08:00
|
|
|
assert onceregistry == warnings.onceregistry
|
|
|
|
assert filters == warnings.filters
|
|
|
|
assert warn is warnings.warn
|
|
|
|
assert warn_explicit is warnings.warn_explicit
|
2015-07-29 07:01:11 +08:00
|
|
|
|
|
|
|
def test_deprecated_explicit_call_raises(self):
|
2015-11-27 02:27:20 +08:00
|
|
|
with pytest.raises(AssertionError):
|
|
|
|
pytest.deprecated_call(self.dep_explicit, 3)
|
2015-07-29 07:01:11 +08:00
|
|
|
|
|
|
|
def test_deprecated_explicit_call(self):
|
2015-11-27 02:27:20 +08:00
|
|
|
pytest.deprecated_call(self.dep_explicit, 0)
|
|
|
|
pytest.deprecated_call(self.dep_explicit, 0)
|
2015-07-29 07:01:11 +08:00
|
|
|
|
2018-05-23 22:48:46 +08:00
|
|
|
@pytest.mark.parametrize("mode", ["context_manager", "call"])
|
2017-06-07 09:25:15 +08:00
|
|
|
def test_deprecated_call_no_warning(self, mode):
|
|
|
|
"""Ensure deprecated_call() raises the expected failure when its block/function does
|
|
|
|
not raise a deprecation warning.
|
|
|
|
"""
|
2018-05-23 22:48:46 +08:00
|
|
|
|
2017-06-07 09:25:15 +08:00
|
|
|
def f():
|
|
|
|
pass
|
|
|
|
|
2018-05-23 22:48:46 +08:00
|
|
|
msg = "Did not produce DeprecationWarning or PendingDeprecationWarning"
|
2018-03-28 11:24:15 +08:00
|
|
|
with pytest.raises(AssertionError, match=msg):
|
2018-05-23 22:48:46 +08:00
|
|
|
if mode == "call":
|
2017-06-07 09:25:15 +08:00
|
|
|
pytest.deprecated_call(f)
|
|
|
|
else:
|
|
|
|
with pytest.deprecated_call():
|
|
|
|
f()
|
2015-09-21 21:18:29 +08:00
|
|
|
|
2018-05-23 22:48:46 +08:00
|
|
|
@pytest.mark.parametrize(
|
|
|
|
"warning_type", [PendingDeprecationWarning, DeprecationWarning]
|
|
|
|
)
|
|
|
|
@pytest.mark.parametrize("mode", ["context_manager", "call"])
|
|
|
|
@pytest.mark.parametrize("call_f_first", [True, False])
|
|
|
|
@pytest.mark.filterwarnings("ignore")
|
2017-06-07 09:25:15 +08:00
|
|
|
def test_deprecated_call_modes(self, warning_type, mode, call_f_first):
|
|
|
|
"""Ensure deprecated_call() captures a deprecation warning as expected inside its
|
|
|
|
block/function.
|
|
|
|
"""
|
2018-05-23 22:48:46 +08:00
|
|
|
|
2015-11-27 02:27:20 +08:00
|
|
|
def f():
|
2017-05-30 09:46:15 +08:00
|
|
|
warnings.warn(warning_type("hi"))
|
2017-06-07 09:25:15 +08:00
|
|
|
return 10
|
|
|
|
|
|
|
|
# ensure deprecated_call() can capture the warning even if it has already been triggered
|
|
|
|
if call_f_first:
|
|
|
|
assert f() == 10
|
2018-05-23 22:48:46 +08:00
|
|
|
if mode == "call":
|
2017-06-07 09:25:15 +08:00
|
|
|
assert pytest.deprecated_call(f) == 10
|
2017-05-30 09:46:15 +08:00
|
|
|
else:
|
|
|
|
with pytest.deprecated_call():
|
2017-06-07 09:25:15 +08:00
|
|
|
assert f() == 10
|
|
|
|
|
2018-05-23 22:48:46 +08:00
|
|
|
@pytest.mark.parametrize("mode", ["context_manager", "call"])
|
2017-06-07 09:25:15 +08:00
|
|
|
def test_deprecated_call_exception_is_raised(self, mode):
|
|
|
|
"""If the block of the code being tested by deprecated_call() raises an exception,
|
|
|
|
it must raise the exception undisturbed.
|
|
|
|
"""
|
2018-05-23 22:48:46 +08:00
|
|
|
|
2017-06-07 09:25:15 +08:00
|
|
|
def f():
|
2018-05-23 22:48:46 +08:00
|
|
|
raise ValueError("some exception")
|
2017-06-07 09:25:15 +08:00
|
|
|
|
2018-05-23 22:48:46 +08:00
|
|
|
with pytest.raises(ValueError, match="some exception"):
|
|
|
|
if mode == "call":
|
2017-06-07 09:25:15 +08:00
|
|
|
pytest.deprecated_call(f)
|
|
|
|
else:
|
|
|
|
with pytest.deprecated_call():
|
|
|
|
f()
|
2015-09-29 00:09:44 +08:00
|
|
|
|
2015-09-29 00:24:20 +08:00
|
|
|
def test_deprecated_call_specificity(self):
|
2018-05-23 22:48:46 +08:00
|
|
|
other_warnings = [
|
|
|
|
Warning,
|
|
|
|
UserWarning,
|
|
|
|
SyntaxWarning,
|
|
|
|
RuntimeWarning,
|
|
|
|
FutureWarning,
|
|
|
|
ImportWarning,
|
|
|
|
UnicodeWarning,
|
|
|
|
]
|
2015-09-29 00:24:20 +08:00
|
|
|
for warning in other_warnings:
|
2018-05-23 22:48:46 +08:00
|
|
|
|
2015-11-27 02:27:20 +08:00
|
|
|
def f():
|
2017-06-07 09:25:15 +08:00
|
|
|
warnings.warn(warning("hi"))
|
|
|
|
|
2015-09-29 00:24:20 +08:00
|
|
|
with pytest.raises(AssertionError):
|
|
|
|
pytest.deprecated_call(f)
|
2017-06-07 09:25:15 +08:00
|
|
|
with pytest.raises(AssertionError):
|
|
|
|
with pytest.deprecated_call():
|
|
|
|
f()
|
2015-09-29 00:24:20 +08:00
|
|
|
|
2015-07-29 07:01:11 +08:00
|
|
|
|
|
|
|
class TestWarns(object):
|
2018-05-23 22:48:46 +08:00
|
|
|
|
2015-07-29 07:01:11 +08:00
|
|
|
def test_strings(self):
|
|
|
|
# different messages, b/c Python suppresses multiple identical warnings
|
|
|
|
source1 = "warnings.warn('w1', RuntimeWarning)"
|
|
|
|
source2 = "warnings.warn('w2', RuntimeWarning)"
|
|
|
|
source3 = "warnings.warn('w3', RuntimeWarning)"
|
|
|
|
pytest.warns(RuntimeWarning, source1)
|
2018-05-23 22:48:46 +08:00
|
|
|
pytest.raises(pytest.fail.Exception, lambda: pytest.warns(UserWarning, source2))
|
2015-07-29 07:01:11 +08:00
|
|
|
pytest.warns(RuntimeWarning, source3)
|
|
|
|
|
|
|
|
def test_function(self):
|
2018-05-23 22:48:46 +08:00
|
|
|
pytest.warns(
|
|
|
|
SyntaxWarning, lambda msg: warnings.warn(msg, SyntaxWarning), "syntax"
|
|
|
|
)
|
2015-07-29 07:01:11 +08:00
|
|
|
|
|
|
|
def test_warning_tuple(self):
|
2018-05-23 22:48:46 +08:00
|
|
|
pytest.warns(
|
|
|
|
(RuntimeWarning, SyntaxWarning), lambda: warnings.warn("w1", RuntimeWarning)
|
|
|
|
)
|
|
|
|
pytest.warns(
|
|
|
|
(RuntimeWarning, SyntaxWarning), lambda: warnings.warn("w2", SyntaxWarning)
|
|
|
|
)
|
|
|
|
pytest.raises(
|
|
|
|
pytest.fail.Exception,
|
|
|
|
lambda: pytest.warns(
|
|
|
|
(RuntimeWarning, SyntaxWarning),
|
|
|
|
lambda: warnings.warn("w3", UserWarning),
|
|
|
|
),
|
|
|
|
)
|
2015-07-29 07:01:11 +08:00
|
|
|
|
|
|
|
def test_as_contextmanager(self):
|
|
|
|
with pytest.warns(RuntimeWarning):
|
|
|
|
warnings.warn("runtime", RuntimeWarning)
|
|
|
|
|
2016-12-20 20:36:57 +08:00
|
|
|
with pytest.warns(UserWarning):
|
|
|
|
warnings.warn("user", UserWarning)
|
|
|
|
|
|
|
|
with pytest.raises(pytest.fail.Exception) as excinfo:
|
2015-07-29 07:01:11 +08:00
|
|
|
with pytest.warns(RuntimeWarning):
|
|
|
|
warnings.warn("user", UserWarning)
|
2018-05-23 22:48:46 +08:00
|
|
|
excinfo.match(
|
|
|
|
r"DID NOT WARN. No warnings of type \(.+RuntimeWarning.+,\) was emitted. "
|
|
|
|
r"The list of emitted warnings is: \[UserWarning\('user',?\)\]."
|
|
|
|
)
|
2015-07-29 07:01:11 +08:00
|
|
|
|
2016-12-20 20:36:57 +08:00
|
|
|
with pytest.raises(pytest.fail.Exception) as excinfo:
|
2015-07-29 07:01:11 +08:00
|
|
|
with pytest.warns(UserWarning):
|
|
|
|
warnings.warn("runtime", RuntimeWarning)
|
2018-05-23 22:48:46 +08:00
|
|
|
excinfo.match(
|
|
|
|
r"DID NOT WARN. No warnings of type \(.+UserWarning.+,\) was emitted. "
|
|
|
|
r"The list of emitted warnings is: \[RuntimeWarning\('runtime',?\)\]."
|
|
|
|
)
|
2016-12-20 20:36:57 +08:00
|
|
|
|
|
|
|
with pytest.raises(pytest.fail.Exception) as excinfo:
|
|
|
|
with pytest.warns(UserWarning):
|
|
|
|
pass
|
2018-05-23 22:48:46 +08:00
|
|
|
excinfo.match(
|
|
|
|
r"DID NOT WARN. No warnings of type \(.+UserWarning.+,\) was emitted. "
|
|
|
|
r"The list of emitted warnings is: \[\]."
|
|
|
|
)
|
2016-12-20 20:36:57 +08:00
|
|
|
|
|
|
|
warning_classes = (UserWarning, FutureWarning)
|
|
|
|
with pytest.raises(pytest.fail.Exception) as excinfo:
|
|
|
|
with pytest.warns(warning_classes) as warninfo:
|
|
|
|
warnings.warn("runtime", RuntimeWarning)
|
|
|
|
warnings.warn("import", ImportWarning)
|
|
|
|
|
2018-05-23 22:48:46 +08:00
|
|
|
message_template = (
|
|
|
|
"DID NOT WARN. No warnings of type {0} was emitted. "
|
|
|
|
"The list of emitted warnings is: {1}."
|
|
|
|
)
|
|
|
|
excinfo.match(
|
|
|
|
re.escape(
|
|
|
|
message_template.format(
|
|
|
|
warning_classes, [each.message for each in warninfo]
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
2015-07-29 07:01:11 +08:00
|
|
|
|
|
|
|
def test_record(self):
|
|
|
|
with pytest.warns(UserWarning) as record:
|
|
|
|
warnings.warn("user", UserWarning)
|
|
|
|
|
|
|
|
assert len(record) == 1
|
|
|
|
assert str(record[0].message) == "user"
|
|
|
|
|
|
|
|
def test_record_only(self):
|
|
|
|
with pytest.warns(None) as record:
|
|
|
|
warnings.warn("user", UserWarning)
|
|
|
|
warnings.warn("runtime", RuntimeWarning)
|
2009-09-06 22:59:39 +08:00
|
|
|
|
2015-07-29 07:01:11 +08:00
|
|
|
assert len(record) == 2
|
|
|
|
assert str(record[0].message) == "user"
|
|
|
|
assert str(record[1].message) == "runtime"
|
2015-08-07 03:05:01 +08:00
|
|
|
|
2016-12-20 21:57:48 +08:00
|
|
|
def test_record_by_subclass(self):
|
|
|
|
with pytest.warns(Warning) as record:
|
|
|
|
warnings.warn("user", UserWarning)
|
|
|
|
warnings.warn("runtime", RuntimeWarning)
|
|
|
|
|
|
|
|
assert len(record) == 2
|
|
|
|
assert str(record[0].message) == "user"
|
|
|
|
assert str(record[1].message) == "runtime"
|
|
|
|
|
2017-07-17 07:25:10 +08:00
|
|
|
class MyUserWarning(UserWarning):
|
|
|
|
pass
|
2016-12-29 17:18:33 +08:00
|
|
|
|
2017-07-17 07:25:10 +08:00
|
|
|
class MyRuntimeWarning(RuntimeWarning):
|
|
|
|
pass
|
2016-12-29 16:34:21 +08:00
|
|
|
|
|
|
|
with pytest.warns((UserWarning, RuntimeWarning)) as record:
|
|
|
|
warnings.warn("user", MyUserWarning)
|
|
|
|
warnings.warn("runtime", MyRuntimeWarning)
|
|
|
|
|
|
|
|
assert len(record) == 2
|
|
|
|
assert str(record[0].message) == "user"
|
|
|
|
assert str(record[1].message) == "runtime"
|
|
|
|
|
2015-08-07 09:30:01 +08:00
|
|
|
def test_double_test(self, testdir):
|
2015-08-07 03:05:01 +08:00
|
|
|
"""If a test is run again, the warning should still be raised"""
|
2018-05-23 22:48:46 +08:00
|
|
|
testdir.makepyfile(
|
|
|
|
"""
|
2015-08-07 09:30:01 +08:00
|
|
|
import pytest
|
|
|
|
import warnings
|
|
|
|
|
|
|
|
@pytest.mark.parametrize('run', [1, 2])
|
|
|
|
def test(run):
|
|
|
|
with pytest.warns(RuntimeWarning):
|
|
|
|
warnings.warn("runtime", RuntimeWarning)
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
2015-08-07 09:30:01 +08:00
|
|
|
result = testdir.runpytest()
|
2018-05-23 22:48:46 +08:00
|
|
|
result.stdout.fnmatch_lines(["*2 passed in*"])
|
2017-08-22 19:48:29 +08:00
|
|
|
|
|
|
|
def test_match_regex(self):
|
2018-05-23 22:48:46 +08:00
|
|
|
with pytest.warns(UserWarning, match=r"must be \d+$"):
|
2017-08-22 19:48:29 +08:00
|
|
|
warnings.warn("value must be 42", UserWarning)
|
|
|
|
|
2017-09-06 07:13:08 +08:00
|
|
|
with pytest.raises(pytest.fail.Exception):
|
2018-05-23 22:48:46 +08:00
|
|
|
with pytest.warns(UserWarning, match=r"must be \d+$"):
|
2017-08-22 19:48:29 +08:00
|
|
|
warnings.warn("this is not here", UserWarning)
|
|
|
|
|
2017-09-06 07:13:08 +08:00
|
|
|
with pytest.raises(pytest.fail.Exception):
|
2018-05-23 22:48:46 +08:00
|
|
|
with pytest.warns(FutureWarning, match=r"must be \d+$"):
|
2017-09-06 07:13:08 +08:00
|
|
|
warnings.warn("value must be 42", UserWarning)
|
|
|
|
|
|
|
|
def test_one_from_multiple_warns(self):
|
2018-05-23 22:48:46 +08:00
|
|
|
with pytest.warns(UserWarning, match=r"aaa"):
|
2017-08-22 19:48:29 +08:00
|
|
|
warnings.warn("cccccccccc", UserWarning)
|
|
|
|
warnings.warn("bbbbbbbbbb", UserWarning)
|
|
|
|
warnings.warn("aaaaaaaaaa", UserWarning)
|
|
|
|
|
2017-09-06 07:13:08 +08:00
|
|
|
def test_none_of_multiple_warns(self):
|
|
|
|
with pytest.raises(pytest.fail.Exception):
|
2018-05-23 22:48:46 +08:00
|
|
|
with pytest.warns(UserWarning, match=r"aaa"):
|
2017-08-22 19:48:29 +08:00
|
|
|
warnings.warn("bbbbbbbbbb", UserWarning)
|
|
|
|
warnings.warn("cccccccccc", UserWarning)
|