1# -*- coding: utf-8 -*-
2"""
3    lektor._compat
4    ~~~~~~~~~~~~~~
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
10    Taken from jinja2/_compat.py
11"""
12# pylint: disable=invalid-name, import-error, unused-import, undefined-variable, reimported
13import sys
14
15
16PY2 = sys.version_info[0] == 2
17_identity = lambda x: x
18
19
20if PY2:
21    unichr = unichr  # pylint: disable=self-assigning-variable  # noqa
22    text_type = unicode  # noqa
23    range_type = xrange  # noqa
24    string_types = (str, unicode)  # noqa
25    integer_types = (int, long)  # noqa
26
27    iterkeys = lambda d: d.iterkeys()
28    itervalues = lambda d: d.itervalues()
29    iteritems = lambda d: d.iteritems()
30
31    from cStringIO import StringIO as BytesIO, StringIO
32    import Queue as queue  # noqa
33
34    NativeStringIO = BytesIO
35
36    exec(  # pylint: disable=exec-used
37        "def reraise(tp, value, tb=None):\n raise tp, value, tb"
38    )
39
40
41else:
42    unichr = chr
43    range_type = range
44    text_type = str
45    string_types = (str,)
46    integer_types = (int,)
47
48    iterkeys = lambda d: iter(d.keys())
49    itervalues = lambda d: iter(d.values())
50    iteritems = lambda d: iter(d.items())
51
52    from io import BytesIO, StringIO
53    import queue  # noqa
54
55    NativeStringIO = StringIO
56
57    def reraise(tp, value, tb=None):
58        if value.__traceback__ is not tb:
59            raise value.with_traceback(tb)
60        raise value
61
62
63def python_2_unicode_compatible(klass):
64    """
65    A decorator that defines __unicode__ and __str__ methods under Python 2.
66    Under Python 3 it does nothing.
67    To support Python 2 and 3 with a single code base, define a __str__ method
68    returning text and apply this decorator to the class.
69    """
70    if PY2:
71        if "__str__" not in klass.__dict__:
72            raise ValueError(
73                "@python_2_unicode_compatible cannot be applied "
74                "to %s because it doesn't define __str__()." % klass.__name__
75            )
76        klass.__unicode__ = klass.__str__
77        klass.__str__ = lambda self: self.__unicode__().encode("utf-8")
78    return klass
79