88import sys
99import warnings
1010
11+ import re
12+
1113from _pytest .fixtures import yield_fixture
1214from _pytest .outcomes import fail
1315
@@ -99,22 +101,24 @@ def warns(expected_warning, *args, **kwargs):
99101 >>> with warns(RuntimeWarning):
100102 ... warnings.warn("my warning", RuntimeWarning)
101103 """
102- wcheck = WarningsChecker ( expected_warning )
104+ match_expr = None
103105 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 )
105109 elif isinstance (args [0 ], str ):
106110 code , = args
107111 assert isinstance (code , str )
108112 frame = sys ._getframe (1 )
109113 loc = frame .f_locals .copy ()
110114 loc .update (kwargs )
111115
112- with wcheck :
116+ with WarningsChecker ( expected_warning , match_expr = match_expr ) :
113117 code = _pytest ._code .Source (code ).compile ()
114118 py .builtin .exec_ (code , frame .f_globals , loc )
115119 else :
116120 func = args [0 ]
117- with wcheck :
121+ with WarningsChecker ( expected_warning , match_expr = match_expr ) :
118122 return func (* args [1 :], ** kwargs )
119123
120124
@@ -174,7 +178,7 @@ def __exit__(self, *exc_info):
174178
175179
176180class WarningsChecker (WarningsRecorder ):
177- def __init__ (self , expected_warning = None ):
181+ def __init__ (self , expected_warning = None , match_expr = None ):
178182 super (WarningsChecker , self ).__init__ ()
179183
180184 msg = ("exceptions must be old-style classes or "
@@ -189,6 +193,7 @@ def __init__(self, expected_warning=None):
189193 raise TypeError (msg % type (expected_warning ))
190194
191195 self .expected_warning = expected_warning
196+ self .match_expr = match_expr
192197
193198 def __exit__ (self , * exc_info ):
194199 super (WarningsChecker , self ).__exit__ (* exc_info )
@@ -203,3 +208,15 @@ def __exit__(self, *exc_info):
203208 "The list of emitted warnings is: {1}." .format (
204209 self .expected_warning ,
205210 [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