_compat.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. """ Compatibility layer.
  2. Some py2/py3 compatibility support based on a stripped down
  3. version of six so we don't have to depend on a specific version
  4. of it.
  5. :copyright: (c) 2014 by Armin Ronacher.
  6. :license: BSD
  7. """
  8. import sys
  9. PY2 = sys.version_info[0] == 2
  10. _identity = lambda x: x
  11. if not PY2:
  12. text_type = str
  13. string_types = (str,)
  14. integer_types = (int, )
  15. iterkeys = lambda d: iter(d.keys())
  16. itervalues = lambda d: iter(d.values())
  17. iteritems = lambda d: iter(d.items())
  18. from io import StringIO
  19. def reraise(tp, value, tb=None):
  20. if value.__traceback__ is not tb:
  21. raise value.with_traceback(tb)
  22. raise value
  23. implements_to_string = _identity
  24. else:
  25. text_type = unicode
  26. string_types = (str, unicode)
  27. integer_types = (int, long)
  28. iterkeys = lambda d: d.iterkeys()
  29. itervalues = lambda d: d.itervalues()
  30. iteritems = lambda d: d.iteritems()
  31. from cStringIO import StringIO
  32. exec('def reraise(tp, value, tb=None):\n raise tp, value, tb')
  33. def implements_to_string(cls):
  34. cls.__unicode__ = cls.__str__
  35. cls.__str__ = lambda x: x.__unicode__().encode('utf-8')
  36. return cls
  37. def with_metaclass(meta, *bases):
  38. # This requires a bit of explanation: the basic idea is to make a
  39. # dummy metaclass for one level of class instantiation that replaces
  40. # itself with the actual metaclass. Because of internal type checks
  41. # we also need to make sure that we downgrade the custom metaclass
  42. # for one level to something closer to type (that's why __call__ and
  43. # __init__ comes back from type etc.).
  44. #
  45. # This has the advantage over six.with_metaclass in that it does not
  46. # introduce dummy classes into the final MRO.
  47. class metaclass(meta):
  48. __call__ = type.__call__
  49. __init__ = type.__init__
  50. def __new__(cls, name, this_bases, d):
  51. if this_bases is None:
  52. return type.__new__(cls, name, (), d)
  53. return meta(name, bases, d)
  54. return metaclass('temporary_class', None, {})
  55. # Certain versions of pypy have a bug where clearing the exception stack
  56. # breaks the __exit__ function in a very peculiar way. This is currently
  57. # true for pypy 2.2.1 for instance. The second level of exception blocks
  58. # is necessary because pypy seems to forget to check if an exception
  59. # happend until the next bytecode instruction?
  60. BROKEN_PYPY_CTXMGR_EXIT = False
  61. if hasattr(sys, 'pypy_version_info'):
  62. class _Mgr(object):
  63. def __enter__(self):
  64. return self
  65. def __exit__(self, *args):
  66. sys.exc_clear()
  67. try:
  68. try:
  69. with _Mgr():
  70. raise AssertionError()
  71. except:
  72. raise
  73. except TypeError:
  74. BROKEN_PYPY_CTXMGR_EXIT = True
  75. except AssertionError:
  76. pass
  77. try:
  78. from collections import OrderedDict
  79. except ImportError:
  80. from UserDict import DictMixin
  81. class OrderedDict(dict, DictMixin):
  82. null = object()
  83. def __init__(self, *args, **kwargs):
  84. self.clear()
  85. self.update(*args, **kwargs)
  86. def clear(self):
  87. self.__map = dict()
  88. self.__order = list()
  89. dict.clear(self)
  90. def __setitem__(self, key, value):
  91. if key not in self:
  92. self.__map[key] = len(self.__order)
  93. self.__order.append(key)
  94. dict.__setitem__(self, key, value)
  95. def __delitem__(self, key):
  96. dict.__delitem__(self, key)
  97. self.__map.pop(key)
  98. self.__order = self.null
  99. def __iter__(self):
  100. for key in self.__order:
  101. if key is not self.null:
  102. yield key
  103. def keys(self):
  104. return list(self)
  105. setdefault = DictMixin.setdefault
  106. update = DictMixin.update
  107. pop = DictMixin.pop
  108. values = DictMixin.values
  109. items = DictMixin.items
  110. iterkeys = DictMixin.iterkeys
  111. itervalues = DictMixin.itervalues
  112. iteritems = DictMixin.iteritems
  113. try:
  114. from importlib import import_module
  115. except ImportError:
  116. def _resolve_name(name, package, level):
  117. """Return the absolute name of the module to be imported."""
  118. if not hasattr(package, 'rindex'):
  119. raise ValueError("'package' not set to a string")
  120. dot = len(package)
  121. for x in xrange(level, 1, -1):
  122. try:
  123. dot = package.rindex('.', 0, dot)
  124. except ValueError:
  125. raise ValueError("attempted relative import beyond top-level "
  126. "package")
  127. return "%s.%s" % (package[:dot], name)
  128. def import_module(name, package=None):
  129. """Import a module.
  130. The 'package' argument is required when performing a relative import. It
  131. specifies the package to use as the anchor point from which to resolve the
  132. relative import to an absolute import.
  133. """
  134. if name.startswith('.'):
  135. if not package:
  136. raise TypeError("relative imports require the 'package' argument")
  137. level = 0
  138. for character in name:
  139. if character != '.':
  140. break
  141. level += 1
  142. name = _resolve_name(name[level:], package, level)
  143. __import__(name)
  144. return sys.modules[name]