8
8
import sys
9
9
import warnings
10
10
11
+ import re
12
+
11
13
from _pytest .fixtures import yield_fixture
12
14
from _pytest .outcomes import fail
13
15
@@ -99,22 +101,24 @@ def warns(expected_warning, *args, **kwargs):
99
101
>>> with warns(RuntimeWarning):
100
102
... warnings.warn("my warning", RuntimeWarning)
101
103
"""
102
- wcheck = WarningsChecker ( expected_warning )
104
+ match_expr = None
103
105
if not args :
104
- return wcheck
106
+ if "match" in kwargs :
107
+ match_expr = kwargs .pop ("match" )
108
+ return WarningsChecker (expected_warning , match_expr = match_expr )
105
109
elif isinstance (args [0 ], str ):
106
110
code , = args
107
111
assert isinstance (code , str )
108
112
frame = sys ._getframe (1 )
109
113
loc = frame .f_locals .copy ()
110
114
loc .update (kwargs )
111
115
112
- with wcheck :
116
+ with WarningsChecker ( expected_warning , match_expr = match_expr ) :
113
117
code = _pytest ._code .Source (code ).compile ()
114
118
py .builtin .exec_ (code , frame .f_globals , loc )
115
119
else :
116
120
func = args [0 ]
117
- with wcheck :
121
+ with WarningsChecker ( expected_warning , match_expr = match_expr ) :
118
122
return func (* args [1 :], ** kwargs )
119
123
120
124
@@ -174,7 +178,7 @@ def __exit__(self, *exc_info):
174
178
175
179
176
180
class WarningsChecker (WarningsRecorder ):
177
- def __init__ (self , expected_warning = None ):
181
+ def __init__ (self , expected_warning = None , match_expr = None ):
178
182
super (WarningsChecker , self ).__init__ ()
179
183
180
184
msg = ("exceptions must be old-style classes or "
@@ -189,6 +193,7 @@ def __init__(self, expected_warning=None):
189
193
raise TypeError (msg % type (expected_warning ))
190
194
191
195
self .expected_warning = expected_warning
196
+ self .match_expr = match_expr
192
197
193
198
def __exit__ (self , * exc_info ):
194
199
super (WarningsChecker , self ).__exit__ (* exc_info )
@@ -203,3 +208,15 @@ def __exit__(self, *exc_info):
203
208
"The list of emitted warnings is: {1}." .format (
204
209
self .expected_warning ,
205
210
[each .message for each in self ]))
211
+ elif self .match_expr is not None :
212
+ for r in self :
213
+ if issubclass (r .category , self .expected_warning ):
214
+ if re .compile (self .match_expr ).search (str (r .message )):
215
+ break
216
+ else :
217
+ fail ("DID NOT WARN. No warnings of type {0} matching"
218
+ " ('{1}') was emitted. The list of emitted warnings"
219
+ " is: {2}." .format (
220
+ self .expected_warning ,
221
+ self .match_expr ,
222
+ [each .message for each in self ]))
0 commit comments