_compat.py 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. # -*- coding: utf-8 -*-
  2. # flake8: noqa
  3. """
  4. flask_admin._compat
  5. ~~~~~~~~~~~~~~~~~~~~~~~
  6. Some py2/py3 compatibility support based on a stripped down
  7. version of six so we don't have to depend on a specific version
  8. of it.
  9. :copyright: (c) 2013 by Armin Ronacher.
  10. :license: BSD, see LICENSE for more details.
  11. """
  12. import sys
  13. PY2 = sys.version_info[0] == 2
  14. VER = sys.version_info
  15. if not PY2:
  16. text_type = str
  17. string_types = (str,)
  18. integer_types = (int, )
  19. iterkeys = lambda d: iter(d.keys())
  20. itervalues = lambda d: iter(d.values())
  21. iteritems = lambda d: iter(d.items())
  22. filter_list = lambda f, l: list(filter(f, l))
  23. def as_unicode(s):
  24. if isinstance(s, bytes):
  25. return s.decode('utf-8')
  26. return str(s)
  27. def csv_encode(s):
  28. ''' Returns unicode string expected by Python 3's csv module '''
  29. return as_unicode(s)
  30. # Various tools
  31. from functools import reduce
  32. from urllib.parse import urljoin, urlparse
  33. else:
  34. text_type = unicode
  35. string_types = (str, unicode)
  36. integer_types = (int, long)
  37. iterkeys = lambda d: d.iterkeys()
  38. itervalues = lambda d: d.itervalues()
  39. iteritems = lambda d: d.iteritems()
  40. filter_list = filter
  41. def as_unicode(s):
  42. if isinstance(s, str):
  43. return s.decode('utf-8')
  44. return unicode(s)
  45. def csv_encode(s):
  46. ''' Returns byte string expected by Python 2's csv module '''
  47. return as_unicode(s).encode('utf-8')
  48. # Helpers
  49. reduce = __builtins__['reduce'] if isinstance(__builtins__, dict) else __builtins__.reduce
  50. from urlparse import urljoin, urlparse
  51. def with_metaclass(meta, *bases):
  52. # This requires a bit of explanation: the basic idea is to make a
  53. # dummy metaclass for one level of class instantiation that replaces
  54. # itself with the actual metaclass. Because of internal type checks
  55. # we also need to make sure that we downgrade the custom metaclass
  56. # for one level to something closer to type (that's why __call__ and
  57. # __init__ comes back from type etc.).
  58. #
  59. # This has the advantage over six.with_metaclass in that it does not
  60. # introduce dummy classes into the final MRO.
  61. class metaclass(meta):
  62. __call__ = type.__call__
  63. __init__ = type.__init__
  64. def __new__(cls, name, this_bases, d):
  65. if this_bases is None:
  66. return type.__new__(cls, name, (), d)
  67. return meta(name, bases, d)
  68. return metaclass('temporary_class', None, {})
  69. try:
  70. from collections import OrderedDict
  71. except ImportError:
  72. from ordereddict import OrderedDict