Small cleanups on _pytest.compat

Small improvements and cleanups
This commit is contained in:
Bruno Oliveira 2019-06-15 10:06:37 -03:00
parent 240828d912
commit 355eb5adfb
5 changed files with 25 additions and 30 deletions

View File

@ -10,6 +10,7 @@ from contextlib import contextmanager
from inspect import Parameter from inspect import Parameter
from inspect import signature from inspect import signature
import attr
import py import py
import _pytest import _pytest
@ -29,10 +30,6 @@ def _format_args(func):
return str(signature(func)) return str(signature(func))
isfunction = inspect.isfunction
isclass = inspect.isclass
# used to work around a python2 exception info leak
exc_clear = getattr(sys, "exc_clear", lambda: None)
# The type of re.compile objects is not exposed in Python. # The type of re.compile objects is not exposed in Python.
REGEX_TYPE = type(re.compile("")) REGEX_TYPE = type(re.compile(""))
@ -129,11 +126,15 @@ def getfuncargnames(function, is_method=False, cls=None):
return arg_names return arg_names
@contextmanager if sys.version_info < (3, 7):
def dummy_context_manager():
"""Context manager that does nothing, useful in situations where you might need an actual context manager or not @contextmanager
depending on some condition. Using this allow to keep the same code""" def nullcontext():
yield yield
else:
from contextlib import nullcontext # noqa
def get_default_arg_names(function): def get_default_arg_names(function):
@ -191,6 +192,7 @@ def ascii_escaped(val):
return _translate_non_printable(ret) return _translate_non_printable(ret)
@attr.s
class _PytestWrapper: class _PytestWrapper:
"""Dummy wrapper around a function object for internal use only. """Dummy wrapper around a function object for internal use only.
@ -199,8 +201,7 @@ class _PytestWrapper:
to issue warnings when the fixture function is called directly. to issue warnings when the fixture function is called directly.
""" """
def __init__(self, obj): obj = attr.ib()
self.obj = obj
def get_real_func(obj): def get_real_func(obj):
@ -280,7 +281,7 @@ def safe_getattr(object, name, default):
def safe_isclass(obj): def safe_isclass(obj):
"""Ignore any exception via isinstance on Python 3.""" """Ignore any exception via isinstance on Python 3."""
try: try:
return isclass(obj) return inspect.isclass(obj)
except Exception: except Exception:
return False return False
@ -304,8 +305,8 @@ def _setup_collect_fakemodule():
pytest.collect = ModuleType("pytest.collect") pytest.collect = ModuleType("pytest.collect")
pytest.collect.__all__ = [] # used for setns pytest.collect.__all__ = [] # used for setns
for attr in COLLECT_FAKEMODULE_ATTRIBUTES: for attr_name in COLLECT_FAKEMODULE_ATTRIBUTES:
setattr(pytest.collect, attr, getattr(pytest, attr)) setattr(pytest.collect, attr_name, getattr(pytest, attr_name))
class CaptureIO(io.TextIOWrapper): class CaptureIO(io.TextIOWrapper):

View File

@ -16,7 +16,6 @@ from _pytest._code.code import FormattedExcinfo
from _pytest._code.code import TerminalRepr from _pytest._code.code import TerminalRepr
from _pytest.compat import _format_args from _pytest.compat import _format_args
from _pytest.compat import _PytestWrapper from _pytest.compat import _PytestWrapper
from _pytest.compat import exc_clear
from _pytest.compat import FuncargnamesCompatAttr from _pytest.compat import FuncargnamesCompatAttr
from _pytest.compat import get_real_func from _pytest.compat import get_real_func
from _pytest.compat import get_real_method from _pytest.compat import get_real_method
@ -25,7 +24,6 @@ from _pytest.compat import getfuncargnames
from _pytest.compat import getimfunc from _pytest.compat import getimfunc
from _pytest.compat import getlocation from _pytest.compat import getlocation
from _pytest.compat import is_generator from _pytest.compat import is_generator
from _pytest.compat import isclass
from _pytest.compat import NOTSET from _pytest.compat import NOTSET
from _pytest.compat import safe_getattr from _pytest.compat import safe_getattr
from _pytest.deprecated import FIXTURE_FUNCTION_CALL from _pytest.deprecated import FIXTURE_FUNCTION_CALL
@ -572,10 +570,6 @@ class FixtureRequest(FuncargnamesCompatAttr):
# check if a higher-level scoped fixture accesses a lower level one # check if a higher-level scoped fixture accesses a lower level one
subrequest._check_scope(argname, self.scope, scope) subrequest._check_scope(argname, self.scope, scope)
# clear sys.exc_info before invoking the fixture (python bug?)
# if it's not explicitly cleared it will leak into the call
exc_clear()
try: try:
# call the fixture function # call the fixture function
fixturedef.execute(request=subrequest) fixturedef.execute(request=subrequest)
@ -970,7 +964,7 @@ class FixtureFunctionMarker:
name = attr.ib(default=None) name = attr.ib(default=None)
def __call__(self, function): def __call__(self, function):
if isclass(function): if inspect.isclass(function):
raise ValueError("class fixtures not supported (maybe in the future)") raise ValueError("class fixtures not supported (maybe in the future)")
if getattr(function, "_pytestfixturefunction", False): if getattr(function, "_pytestfixturefunction", False):

View File

@ -6,7 +6,7 @@ from contextlib import contextmanager
import py import py
import pytest import pytest
from _pytest.compat import dummy_context_manager from _pytest.compat import nullcontext
from _pytest.config import create_terminal_writer from _pytest.config import create_terminal_writer
from _pytest.pathlib import Path from _pytest.pathlib import Path
@ -436,7 +436,7 @@ class LoggingPlugin:
self.log_cli_handler = None self.log_cli_handler = None
self.live_logs_context = lambda: dummy_context_manager() self.live_logs_context = lambda: nullcontext()
# Note that the lambda for the live_logs_context is needed because # Note that the lambda for the live_logs_context is needed because
# live_logs_context can otherwise not be entered multiple times due # live_logs_context can otherwise not be entered multiple times due
# to limitations of contextlib.contextmanager. # to limitations of contextlib.contextmanager.
@ -676,7 +676,7 @@ class _LiveLoggingStreamHandler(logging.StreamHandler):
ctx_manager = ( ctx_manager = (
self.capture_manager.global_and_fixture_disabled() self.capture_manager.global_and_fixture_disabled()
if self.capture_manager if self.capture_manager
else dummy_context_manager() else nullcontext()
) )
with ctx_manager: with ctx_manager:
if not self._first_record_emitted: if not self._first_record_emitted:

View File

@ -23,8 +23,6 @@ from _pytest.compat import getfslineno
from _pytest.compat import getimfunc from _pytest.compat import getimfunc
from _pytest.compat import getlocation from _pytest.compat import getlocation
from _pytest.compat import is_generator from _pytest.compat import is_generator
from _pytest.compat import isclass
from _pytest.compat import isfunction
from _pytest.compat import NOTSET from _pytest.compat import NOTSET
from _pytest.compat import REGEX_TYPE from _pytest.compat import REGEX_TYPE
from _pytest.compat import safe_getattr from _pytest.compat import safe_getattr
@ -207,7 +205,7 @@ def pytest_pycollect_makeitem(collector, name, obj):
# We need to try and unwrap the function if it's a functools.partial # We need to try and unwrap the function if it's a functools.partial
# or a funtools.wrapped. # or a funtools.wrapped.
# We musn't if it's been wrapped with mock.patch (python 2 only) # We musn't if it's been wrapped with mock.patch (python 2 only)
if not (isfunction(obj) or isfunction(get_real_func(obj))): if not (inspect.isfunction(obj) or inspect.isfunction(get_real_func(obj))):
filename, lineno = getfslineno(obj) filename, lineno = getfslineno(obj)
warnings.warn_explicit( warnings.warn_explicit(
message=PytestCollectionWarning( message=PytestCollectionWarning(
@ -1190,7 +1188,7 @@ def _idval(val, argname, idx, idfn, item, config):
return ascii_escaped(val.pattern) return ascii_escaped(val.pattern)
elif enum is not None and isinstance(val, enum.Enum): elif enum is not None and isinstance(val, enum.Enum):
return str(val) return str(val)
elif (isclass(val) or isfunction(val)) and hasattr(val, "__name__"): elif (inspect.isclass(val) or inspect.isfunction(val)) and hasattr(val, "__name__"):
return val.__name__ return val.__name__
return str(argname) + str(idx) return str(argname) + str(idx)

View File

@ -1,3 +1,4 @@
import inspect
import math import math
import pprint import pprint
import sys import sys
@ -13,7 +14,6 @@ from more_itertools.more import always_iterable
import _pytest._code import _pytest._code
from _pytest import deprecated from _pytest import deprecated
from _pytest.compat import isclass
from _pytest.compat import STRING_TYPES from _pytest.compat import STRING_TYPES
from _pytest.outcomes import fail from _pytest.outcomes import fail
@ -658,7 +658,9 @@ def raises(expected_exception, *args, **kwargs):
""" """
__tracebackhide__ = True __tracebackhide__ = True
for exc in filterfalse(isclass, always_iterable(expected_exception, BASE_TYPE)): for exc in filterfalse(
inspect.isclass, always_iterable(expected_exception, BASE_TYPE)
):
msg = ( msg = (
"exceptions must be old-style classes or" "exceptions must be old-style classes or"
" derived from BaseException, not %s" " derived from BaseException, not %s"