_compat.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. # -*- coding: utf-8 -*-
  2. """
  3. flask._compat
  4. ~~~~~~~~~~~~~
  5. Some py2/py3 compatibility support based on a stripped down
  6. version of six so we don't have to depend on a specific version
  7. of it.
  8. :copyright: (c) 2015 by Armin Ronacher.
  9. :license: BSD, see LICENSE for more details.
  10. """
  11. import sys
  12. PY2 = sys.version_info[0] == 2
  13. _identity = lambda x: x
  14. if not PY2:
  15. text_type = str
  16. string_types = (str,)
  17. integer_types = (int,)
  18. iterkeys = lambda d: iter(d.keys())
  19. itervalues = lambda d: iter(d.values())
  20. iteritems = lambda d: iter(d.items())
  21. from io import StringIO
  22. def reraise(tp, value, tb=None):
  23. if value.__traceback__ is not tb:
  24. raise value.with_traceback(tb)
  25. raise value
  26. implements_to_string = _identity
  27. else:
  28. text_type = unicode
  29. string_types = (str, unicode)
  30. integer_types = (int, long)
  31. iterkeys = lambda d: d.iterkeys()
  32. itervalues = lambda d: d.itervalues()
  33. iteritems = lambda d: d.iteritems()
  34. from cStringIO import StringIO
  35. exec('def reraise(tp, value, tb=None):\n raise tp, value, tb')
  36. def implements_to_string(cls):
  37. cls.__unicode__ = cls.__str__
  38. cls.__str__ = lambda x: x.__unicode__().encode('utf-8')
  39. return cls
  40. def with_metaclass(meta, *bases):
  41. """Create a base class with a metaclass."""
  42. # This requires a bit of explanation: the basic idea is to make a
  43. # dummy metaclass for one level of class instantiation that replaces
  44. # itself with the actual metaclass.
  45. class metaclass(type):
  46. def __new__(cls, name, this_bases, d):
  47. return meta(name, bases, d)
  48. return type.__new__(metaclass, 'temporary_class', (), {})
  49. # Certain versions of pypy have a bug where clearing the exception stack
  50. # breaks the __exit__ function in a very peculiar way. This is currently
  51. # true for pypy 2.2.1 for instance. The second level of exception blocks
  52. # is necessary because pypy seems to forget to check if an exception
  53. # happened until the next bytecode instruction?
  54. BROKEN_PYPY_CTXMGR_EXIT = False
  55. if hasattr(sys, 'pypy_version_info'):
  56. class _Mgr(object):
  57. def __enter__(self):
  58. return self
  59. def __exit__(self, *args):
  60. sys.exc_clear()
  61. try:
  62. try:
  63. with _Mgr():
  64. raise AssertionError()
  65. except:
  66. raise
  67. except TypeError:
  68. BROKEN_PYPY_CTXMGR_EXIT = True
  69. except AssertionError:
  70. pass