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,13 +126,17 @@ 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): | ||||||
|     # Note: this code intentionally mirrors the code at the beginning of getfuncargnames, |     # Note: this code intentionally mirrors the code at the beginning of getfuncargnames, | ||||||
|     # to get the arguments which were excluded from its result because they had default values |     # to get the arguments which were excluded from its result because they had default values | ||||||
|  | @ -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