PageRenderTime 19ms CodeModel.GetById 11ms app.highlight 6ms RepoModel.GetById 1ms app.codeStats 0ms

/nose/pyversion.py

https://bitbucket.org/jpellerin/nose/
Python | 130 lines | 89 code | 17 blank | 24 comment | 12 complexity | 4e947d05902f1ff278cdcb7e9df69356 MD5 | raw file
  1"""
  2This module contains fixups for using nose under different versions of Python.
  3"""
  4import sys
  5import os
  6import types
  7import inspect
  8import nose.util
  9
 10__all__ = ['make_instancemethod', 'cmp_to_key', 'sort_list', 'ClassType',
 11           'TypeType', 'UNICODE_STRINGS', 'unbound_method', 'ismethod',
 12           'bytes_']
 13
 14# In Python 3.x, all strings are unicode (the call to 'unicode()' in the 2.x
 15# source will be replaced with 'str()' when running 2to3, so this test will
 16# then become true)
 17UNICODE_STRINGS = (type(unicode()) == type(str()))
 18
 19# new.instancemethod() is obsolete for new-style classes (Python 3.x)
 20# We need to use descriptor methods instead.
 21try:
 22    import new
 23    def make_instancemethod(function, instance):
 24        return new.instancemethod(function.im_func, instance,
 25                                  instance.__class__)
 26except ImportError:
 27    def make_instancemethod(function, instance):
 28        return function.__get__(instance, instance.__class__)
 29
 30# To be forward-compatible, we do all list sorts using keys instead of cmp
 31# functions.  However, part of the unittest.TestLoader API involves a
 32# user-provideable cmp function, so we need some way to convert that.
 33def cmp_to_key(mycmp):
 34    'Convert a cmp= function into a key= function'
 35    class Key(object):
 36        def __init__(self, obj):
 37            self.obj = obj
 38        def __lt__(self, other):
 39            return mycmp(self.obj, other.obj) < 0
 40        def __gt__(self, other):
 41            return mycmp(self.obj, other.obj) > 0
 42        def __eq__(self, other):
 43            return mycmp(self.obj, other.obj) == 0
 44    return Key
 45
 46# Python 2.3 also does not support list-sorting by key, so we need to convert
 47# keys to cmp functions if we're running on old Python..
 48if sys.version_info < (2, 4):
 49    def sort_list(l, key, reverse=False):
 50        if reverse:
 51            return l.sort(lambda a, b: cmp(key(b), key(a)))
 52        else:
 53            return l.sort(lambda a, b: cmp(key(a), key(b)))
 54else:
 55    def sort_list(l, key, reverse=False):
 56        return l.sort(key=key, reverse=reverse)
 57
 58# In Python 3.x, all objects are "new style" objects descended from 'type', and
 59# thus types.ClassType and types.TypeType don't exist anymore.  For
 60# compatibility, we make sure they still work.
 61if hasattr(types, 'ClassType'):
 62    ClassType = types.ClassType
 63    TypeType = types.TypeType
 64else:
 65    ClassType = type
 66    TypeType = type
 67
 68# The following emulates the behavior (we need) of an 'unbound method' under
 69# Python 3.x (namely, the ability to have a class associated with a function
 70# definition so that things can do stuff based on its associated class)
 71class UnboundMethod:
 72    def __init__(self, cls, func):
 73        # Make sure we have all the same attributes as the original function,
 74        # so that the AttributeSelector plugin will work correctly...
 75        self.__dict__ = func.__dict__.copy()
 76        self._func = func
 77        self.__self__ = UnboundSelf(cls)
 78
 79    def address(self):
 80        cls = self.__self__.cls
 81        modname = cls.__module__
 82        module = sys.modules[modname]
 83        filename = getattr(module, '__file__', None)
 84        if filename is not None:
 85            filename = os.path.abspath(filename)
 86        return (nose.util.src(filename), modname, "%s.%s" % (cls.__name__,
 87                                                        self._func.__name__))
 88
 89    def __call__(self, *args, **kwargs):
 90        return self._func(*args, **kwargs)
 91
 92    def __getattr__(self, attr):
 93        return getattr(self._func, attr)
 94
 95    def __repr__(self):
 96        return '<unbound method %s.%s>' % (self.__self__.cls.__name__,
 97                                           self._func.__name__)
 98
 99class UnboundSelf:
100    def __init__(self, cls):
101        self.cls = cls
102
103    # We have to do this hackery because Python won't let us override the
104    # __class__ attribute...
105    def __getattribute__(self, attr):
106        if attr == '__class__':
107            return self.cls
108        else:
109            return object.__getattribute__(self, attr)
110
111def unbound_method(cls, func):
112    if inspect.ismethod(func):
113        return func
114    if not inspect.isfunction(func):
115        raise TypeError('%s is not a function' % (repr(func),))
116    return UnboundMethod(cls, func)
117
118def ismethod(obj):
119    return inspect.ismethod(obj) or isinstance(obj, UnboundMethod)
120
121
122# Make a pseudo-bytes function that can be called without the encoding arg:
123if sys.version_info >= (3, 0):
124    def bytes_(s, encoding='utf8'):
125        if isinstance(s, bytes):
126            return s
127        return bytes(s, encoding)
128else:
129    def bytes_(s, encoding=None):
130        return str(s)