1""" 2python version compatibility code 3""" 4from __future__ import absolute_import, division, print_function 5import sys 6import inspect 7import types 8import re 9import functools 10 11import py 12 13import _pytest 14 15 16 17try: 18 import enum 19except ImportError: # pragma: no cover 20 # Only available in Python 3.4+ or as a backport 21 enum = None 22 23 24_PY3 = sys.version_info > (3, 0) 25_PY2 = not _PY3 26 27 28NoneType = type(None) 29NOTSET = object() 30 31PY35 = sys.version_info[:2] >= (3, 5) 32PY36 = sys.version_info[:2] >= (3, 6) 33MODULE_NOT_FOUND_ERROR = 'ModuleNotFoundError' if PY36 else 'ImportError' 34 35if hasattr(inspect, 'signature'): 36 def _format_args(func): 37 return str(inspect.signature(func)) 38else: 39 def _format_args(func): 40 return inspect.formatargspec(*inspect.getargspec(func)) 41 42isfunction = inspect.isfunction 43isclass = inspect.isclass 44# used to work around a python2 exception info leak 45exc_clear = getattr(sys, 'exc_clear', lambda: None) 46# The type of re.compile objects is not exposed in Python. 47REGEX_TYPE = type(re.compile('')) 48 49 50def is_generator(func): 51 genfunc = inspect.isgeneratorfunction(func) 52 return genfunc and not iscoroutinefunction(func) 53 54 55def iscoroutinefunction(func): 56 """Return True if func is a decorated coroutine function. 57 58 Note: copied and modified from Python 3.5's builtin couroutines.py to avoid import asyncio directly, 59 which in turns also initializes the "logging" module as side-effect (see issue #8). 60 """ 61 return (getattr(func, '_is_coroutine', False) or 62 (hasattr(inspect, 'iscoroutinefunction') and inspect.iscoroutinefunction(func))) 63 64 65def getlocation(function, curdir): 66 import inspect 67 fn = py.path.local(inspect.getfile(function)) 68 lineno = py.builtin._getcode(function).co_firstlineno 69 if fn.relto(curdir): 70 fn = fn.relto(curdir) 71 return "%s:%d" %(fn, lineno+1) 72 73 74def num_mock_patch_args(function): 75 """ return number of arguments used up by mock arguments (if any) """ 76 patchings = getattr(function, "patchings", None) 77 if not patchings: 78 return 0 79 mock = sys.modules.get("mock", sys.modules.get("unittest.mock", None)) 80 if mock is not None: 81 return len([p for p in patchings 82 if not p.attribute_name and p.new is mock.DEFAULT]) 83 return len(patchings) 84 85 86def getfuncargnames(function, startindex=None): 87 # XXX merge with main.py's varnames 88 #assert not isclass(function) 89 realfunction = function 90 while hasattr(realfunction, "__wrapped__"): 91 realfunction = realfunction.__wrapped__ 92 if startindex is None: 93 startindex = inspect.ismethod(function) and 1 or 0 94 if realfunction != function: 95 startindex += num_mock_patch_args(function) 96 function = realfunction 97 if isinstance(function, functools.partial): 98 argnames = inspect.getargs(_pytest._code.getrawcode(function.func))[0] 99 partial = function 100 argnames = argnames[len(partial.args):] 101 if partial.keywords: 102 for kw in partial.keywords: 103 argnames.remove(kw) 104 else: 105 argnames = inspect.getargs(_pytest._code.getrawcode(function))[0] 106 defaults = getattr(function, 'func_defaults', 107 getattr(function, '__defaults__', None)) or () 108 numdefaults = len(defaults) 109 if numdefaults: 110 return tuple(argnames[startindex:-numdefaults]) 111 return tuple(argnames[startindex:]) 112 113 114 115if sys.version_info[:2] == (2, 6): 116 def isclass(object): 117 """ Return true if the object is a class. Overrides inspect.isclass for 118 python 2.6 because it will return True for objects which always return 119 something on __getattr__ calls (see #1035). 120 Backport of https://hg.python.org/cpython/rev/35bf8f7a8edc 121 """ 122 return isinstance(object, (type, types.ClassType)) 123 124 125if _PY3: 126 import codecs 127 imap = map 128 STRING_TYPES = bytes, str 129 UNICODE_TYPES = str, 130 131 def _escape_strings(val): 132 """If val is pure ascii, returns it as a str(). Otherwise, escapes 133 bytes objects into a sequence of escaped bytes: 134 135 b'\xc3\xb4\xc5\xd6' -> u'\\xc3\\xb4\\xc5\\xd6' 136 137 and escapes unicode objects into a sequence of escaped unicode 138 ids, e.g.: 139 140 '4\\nV\\U00043efa\\x0eMXWB\\x1e\\u3028\\u15fd\\xcd\\U0007d944' 141 142 note: 143 the obvious "v.decode('unicode-escape')" will return 144 valid utf-8 unicode if it finds them in bytes, but we 145 want to return escaped bytes for any byte, even if they match 146 a utf-8 string. 147 148 """ 149 if isinstance(val, bytes): 150 if val: 151 # source: http://goo.gl/bGsnwC 152 encoded_bytes, _ = codecs.escape_encode(val) 153 return encoded_bytes.decode('ascii') 154 else: 155 # empty bytes crashes codecs.escape_encode (#1087) 156 return '' 157 else: 158 return val.encode('unicode_escape').decode('ascii') 159else: 160 STRING_TYPES = bytes, str, unicode 161 UNICODE_TYPES = unicode, 162 163 from itertools import imap # NOQA 164 165 def _escape_strings(val): 166 """In py2 bytes and str are the same type, so return if it's a bytes 167 object, return it unchanged if it is a full ascii string, 168 otherwise escape it into its binary form. 169 170 If it's a unicode string, change the unicode characters into 171 unicode escapes. 172 173 """ 174 if isinstance(val, bytes): 175 try: 176 return val.encode('ascii') 177 except UnicodeDecodeError: 178 return val.encode('string-escape') 179 else: 180 return val.encode('unicode-escape') 181 182 183def get_real_func(obj): 184 """ gets the real function object of the (possibly) wrapped object by 185 functools.wraps or functools.partial. 186 """ 187 start_obj = obj 188 for i in range(100): 189 new_obj = getattr(obj, '__wrapped__', None) 190 if new_obj is None: 191 break 192 obj = new_obj 193 else: 194 raise ValueError( 195 ("could not find real function of {start}" 196 "\nstopped at {current}").format( 197 start=py.io.saferepr(start_obj), 198 current=py.io.saferepr(obj))) 199 if isinstance(obj, functools.partial): 200 obj = obj.func 201 return obj 202 203 204def getfslineno(obj): 205 # xxx let decorators etc specify a sane ordering 206 obj = get_real_func(obj) 207 if hasattr(obj, 'place_as'): 208 obj = obj.place_as 209 fslineno = _pytest._code.getfslineno(obj) 210 assert isinstance(fslineno[1], int), obj 211 return fslineno 212 213 214def getimfunc(func): 215 try: 216 return func.__func__ 217 except AttributeError: 218 try: 219 return func.im_func 220 except AttributeError: 221 return func 222 223 224def safe_getattr(object, name, default): 225 """ Like getattr but return default upon any Exception. 226 227 Attribute access can potentially fail for 'evil' Python objects. 228 See issue #214. 229 """ 230 try: 231 return getattr(object, name, default) 232 except Exception: 233 return default 234 235 236def _is_unittest_unexpected_success_a_failure(): 237 """Return if the test suite should fail if a @expectedFailure unittest test PASSES. 238 239 From https://docs.python.org/3/library/unittest.html?highlight=unittest#unittest.TestResult.wasSuccessful: 240 Changed in version 3.4: Returns False if there were any 241 unexpectedSuccesses from tests marked with the expectedFailure() decorator. 242 """ 243 return sys.version_info >= (3, 4) 244 245 246if _PY3: 247 def safe_str(v): 248 """returns v as string""" 249 return str(v) 250else: 251 def safe_str(v): 252 """returns v as string, converting to ascii if necessary""" 253 try: 254 return str(v) 255 except UnicodeError: 256 if not isinstance(v, unicode): 257 v = unicode(v) 258 errors = 'replace' 259 return v.encode('utf-8', errors) 260 261 262COLLECT_FAKEMODULE_ATTRIBUTES = ( 263 'Collector', 264 'Module', 265 'Generator', 266 'Function', 267 'Instance', 268 'Session', 269 'Item', 270 'Class', 271 'File', 272 '_fillfuncargs', 273) 274 275 276def _setup_collect_fakemodule(): 277 from types import ModuleType 278 import pytest 279 pytest.collect = ModuleType('pytest.collect') 280 pytest.collect.__all__ = [] # used for setns 281 for attr in COLLECT_FAKEMODULE_ATTRIBUTES: 282 setattr(pytest.collect, attr, getattr(pytest, attr)) 283 284 285if _PY2: 286 from py.io import TextIO as CaptureIO 287else: 288 import io 289 290 class CaptureIO(io.TextIOWrapper): 291 def __init__(self): 292 super(CaptureIO, self).__init__( 293 io.BytesIO(), 294 encoding='UTF-8', newline='', write_through=True, 295 ) 296 297 def getvalue(self): 298 return self.buffer.getvalue().decode('UTF-8') 299 300class FuncargnamesCompatAttr(object): 301 """ helper class so that Metafunc, Function and FixtureRequest 302 don't need to each define the "funcargnames" compatibility attribute. 303 """ 304 @property 305 def funcargnames(self): 306 """ alias attribute for ``fixturenames`` for pre-2.3 compatibility""" 307 return self.fixturenames 308