Skip to content

Commit 604a021

Browse files
Merge pull request #1196 from nicoddemus/deprecated-call-1190
Make deprecated_call() use monkey-patching again , fixes #1190
2 parents 320c95c + 603d81e commit 604a021

File tree

3 files changed

+81
-31
lines changed

3 files changed

+81
-31
lines changed

CHANGELOG

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
2.8.4.dev
2+
---------
3+
4+
- fix #1190: ``deprecated_call()`` now works when the deprecated
5+
function has been already called by another test in the same
6+
module. Thanks Mikhail Chernykh for the report and Bruno Oliveira for the
7+
PR.
8+
19
2.8.3
210
-----
311

_pytest/recwarn.py

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

3030

3131
def deprecated_call(func, *args, **kwargs):
32-
"""Assert that ``func(*args, **kwargs)`` triggers a DeprecationWarning.
32+
""" assert that calling ``func(*args, **kwargs)`` triggers a
33+
``DeprecationWarning`` or ``PendingDeprecationWarning``.
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.
3338
"""
34-
wrec = WarningsRecorder()
35-
with wrec:
36-
warnings.simplefilter('always') # ensure all warnings are triggered
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)
51+
52+
old_warn = warnings.warn
53+
old_warn_explicit = warnings.warn_explicit
54+
warnings.warn_explicit = warn_explicit
55+
warnings.warn = warn
56+
try:
3757
ret = func(*args, **kwargs)
38-
39-
depwarnings = (DeprecationWarning, PendingDeprecationWarning)
40-
if not any(r.category in depwarnings for r in wrec):
58+
finally:
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):
4163
__tracebackhide__ = True
4264
raise AssertionError("%r did not produce DeprecationWarning" % (func,))
43-
4465
return ret
4566

4667

testing/test_recwarn.py

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -63,32 +63,30 @@ def test_invalid_enter_exit(self):
6363
with rec:
6464
pass # can't enter twice
6565

66-
#
67-
# ============ test pytest.deprecated_call() ==============
68-
#
6966

70-
def dep(i):
71-
if i == 0:
72-
py.std.warnings.warn("is deprecated", DeprecationWarning)
73-
return 42
67+
class TestDeprecatedCall(object):
68+
"""test pytest.deprecated_call()"""
7469

75-
reg = {}
76-
def dep_explicit(i):
77-
if i == 0:
78-
py.std.warnings.warn_explicit("dep_explicit", category=DeprecationWarning,
79-
filename="hello", lineno=3)
70+
def dep(self, i):
71+
if i == 0:
72+
py.std.warnings.warn("is deprecated", DeprecationWarning)
73+
return 42
74+
75+
def dep_explicit(self, i):
76+
if i == 0:
77+
py.std.warnings.warn_explicit("dep_explicit", category=DeprecationWarning,
78+
filename="hello", lineno=3)
8079

81-
class TestDeprecatedCall(object):
8280
def test_deprecated_call_raises(self):
83-
excinfo = pytest.raises(AssertionError,
84-
"pytest.deprecated_call(dep, 3)")
81+
with pytest.raises(AssertionError) as excinfo:
82+
pytest.deprecated_call(self.dep, 3)
8583
assert str(excinfo).find("did not produce") != -1
8684

8785
def test_deprecated_call(self):
88-
pytest.deprecated_call(dep, 0)
86+
pytest.deprecated_call(self.dep, 0)
8987

9088
def test_deprecated_call_ret(self):
91-
ret = pytest.deprecated_call(dep, 0)
89+
ret = pytest.deprecated_call(self.dep, 0)
9290
assert ret == 42
9391

9492
def test_deprecated_call_preserves(self):
@@ -104,25 +102,48 @@ def test_deprecated_call_preserves(self):
104102
assert warn_explicit is py.std.warnings.warn_explicit
105103

106104
def test_deprecated_explicit_call_raises(self):
107-
pytest.raises(AssertionError,
108-
"pytest.deprecated_call(dep_explicit, 3)")
105+
with pytest.raises(AssertionError):
106+
pytest.deprecated_call(self.dep_explicit, 3)
109107

110108
def test_deprecated_explicit_call(self):
111-
pytest.deprecated_call(dep_explicit, 0)
112-
pytest.deprecated_call(dep_explicit, 0)
109+
pytest.deprecated_call(self.dep_explicit, 0)
110+
pytest.deprecated_call(self.dep_explicit, 0)
113111

114112
def test_deprecated_call_pending(self):
115-
f = lambda: py.std.warnings.warn(PendingDeprecationWarning("hi"))
113+
def f():
114+
py.std.warnings.warn(PendingDeprecationWarning("hi"))
116115
pytest.deprecated_call(f)
117116

118117
def test_deprecated_call_specificity(self):
119118
other_warnings = [Warning, UserWarning, SyntaxWarning, RuntimeWarning,
120119
FutureWarning, ImportWarning, UnicodeWarning]
121120
for warning in other_warnings:
122-
f = lambda: py.std.warnings.warn(warning("hi"))
121+
def f():
122+
py.std.warnings.warn(warning("hi"))
123123
with pytest.raises(AssertionError):
124124
pytest.deprecated_call(f)
125125

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

127148
class TestWarns(object):
128149
def test_strings(self):

0 commit comments

Comments
 (0)