summaryrefslogtreecommitdiff
path: root/lib/spack/external/_pytest/compat.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/spack/external/_pytest/compat.py')
-rw-r--r--lib/spack/external/_pytest/compat.py140
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