Small cleanups on _pytest.compat (#5451)
Small cleanups on _pytest.compat
This commit is contained in:
commit
689ce112e7
|
@ -244,17 +244,9 @@ def _compare_eq_iterable(left, right, verbose=0):
|
||||||
# dynamic import to speedup pytest
|
# dynamic import to speedup pytest
|
||||||
import difflib
|
import difflib
|
||||||
|
|
||||||
try:
|
left_formatting = pprint.pformat(left).splitlines()
|
||||||
left_formatting = pprint.pformat(left).splitlines()
|
right_formatting = pprint.pformat(right).splitlines()
|
||||||
right_formatting = pprint.pformat(right).splitlines()
|
explanation = ["Full diff:"]
|
||||||
explanation = ["Full diff:"]
|
|
||||||
except Exception:
|
|
||||||
# hack: PrettyPrinter.pformat() in python 2 fails when formatting items that can't be sorted(), ie, calling
|
|
||||||
# sorted() on a list would raise. See issue #718.
|
|
||||||
# As a workaround, the full diff is generated by using the repr() string of each item of each container.
|
|
||||||
left_formatting = sorted(repr(x) for x in left)
|
|
||||||
right_formatting = sorted(repr(x) for x in right)
|
|
||||||
explanation = ["Full diff (fallback to calling repr on each item):"]
|
|
||||||
explanation.extend(
|
explanation.extend(
|
||||||
line.strip() for line in difflib.ndiff(left_formatting, right_formatting)
|
line.strip() for line in difflib.ndiff(left_formatting, right_formatting)
|
||||||
)
|
)
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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(
|
||||||
|
@ -1172,8 +1170,6 @@ def _idval(val, argname, idx, idfn, item, config):
|
||||||
# See issue https://github.com/pytest-dev/pytest/issues/2169
|
# See issue https://github.com/pytest-dev/pytest/issues/2169
|
||||||
msg = "{}: error raised while trying to determine id of parameter '{}' at position {}\n"
|
msg = "{}: error raised while trying to determine id of parameter '{}' at position {}\n"
|
||||||
msg = msg.format(item.nodeid, argname, idx)
|
msg = msg.format(item.nodeid, argname, idx)
|
||||||
# we only append the exception type and message because on Python 2 reraise does nothing
|
|
||||||
msg += " {}: {}\n".format(type(e).__name__, e)
|
|
||||||
raise ValueError(msg) from e
|
raise ValueError(msg) from e
|
||||||
elif config:
|
elif config:
|
||||||
hook_id = config.hook.pytest_make_parametrize_id(
|
hook_id = config.hook.pytest_make_parametrize_id(
|
||||||
|
@ -1190,7 +1186,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)
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import inspect
|
||||||
import math
|
import math
|
||||||
import pprint
|
import pprint
|
||||||
import sys
|
import sys
|
||||||
|
@ -13,27 +14,12 @@ 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
|
||||||
|
|
||||||
BASE_TYPE = (type, STRING_TYPES)
|
BASE_TYPE = (type, STRING_TYPES)
|
||||||
|
|
||||||
|
|
||||||
def _cmp_raises_type_error(self, other):
|
|
||||||
"""__cmp__ implementation which raises TypeError. Used
|
|
||||||
by Approx base classes to implement only == and != and raise a
|
|
||||||
TypeError for other comparisons.
|
|
||||||
|
|
||||||
Needed in Python 2 only, Python 3 all it takes is not implementing the
|
|
||||||
other operators at all.
|
|
||||||
"""
|
|
||||||
__tracebackhide__ = True
|
|
||||||
raise TypeError(
|
|
||||||
"Comparison operators other than == and != not supported by approx objects"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _non_numeric_type_error(value, at):
|
def _non_numeric_type_error(value, at):
|
||||||
at_str = " at {}".format(at) if at else ""
|
at_str = " at {}".format(at) if at else ""
|
||||||
return TypeError(
|
return TypeError(
|
||||||
|
@ -658,7 +644,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"
|
||||||
|
|
|
@ -506,8 +506,8 @@ class TestMetafunc:
|
||||||
result = testdir.runpytest()
|
result = testdir.runpytest()
|
||||||
result.stdout.fnmatch_lines(
|
result.stdout.fnmatch_lines(
|
||||||
[
|
[
|
||||||
"*test_foo: error raised while trying to determine id of parameter 'arg' at position 0",
|
|
||||||
"*Exception: bad ids",
|
"*Exception: bad ids",
|
||||||
|
"*test_foo: error raised while trying to determine id of parameter 'arg' at position 0",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue