Skip to content

Commit 74c2117

Browse files
committed
deprecated_call now uses monkey patching strategy to capture warnings
similar to what we had in 2.7, with a few enhancements Fix pytest-dev#1190
1 parent 6378cdf commit 74c2117

File tree

2 files changed

+46
-16
lines changed

2 files changed

+46
-16
lines changed

_pytest/recwarn.py

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,29 +29,39 @@ def pytest_namespace():
2929

3030

3131
def deprecated_call(func, *args, **kwargs):
32-
""" assert that calling ``func(*args, **kwargs)``
33-
triggers a DeprecationWarning.
32+
""" assert that calling ``func(*args, **kwargs)`` triggers a
33+
DeprecationWarning.
34+
35+
Note: we cannot use WarningsRecorder here because it is still subject
36+
to the mechanism that prevents warnings of the same type from being
37+
triggered twice for the same module. See #1190.
3438
"""
35-
l = []
36-
oldwarn_explicit = getattr(warnings, 'warn_explicit')
37-
def warn_explicit(*args, **kwargs):
38-
l.append(args)
39-
oldwarn_explicit(*args, **kwargs)
40-
oldwarn = getattr(warnings, 'warn')
41-
def warn(*args, **kwargs):
42-
l.append(args)
43-
oldwarn(*args, **kwargs)
39+
categories = []
40+
41+
def warn_explicit(message, category, *args, **kwargs):
42+
categories.append(category)
43+
old_warn_explicit(message, category, *args, **kwargs)
44+
45+
def warn(message, category=None, **kwargs):
46+
if isinstance(message, Warning):
47+
categories.append(message.__class__)
48+
else:
49+
categories.append(category)
50+
old_warn(message, category, *args, **kwargs)
4451

52+
old_warn = warnings.warn
53+
old_warn_explicit = warnings.warn_explicit
4554
warnings.warn_explicit = warn_explicit
4655
warnings.warn = warn
4756
try:
4857
ret = func(*args, **kwargs)
4958
finally:
50-
warnings.warn_explicit = oldwarn_explicit
51-
warnings.warn = oldwarn
52-
if not l:
59+
warnings.warn_explicit = old_warn_explicit
60+
warnings.warn = old_warn
61+
deprecation_categories = (DeprecationWarning, PendingDeprecationWarning)
62+
if not any(issubclass(c, deprecation_categories) for c in categories):
5363
__tracebackhide__ = True
54-
raise AssertionError("%r did not produce DeprecationWarning" %(func,))
64+
raise AssertionError("%r did not produce DeprecationWarning" % (func,))
5565
return ret
5666

5767

testing/test_recwarn.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ def dep(i):
7272
py.std.warnings.warn("is deprecated", DeprecationWarning)
7373
return 42
7474

75-
reg = {}
7675
def dep_explicit(i):
7776
if i == 0:
7877
py.std.warnings.warn_explicit("dep_explicit", category=DeprecationWarning,
@@ -123,6 +122,27 @@ def test_deprecated_call_specificity(self):
123122
with pytest.raises(AssertionError):
124123
pytest.deprecated_call(f)
125124

125+
def test_deprecated_function_already_called(self, testdir):
126+
"""deprecated_call should be able to catch a call to a deprecated
127+
function even if that function has already been called in the same
128+
module. See #1190.
129+
"""
130+
testdir.makepyfile("""
131+
import warnings
132+
import pytest
133+
134+
def deprecated_function():
135+
warnings.warn("deprecated", DeprecationWarning)
136+
137+
def test_one():
138+
deprecated_function()
139+
140+
def test_two():
141+
pytest.deprecated_call(deprecated_function)
142+
""")
143+
result = testdir.runpytest()
144+
result.stdout.fnmatch_lines('*=== 2 passed in *===')
145+
126146

127147
class TestWarns(object):
128148
def test_strings(self):

0 commit comments

Comments
 (0)