Merge pull request #2303 from nicoddemus/recwarn-refactor
Refactor recwarn to use warnings.catch_warnings instead of custom code
This commit is contained in:
commit
5482dfe0f3
|
@ -6,11 +6,10 @@ import py
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
import pytest
|
import pytest
|
||||||
from collections import namedtuple
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.yield_fixture
|
@pytest.yield_fixture
|
||||||
def recwarn(request):
|
def recwarn():
|
||||||
"""Return a WarningsRecorder instance that provides these methods:
|
"""Return a WarningsRecorder instance that provides these methods:
|
||||||
|
|
||||||
* ``pop(category=None)``: return last warning matching the category.
|
* ``pop(category=None)``: return last warning matching the category.
|
||||||
|
@ -115,19 +114,14 @@ def warns(expected_warning, *args, **kwargs):
|
||||||
return func(*args[1:], **kwargs)
|
return func(*args[1:], **kwargs)
|
||||||
|
|
||||||
|
|
||||||
RecordedWarning = namedtuple('RecordedWarning', (
|
class WarningsRecorder(warnings.catch_warnings):
|
||||||
'message', 'category', 'filename', 'lineno', 'file', 'line',
|
|
||||||
))
|
|
||||||
|
|
||||||
|
|
||||||
class WarningsRecorder(object):
|
|
||||||
"""A context manager to record raised warnings.
|
"""A context manager to record raised warnings.
|
||||||
|
|
||||||
Adapted from `warnings.catch_warnings`.
|
Adapted from `warnings.catch_warnings`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, module=None):
|
def __init__(self):
|
||||||
self._module = sys.modules['warnings'] if module is None else module
|
super(WarningsRecorder, self).__init__(record=True)
|
||||||
self._entered = False
|
self._entered = False
|
||||||
self._list = []
|
self._list = []
|
||||||
|
|
||||||
|
@ -164,38 +158,20 @@ class WarningsRecorder(object):
|
||||||
if self._entered:
|
if self._entered:
|
||||||
__tracebackhide__ = True
|
__tracebackhide__ = True
|
||||||
raise RuntimeError("Cannot enter %r twice" % self)
|
raise RuntimeError("Cannot enter %r twice" % self)
|
||||||
self._entered = True
|
self._list = super(WarningsRecorder, self).__enter__()
|
||||||
self._filters = self._module.filters
|
warnings.simplefilter('always')
|
||||||
self._module.filters = self._filters[:]
|
|
||||||
self._showwarning = self._module.showwarning
|
|
||||||
|
|
||||||
def showwarning(message, category, filename, lineno,
|
|
||||||
file=None, line=None):
|
|
||||||
self._list.append(RecordedWarning(
|
|
||||||
message, category, filename, lineno, file, line))
|
|
||||||
|
|
||||||
# still perform old showwarning functionality
|
|
||||||
self._showwarning(
|
|
||||||
message, category, filename, lineno, file=file, line=line)
|
|
||||||
|
|
||||||
self._module.showwarning = showwarning
|
|
||||||
|
|
||||||
# allow the same warning to be raised more than once
|
|
||||||
|
|
||||||
self._module.simplefilter('always')
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __exit__(self, *exc_info):
|
def __exit__(self, *exc_info):
|
||||||
if not self._entered:
|
if not self._entered:
|
||||||
__tracebackhide__ = True
|
__tracebackhide__ = True
|
||||||
raise RuntimeError("Cannot exit %r without entering first" % self)
|
raise RuntimeError("Cannot exit %r without entering first" % self)
|
||||||
self._module.filters = self._filters
|
super(WarningsRecorder, self).__exit__(*exc_info)
|
||||||
self._module.showwarning = self._showwarning
|
|
||||||
|
|
||||||
|
|
||||||
class WarningsChecker(WarningsRecorder):
|
class WarningsChecker(WarningsRecorder):
|
||||||
def __init__(self, expected_warning=None, module=None):
|
def __init__(self, expected_warning=None):
|
||||||
super(WarningsChecker, self).__init__(module=module)
|
super(WarningsChecker, self).__init__()
|
||||||
|
|
||||||
msg = ("exceptions must be old-style classes or "
|
msg = ("exceptions must be old-style classes or "
|
||||||
"derived from Warning, not %s")
|
"derived from Warning, not %s")
|
||||||
|
|
|
@ -8,25 +8,19 @@ from _pytest.recwarn import WarningsRecorder
|
||||||
def test_recwarn_functional(testdir):
|
def test_recwarn_functional(testdir):
|
||||||
reprec = testdir.inline_runsource("""
|
reprec = testdir.inline_runsource("""
|
||||||
import warnings
|
import warnings
|
||||||
oldwarn = warnings.showwarning
|
|
||||||
def test_method(recwarn):
|
def test_method(recwarn):
|
||||||
assert warnings.showwarning != oldwarn
|
|
||||||
warnings.warn("hello")
|
warnings.warn("hello")
|
||||||
warn = recwarn.pop()
|
warn = recwarn.pop()
|
||||||
assert isinstance(warn.message, UserWarning)
|
assert isinstance(warn.message, UserWarning)
|
||||||
def test_finalized():
|
|
||||||
assert warnings.showwarning == oldwarn
|
|
||||||
""")
|
""")
|
||||||
res = reprec.countoutcomes()
|
res = reprec.countoutcomes()
|
||||||
assert tuple(res) == (2, 0, 0), res
|
assert tuple(res) == (1, 0, 0), res
|
||||||
|
|
||||||
|
|
||||||
class TestWarningsRecorderChecker(object):
|
class TestWarningsRecorderChecker(object):
|
||||||
def test_recording(self, recwarn):
|
def test_recording(self):
|
||||||
showwarning = py.std.warnings.showwarning
|
|
||||||
rec = WarningsRecorder()
|
rec = WarningsRecorder()
|
||||||
with rec:
|
with rec:
|
||||||
assert py.std.warnings.showwarning != showwarning
|
|
||||||
assert not rec.list
|
assert not rec.list
|
||||||
py.std.warnings.warn_explicit("hello", UserWarning, "xyz", 13)
|
py.std.warnings.warn_explicit("hello", UserWarning, "xyz", 13)
|
||||||
assert len(rec.list) == 1
|
assert len(rec.list) == 1
|
||||||
|
@ -40,8 +34,6 @@ class TestWarningsRecorderChecker(object):
|
||||||
assert l is rec.list
|
assert l is rec.list
|
||||||
pytest.raises(AssertionError, "rec.pop()")
|
pytest.raises(AssertionError, "rec.pop()")
|
||||||
|
|
||||||
assert showwarning == py.std.warnings.showwarning
|
|
||||||
|
|
||||||
def test_typechecking(self):
|
def test_typechecking(self):
|
||||||
from _pytest.recwarn import WarningsChecker
|
from _pytest.recwarn import WarningsChecker
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
|
@ -217,7 +209,6 @@ class TestWarns(object):
|
||||||
excinfo.match(re.escape(message_template.format(warning_classes,
|
excinfo.match(re.escape(message_template.format(warning_classes,
|
||||||
[each.message for each in warninfo])))
|
[each.message for each in warninfo])))
|
||||||
|
|
||||||
|
|
||||||
def test_record(self):
|
def test_record(self):
|
||||||
with pytest.warns(UserWarning) as record:
|
with pytest.warns(UserWarning) as record:
|
||||||
warnings.warn("user", UserWarning)
|
warnings.warn("user", UserWarning)
|
||||||
|
@ -225,9 +216,6 @@ class TestWarns(object):
|
||||||
assert len(record) == 1
|
assert len(record) == 1
|
||||||
assert str(record[0].message) == "user"
|
assert str(record[0].message) == "user"
|
||||||
|
|
||||||
print(repr(record[0]))
|
|
||||||
assert str(record[0].message) in repr(record[0])
|
|
||||||
|
|
||||||
def test_record_only(self):
|
def test_record_only(self):
|
||||||
with pytest.warns(None) as record:
|
with pytest.warns(None) as record:
|
||||||
warnings.warn("user", UserWarning)
|
warnings.warn("user", UserWarning)
|
||||||
|
|
Loading…
Reference in New Issue