| 229 | |
| 230 | @final |
| 231 | class WarningsChecker(WarningsRecorder): |
| 232 | def __init__( |
| 233 | self, |
| 234 | expected_warning: Optional[ |
| 235 | Union[Type[Warning], Tuple[Type[Warning], ...]] |
| 236 | ] = Warning, |
| 237 | match_expr: Optional[Union[str, Pattern[str]]] = None, |
| 238 | *, |
| 239 | _ispytest: bool = False, |
| 240 | ) -> None: |
| 241 | check_ispytest(_ispytest) |
| 242 | super().__init__(_ispytest=True) |
| 243 | |
| 244 | msg = "exceptions must be derived from Warning, not %s" |
| 245 | if expected_warning is None: |
| 246 | warnings.warn(WARNS_NONE_ARG, stacklevel=4) |
| 247 | expected_warning_tup = None |
| 248 | elif isinstance(expected_warning, tuple): |
| 249 | for exc in expected_warning: |
| 250 | if not issubclass(exc, Warning): |
| 251 | raise TypeError(msg % type(exc)) |
| 252 | expected_warning_tup = expected_warning |
| 253 | elif issubclass(expected_warning, Warning): |
| 254 | expected_warning_tup = (expected_warning,) |
| 255 | else: |
| 256 | raise TypeError(msg % type(expected_warning)) |
| 257 | |
| 258 | self.expected_warning = expected_warning_tup |
| 259 | self.match_expr = match_expr |
| 260 | |
| 261 | def __exit__( |
| 262 | self, |
| 263 | exc_type: Optional[Type[BaseException]], |
| 264 | exc_val: Optional[BaseException], |
| 265 | exc_tb: Optional[TracebackType], |
| 266 | ) -> None: |
| 267 | super().__exit__(exc_type, exc_val, exc_tb) |
| 268 | |
| 269 | __tracebackhide__ = True |
| 270 | |
| 271 | # only check if we're not currently handling an exception |
| 272 | if exc_type is None and exc_val is None and exc_tb is None: |
| 273 | if self.expected_warning is not None: |
| 274 | if not any(issubclass(r.category, self.expected_warning) for r in self): |
| 275 | __tracebackhide__ = True |
| 276 | fail( |
| 277 | "DID NOT WARN. No warnings of type {} were emitted. " |
| 278 | "The list of emitted warnings is: {}.".format( |
| 279 | self.expected_warning, [each.message for each in self] |
| 280 | ) |
| 281 | ) |
| 282 | elif self.match_expr is not None: |
| 283 | for r in self: |
| 284 | if issubclass(r.category, self.expected_warning): |
| 285 | if re.compile(self.match_expr).search(str(r.message)): |
| 286 | break |
| 287 | else: |
| 288 | fail( |
no outgoing calls