204 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			204 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Python
		
	
	
	
"""
 | 
						|
python version compatibility code
 | 
						|
"""
 | 
						|
import sys
 | 
						|
import inspect
 | 
						|
import types
 | 
						|
import re
 | 
						|
import functools
 | 
						|
 | 
						|
import py
 | 
						|
 | 
						|
import  _pytest
 | 
						|
 | 
						|
 | 
						|
 | 
						|
try:
 | 
						|
    import enum
 | 
						|
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
 | 
						|
 | 
						|
 | 
						|
NoneType = type(None)
 | 
						|
NOTSET = object()
 | 
						|
 | 
						|
if hasattr(inspect, 'signature'):
 | 
						|
    def _format_args(func):
 | 
						|
        return str(inspect.signature(func))
 | 
						|
else:
 | 
						|
    def _format_args(func):
 | 
						|
        return inspect.formatargspec(*inspect.getargspec(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.
 | 
						|
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
 | 
						|
 | 
						|
 | 
						|
def getlocation(function, curdir):
 | 
						|
    import inspect
 | 
						|
    fn = py.path.local(inspect.getfile(function))
 | 
						|
    lineno = py.builtin._getcode(function).co_firstlineno
 | 
						|
    if fn.relto(curdir):
 | 
						|
        fn = fn.relto(curdir)
 | 
						|
    return "%s:%d" %(fn, lineno+1)
 | 
						|
 | 
						|
 | 
						|
def num_mock_patch_args(function):
 | 
						|
    """ return number of arguments used up by mock arguments (if any) """
 | 
						|
    patchings = getattr(function, "patchings", None)
 | 
						|
    if not patchings:
 | 
						|
        return 0
 | 
						|
    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])
 | 
						|
    return len(patchings)
 | 
						|
 | 
						|
 | 
						|
def getfuncargnames(function, startindex=None):
 | 
						|
    # XXX merge with main.py's varnames
 | 
						|
    #assert not isclass(function)
 | 
						|
    realfunction = function
 | 
						|
    while hasattr(realfunction, "__wrapped__"):
 | 
						|
        realfunction = realfunction.__wrapped__
 | 
						|
    if startindex is None:
 | 
						|
        startindex = inspect.ismethod(function) and 1 or 0
 | 
						|
    if realfunction != function:
 | 
						|
        startindex += num_mock_patch_args(function)
 | 
						|
        function = realfunction
 | 
						|
    if isinstance(function, functools.partial):
 | 
						|
        argnames = inspect.getargs(_pytest._code.getrawcode(function.func))[0]
 | 
						|
        partial = function
 | 
						|
        argnames = argnames[len(partial.args):]
 | 
						|
        if partial.keywords:
 | 
						|
            for kw in partial.keywords:
 | 
						|
                argnames.remove(kw)
 | 
						|
    else:
 | 
						|
        argnames = inspect.getargs(_pytest._code.getrawcode(function))[0]
 | 
						|
    defaults = getattr(function, 'func_defaults',
 | 
						|
                       getattr(function, '__defaults__', None)) or ()
 | 
						|
    numdefaults = len(defaults)
 | 
						|
    if numdefaults:
 | 
						|
        return tuple(argnames[startindex:-numdefaults])
 | 
						|
    return tuple(argnames[startindex:])
 | 
						|
 | 
						|
 | 
						|
 | 
						|
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
 | 
						|
        something on __getattr__ calls (see #1035).
 | 
						|
        Backport of https://hg.python.org/cpython/rev/35bf8f7a8edc
 | 
						|
        """
 | 
						|
        return isinstance(object, (type, types.ClassType))
 | 
						|
 | 
						|
 | 
						|
if _PY3:
 | 
						|
    import codecs
 | 
						|
 | 
						|
    STRING_TYPES = bytes, str
 | 
						|
 | 
						|
    def _escape_strings(val):
 | 
						|
        """If val is pure ascii, returns it as a str().  Otherwise, escapes
 | 
						|
        bytes objects into a sequence of escaped bytes:
 | 
						|
 | 
						|
        b'\xc3\xb4\xc5\xd6' -> u'\\xc3\\xb4\\xc5\\xd6'
 | 
						|
 | 
						|
        and escapes unicode objects into a sequence of escaped unicode
 | 
						|
        ids, e.g.:
 | 
						|
 | 
						|
        '4\\nV\\U00043efa\\x0eMXWB\\x1e\\u3028\\u15fd\\xcd\\U0007d944'
 | 
						|
 | 
						|
        note:
 | 
						|
           the obvious "v.decode('unicode-escape')" will return
 | 
						|
           valid utf-8 unicode if it finds them in bytes, but we
 | 
						|
           want to return escaped bytes for any byte, even if they match
 | 
						|
           a utf-8 string.
 | 
						|
 | 
						|
        """
 | 
						|
        if isinstance(val, bytes):
 | 
						|
            if val:
 | 
						|
                # source: http://goo.gl/bGsnwC
 | 
						|
                encoded_bytes, _ = codecs.escape_encode(val)
 | 
						|
                return encoded_bytes.decode('ascii')
 | 
						|
            else:
 | 
						|
                # empty bytes crashes codecs.escape_encode (#1087)
 | 
						|
                return ''
 | 
						|
        else:
 | 
						|
            return val.encode('unicode_escape').decode('ascii')
 | 
						|
else:
 | 
						|
    STRING_TYPES = bytes, str, unicode
 | 
						|
 | 
						|
    def _escape_strings(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.
 | 
						|
 | 
						|
        If it's a unicode string, change the unicode characters into
 | 
						|
        unicode escapes.
 | 
						|
 | 
						|
        """
 | 
						|
        if isinstance(val, bytes):
 | 
						|
            try:
 | 
						|
                return val.encode('ascii')
 | 
						|
            except UnicodeDecodeError:
 | 
						|
                return val.encode('string-escape')
 | 
						|
        else:
 | 
						|
            return val.encode('unicode-escape')
 | 
						|
 | 
						|
 | 
						|
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__
 | 
						|
    if isinstance(obj, functools.partial):
 | 
						|
        obj = obj.func
 | 
						|
    return obj
 | 
						|
 | 
						|
def getfslineno(obj):
 | 
						|
    # xxx let decorators etc specify a sane ordering
 | 
						|
    obj = get_real_func(obj)
 | 
						|
    if hasattr(obj, 'place_as'):
 | 
						|
        obj = obj.place_as
 | 
						|
    fslineno = _pytest._code.getfslineno(obj)
 | 
						|
    assert isinstance(fslineno[1], int), obj
 | 
						|
    return fslineno
 | 
						|
 | 
						|
def getimfunc(func):
 | 
						|
    try:
 | 
						|
        return func.__func__
 | 
						|
    except AttributeError:
 | 
						|
        try:
 | 
						|
            return func.im_func
 | 
						|
        except AttributeError:
 | 
						|
            return func
 | 
						|
 | 
						|
def safe_getattr(object, name, default):
 | 
						|
    """ Like getattr but return default upon any Exception.
 | 
						|
 | 
						|
    Attribute access can potentially fail for 'evil' Python objects.
 | 
						|
    See issue214
 | 
						|
    """
 | 
						|
    try:
 | 
						|
        return getattr(object, name, default)
 | 
						|
    except Exception:
 | 
						|
        return default
 |