mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-18 08:50:57 +07:00
212 lines
6.2 KiB
Python
212 lines
6.2 KiB
Python
"""Utility functions and classes used by nose internally.
|
|
"""
|
|
import inspect
|
|
import os
|
|
import sys
|
|
import types
|
|
try:
|
|
# for python 3
|
|
from types import ClassType, TypeType
|
|
class_types = (ClassType, TypeType)
|
|
except:
|
|
class_types = (type, )
|
|
|
|
try:
|
|
#for jython
|
|
from compiler.consts import CO_GENERATOR
|
|
except:
|
|
CO_GENERATOR=0x20
|
|
|
|
PYTHON_VERSION_MAJOR = sys.version_info[0]
|
|
PYTHON_VERSION_MINOR = sys.version_info[1]
|
|
|
|
def cmp_lineno(a, b):
|
|
"""Compare functions by their line numbers.
|
|
"""
|
|
return cmp(func_lineno(a), func_lineno(b))
|
|
|
|
def func_lineno(func):
|
|
"""Get the line number of a function.
|
|
"""
|
|
try:
|
|
return func.compat_co_firstlineno
|
|
except AttributeError:
|
|
try:
|
|
if PYTHON_VERSION_MAJOR == 3:
|
|
return func.__code__.co_firstlineno
|
|
return func.func_code.co_firstlineno
|
|
except AttributeError:
|
|
return -1
|
|
|
|
def isclass(obj):
|
|
obj_type = type(obj)
|
|
return obj_type in class_types or issubclass(obj_type, type)
|
|
|
|
def isgenerator(func):
|
|
if PYTHON_VERSION_MAJOR == 3:
|
|
return inspect.isgeneratorfunction(func)
|
|
try:
|
|
return func.func_code.co_flags & CO_GENERATOR != 0
|
|
except AttributeError:
|
|
return False
|
|
|
|
def resolve_name(name, module=None):
|
|
"""Resolve a dotted name to a module and its parts.
|
|
"""
|
|
parts = name.split('.')
|
|
parts_copy = parts[:]
|
|
if module is None:
|
|
while parts_copy:
|
|
try:
|
|
module = __import__('.'.join(parts_copy))
|
|
break
|
|
except ImportError:
|
|
del parts_copy[-1]
|
|
if not parts_copy:
|
|
raise
|
|
parts = parts[1:]
|
|
obj = module
|
|
for part in parts:
|
|
obj = getattr(obj, part)
|
|
return obj
|
|
|
|
def try_run(obj, names):
|
|
"""Given a list of possible method names, try to run them with the
|
|
provided object.
|
|
"""
|
|
for name in names:
|
|
func = getattr(obj, name, None)
|
|
if func is not None:
|
|
if type(obj) == types.ModuleType:
|
|
try:
|
|
args, varargs, varkw, defaults = inspect.getargspec(func)
|
|
except TypeError:
|
|
if hasattr(func, '__call__'):
|
|
func = func.__call__
|
|
try:
|
|
args, varargs, varkw, defaults = \
|
|
inspect.getargspec(func)
|
|
args.pop(0)
|
|
except TypeError:
|
|
raise TypeError("Attribute %s of %r is not a python "
|
|
"function. Only functions or callables"
|
|
" may be used as fixtures." %
|
|
(name, obj))
|
|
if len(args):
|
|
return func(obj)
|
|
return func()
|
|
|
|
def src(filename):
|
|
"""Find the python source file for a .pyc, .pyo
|
|
or $py.class file on jython
|
|
"""
|
|
if filename is None:
|
|
return filename
|
|
if sys.platform.startswith('java') and filename.endswith('$py.class'):
|
|
return '.'.join((filename[:-9], 'py'))
|
|
base, ext = os.path.splitext(filename)
|
|
if ext in ('.pyc', '.pyo', '.py'):
|
|
return '.'.join((base, 'py'))
|
|
return filename
|
|
|
|
def transplant_class(cls, module):
|
|
"""
|
|
Make a class appear to reside in `module`, rather than the module in which
|
|
it is actually defined.
|
|
"""
|
|
class C(cls):
|
|
pass
|
|
C.__module__ = module
|
|
C.__name__ = cls.__name__
|
|
return C
|
|
|
|
def transplant_func(func, module = None):
|
|
"""
|
|
Make a function imported from module A appear as if it is located
|
|
in module B.
|
|
"""
|
|
|
|
def newfunc(*arg, **kw):
|
|
return func(*arg, **kw)
|
|
|
|
newfunc = make_decorator(func)(newfunc)
|
|
if module is None:
|
|
newfunc.__module__ = inspect.getmodule(func)
|
|
else:
|
|
newfunc.__module__ = module
|
|
return newfunc
|
|
|
|
def make_decorator(func):
|
|
"""
|
|
Wraps a test decorator so as to properly replicate metadata
|
|
of the decorated function.
|
|
"""
|
|
def decorate(newfunc):
|
|
if hasattr(func, 'compat_func_name'):
|
|
name = func.compat_func_name
|
|
else:
|
|
name = func.__name__
|
|
newfunc.__dict__ = func.__dict__
|
|
newfunc.__doc__ = func.__doc__
|
|
if not hasattr(newfunc, 'compat_co_firstlineno'):
|
|
if PYTHON_VERSION_MAJOR == 3:
|
|
newfunc.compat_co_firstlineno = func.__code__.co_firstlineno
|
|
else:
|
|
newfunc.compat_co_firstlineno = func.func_code.co_firstlineno
|
|
try:
|
|
newfunc.__name__ = name
|
|
except TypeError:
|
|
newfunc.compat_func_name = name
|
|
return newfunc
|
|
return decorate
|
|
|
|
# trick for python 3
|
|
# The following emulates the behavior (we need) of an 'unbound method' under
|
|
# Python 3.x (namely, the ability to have a class associated with a function
|
|
# definition so that things can do stuff based on its associated class)
|
|
|
|
class UnboundMethod:
|
|
def __init__(self, cls, func):
|
|
self.func = func
|
|
self.__self__ = UnboundSelf(cls)
|
|
|
|
def address(self):
|
|
cls = self.__self__.cls
|
|
module = cls.__module__
|
|
m = sys.modules[module]
|
|
file = getattr(m, '__file__', None)
|
|
if file is not None:
|
|
file = os.path.abspath(file)
|
|
return (nose.util.src(file), module, "%s.%s" % (cls.__name__, self.func.__name__))
|
|
|
|
def __call__(self, *args, **kwargs):
|
|
return self.func(*args, **kwargs)
|
|
|
|
def __getattr__(self, attr):
|
|
return getattr(self.func, attr)
|
|
|
|
class UnboundSelf:
|
|
def __init__(self, cls):
|
|
self.cls = cls
|
|
|
|
# We have to do this hackery because Python won't let us override the
|
|
# __class__ attribute...
|
|
def __getattribute__(self, attr):
|
|
if attr == '__class__':
|
|
return self.cls
|
|
else:
|
|
return object.__getattribute__(self, attr)
|
|
|
|
def unbound_method(cls, func):
|
|
if inspect.ismethod(func):
|
|
return func
|
|
if not inspect.isfunction(func):
|
|
raise TypeError('%s is not a function' % (repr(func),))
|
|
return UnboundMethod(cls, func)
|
|
|
|
def ismethod(obj):
|
|
return inspect.ismethod(obj) or isinstance(obj, UnboundMethod)
|
|
|
|
def isunboundmethod(obj):
|
|
return (inspect.ismethod(obj) and obj.im_self is None) or isinstance(obj, UnboundMethod)
|