1"""
2A selection of cross-compatible functions for Python 2 and 3.
3
4This module exports useful functions for 2/3 compatible code:
5
6 * bind_method: binds functions to classes
7 * ``native_str_to_bytes`` and ``bytes_to_native_str``
8 * ``native_str``: always equal to the native platform string object (because
9 this may be shadowed by imports from future.builtins)
10 * lists: lrange(), lmap(), lzip(), lfilter()
11 * iterable method compatibility:
12 - iteritems, iterkeys, itervalues
13 - viewitems, viewkeys, viewvalues
14
15 These use the original method if available, otherwise they use items,
16 keys, values.
17
18 * types:
19
20 * text_type: unicode in Python 2, str in Python 3
21 * string_types: basestring in Python 2, str in Python 3
22 * binary_type: str in Python 2, bytes in Python 3
23 * integer_types: (int, long) in Python 2, int in Python 3
24 * class_types: (type, types.ClassType) in Python 2, type in Python 3
25
26 * bchr(c):
27 Take an integer and make a 1-character byte string
28 * bord(c)
29 Take the result of indexing on a byte string and make an integer
30 * tobytes(s)
31 Take a text string, a byte string, or a sequence of characters taken
32 from a byte string, and make a byte string.
33
34 * raise_from()
35 * raise_with_traceback()
36
37This module also defines these decorators:
38
39 * ``python_2_unicode_compatible``
40 * ``with_metaclass``
41 * ``implements_iterator``
42
43Some of the functions in this module come from the following sources:
44
45 * Jinja2 (BSD licensed: see
46 https://github.com/mitsuhiko/jinja2/blob/master/LICENSE)
47 * Pandas compatibility module pandas.compat
48 * six.py by Benjamin Peterson
49 * Django
50"""
51
52import types
53import sys
54import numbers
55import functools
56import copy
57import inspect
58
59
60PY3 = sys.version_info[0] >= 3
61PY34_PLUS = sys.version_info[0:2] >= (3, 4)
62PY35_PLUS = sys.version_info[0:2] >= (3, 5)
63PY36_PLUS = sys.version_info[0:2] >= (3, 6)
64PY37_PLUS = sys.version_info[0:2] >= (3, 7)
65PY38_PLUS = sys.version_info[0:2] >= (3, 8)
66PY39_PLUS = sys.version_info[0:2] >= (3, 9)
67PY2 = sys.version_info[0] == 2
68PY26 = sys.version_info[0:2] == (2, 6)
69PY27 = sys.version_info[0:2] == (2, 7)
70PYPY = hasattr(sys, 'pypy_translation_info')
71
72
73def python_2_unicode_compatible(cls):
74 """
75 A decorator that defines __unicode__ and __str__ methods under Python
76 2. Under Python 3, this decorator is a no-op.
77
78 To support Python 2 and 3 with a single code base, define a __str__
79 method returning unicode text and apply this decorator to the class, like
80 this::
81
82 >>> from future.utils import python_2_unicode_compatible
83
84 >>> @python_2_unicode_compatible
85 ... class MyClass(object):
86 ... def __str__(self):
87 ... return u'Unicode string: \u5b54\u5b50'
88
89 >>> a = MyClass()
90
91 Then, after this import:
92
93 >>> from future.builtins import str
94
95 the following is ``True`` on both Python 3 and 2::
96
97 >>> str(a) == a.encode('utf-8').decode('utf-8')
98 True
99
100 and, on a Unicode-enabled terminal with the right fonts, these both print the
101 Chinese characters for Confucius::
102
103 >>> print(a)
104 >>> print(str(a))
105
106 The implementation comes from django.utils.encoding.
107 """
108 if not PY3:
109 cls.__unicode__ = cls.__str__
110 cls.__str__ = lambda self: self.__unicode__().encode('utf-8')
111 return cls
112
113
114def with_metaclass(meta, *bases):
115 """
116 Function from jinja2/_compat.py. License: BSD.
117
118 Use it like this::
119
120 class BaseForm(object):
121 pass
122
123 class FormType(type):
124 pass
125
126 class Form(with_metaclass(FormType, BaseForm)):
127 pass
128
129 This requires a bit of explanation: the basic idea is to make a
130 dummy metaclass for one level of class instantiation that replaces
131 itself with the actual metaclass. Because of internal type checks
132 we also need to make sure that we downgrade the custom metaclass
133 for one level to something closer to type (that's why __call__ and
134 __init__ comes back from type etc.).
135
136 This has the advantage over six.with_metaclass of not introducing
137 dummy classes into the final MRO.
138 """
139 class metaclass(meta):
140 __call__ = type.__call__
141 __init__ = type.__init__
142 def __new__(cls, name, this_bases, d):
143 if this_bases is None:
144 return type.__new__(cls, name, (), d)
145 return meta(name, bases, d)
146 return metaclass('temporary_class', None, {})
147
148
149# Definitions from pandas.compat and six.py follow:
150if PY3:
151 def bchr(s):
152 return bytes([s])
153 def bstr(s):
154 if isinstance(s, str):
155 return bytes(s, 'latin-1')
156 else:
157 return bytes(s)
158 def bord(s):
159 return s
160
161 string_types = str,
162 integer_types = int,
163 class_types = type,
164 text_type = str
165 binary_type = bytes
166
167else:
168 # Python 2
169 def bchr(s):
170 return chr(s)
171 def bstr(s):
172 return str(s)
173 def bord(s):
174 return ord(s)
175
176 string_types = basestring,
177 integer_types = (int, long)
178 class_types = (type, types.ClassType)
179 text_type = unicode
180 binary_type = str
181
182###
183
184if PY3:
185 def tobytes(s):
186 if isinstance(s, bytes):
187 return s
188 else:
189 if isinstance(s, str):
190 return s.encode('latin-1')
191 else:
192 return bytes(s)
193else:
194 # Python 2
195 def tobytes(s):
196 if isinstance(s, unicode):
197 return s.encode('latin-1')
198 else:
199 return ''.join(s)
200
201tobytes.__doc__ = """
202 Encodes to latin-1 (where the first 256 chars are the same as
203 ASCII.)
204 """
205
206if PY3:
207 def native_str_to_bytes(s, encoding='utf-8'):
208 return s.encode(encoding)
209
210 def bytes_to_native_str(b, encoding='utf-8'):
211 return b.decode(encoding)
212
213 def text_to_native_str(t, encoding=None):
214 return t
215else:
216 # Python 2
217 def native_str_to_bytes(s, encoding=None):
218 from future.types import newbytes # to avoid a circular import
219 return newbytes(s)
220
221 def bytes_to_native_str(b, encoding=None):
222 return native(b)
223
224 def text_to_native_str(t, encoding='ascii'):
225 """
226 Use this to create a Py2 native string when "from __future__ import
227 unicode_literals" is in effect.
228 """
229 return unicode(t).encode(encoding)
230
231native_str_to_bytes.__doc__ = """
232 On Py3, returns an encoded string.
233 On Py2, returns a newbytes type, ignoring the ``encoding`` argument.
234 """
235
236if PY3:
237 # list-producing versions of the major Python iterating functions
238 def lrange(*args, **kwargs):
239 return list(range(*args, **kwargs))
240
241 def lzip(*args, **kwargs):
242 return list(zip(*args, **kwargs))
243
244 def lmap(*args, **kwargs):
245 return list(map(*args, **kwargs))
246
247 def lfilter(*args, **kwargs):
248 return list(filter(*args, **kwargs))
249else:
250 import __builtin__
251 # Python 2-builtin ranges produce lists
252 lrange = __builtin__.range
253 lzip = __builtin__.zip
254 lmap = __builtin__.map
255 lfilter = __builtin__.filter
256
257
258def isidentifier(s, dotted=False):
259 '''
260 A function equivalent to the str.isidentifier method on Py3
261 '''
262 if dotted:
263 return all(isidentifier(a) for a in s.split('.'))
264 if PY3:
265 return s.isidentifier()
266 else:
267 import re
268 _name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")
269 return bool(_name_re.match(s))
270
271
272def viewitems(obj, **kwargs):
273 """
274 Function for iterating over dictionary items with the same set-like
275 behaviour on Py2.7 as on Py3.
276
277 Passes kwargs to method."""
278 func = getattr(obj, "viewitems", None)
279 if not func:
280 func = obj.items
281 return func(**kwargs)
282
283
284def viewkeys(obj, **kwargs):
285 """
286 Function for iterating over dictionary keys with the same set-like
287 behaviour on Py2.7 as on Py3.
288
289 Passes kwargs to method."""
290 func = getattr(obj, "viewkeys", None)
291 if not func:
292 func = obj.keys
293 return func(**kwargs)
294
295
296def viewvalues(obj, **kwargs):
297 """
298 Function for iterating over dictionary values with the same set-like
299 behaviour on Py2.7 as on Py3.
300
301 Passes kwargs to method."""
302 func = getattr(obj, "viewvalues", None)
303 if not func:
304 func = obj.values
305 return func(**kwargs)
306
307
308def iteritems(obj, **kwargs):
309 """Use this only if compatibility with Python versions before 2.7 is
310 required. Otherwise, prefer viewitems().
311 """
312 func = getattr(obj, "iteritems", None)
313 if not func:
314 func = obj.items
315 return func(**kwargs)
316
317
318def iterkeys(obj, **kwargs):
319 """Use this only if compatibility with Python versions before 2.7 is
320 required. Otherwise, prefer viewkeys().
321 """
322 func = getattr(obj, "iterkeys", None)
323 if not func:
324 func = obj.keys
325 return func(**kwargs)
326
327
328def itervalues(obj, **kwargs):
329 """Use this only if compatibility with Python versions before 2.7 is
330 required. Otherwise, prefer viewvalues().
331 """
332 func = getattr(obj, "itervalues", None)
333 if not func:
334 func = obj.values
335 return func(**kwargs)
336
337
338def bind_method(cls, name, func):
339 """Bind a method to class, python 2 and python 3 compatible.
340
341 Parameters
342 ----------
343
344 cls : type
345 class to receive bound method
346 name : basestring
347 name of method on class instance
348 func : function
349 function to be bound as method
350
351 Returns
352 -------
353 None
354 """
355 # only python 2 has an issue with bound/unbound methods
356 if not PY3:
357 setattr(cls, name, types.MethodType(func, None, cls))
358 else:
359 setattr(cls, name, func)
360
361
362def getexception():
363 return sys.exc_info()[1]
364
365
366def _get_caller_globals_and_locals():
367 """
368 Returns the globals and locals of the calling frame.
369
370 Is there an alternative to frame hacking here?
371 """
372 caller_frame = inspect.stack()[2]
373 myglobals = caller_frame[0].f_globals
374 mylocals = caller_frame[0].f_locals
375 return myglobals, mylocals
376
377
378def _repr_strip(mystring):
379 """
380 Returns the string without any initial or final quotes.
381 """
382 r = repr(mystring)
383 if r.startswith("'") and r.endswith("'"):
384 return r[1:-1]
385 else:
386 return r
387
388
389if PY3:
390 def raise_from(exc, cause):
391 """
392 Equivalent to:
393
394 raise EXCEPTION from CAUSE
395
396 on Python 3. (See PEP 3134).
397 """
398 myglobals, mylocals = _get_caller_globals_and_locals()
399
400 # We pass the exception and cause along with other globals
401 # when we exec():
402 myglobals = myglobals.copy()
403 myglobals['__python_future_raise_from_exc'] = exc
404 myglobals['__python_future_raise_from_cause'] = cause
405 execstr = "raise __python_future_raise_from_exc from __python_future_raise_from_cause"
406 exec(execstr, myglobals, mylocals)
407
408 def raise_(tp, value=None, tb=None):
409 """
410 A function that matches the Python 2.x ``raise`` statement. This
411 allows re-raising exceptions with the cls value and traceback on
412 Python 2 and 3.
413 """
414 if isinstance(tp, BaseException):
415 # If the first object is an instance, the type of the exception
416 # is the class of the instance, the instance itself is the value,
417 # and the second object must be None.
418 if value is not None:
419 raise TypeError("instance exception may not have a separate value")
420 exc = tp
421 elif isinstance(tp, type) and not issubclass(tp, BaseException):
422 # If the first object is a class, it becomes the type of the
423 # exception.
424 raise TypeError("class must derive from BaseException, not %s" % tp.__name__)
425 else:
426 # The second object is used to determine the exception value: If it
427 # is an instance of the class, the instance becomes the exception
428 # value. If the second object is a tuple, it is used as the argument
429 # list for the class constructor; if it is None, an empty argument
430 # list is used, and any other object is treated as a single argument
431 # to the constructor. The instance so created by calling the
432 # constructor is used as the exception value.
433 if isinstance(value, tp):
434 exc = value
435 elif isinstance(value, tuple):
436 exc = tp(*value)
437 elif value is None:
438 exc = tp()
439 else:
440 exc = tp(value)
441
442 if exc.__traceback__ is not tb:
443 raise exc.with_traceback(tb)
444 raise exc
445
446 def raise_with_traceback(exc, traceback=Ellipsis):
447 if traceback == Ellipsis:
448 _, _, traceback = sys.exc_info()
449 raise exc.with_traceback(traceback)
450
451else:
452 def raise_from(exc, cause):
453 """
454 Equivalent to:
455
456 raise EXCEPTION from CAUSE
457
458 on Python 3. (See PEP 3134).
459 """
460 # Is either arg an exception class (e.g. IndexError) rather than
461 # instance (e.g. IndexError('my message here')? If so, pass the
462 # name of the class undisturbed through to "raise ... from ...".
463 if isinstance(exc, type) and issubclass(exc, Exception):
464 e = exc()
465 # exc = exc.__name__
466 # execstr = "e = " + _repr_strip(exc) + "()"
467 # myglobals, mylocals = _get_caller_globals_and_locals()
468 # exec(execstr, myglobals, mylocals)
469 else:
470 e = exc
471 e.__suppress_context__ = False
472 if isinstance(cause, type) and issubclass(cause, Exception):
473 e.__cause__ = cause()
474 e.__cause__.__traceback__ = sys.exc_info()[2]
475 e.__suppress_context__ = True
476 elif cause is None:
477 e.__cause__ = None
478 e.__suppress_context__ = True
479 elif isinstance(cause, BaseException):
480 e.__cause__ = cause
481 object.__setattr__(e.__cause__, '__traceback__', sys.exc_info()[2])
482 e.__suppress_context__ = True
483 else:
484 raise TypeError("exception causes must derive from BaseException")
485 e.__context__ = sys.exc_info()[1]
486 raise e
487
488 exec('''
489def raise_(tp, value=None, tb=None):
490 raise tp, value, tb
491
492def raise_with_traceback(exc, traceback=Ellipsis):
493 if traceback == Ellipsis:
494 _, _, traceback = sys.exc_info()
495 raise exc, None, traceback
496'''.strip())
497
498
499raise_with_traceback.__doc__ = (
500"""Raise exception with existing traceback.
501If traceback is not passed, uses sys.exc_info() to get traceback."""
502)
503
504
505# Deprecated alias for backward compatibility with ``future`` versions < 0.11:
506reraise = raise_
507
508
509def implements_iterator(cls):
510 '''
511 From jinja2/_compat.py. License: BSD.
512
513 Use as a decorator like this::
514
515 @implements_iterator
516 class UppercasingIterator(object):
517 def __init__(self, iterable):
518 self._iter = iter(iterable)
519 def __iter__(self):
520 return self
521 def __next__(self):
522 return next(self._iter).upper()
523
524 '''
525 if PY3:
526 return cls
527 else:
528 cls.next = cls.__next__
529 del cls.__next__
530 return cls
531
532if PY3:
533 get_next = lambda x: x.__next__
534else:
535 get_next = lambda x: x.next
536
537
538def encode_filename(filename):
539 if PY3:
540 return filename
541 else:
542 if isinstance(filename, unicode):
543 return filename.encode('utf-8')
544 return filename
545
546
547def is_new_style(cls):
548 """
549 Python 2.7 has both new-style and old-style classes. Old-style classes can
550 be pesky in some circumstances, such as when using inheritance. Use this
551 function to test for whether a class is new-style. (Python 3 only has
552 new-style classes.)
553 """
554 return hasattr(cls, '__class__') and ('__dict__' in dir(cls)
555 or hasattr(cls, '__slots__'))
556
557# The native platform string and bytes types. Useful because ``str`` and
558# ``bytes`` are redefined on Py2 by ``from future.builtins import *``.
559native_str = str
560native_bytes = bytes
561
562
563def istext(obj):
564 """
565 Deprecated. Use::
566 >>> isinstance(obj, str)
567 after this import:
568 >>> from future.builtins import str
569 """
570 return isinstance(obj, type(u''))
571
572
573def isbytes(obj):
574 """
575 Deprecated. Use::
576 >>> isinstance(obj, bytes)
577 after this import:
578 >>> from future.builtins import bytes
579 """
580 return isinstance(obj, type(b''))
581
582
583def isnewbytes(obj):
584 """
585 Equivalent to the result of ``type(obj) == type(newbytes)``
586 in other words, it is REALLY a newbytes instance, not a Py2 native str
587 object?
588
589 Note that this does not cover subclasses of newbytes, and it is not
590 equivalent to ininstance(obj, newbytes)
591 """
592 return type(obj).__name__ == 'newbytes'
593
594
595def isint(obj):
596 """
597 Deprecated. Tests whether an object is a Py3 ``int`` or either a Py2 ``int`` or
598 ``long``.
599
600 Instead of using this function, you can use:
601
602 >>> from future.builtins import int
603 >>> isinstance(obj, int)
604
605 The following idiom is equivalent:
606
607 >>> from numbers import Integral
608 >>> isinstance(obj, Integral)
609 """
610
611 return isinstance(obj, numbers.Integral)
612
613
614def native(obj):
615 """
616 On Py3, this is a no-op: native(obj) -> obj
617
618 On Py2, returns the corresponding native Py2 types that are
619 superclasses for backported objects from Py3:
620
621 >>> from builtins import str, bytes, int
622
623 >>> native(str(u'ABC'))
624 u'ABC'
625 >>> type(native(str(u'ABC')))
626 unicode
627
628 >>> native(bytes(b'ABC'))
629 b'ABC'
630 >>> type(native(bytes(b'ABC')))
631 bytes
632
633 >>> native(int(10**20))
634 100000000000000000000L
635 >>> type(native(int(10**20)))
636 long
637
638 Existing native types on Py2 will be returned unchanged:
639
640 >>> type(native(u'ABC'))
641 unicode
642 """
643 if hasattr(obj, '__native__'):
644 return obj.__native__()
645 else:
646 return obj
647
648
649# Implementation of exec_ is from ``six``:
650if PY3:
651 import builtins
652 exec_ = getattr(builtins, "exec")
653else:
654 def exec_(code, globs=None, locs=None):
655 """Execute code in a namespace."""
656 if globs is None:
657 frame = sys._getframe(1)
658 globs = frame.f_globals
659 if locs is None:
660 locs = frame.f_locals
661 del frame
662 elif locs is None:
663 locs = globs
664 exec("""exec code in globs, locs""")
665
666
667# Defined here for backward compatibility:
668def old_div(a, b):
669 """
670 DEPRECATED: import ``old_div`` from ``past.utils`` instead.
671
672 Equivalent to ``a / b`` on Python 2 without ``from __future__ import
673 division``.
674
675 TODO: generalize this to other objects (like arrays etc.)
676 """
677 if isinstance(a, numbers.Integral) and isinstance(b, numbers.Integral):
678 return a // b
679 else:
680 return a / b
681
682
683def as_native_str(encoding='utf-8'):
684 '''
685 A decorator to turn a function or method call that returns text, i.e.
686 unicode, into one that returns a native platform str.
687
688 Use it as a decorator like this::
689
690 from __future__ import unicode_literals
691
692 class MyClass(object):
693 @as_native_str(encoding='ascii')
694 def __repr__(self):
695 return next(self._iter).upper()
696 '''
697 if PY3:
698 return lambda f: f
699 else:
700 def encoder(f):
701 @functools.wraps(f)
702 def wrapper(*args, **kwargs):
703 return f(*args, **kwargs).encode(encoding=encoding)
704 return wrapper
705 return encoder
706
707# listvalues and listitems definitions from Nick Coghlan's (withdrawn)
708# PEP 496:
709try:
710 dict.iteritems
711except AttributeError:
712 # Python 3
713 def listvalues(d):
714 return list(d.values())
715 def listitems(d):
716 return list(d.items())
717else:
718 # Python 2
719 def listvalues(d):
720 return d.values()
721 def listitems(d):
722 return d.items()
723
724if PY3:
725 def ensure_new_type(obj):
726 return obj
727else:
728 def ensure_new_type(obj):
729 from future.types.newbytes import newbytes
730 from future.types.newstr import newstr
731 from future.types.newint import newint
732 from future.types.newdict import newdict
733
734 native_type = type(native(obj))
735
736 # Upcast only if the type is already a native (non-future) type
737 if issubclass(native_type, type(obj)):
738 # Upcast
739 if native_type == str: # i.e. Py2 8-bit str
740 return newbytes(obj)
741 elif native_type == unicode:
742 return newstr(obj)
743 elif native_type == int:
744 return newint(obj)
745 elif native_type == long:
746 return newint(obj)
747 elif native_type == dict:
748 return newdict(obj)
749 else:
750 return obj
751 else:
752 # Already a new type
753 assert type(obj) in [newbytes, newstr]
754 return obj
755
756
757__all__ = ['PY2', 'PY26', 'PY3', 'PYPY',
758 'as_native_str', 'binary_type', 'bind_method', 'bord', 'bstr',
759 'bytes_to_native_str', 'class_types', 'encode_filename',
760 'ensure_new_type', 'exec_', 'get_next', 'getexception',
761 'implements_iterator', 'integer_types', 'is_new_style', 'isbytes',
762 'isidentifier', 'isint', 'isnewbytes', 'istext', 'iteritems',
763 'iterkeys', 'itervalues', 'lfilter', 'listitems', 'listvalues',
764 'lmap', 'lrange', 'lzip', 'native', 'native_bytes', 'native_str',
765 'native_str_to_bytes', 'old_div',
766 'python_2_unicode_compatible', 'raise_',
767 'raise_with_traceback', 'reraise', 'string_types',
768 'text_to_native_str', 'text_type', 'tobytes', 'viewitems',
769 'viewkeys', 'viewvalues', 'with_metaclass'
770 ]