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