pyversion.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. """
  2. This module contains fixups for using nose under different versions of Python.
  3. """
  4. import sys
  5. import os
  6. import traceback
  7. import types
  8. import inspect
  9. import nose.util
  10. __all__ = ['make_instancemethod', 'cmp_to_key', 'sort_list', 'ClassType',
  11. 'TypeType', 'UNICODE_STRINGS', 'unbound_method', 'ismethod',
  12. 'bytes_', 'is_base_exception', 'force_unicode', 'exc_to_unicode',
  13. 'format_exception']
  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)
  17. UNICODE_STRINGS = (type(unicode()) == type(str()))
  18. if sys.version_info[:2] < (3, 0):
  19. def force_unicode(s, encoding='UTF-8'):
  20. try:
  21. s = unicode(s)
  22. except UnicodeDecodeError:
  23. s = str(s).decode(encoding, 'replace')
  24. return s
  25. else:
  26. def force_unicode(s, encoding='UTF-8'):
  27. return str(s)
  28. # new.instancemethod() is obsolete for new-style classes (Python 3.x)
  29. # We need to use descriptor methods instead.
  30. try:
  31. import new
  32. def make_instancemethod(function, instance):
  33. return new.instancemethod(function.im_func, instance,
  34. instance.__class__)
  35. except ImportError:
  36. def make_instancemethod(function, instance):
  37. return function.__get__(instance, instance.__class__)
  38. # To be forward-compatible, we do all list sorts using keys instead of cmp
  39. # functions. However, part of the unittest.TestLoader API involves a
  40. # user-provideable cmp function, so we need some way to convert that.
  41. def cmp_to_key(mycmp):
  42. 'Convert a cmp= function into a key= function'
  43. class Key(object):
  44. def __init__(self, obj):
  45. self.obj = obj
  46. def __lt__(self, other):
  47. return mycmp(self.obj, other.obj) < 0
  48. def __gt__(self, other):
  49. return mycmp(self.obj, other.obj) > 0
  50. def __eq__(self, other):
  51. return mycmp(self.obj, other.obj) == 0
  52. return Key
  53. # Python 2.3 also does not support list-sorting by key, so we need to convert
  54. # keys to cmp functions if we're running on old Python..
  55. if sys.version_info < (2, 4):
  56. def sort_list(l, key, reverse=False):
  57. if reverse:
  58. return l.sort(lambda a, b: cmp(key(b), key(a)))
  59. else:
  60. return l.sort(lambda a, b: cmp(key(a), key(b)))
  61. else:
  62. def sort_list(l, key, reverse=False):
  63. return l.sort(key=key, reverse=reverse)
  64. # In Python 3.x, all objects are "new style" objects descended from 'type', and
  65. # thus types.ClassType and types.TypeType don't exist anymore. For
  66. # compatibility, we make sure they still work.
  67. if hasattr(types, 'ClassType'):
  68. ClassType = types.ClassType
  69. TypeType = types.TypeType
  70. else:
  71. ClassType = type
  72. TypeType = type
  73. # The following emulates the behavior (we need) of an 'unbound method' under
  74. # Python 3.x (namely, the ability to have a class associated with a function
  75. # definition so that things can do stuff based on its associated class)
  76. class UnboundMethod:
  77. def __init__(self, cls, func):
  78. # Make sure we have all the same attributes as the original function,
  79. # so that the AttributeSelector plugin will work correctly...
  80. self.__dict__ = func.__dict__.copy()
  81. self._func = func
  82. self.__self__ = UnboundSelf(cls)
  83. if sys.version_info < (3, 0):
  84. self.im_class = cls
  85. self.__doc__ = getattr(func, '__doc__', None)
  86. def address(self):
  87. cls = self.__self__.cls
  88. modname = cls.__module__
  89. module = sys.modules[modname]
  90. filename = getattr(module, '__file__', None)
  91. if filename is not None:
  92. filename = os.path.abspath(filename)
  93. return (nose.util.src(filename), modname, "%s.%s" % (cls.__name__,
  94. self._func.__name__))
  95. def __call__(self, *args, **kwargs):
  96. return self._func(*args, **kwargs)
  97. def __getattr__(self, attr):
  98. return getattr(self._func, attr)
  99. def __repr__(self):
  100. return '<unbound method %s.%s>' % (self.__self__.cls.__name__,
  101. self._func.__name__)
  102. class UnboundSelf:
  103. def __init__(self, cls):
  104. self.cls = cls
  105. # We have to do this hackery because Python won't let us override the
  106. # __class__ attribute...
  107. def __getattribute__(self, attr):
  108. if attr == '__class__':
  109. return self.cls
  110. else:
  111. return object.__getattribute__(self, attr)
  112. def unbound_method(cls, func):
  113. if inspect.ismethod(func):
  114. return func
  115. if not inspect.isfunction(func):
  116. raise TypeError('%s is not a function' % (repr(func),))
  117. return UnboundMethod(cls, func)
  118. def ismethod(obj):
  119. return inspect.ismethod(obj) or isinstance(obj, UnboundMethod)
  120. # Make a pseudo-bytes function that can be called without the encoding arg:
  121. if sys.version_info >= (3, 0):
  122. def bytes_(s, encoding='utf8'):
  123. if isinstance(s, bytes):
  124. return s
  125. return bytes(s, encoding)
  126. else:
  127. def bytes_(s, encoding=None):
  128. return str(s)
  129. if sys.version_info[:2] >= (2, 6):
  130. def isgenerator(o):
  131. if isinstance(o, UnboundMethod):
  132. o = o._func
  133. return inspect.isgeneratorfunction(o) or inspect.isgenerator(o)
  134. else:
  135. try:
  136. from compiler.consts import CO_GENERATOR
  137. except ImportError:
  138. # IronPython doesn't have a complier module
  139. CO_GENERATOR=0x20
  140. def isgenerator(func):
  141. try:
  142. return func.func_code.co_flags & CO_GENERATOR != 0
  143. except AttributeError:
  144. return False
  145. # Make a function to help check if an exception is derived from BaseException.
  146. # In Python 2.4, we just use Exception instead.
  147. if sys.version_info[:2] < (2, 5):
  148. def is_base_exception(exc):
  149. return isinstance(exc, Exception)
  150. else:
  151. def is_base_exception(exc):
  152. return isinstance(exc, BaseException)
  153. if sys.version_info[:2] < (3, 0):
  154. def exc_to_unicode(ev, encoding='utf-8'):
  155. if is_base_exception(ev):
  156. if not hasattr(ev, '__unicode__'):
  157. # 2.5-
  158. if not hasattr(ev, 'message'):
  159. # 2.4
  160. msg = len(ev.args) and ev.args[0] or ''
  161. else:
  162. msg = ev.message
  163. msg = force_unicode(msg, encoding=encoding)
  164. clsname = force_unicode(ev.__class__.__name__,
  165. encoding=encoding)
  166. ev = u'%s: %s' % (clsname, msg)
  167. elif not isinstance(ev, unicode):
  168. ev = repr(ev)
  169. return force_unicode(ev, encoding=encoding)
  170. else:
  171. def exc_to_unicode(ev, encoding='utf-8'):
  172. return str(ev)
  173. def format_exception(exc_info, encoding='UTF-8'):
  174. ec, ev, tb = exc_info
  175. # Our exception object may have been turned into a string, and Python 3's
  176. # traceback.format_exception() doesn't take kindly to that (it expects an
  177. # actual exception object). So we work around it, by doing the work
  178. # ourselves if ev is not an exception object.
  179. if not is_base_exception(ev):
  180. tb_data = force_unicode(
  181. ''.join(traceback.format_tb(tb)),
  182. encoding)
  183. ev = exc_to_unicode(ev)
  184. return tb_data + ev
  185. else:
  186. return force_unicode(
  187. ''.join(traceback.format_exception(*exc_info)),
  188. encoding)