diff options
Diffstat (limited to 'lib/spack/external/_pytest/compat.py')
-rw-r--r-- | lib/spack/external/_pytest/compat.py | 140 |
1 files changed, 118 insertions, 22 deletions
diff --git a/lib/spack/external/_pytest/compat.py b/lib/spack/external/_pytest/compat.py index 51fc3bc5c1..255f69ce0d 100644 --- a/lib/spack/external/_pytest/compat.py +++ b/lib/spack/external/_pytest/compat.py @@ -1,6 +1,7 @@ """ python version compatibility code """ +from __future__ import absolute_import, division, print_function import sys import inspect import types @@ -9,8 +10,8 @@ import functools import py -import _pytest - +import _pytest +from _pytest.outcomes import TEST_OUTCOME try: @@ -19,6 +20,7 @@ except ImportError: # pragma: no cover # Only available in Python 3.4+ or as a backport enum = None + _PY3 = sys.version_info > (3, 0) _PY2 = not _PY3 @@ -26,6 +28,10 @@ _PY2 = not _PY3 NoneType = type(None) NOTSET = object() +PY35 = sys.version_info[:2] >= (3, 5) +PY36 = sys.version_info[:2] >= (3, 6) +MODULE_NOT_FOUND_ERROR = 'ModuleNotFoundError' if PY36 else 'ImportError' + if hasattr(inspect, 'signature'): def _format_args(func): return str(inspect.signature(func)) @@ -42,11 +48,18 @@ REGEX_TYPE = type(re.compile('')) def is_generator(func): - try: - return _pytest._code.getrawcode(func).co_flags & 32 # generator function - except AttributeError: # builtin functions have no bytecode - # assume them to not be generators - return False + genfunc = inspect.isgeneratorfunction(func) + return genfunc and not iscoroutinefunction(func) + + +def iscoroutinefunction(func): + """Return True if func is a decorated coroutine function. + + Note: copied and modified from Python 3.5's builtin couroutines.py to avoid import asyncio directly, + which in turns also initializes the "logging" module as side-effect (see issue #8). + """ + return (getattr(func, '_is_coroutine', False) or + (hasattr(inspect, 'iscoroutinefunction') and inspect.iscoroutinefunction(func))) def getlocation(function, curdir): @@ -55,7 +68,7 @@ def getlocation(function, curdir): lineno = py.builtin._getcode(function).co_firstlineno if fn.relto(curdir): fn = fn.relto(curdir) - return "%s:%d" %(fn, lineno+1) + return "%s:%d" % (fn, lineno + 1) def num_mock_patch_args(function): @@ -66,13 +79,21 @@ def num_mock_patch_args(function): mock = sys.modules.get("mock", sys.modules.get("unittest.mock", None)) if mock is not None: return len([p for p in patchings - if not p.attribute_name and p.new is mock.DEFAULT]) + if not p.attribute_name and p.new is mock.DEFAULT]) return len(patchings) -def getfuncargnames(function, startindex=None): +def getfuncargnames(function, startindex=None, cls=None): + """ + @RonnyPfannschmidt: This function should be refactored when we revisit fixtures. The + fixture mechanism should ask the node for the fixture names, and not try to obtain + directly from the function object well after collection has occurred. + """ + if startindex is None and cls is not None: + is_staticmethod = isinstance(cls.__dict__.get(function.__name__, None), staticmethod) + startindex = 0 if is_staticmethod else 1 # XXX merge with main.py's varnames - #assert not isclass(function) + # assert not isclass(function) realfunction = function while hasattr(realfunction, "__wrapped__"): realfunction = realfunction.__wrapped__ @@ -98,8 +119,7 @@ def getfuncargnames(function, startindex=None): return tuple(argnames[startindex:]) - -if sys.version_info[:2] == (2, 6): +if sys.version_info[:2] == (2, 6): def isclass(object): """ Return true if the object is a class. Overrides inspect.isclass for python 2.6 because it will return True for objects which always return @@ -111,10 +131,12 @@ if sys.version_info[:2] == (2, 6): if _PY3: import codecs - + imap = map + izip = zip STRING_TYPES = bytes, str + UNICODE_TYPES = str, - def _escape_strings(val): + def _ascii_escaped(val): """If val is pure ascii, returns it as a str(). Otherwise, escapes bytes objects into a sequence of escaped bytes: @@ -144,8 +166,11 @@ if _PY3: return val.encode('unicode_escape').decode('ascii') else: STRING_TYPES = bytes, str, unicode + UNICODE_TYPES = unicode, - def _escape_strings(val): + from itertools import imap, izip # NOQA + + def _ascii_escaped(val): """In py2 bytes and str are the same type, so return if it's a bytes object, return it unchanged if it is a full ascii string, otherwise escape it into its binary form. @@ -167,8 +192,18 @@ def get_real_func(obj): """ gets the real function object of the (possibly) wrapped object by functools.wraps or functools.partial. """ - while hasattr(obj, "__wrapped__"): - obj = obj.__wrapped__ + start_obj = obj + for i in range(100): + new_obj = getattr(obj, '__wrapped__', None) + if new_obj is None: + break + obj = new_obj + else: + raise ValueError( + ("could not find real function of {start}" + "\nstopped at {current}").format( + start=py.io.saferepr(start_obj), + current=py.io.saferepr(obj))) if isinstance(obj, functools.partial): obj = obj.func return obj @@ -195,14 +230,16 @@ def getimfunc(func): def safe_getattr(object, name, default): - """ Like getattr but return default upon any Exception. + """ Like getattr but return default upon any Exception or any OutcomeException. Attribute access can potentially fail for 'evil' Python objects. - See issue214 + See issue #214. + It catches OutcomeException because of #2490 (issue #580), new outcomes are derived from BaseException + instead of Exception (for more details check #2707) """ try: return getattr(object, name, default) - except Exception: + except TEST_OUTCOME: return default @@ -226,5 +263,64 @@ else: try: return str(v) except UnicodeError: + if not isinstance(v, unicode): + v = unicode(v) errors = 'replace' - return v.encode('ascii', errors) + return v.encode('utf-8', errors) + + +COLLECT_FAKEMODULE_ATTRIBUTES = ( + 'Collector', + 'Module', + 'Generator', + 'Function', + 'Instance', + 'Session', + 'Item', + 'Class', + 'File', + '_fillfuncargs', +) + + +def _setup_collect_fakemodule(): + from types import ModuleType + import pytest + pytest.collect = ModuleType('pytest.collect') + pytest.collect.__all__ = [] # used for setns + for attr in COLLECT_FAKEMODULE_ATTRIBUTES: + setattr(pytest.collect, attr, getattr(pytest, attr)) + + +if _PY2: + # Without this the test_dupfile_on_textio will fail, otherwise CaptureIO could directly inherit from StringIO. + from py.io import TextIO + + class CaptureIO(TextIO): + + @property + def encoding(self): + return getattr(self, '_encoding', 'UTF-8') + +else: + import io + + class CaptureIO(io.TextIOWrapper): + def __init__(self): + super(CaptureIO, self).__init__( + io.BytesIO(), + encoding='UTF-8', newline='', write_through=True, + ) + + def getvalue(self): + return self.buffer.getvalue().decode('UTF-8') + + +class FuncargnamesCompatAttr(object): + """ helper class so that Metafunc, Function and FixtureRequest + don't need to each define the "funcargnames" compatibility attribute. + """ + @property + def funcargnames(self): + """ alias attribute for ``fixturenames`` for pre-2.3 compatibility""" + return self.fixturenames |