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 warnings
from contextlib import contextmanager
from functools import lru_cache
from typing import Generator
from typing import Tuple
import pytest
from _pytest.compat import TYPE_CHECKING
from _pytest.main import Session
if TYPE_CHECKING:
from typing_extensions import Type
def _setoption(wmod, arg):
"""
Copy of the warning._setoption function but does not escape arguments.
@lru_cache(maxsize=50)
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(":")
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:
parts.append("")
action, message, category, module, lineno = [s.strip() for s in parts]
action = wmod._getaction(action)
category = wmod._getcategory(category)
if lineno:
action_, message, category_, module, lineno_ = [s.strip() for s in parts]
action = warnings._getaction(action_) # type: str # type: ignore[attr-defined]
category = warnings._getcategory(
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:
lineno = int(lineno)
lineno = int(lineno_)
if lineno < 0:
raise ValueError
except (ValueError, OverflowError):
raise wmod._OptionError("invalid lineno {!r}".format(lineno))
raise warnings._OptionError("invalid lineno {!r}".format(lineno_))
else:
lineno = 0
wmod.filterwarnings(action, message, category, module, lineno)
return (action, message, category, module, lineno)
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 be applied in the inverse order of precedence
for arg in inifilters:
_setoption(warnings, arg)
warnings.filterwarnings(*_parse_filter(arg, escape=False))
for arg in cmdline_filters:
warnings._setoption(arg)
warnings.filterwarnings(*_parse_filter(arg, escape=True))
if item is not None:
for mark in item.iter_markers(name="filterwarnings"):
for arg in mark.args:
_setoption(warnings, arg)
warnings.filterwarnings(*_parse_filter(arg, escape=False))
yield