Merge pull request #7176 from bluetech/warnings-optimize-parse

warnings: speed up work done in catch_warnings_for_item()
This commit is contained in:
Ran Benita 2020-05-07 19:34:28 +03:00 committed by GitHub
commit 32c00db0bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 32 additions and 14 deletions

View File

@ -1,34 +1,52 @@
import re
import sys import sys
import warnings import warnings
from contextlib import contextmanager from contextlib import contextmanager
from functools import lru_cache
from typing import Generator from typing import Generator
from typing import Tuple
import pytest import pytest
from _pytest.compat import TYPE_CHECKING
from _pytest.main import Session from _pytest.main import Session
if TYPE_CHECKING:
from typing_extensions import Type
def _setoption(wmod, arg):
""" @lru_cache(maxsize=50)
Copy of the warning._setoption function but does not escape arguments. def _parse_filter(
arg: str, *, escape: bool
) -> "Tuple[str, str, Type[Warning], str, int]":
"""Parse a warnings filter string.
This is copied from warnings._setoption, but does not apply the filter,
only parses it, and makes the escaping optional.
""" """
parts = arg.split(":") parts = arg.split(":")
if len(parts) > 5: if len(parts) > 5:
raise wmod._OptionError("too many fields (max 5): {!r}".format(arg)) raise warnings._OptionError("too many fields (max 5): {!r}".format(arg))
while len(parts) < 5: while len(parts) < 5:
parts.append("") parts.append("")
action, message, category, module, lineno = [s.strip() for s in parts] action_, message, category_, module, lineno_ = [s.strip() for s in parts]
action = wmod._getaction(action) action = warnings._getaction(action_) # type: str # type: ignore[attr-defined]
category = wmod._getcategory(category) category = warnings._getcategory(
if lineno: category_
) # type: Type[Warning] # type: ignore[attr-defined]
if message and escape:
message = re.escape(message)
if module and escape:
module = re.escape(module) + r"\Z"
if lineno_:
try: try:
lineno = int(lineno) lineno = int(lineno_)
if lineno < 0: if lineno < 0:
raise ValueError raise ValueError
except (ValueError, OverflowError): except (ValueError, OverflowError):
raise wmod._OptionError("invalid lineno {!r}".format(lineno)) raise warnings._OptionError("invalid lineno {!r}".format(lineno_))
else: else:
lineno = 0 lineno = 0
wmod.filterwarnings(action, message, category, module, lineno) return (action, message, category, module, lineno)
def pytest_addoption(parser): def pytest_addoption(parser):
@ -79,15 +97,15 @@ def catch_warnings_for_item(config, ihook, when, item):
# filters should have this precedence: mark, cmdline options, ini # filters should have this precedence: mark, cmdline options, ini
# filters should be applied in the inverse order of precedence # filters should be applied in the inverse order of precedence
for arg in inifilters: for arg in inifilters:
_setoption(warnings, arg) warnings.filterwarnings(*_parse_filter(arg, escape=False))
for arg in cmdline_filters: for arg in cmdline_filters:
warnings._setoption(arg) warnings.filterwarnings(*_parse_filter(arg, escape=True))
if item is not None: if item is not None:
for mark in item.iter_markers(name="filterwarnings"): for mark in item.iter_markers(name="filterwarnings"):
for arg in mark.args: for arg in mark.args:
_setoption(warnings, arg) warnings.filterwarnings(*_parse_filter(arg, escape=False))
yield yield