|
| 1 | +""" |
| 2 | +python version compatibility code |
| 3 | +""" |
| 4 | +import sys |
| 5 | +import inspect |
| 6 | +import types |
| 7 | +import re |
| 8 | +import functools |
| 9 | + |
| 10 | +import py |
| 11 | + |
| 12 | +import _pytest |
| 13 | + |
| 14 | + |
| 15 | + |
| 16 | +try: |
| 17 | + import enum |
| 18 | +except ImportError: # pragma: no cover |
| 19 | + # Only available in Python 3.4+ or as a backport |
| 20 | + enum = None |
| 21 | + |
| 22 | +_PY3 = sys.version_info > (3, 0) |
| 23 | +_PY2 = not _PY3 |
| 24 | + |
| 25 | + |
| 26 | +NoneType = type(None) |
| 27 | +NOTSET = object() |
| 28 | + |
| 29 | +if hasattr(inspect, 'signature'): |
| 30 | + def _format_args(func): |
| 31 | + return str(inspect.signature(func)) |
| 32 | +else: |
| 33 | + def _format_args(func): |
| 34 | + return inspect.formatargspec(*inspect.getargspec(func)) |
| 35 | + |
| 36 | +isfunction = inspect.isfunction |
| 37 | +isclass = inspect.isclass |
| 38 | +# used to work around a python2 exception info leak |
| 39 | +exc_clear = getattr(sys, 'exc_clear', lambda: None) |
| 40 | +# The type of re.compile objects is not exposed in Python. |
| 41 | +REGEX_TYPE = type(re.compile('')) |
| 42 | + |
| 43 | + |
| 44 | +def is_generator(func): |
| 45 | + try: |
| 46 | + return _pytest._code.getrawcode(func).co_flags & 32 # generator function |
| 47 | + except AttributeError: # builtin functions have no bytecode |
| 48 | + # assume them to not be generators |
| 49 | + return False |
| 50 | + |
| 51 | + |
| 52 | +def getlocation(function, curdir): |
| 53 | + import inspect |
| 54 | + fn = py.path.local(inspect.getfile(function)) |
| 55 | + lineno = py.builtin._getcode(function).co_firstlineno |
| 56 | + if fn.relto(curdir): |
| 57 | + fn = fn.relto(curdir) |
| 58 | + return "%s:%d" %(fn, lineno+1) |
| 59 | + |
| 60 | + |
| 61 | +def num_mock_patch_args(function): |
| 62 | + """ return number of arguments used up by mock arguments (if any) """ |
| 63 | + patchings = getattr(function, "patchings", None) |
| 64 | + if not patchings: |
| 65 | + return 0 |
| 66 | + mock = sys.modules.get("mock", sys.modules.get("unittest.mock", None)) |
| 67 | + if mock is not None: |
| 68 | + return len([p for p in patchings |
| 69 | + if not p.attribute_name and p.new is mock.DEFAULT]) |
| 70 | + return len(patchings) |
| 71 | + |
| 72 | + |
| 73 | +def getfuncargnames(function, startindex=None): |
| 74 | + # XXX merge with main.py's varnames |
| 75 | + #assert not isclass(function) |
| 76 | + realfunction = function |
| 77 | + while hasattr(realfunction, "__wrapped__"): |
| 78 | + realfunction = realfunction.__wrapped__ |
| 79 | + if startindex is None: |
| 80 | + startindex = inspect.ismethod(function) and 1 or 0 |
| 81 | + if realfunction != function: |
| 82 | + startindex += num_mock_patch_args(function) |
| 83 | + function = realfunction |
| 84 | + if isinstance(function, functools.partial): |
| 85 | + argnames = inspect.getargs(_pytest._code.getrawcode(function.func))[0] |
| 86 | + partial = function |
| 87 | + argnames = argnames[len(partial.args):] |
| 88 | + if partial.keywords: |
| 89 | + for kw in partial.keywords: |
| 90 | + argnames.remove(kw) |
| 91 | + else: |
| 92 | + argnames = inspect.getargs(_pytest._code.getrawcode(function))[0] |
| 93 | + defaults = getattr(function, 'func_defaults', |
| 94 | + getattr(function, '__defaults__', None)) or () |
| 95 | + numdefaults = len(defaults) |
| 96 | + if numdefaults: |
| 97 | + return tuple(argnames[startindex:-numdefaults]) |
| 98 | + return tuple(argnames[startindex:]) |
| 99 | + |
| 100 | + |
| 101 | + |
| 102 | +if sys.version_info[:2] == (2, 6): |
| 103 | + def isclass(object): |
| 104 | + """ Return true if the object is a class. Overrides inspect.isclass for |
| 105 | + python 2.6 because it will return True for objects which always return |
| 106 | + something on __getattr__ calls (see #1035). |
| 107 | + Backport of https://hg.python.org/cpython/rev/35bf8f7a8edc |
| 108 | + """ |
| 109 | + return isinstance(object, (type, types.ClassType)) |
| 110 | + |
| 111 | + |
| 112 | +if _PY3: |
| 113 | + import codecs |
| 114 | + |
| 115 | + STRING_TYPES = bytes, str |
| 116 | + |
| 117 | + def _escape_strings(val): |
| 118 | + """If val is pure ascii, returns it as a str(). Otherwise, escapes |
| 119 | + bytes objects into a sequence of escaped bytes: |
| 120 | +
|
| 121 | + b'\xc3\xb4\xc5\xd6' -> u'\\xc3\\xb4\\xc5\\xd6' |
| 122 | +
|
| 123 | + and escapes unicode objects into a sequence of escaped unicode |
| 124 | + ids, e.g.: |
| 125 | +
|
| 126 | + '4\\nV\\U00043efa\\x0eMXWB\\x1e\\u3028\\u15fd\\xcd\\U0007d944' |
| 127 | +
|
| 128 | + note: |
| 129 | + the obvious "v.decode('unicode-escape')" will return |
| 130 | + valid utf-8 unicode if it finds them in bytes, but we |
| 131 | + want to return escaped bytes for any byte, even if they match |
| 132 | + a utf-8 string. |
| 133 | +
|
| 134 | + """ |
| 135 | + if isinstance(val, bytes): |
| 136 | + if val: |
| 137 | + # source: http://goo.gl/bGsnwC |
| 138 | + encoded_bytes, _ = codecs.escape_encode(val) |
| 139 | + return encoded_bytes.decode('ascii') |
| 140 | + else: |
| 141 | + # empty bytes crashes codecs.escape_encode (#1087) |
| 142 | + return '' |
| 143 | + else: |
| 144 | + return val.encode('unicode_escape').decode('ascii') |
| 145 | +else: |
| 146 | + STRING_TYPES = bytes, str, unicode |
| 147 | + |
| 148 | + def _escape_strings(val): |
| 149 | + """In py2 bytes and str are the same type, so return if it's a bytes |
| 150 | + object, return it unchanged if it is a full ascii string, |
| 151 | + otherwise escape it into its binary form. |
| 152 | +
|
| 153 | + If it's a unicode string, change the unicode characters into |
| 154 | + unicode escapes. |
| 155 | +
|
| 156 | + """ |
| 157 | + if isinstance(val, bytes): |
| 158 | + try: |
| 159 | + return val.encode('ascii') |
| 160 | + except UnicodeDecodeError: |
| 161 | + return val.encode('string-escape') |
| 162 | + else: |
| 163 | + return val.encode('unicode-escape') |
| 164 | + |
| 165 | + |
| 166 | +def get_real_func(obj): |
| 167 | + """ gets the real function object of the (possibly) wrapped object by |
| 168 | + functools.wraps or functools.partial. |
| 169 | + """ |
| 170 | + while hasattr(obj, "__wrapped__"): |
| 171 | + obj = obj.__wrapped__ |
| 172 | + if isinstance(obj, functools.partial): |
| 173 | + obj = obj.func |
| 174 | + return obj |
| 175 | + |
| 176 | +def getfslineno(obj): |
| 177 | + # xxx let decorators etc specify a sane ordering |
| 178 | + obj = get_real_func(obj) |
| 179 | + if hasattr(obj, 'place_as'): |
| 180 | + obj = obj.place_as |
| 181 | + fslineno = _pytest._code.getfslineno(obj) |
| 182 | + assert isinstance(fslineno[1], int), obj |
| 183 | + return fslineno |
| 184 | + |
| 185 | +def getimfunc(func): |
| 186 | + try: |
| 187 | + return func.__func__ |
| 188 | + except AttributeError: |
| 189 | + try: |
| 190 | + return func.im_func |
| 191 | + except AttributeError: |
| 192 | + return func |
| 193 | + |
| 194 | +def safe_getattr(object, name, default): |
| 195 | + """ Like getattr but return default upon any Exception. |
| 196 | +
|
| 197 | + Attribute access can potentially fail for 'evil' Python objects. |
| 198 | + See issue214 |
| 199 | + """ |
| 200 | + try: |
| 201 | + return getattr(object, name, default) |
| 202 | + except Exception: |
| 203 | + return default |
0 commit comments