1"""Utilities for writing code that runs on Python 2 and 3"""
2
3# Copyright (c) 2010-2012 Benjamin Peterson
4#
5# Permission is hereby granted, free of charge, to any person obtaining a copy of
6# this software and associated documentation files (the "Software"), to deal in
7# the Software without restriction, including without limitation the rights to
8# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9# the Software, and to permit persons to whom the Software is furnished to do so,
10# subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be included in all
13# copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22import operator
23import sys
24import types
25
26__author__ = "Benjamin Peterson <benjamin@python.org>"
27__version__ = "1.2.0"
28
29
30# True if we are running on Python 3.
31PY3 = sys.version_info[0] == 3
32
33if PY3:
34    string_types = str,
35    integer_types = int,
36    class_types = type,
37    text_type = str
38    binary_type = bytes
39
40    MAXSIZE = sys.maxsize
41else:
42    string_types = basestring,
43    integer_types = (int, long)
44    class_types = (type, types.ClassType)
45    text_type = unicode
46    binary_type = str
47
48    if sys.platform.startswith("java"):
49        # Jython always uses 32 bits.
50        MAXSIZE = int((1 << 31) - 1)
51    else:
52        # It's possible to have sizeof(long) != sizeof(Py_ssize_t).
53        class X(object):
54            def __len__(self):
55                return 1 << 31
56        try:
57            len(X())
58        except OverflowError:
59            # 32-bit
60            MAXSIZE = int((1 << 31) - 1)
61        else:
62            # 64-bit
63            MAXSIZE = int((1 << 63) - 1)
64            del X
65
66
67def _add_doc(func, doc):
68    """Add documentation to a function."""
69    func.__doc__ = doc
70
71
72def _import_module(name):
73    """Import module, returning the module after the last dot."""
74    __import__(name)
75    return sys.modules[name]
76
77
78# Replacement for lazy loading stuff in upstream six.  See gh-2764
79if PY3:
80    import builtins
81    import functools
82    reduce = functools.reduce
83    zip = builtins.zip
84    xrange = builtins.range
85else:
86    import __builtin__
87    import itertools
88    builtins = __builtin__
89    reduce = __builtin__.reduce
90    zip = itertools.izip
91    xrange = __builtin__.xrange
92
93
94if PY3:
95    _meth_func = "__func__"
96    _meth_self = "__self__"
97
98    _func_code = "__code__"
99    _func_defaults = "__defaults__"
100
101    _iterkeys = "keys"
102    _itervalues = "values"
103    _iteritems = "items"
104else:
105    _meth_func = "im_func"
106    _meth_self = "im_self"
107
108    _func_code = "func_code"
109    _func_defaults = "func_defaults"
110
111    _iterkeys = "iterkeys"
112    _itervalues = "itervalues"
113    _iteritems = "iteritems"
114
115
116try:
117    advance_iterator = next
118except NameError:
119    def advance_iterator(it):
120        return it.next()
121next = advance_iterator
122
123
124if PY3:
125    def get_unbound_function(unbound):
126        return unbound
127
128    Iterator = object
129
130    def callable(obj):
131        return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
132else:
133    def get_unbound_function(unbound):
134        return unbound.im_func
135
136    class Iterator(object):
137
138        def next(self):
139            return type(self).__next__(self)
140
141    callable = callable
142_add_doc(get_unbound_function,
143         """Get the function out of a possibly unbound function""")
144
145
146get_method_function = operator.attrgetter(_meth_func)
147get_method_self = operator.attrgetter(_meth_self)
148get_function_code = operator.attrgetter(_func_code)
149get_function_defaults = operator.attrgetter(_func_defaults)
150
151
152def iterkeys(d):
153    """Return an iterator over the keys of a dictionary."""
154    return iter(getattr(d, _iterkeys)())
155
156
157def itervalues(d):
158    """Return an iterator over the values of a dictionary."""
159    return iter(getattr(d, _itervalues)())
160
161
162def iteritems(d):
163    """Return an iterator over the (key, value) pairs of a dictionary."""
164    return iter(getattr(d, _iteritems)())
165
166
167if PY3:
168    def b(s):
169        return s.encode("latin-1")
170
171    def u(s):
172        return s
173
174    if sys.version_info[1] <= 1:
175        def int2byte(i):
176            return bytes((i,))
177    else:
178        # This is about 2x faster than the implementation above on 3.2+
179        int2byte = operator.methodcaller("to_bytes", 1, "big")
180    import io
181    StringIO = io.StringIO
182    BytesIO = io.BytesIO
183else:
184    def b(s):
185        return s
186
187    def u(s):
188        return unicode(s, "unicode_escape")
189    int2byte = chr
190    import StringIO
191    StringIO = BytesIO = StringIO.StringIO
192_add_doc(b, """Byte literal""")
193_add_doc(u, """Text literal""")
194
195
196if PY3:
197    import builtins
198    exec_ = getattr(builtins, "exec")
199
200    def reraise(tp, value, tb=None):
201        if value.__traceback__ is not tb:
202            raise value.with_traceback(tb)
203        raise value
204
205    print_ = getattr(builtins, "print")
206    del builtins
207
208else:
209    def exec_(code, globs=None, locs=None):
210        """Execute code in a namespace."""
211        if globs is None:
212            frame = sys._getframe(1)
213            globs = frame.f_globals
214            if locs is None:
215                locs = frame.f_locals
216            del frame
217        elif locs is None:
218            locs = globs
219        exec("""exec code in globs, locs""")
220
221    exec_("""def reraise(tp, value, tb=None):
222    raise tp, value, tb
223""")
224
225    def print_(*args, **kwargs):
226        """The new-style print function."""
227        fp = kwargs.pop("file", sys.stdout)
228        if fp is None:
229            return
230
231        def write(data):
232            if not isinstance(data, basestring):
233                data = str(data)
234            fp.write(data)
235        want_unicode = False
236        sep = kwargs.pop("sep", None)
237        if sep is not None:
238            if isinstance(sep, unicode):
239                want_unicode = True
240            elif not isinstance(sep, str):
241                raise TypeError("sep must be None or a string")
242        end = kwargs.pop("end", None)
243        if end is not None:
244            if isinstance(end, unicode):
245                want_unicode = True
246            elif not isinstance(end, str):
247                raise TypeError("end must be None or a string")
248        if kwargs:
249            raise TypeError("invalid keyword arguments to print()")
250        if not want_unicode:
251            for arg in args:
252                if isinstance(arg, unicode):
253                    want_unicode = True
254                    break
255        if want_unicode:
256            newline = unicode("\n")
257            space = unicode(" ")
258        else:
259            newline = "\n"
260            space = " "
261        if sep is None:
262            sep = space
263        if end is None:
264            end = newline
265        for i, arg in enumerate(args):
266            if i:
267                write(sep)
268            write(arg)
269        write(end)
270
271_add_doc(reraise, """Reraise an exception.""")
272
273
274def with_metaclass(meta, base=object):
275    """Create a base class with a metaclass."""
276    return meta("NewBase", (base,), {})
277