|
| 1 | +import re |
1 | 2 | import sys
|
2 | 3 | import warnings
|
3 | 4 | from contextlib import contextmanager
|
| 5 | +from functools import lru_cache |
4 | 6 | from typing import Generator
|
| 7 | +from typing import Tuple |
5 | 8 |
|
6 | 9 | import pytest
|
| 10 | +from _pytest.compat import TYPE_CHECKING |
7 | 11 | from _pytest.main import Session
|
8 | 12 |
|
| 13 | +if TYPE_CHECKING: |
| 14 | + from typing_extensions import Type |
9 | 15 |
|
10 |
| -def _setoption(wmod, arg): |
11 |
| - """ |
12 |
| - Copy of the warning._setoption function but does not escape arguments. |
| 16 | + |
| 17 | +@lru_cache(maxsize=50) |
| 18 | +def _parse_filter( |
| 19 | + arg: str, *, escape: bool |
| 20 | +) -> "Tuple[str, str, Type[Warning], str, int]": |
| 21 | + """Parse a warnings filter string. |
| 22 | +
|
| 23 | + This is copied from warnings._setoption, but does not apply the filter, |
| 24 | + only parses it, and makes the escaping optional. |
13 | 25 | """
|
14 | 26 | parts = arg.split(":")
|
15 | 27 | if len(parts) > 5:
|
16 |
| - raise wmod._OptionError("too many fields (max 5): {!r}".format(arg)) |
| 28 | + raise warnings._OptionError("too many fields (max 5): {!r}".format(arg)) |
17 | 29 | while len(parts) < 5:
|
18 | 30 | parts.append("")
|
19 |
| - action, message, category, module, lineno = [s.strip() for s in parts] |
20 |
| - action = wmod._getaction(action) |
21 |
| - category = wmod._getcategory(category) |
22 |
| - if lineno: |
| 31 | + action_, message, category_, module, lineno_ = [s.strip() for s in parts] |
| 32 | + action = warnings._getaction(action_) # type: str # type: ignore[attr-defined] |
| 33 | + category = warnings._getcategory( |
| 34 | + category_ |
| 35 | + ) # type: Type[Warning] # type: ignore[attr-defined] |
| 36 | + if message and escape: |
| 37 | + message = re.escape(message) |
| 38 | + if module and escape: |
| 39 | + module = re.escape(module) + r"\Z" |
| 40 | + if lineno_: |
23 | 41 | try:
|
24 |
| - lineno = int(lineno) |
| 42 | + lineno = int(lineno_) |
25 | 43 | if lineno < 0:
|
26 | 44 | raise ValueError
|
27 | 45 | except (ValueError, OverflowError):
|
28 |
| - raise wmod._OptionError("invalid lineno {!r}".format(lineno)) |
| 46 | + raise warnings._OptionError("invalid lineno {!r}".format(lineno_)) |
29 | 47 | else:
|
30 | 48 | lineno = 0
|
31 |
| - wmod.filterwarnings(action, message, category, module, lineno) |
| 49 | + return (action, message, category, module, lineno) |
32 | 50 |
|
33 | 51 |
|
34 | 52 | def pytest_addoption(parser):
|
@@ -79,15 +97,15 @@ def catch_warnings_for_item(config, ihook, when, item):
|
79 | 97 | # filters should have this precedence: mark, cmdline options, ini
|
80 | 98 | # filters should be applied in the inverse order of precedence
|
81 | 99 | for arg in inifilters:
|
82 |
| - _setoption(warnings, arg) |
| 100 | + warnings.filterwarnings(*_parse_filter(arg, escape=False)) |
83 | 101 |
|
84 | 102 | for arg in cmdline_filters:
|
85 |
| - warnings._setoption(arg) |
| 103 | + warnings.filterwarnings(*_parse_filter(arg, escape=True)) |
86 | 104 |
|
87 | 105 | if item is not None:
|
88 | 106 | for mark in item.iter_markers(name="filterwarnings"):
|
89 | 107 | for arg in mark.args:
|
90 |
| - _setoption(warnings, arg) |
| 108 | + warnings.filterwarnings(*_parse_filter(arg, escape=False)) |
91 | 109 |
|
92 | 110 | yield
|
93 | 111 |
|
|
0 commit comments