123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- """ Compatibility layer.
- Some py2/py3 compatibility support based on a stripped down
- version of six so we don't have to depend on a specific version
- of it.
- :copyright: (c) 2014 by Armin Ronacher.
- :license: BSD
- """
- import sys
- PY2 = sys.version_info[0] == 2
- _identity = lambda x: x
- if not PY2:
- text_type = str
- string_types = (str,)
- integer_types = (int, )
- iterkeys = lambda d: iter(d.keys())
- itervalues = lambda d: iter(d.values())
- iteritems = lambda d: iter(d.items())
- from io import StringIO
- def reraise(tp, value, tb=None):
- if value.__traceback__ is not tb:
- raise value.with_traceback(tb)
- raise value
- implements_to_string = _identity
- else:
- text_type = unicode
- string_types = (str, unicode)
- integer_types = (int, long)
- iterkeys = lambda d: d.iterkeys()
- itervalues = lambda d: d.itervalues()
- iteritems = lambda d: d.iteritems()
- from cStringIO import StringIO
- exec('def reraise(tp, value, tb=None):\n raise tp, value, tb')
- def implements_to_string(cls):
- cls.__unicode__ = cls.__str__
- cls.__str__ = lambda x: x.__unicode__().encode('utf-8')
- return cls
- def with_metaclass(meta, *bases):
- # This requires a bit of explanation: the basic idea is to make a
- # dummy metaclass for one level of class instantiation that replaces
- # itself with the actual metaclass. Because of internal type checks
- # we also need to make sure that we downgrade the custom metaclass
- # for one level to something closer to type (that's why __call__ and
- # __init__ comes back from type etc.).
- #
- # This has the advantage over six.with_metaclass in that it does not
- # introduce dummy classes into the final MRO.
- class metaclass(meta):
- __call__ = type.__call__
- __init__ = type.__init__
- def __new__(cls, name, this_bases, d):
- if this_bases is None:
- return type.__new__(cls, name, (), d)
- return meta(name, bases, d)
- return metaclass('temporary_class', None, {})
- # Certain versions of pypy have a bug where clearing the exception stack
- # breaks the __exit__ function in a very peculiar way. This is currently
- # true for pypy 2.2.1 for instance. The second level of exception blocks
- # is necessary because pypy seems to forget to check if an exception
- # happend until the next bytecode instruction?
- BROKEN_PYPY_CTXMGR_EXIT = False
- if hasattr(sys, 'pypy_version_info'):
- class _Mgr(object):
- def __enter__(self):
- return self
- def __exit__(self, *args):
- sys.exc_clear()
- try:
- try:
- with _Mgr():
- raise AssertionError()
- except:
- raise
- except TypeError:
- BROKEN_PYPY_CTXMGR_EXIT = True
- except AssertionError:
- pass
- try:
- from collections import OrderedDict
- except ImportError:
- from UserDict import DictMixin
- class OrderedDict(dict, DictMixin):
- null = object()
- def __init__(self, *args, **kwargs):
- self.clear()
- self.update(*args, **kwargs)
- def clear(self):
- self.__map = dict()
- self.__order = list()
- dict.clear(self)
- def __setitem__(self, key, value):
- if key not in self:
- self.__map[key] = len(self.__order)
- self.__order.append(key)
- dict.__setitem__(self, key, value)
- def __delitem__(self, key):
- dict.__delitem__(self, key)
- self.__map.pop(key)
- self.__order = self.null
- def __iter__(self):
- for key in self.__order:
- if key is not self.null:
- yield key
- def keys(self):
- return list(self)
- setdefault = DictMixin.setdefault
- update = DictMixin.update
- pop = DictMixin.pop
- values = DictMixin.values
- items = DictMixin.items
- iterkeys = DictMixin.iterkeys
- itervalues = DictMixin.itervalues
- iteritems = DictMixin.iteritems
- try:
- from importlib import import_module
- except ImportError:
- def _resolve_name(name, package, level):
- """Return the absolute name of the module to be imported."""
- if not hasattr(package, 'rindex'):
- raise ValueError("'package' not set to a string")
- dot = len(package)
- for x in xrange(level, 1, -1):
- try:
- dot = package.rindex('.', 0, dot)
- except ValueError:
- raise ValueError("attempted relative import beyond top-level "
- "package")
- return "%s.%s" % (package[:dot], name)
- def import_module(name, package=None):
- """Import a module.
- The 'package' argument is required when performing a relative import. It
- specifies the package to use as the anchor point from which to resolve the
- relative import to an absolute import.
- """
- if name.startswith('.'):
- if not package:
- raise TypeError("relative imports require the 'package' argument")
- level = 0
- for character in name:
- if character != '.':
- break
- level += 1
- name = _resolve_name(name[level:], package, level)
- __import__(name)
- return sys.modules[name]
|