1"""Utility functions and classes used by nose internally. 2""" 3import inspect 4import os 5import sys 6import types 7try: 8 # for python 3 9 from types import ClassType, TypeType 10 class_types = (ClassType, TypeType) 11except: 12 class_types = (type, ) 13 14try: 15 #for jython 16 from compiler.consts import CO_GENERATOR 17except: 18 CO_GENERATOR=0x20 19 20PYTHON_VERSION_MAJOR = sys.version_info[0] 21PYTHON_VERSION_MINOR = sys.version_info[1] 22 23def cmp_lineno(a, b): 24 """Compare functions by their line numbers. 25 """ 26 return cmp(func_lineno(a), func_lineno(b)) 27 28def func_lineno(func): 29 """Get the line number of a function. 30 """ 31 try: 32 return func.compat_co_firstlineno 33 except AttributeError: 34 try: 35 if PYTHON_VERSION_MAJOR == 3: 36 return func.__code__.co_firstlineno 37 return func.func_code.co_firstlineno 38 except AttributeError: 39 return -1 40 41def isclass(obj): 42 obj_type = type(obj) 43 return obj_type in class_types or issubclass(obj_type, type) 44 45def isgenerator(func): 46 if PYTHON_VERSION_MAJOR == 3: 47 return inspect.isgeneratorfunction(func) 48 try: 49 return func.func_code.co_flags & CO_GENERATOR != 0 50 except AttributeError: 51 return False 52 53def resolve_name(name, module=None): 54 """Resolve a dotted name to a module and its parts. 55 """ 56 parts = name.split('.') 57 parts_copy = parts[:] 58 if module is None: 59 while parts_copy: 60 try: 61 module = __import__('.'.join(parts_copy)) 62 break 63 except ImportError: 64 del parts_copy[-1] 65 if not parts_copy: 66 raise 67 parts = parts[1:] 68 obj = module 69 for part in parts: 70 obj = getattr(obj, part) 71 return obj 72 73def try_run(obj, names): 74 """Given a list of possible method names, try to run them with the 75 provided object. 76 """ 77 for name in names: 78 func = getattr(obj, name, None) 79 if func is not None: 80 if type(obj) == types.ModuleType: 81 try: 82 args, varargs, varkw, defaults = inspect.getargspec(func) 83 except TypeError: 84 if hasattr(func, '__call__'): 85 func = func.__call__ 86 try: 87 args, varargs, varkw, defaults = \ 88 inspect.getargspec(func) 89 args.pop(0) 90 except TypeError: 91 raise TypeError("Attribute %s of %r is not a python " 92 "function. Only functions or callables" 93 " may be used as fixtures." % 94 (name, obj)) 95 if len(args): 96 return func(obj) 97 return func() 98 99def src(filename): 100 """Find the python source file for a .pyc, .pyo 101 or $py.class file on jython 102 """ 103 if filename is None: 104 return filename 105 if sys.platform.startswith('java') and filename.endswith('$py.class'): 106 return '.'.join((filename[:-9], 'py')) 107 base, ext = os.path.splitext(filename) 108 if ext in ('.pyc', '.pyo', '.py'): 109 return '.'.join((base, 'py')) 110 return filename 111 112def transplant_class(cls, module): 113 """ 114 Make a class appear to reside in `module`, rather than the module in which 115 it is actually defined. 116 """ 117 class C(cls): 118 pass 119 C.__module__ = module 120 C.__name__ = cls.__name__ 121 return C 122 123def transplant_func(func, module = None): 124 """ 125 Make a function imported from module A appear as if it is located 126 in module B. 127 """ 128 129 def newfunc(*arg, **kw): 130 return func(*arg, **kw) 131 132 newfunc = make_decorator(func)(newfunc) 133 if module is None: 134 newfunc.__module__ = inspect.getmodule(func) 135 else: 136 newfunc.__module__ = module 137 return newfunc 138 139def make_decorator(func): 140 """ 141 Wraps a test decorator so as to properly replicate metadata 142 of the decorated function. 143 """ 144 def decorate(newfunc): 145 if hasattr(func, 'compat_func_name'): 146 name = func.compat_func_name 147 else: 148 name = func.__name__ 149 newfunc.__dict__ = func.__dict__ 150 newfunc.__doc__ = func.__doc__ 151 if not hasattr(newfunc, 'compat_co_firstlineno'): 152 if PYTHON_VERSION_MAJOR == 3: 153 newfunc.compat_co_firstlineno = func.__code__.co_firstlineno 154 else: 155 newfunc.compat_co_firstlineno = func.func_code.co_firstlineno 156 try: 157 newfunc.__name__ = name 158 except TypeError: 159 newfunc.compat_func_name = name 160 return newfunc 161 return decorate 162 163# trick for python 3 164# The following emulates the behavior (we need) of an 'unbound method' under 165# Python 3.x (namely, the ability to have a class associated with a function 166# definition so that things can do stuff based on its associated class) 167 168class UnboundMethod: 169 def __init__(self, cls, func): 170 self.func = func 171 self.__self__ = UnboundSelf(cls) 172 173 def address(self): 174 cls = self.__self__.cls 175 module = cls.__module__ 176 m = sys.modules[module] 177 file = getattr(m, '__file__', None) 178 if file is not None: 179 file = os.path.abspath(file) 180 return (nose.util.src(file), module, "%s.%s" % (cls.__name__, self.func.__name__)) 181 182 def __call__(self, *args, **kwargs): 183 return self.func(*args, **kwargs) 184 185 def __getattr__(self, attr): 186 return getattr(self.func, attr) 187 188class UnboundSelf: 189 def __init__(self, cls): 190 self.cls = cls 191 192 # We have to do this hackery because Python won't let us override the 193 # __class__ attribute... 194 def __getattribute__(self, attr): 195 if attr == '__class__': 196 return self.cls 197 else: 198 return object.__getattribute__(self, attr) 199 200def unbound_method(cls, func): 201 if inspect.ismethod(func): 202 return func 203 if not inspect.isfunction(func): 204 raise TypeError('%s is not a function' % (repr(func),)) 205 return UnboundMethod(cls, func) 206 207def ismethod(obj): 208 return inspect.ismethod(obj) or isinstance(obj, UnboundMethod) 209 210def isunboundmethod(obj): 211 return (inspect.ismethod(obj) and obj.im_self is None) or isinstance(obj, UnboundMethod) 212