_compat.py 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  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: © 2010 by the Pallets team.
  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 inspect import getfullargspec as getargspec
  22. from io import StringIO
  23. def reraise(tp, value, tb=None):
  24. if value.__traceback__ is not tb:
  25. raise value.with_traceback(tb)
  26. raise value
  27. implements_to_string = _identity
  28. else:
  29. text_type = unicode
  30. string_types = (str, unicode)
  31. integer_types = (int, long)
  32. iterkeys = lambda d: d.iterkeys()
  33. itervalues = lambda d: d.itervalues()
  34. iteritems = lambda d: d.iteritems()
  35. from inspect import getargspec
  36. from cStringIO import StringIO
  37. exec('def reraise(tp, value, tb=None):\n raise tp, value, tb')
  38. def implements_to_string(cls):
  39. cls.__unicode__ = cls.__str__
  40. cls.__str__ = lambda x: x.__unicode__().encode('utf-8')
  41. return cls
  42. def with_metaclass(meta, *bases):
  43. """Create a base class with a metaclass."""
  44. # This requires a bit of explanation: the basic idea is to make a
  45. # dummy metaclass for one level of class instantiation that replaces
  46. # itself with the actual metaclass.
  47. class metaclass(type):
  48. def __new__(cls, name, this_bases, d):
  49. return meta(name, bases, d)
  50. return type.__new__(metaclass, 'temporary_class', (), {})
  51. # Certain versions of pypy have a bug where clearing the exception stack
  52. # breaks the __exit__ function in a very peculiar way. The second level of
  53. # exception blocks is necessary because pypy seems to forget to check if an
  54. # exception happened until the next bytecode instruction?
  55. #
  56. # Relevant PyPy bugfix commit:
  57. # https://bitbucket.org/pypy/pypy/commits/77ecf91c635a287e88e60d8ddb0f4e9df4003301
  58. # According to ronan on #pypy IRC, it is released in PyPy2 2.3 and later
  59. # versions.
  60. #
  61. # Ubuntu 14.04 has PyPy 2.2.1, which does exhibit this bug.
  62. BROKEN_PYPY_CTXMGR_EXIT = False
  63. if hasattr(sys, 'pypy_version_info'):
  64. class _Mgr(object):
  65. def __enter__(self):
  66. return self
  67. def __exit__(self, *args):
  68. if hasattr(sys, 'exc_clear'):
  69. # Python 3 (PyPy3) doesn't have exc_clear
  70. sys.exc_clear()
  71. try:
  72. try:
  73. with _Mgr():
  74. raise AssertionError()
  75. except:
  76. raise
  77. except TypeError:
  78. BROKEN_PYPY_CTXMGR_EXIT = True
  79. except AssertionError:
  80. pass