asd
This commit is contained in:
		| @ -0,0 +1,51 @@ | ||||
| """ | ||||
| A module that brings in equivalents of the new and modified Python 3 | ||||
| builtins into Py2. Has no effect on Py3. | ||||
|  | ||||
| See the docs `here <https://python-future.org/what-else.html>`_ | ||||
| (``docs/what-else.rst``) for more information. | ||||
|  | ||||
| """ | ||||
|  | ||||
| from future.builtins.iterators import (filter, map, zip) | ||||
| # The isinstance import is no longer needed. We provide it only for | ||||
| # backward-compatibility with future v0.8.2. It will be removed in future v1.0. | ||||
| from future.builtins.misc import (ascii, chr, hex, input, isinstance, next, | ||||
|                                   oct, open, pow, round, super, max, min) | ||||
| from future.utils import PY3 | ||||
|  | ||||
| if PY3: | ||||
|     import builtins | ||||
|     bytes = builtins.bytes | ||||
|     dict = builtins.dict | ||||
|     int = builtins.int | ||||
|     list = builtins.list | ||||
|     object = builtins.object | ||||
|     range = builtins.range | ||||
|     str = builtins.str | ||||
|     __all__ = [] | ||||
| else: | ||||
|     from future.types import (newbytes as bytes, | ||||
|                               newdict as dict, | ||||
|                               newint as int, | ||||
|                               newlist as list, | ||||
|                               newobject as object, | ||||
|                               newrange as range, | ||||
|                               newstr as str) | ||||
| from future import utils | ||||
|  | ||||
|  | ||||
| if not utils.PY3: | ||||
|     # We only import names that shadow the builtins on Py2. No other namespace | ||||
|     # pollution on Py2. | ||||
|  | ||||
|     # Only shadow builtins on Py2; no new names | ||||
|     __all__ = ['filter', 'map', 'zip', | ||||
|                'ascii', 'chr', 'hex', 'input', 'next', 'oct', 'open', 'pow', | ||||
|                'round', 'super', | ||||
|                'bytes', 'dict', 'int', 'list', 'object', 'range', 'str', 'max', 'min' | ||||
|               ] | ||||
|  | ||||
| else: | ||||
|     # No namespace pollution on Py3 | ||||
|     __all__ = [] | ||||
| @ -0,0 +1,66 @@ | ||||
| """ | ||||
| This disables builtin functions (and one exception class) which are | ||||
| removed from Python 3.3. | ||||
|  | ||||
| This module is designed to be used like this:: | ||||
|  | ||||
|     from future.builtins.disabled import * | ||||
|  | ||||
| This disables the following obsolete Py2 builtin functions:: | ||||
|  | ||||
|     apply, cmp, coerce, execfile, file, input, long, | ||||
|     raw_input, reduce, reload, unicode, xrange | ||||
|  | ||||
| We don't hack __builtin__, which is very fragile because it contaminates | ||||
| imported modules too. Instead, we just create new functions with | ||||
| the same names as the obsolete builtins from Python 2 which raise | ||||
| NameError exceptions when called. | ||||
|  | ||||
| Note that both ``input()`` and ``raw_input()`` are among the disabled | ||||
| functions (in this module). Although ``input()`` exists as a builtin in | ||||
| Python 3, the Python 2 ``input()`` builtin is unsafe to use because it | ||||
| can lead to shell injection. Therefore we shadow it by default upon ``from | ||||
| future.builtins.disabled import *``, in case someone forgets to import our | ||||
| replacement ``input()`` somehow and expects Python 3 semantics. | ||||
|  | ||||
| See the ``future.builtins.misc`` module for a working version of | ||||
| ``input`` with Python 3 semantics. | ||||
|  | ||||
| (Note that callable() is not among the functions disabled; this was | ||||
| reintroduced into Python 3.2.) | ||||
|  | ||||
| This exception class is also disabled: | ||||
|  | ||||
|     StandardError | ||||
|  | ||||
| """ | ||||
|  | ||||
| from __future__ import division, absolute_import, print_function | ||||
|  | ||||
| from future import utils | ||||
|  | ||||
|  | ||||
| OBSOLETE_BUILTINS = ['apply', 'chr', 'cmp', 'coerce', 'execfile', 'file', | ||||
|                      'input', 'long', 'raw_input', 'reduce', 'reload', | ||||
|                      'unicode', 'xrange', 'StandardError'] | ||||
|  | ||||
|  | ||||
| def disabled_function(name): | ||||
|     ''' | ||||
|     Returns a function that cannot be called | ||||
|     ''' | ||||
|     def disabled(*args, **kwargs): | ||||
|         ''' | ||||
|         A function disabled by the ``future`` module. This function is | ||||
|         no longer a builtin in Python 3. | ||||
|         ''' | ||||
|         raise NameError('obsolete Python 2 builtin {0} is disabled'.format(name)) | ||||
|     return disabled | ||||
|  | ||||
|  | ||||
| if not utils.PY3: | ||||
|     for fname in OBSOLETE_BUILTINS: | ||||
|         locals()[fname] = disabled_function(fname) | ||||
|     __all__ = OBSOLETE_BUILTINS | ||||
| else: | ||||
|     __all__ = [] | ||||
| @ -0,0 +1,52 @@ | ||||
| """ | ||||
| This module is designed to be used as follows:: | ||||
|  | ||||
|     from future.builtins.iterators import * | ||||
|  | ||||
| And then, for example:: | ||||
|  | ||||
|     for i in range(10**15): | ||||
|         pass | ||||
|  | ||||
|     for (a, b) in zip(range(10**15), range(-10**15, 0)): | ||||
|         pass | ||||
|  | ||||
| Note that this is standard Python 3 code, plus some imports that do | ||||
| nothing on Python 3. | ||||
|  | ||||
| The iterators this brings in are:: | ||||
|  | ||||
| - ``range`` | ||||
| - ``filter`` | ||||
| - ``map`` | ||||
| - ``zip`` | ||||
|  | ||||
| On Python 2, ``range`` is a pure-Python backport of Python 3's ``range`` | ||||
| iterator with slicing support. The other iterators (``filter``, ``map``, | ||||
| ``zip``) are from the ``itertools`` module on Python 2. On Python 3 these | ||||
| are available in the module namespace but not exported for * imports via | ||||
| __all__ (zero no namespace pollution). | ||||
|  | ||||
| Note that these are also available in the standard library | ||||
| ``future_builtins`` module on Python 2 -- but not Python 3, so using | ||||
| the standard library version is not portable, nor anywhere near complete. | ||||
| """ | ||||
|  | ||||
| from __future__ import division, absolute_import, print_function | ||||
|  | ||||
| import itertools | ||||
| from future import utils | ||||
|  | ||||
| if not utils.PY3: | ||||
|     filter = itertools.ifilter | ||||
|     map = itertools.imap | ||||
|     from future.types import newrange as range | ||||
|     zip = itertools.izip | ||||
|     __all__ = ['filter', 'map', 'range', 'zip'] | ||||
| else: | ||||
|     import builtins | ||||
|     filter = builtins.filter | ||||
|     map = builtins.map | ||||
|     range = builtins.range | ||||
|     zip = builtins.zip | ||||
|     __all__ = [] | ||||
							
								
								
									
										135
									
								
								venv/lib/python3.12/site-packages/future/builtins/misc.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								venv/lib/python3.12/site-packages/future/builtins/misc.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,135 @@ | ||||
| """ | ||||
| A module that brings in equivalents of various modified Python 3 builtins | ||||
| into Py2. Has no effect on Py3. | ||||
|  | ||||
| The builtin functions are: | ||||
|  | ||||
| - ``ascii`` (from Py2's future_builtins module) | ||||
| - ``hex`` (from Py2's future_builtins module) | ||||
| - ``oct`` (from Py2's future_builtins module) | ||||
| - ``chr`` (equivalent to ``unichr`` on Py2) | ||||
| - ``input`` (equivalent to ``raw_input`` on Py2) | ||||
| - ``next`` (calls ``__next__`` if it exists, else ``next`` method) | ||||
| - ``open`` (equivalent to io.open on Py2) | ||||
| - ``super`` (backport of Py3's magic zero-argument super() function | ||||
| - ``round`` (new "Banker's Rounding" behaviour from Py3) | ||||
| - ``max`` (new default option from Py3.4) | ||||
| - ``min`` (new default option from Py3.4) | ||||
|  | ||||
| ``isinstance`` is also currently exported for backwards compatibility | ||||
| with v0.8.2, although this has been deprecated since v0.9. | ||||
|  | ||||
|  | ||||
| input() | ||||
| ------- | ||||
| Like the new ``input()`` function from Python 3 (without eval()), except | ||||
| that it returns bytes. Equivalent to Python 2's ``raw_input()``. | ||||
|  | ||||
| Warning: By default, importing this module *removes* the old Python 2 | ||||
| input() function entirely from ``__builtin__`` for safety. This is | ||||
| because forgetting to import the new ``input`` from ``future`` might | ||||
| otherwise lead to a security vulnerability (shell injection) on Python 2. | ||||
|  | ||||
| To restore it, you can retrieve it yourself from | ||||
| ``__builtin__._old_input``. | ||||
|  | ||||
| Fortunately, ``input()`` seems to be seldom used in the wild in Python | ||||
| 2... | ||||
|  | ||||
| """ | ||||
|  | ||||
| from future import utils | ||||
|  | ||||
|  | ||||
| if utils.PY2: | ||||
|     from io import open | ||||
|     from future_builtins import ascii, oct, hex | ||||
|     from __builtin__ import unichr as chr, pow as _builtin_pow | ||||
|     import __builtin__ | ||||
|  | ||||
|     # Only for backward compatibility with future v0.8.2: | ||||
|     isinstance = __builtin__.isinstance | ||||
|  | ||||
|     # Warning: Python 2's input() is unsafe and MUST not be able to be used | ||||
|     # accidentally by someone who expects Python 3 semantics but forgets | ||||
|     # to import it on Python 2. Versions of ``future`` prior to 0.11 | ||||
|     # deleted it from __builtin__.  Now we keep in __builtin__ but shadow | ||||
|     # the name like all others. Just be sure to import ``input``. | ||||
|  | ||||
|     input = raw_input | ||||
|  | ||||
|     from future.builtins.newnext import newnext as next | ||||
|     from future.builtins.newround import newround as round | ||||
|     from future.builtins.newsuper import newsuper as super | ||||
|     from future.builtins.new_min_max import newmax as max | ||||
|     from future.builtins.new_min_max import newmin as min | ||||
|     from future.types.newint import newint | ||||
|  | ||||
|     _SENTINEL = object() | ||||
|  | ||||
|     def pow(x, y, z=_SENTINEL): | ||||
|         """ | ||||
|         pow(x, y[, z]) -> number | ||||
|  | ||||
|         With two arguments, equivalent to x**y.  With three arguments, | ||||
|         equivalent to (x**y) % z, but may be more efficient (e.g. for ints). | ||||
|         """ | ||||
|         # Handle newints | ||||
|         if isinstance(x, newint): | ||||
|             x = long(x) | ||||
|         if isinstance(y, newint): | ||||
|             y = long(y) | ||||
|         if isinstance(z, newint): | ||||
|             z = long(z) | ||||
|  | ||||
|         try: | ||||
|             if z == _SENTINEL: | ||||
|                 return _builtin_pow(x, y) | ||||
|             else: | ||||
|                 return _builtin_pow(x, y, z) | ||||
|         except ValueError: | ||||
|             if z == _SENTINEL: | ||||
|                 return _builtin_pow(x+0j, y) | ||||
|             else: | ||||
|                 return _builtin_pow(x+0j, y, z) | ||||
|  | ||||
|  | ||||
|     # ``future`` doesn't support Py3.0/3.1. If we ever did, we'd add this: | ||||
|     #     callable = __builtin__.callable | ||||
|  | ||||
|     __all__ = ['ascii', 'chr', 'hex', 'input', 'isinstance', 'next', 'oct', | ||||
|                'open', 'pow', 'round', 'super', 'max', 'min'] | ||||
|  | ||||
| else: | ||||
|     import builtins | ||||
|     ascii = builtins.ascii | ||||
|     chr = builtins.chr | ||||
|     hex = builtins.hex | ||||
|     input = builtins.input | ||||
|     next = builtins.next | ||||
|     # Only for backward compatibility with future v0.8.2: | ||||
|     isinstance = builtins.isinstance | ||||
|     oct = builtins.oct | ||||
|     open = builtins.open | ||||
|     pow = builtins.pow | ||||
|     round = builtins.round | ||||
|     super = builtins.super | ||||
|     if utils.PY34_PLUS: | ||||
|         max = builtins.max | ||||
|         min = builtins.min | ||||
|         __all__ = [] | ||||
|     else: | ||||
|         from future.builtins.new_min_max import newmax as max | ||||
|         from future.builtins.new_min_max import newmin as min | ||||
|         __all__ = ['min', 'max'] | ||||
|  | ||||
|     # The callable() function was removed from Py3.0 and 3.1 and | ||||
|     # reintroduced into Py3.2+. ``future`` doesn't support Py3.0/3.1. If we ever | ||||
|     # did, we'd add this: | ||||
|     # try: | ||||
|     #     callable = builtins.callable | ||||
|     # except AttributeError: | ||||
|     #     # Definition from Pandas | ||||
|     #     def callable(obj): | ||||
|     #         return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) | ||||
|     #     __all__.append('callable') | ||||
| @ -0,0 +1,59 @@ | ||||
| import itertools | ||||
|  | ||||
| from future import utils | ||||
| if utils.PY2: | ||||
|     from __builtin__ import max as _builtin_max, min as _builtin_min | ||||
| else: | ||||
|     from builtins import max as _builtin_max, min as _builtin_min | ||||
|  | ||||
| _SENTINEL = object() | ||||
|  | ||||
|  | ||||
| def newmin(*args, **kwargs): | ||||
|     return new_min_max(_builtin_min, *args, **kwargs) | ||||
|  | ||||
|  | ||||
| def newmax(*args, **kwargs): | ||||
|     return new_min_max(_builtin_max, *args, **kwargs) | ||||
|  | ||||
|  | ||||
| def new_min_max(_builtin_func, *args, **kwargs): | ||||
|     """ | ||||
|     To support the argument "default" introduced in python 3.4 for min and max | ||||
|     :param _builtin_func: builtin min or builtin max | ||||
|     :param args: | ||||
|     :param kwargs: | ||||
|     :return: returns the min or max based on the arguments passed | ||||
|     """ | ||||
|  | ||||
|     for key, _ in kwargs.items(): | ||||
|         if key not in set(['key', 'default']): | ||||
|             raise TypeError('Illegal argument %s', key) | ||||
|  | ||||
|     if len(args) == 0: | ||||
|         raise TypeError | ||||
|  | ||||
|     if len(args) != 1 and kwargs.get('default', _SENTINEL) is not _SENTINEL: | ||||
|         raise TypeError | ||||
|  | ||||
|     if len(args) == 1: | ||||
|         iterator = iter(args[0]) | ||||
|         try: | ||||
|             first = next(iterator) | ||||
|         except StopIteration: | ||||
|             if kwargs.get('default', _SENTINEL) is not _SENTINEL: | ||||
|                 return kwargs.get('default') | ||||
|             else: | ||||
|                 raise ValueError('{}() arg is an empty sequence'.format(_builtin_func.__name__)) | ||||
|         else: | ||||
|             iterator = itertools.chain([first], iterator) | ||||
|         if kwargs.get('key') is not None: | ||||
|             return _builtin_func(iterator, key=kwargs.get('key')) | ||||
|         else: | ||||
|             return _builtin_func(iterator) | ||||
|  | ||||
|     if len(args) > 1: | ||||
|         if kwargs.get('key') is not None: | ||||
|             return _builtin_func(args, key=kwargs.get('key')) | ||||
|         else: | ||||
|             return _builtin_func(args) | ||||
							
								
								
									
										70
									
								
								venv/lib/python3.12/site-packages/future/builtins/newnext.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								venv/lib/python3.12/site-packages/future/builtins/newnext.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,70 @@ | ||||
| ''' | ||||
| This module provides a newnext() function in Python 2 that mimics the | ||||
| behaviour of ``next()`` in Python 3, falling back to Python 2's behaviour for | ||||
| compatibility if this fails. | ||||
|  | ||||
| ``newnext(iterator)`` calls the iterator's ``__next__()`` method if it exists. If this | ||||
| doesn't exist, it falls back to calling a ``next()`` method. | ||||
|  | ||||
| For example: | ||||
|  | ||||
|     >>> class Odds(object): | ||||
|     ...     def __init__(self, start=1): | ||||
|     ...         self.value = start - 2 | ||||
|     ...     def __next__(self):                 # note the Py3 interface | ||||
|     ...         self.value += 2 | ||||
|     ...         return self.value | ||||
|     ...     def __iter__(self): | ||||
|     ...         return self | ||||
|     ... | ||||
|     >>> iterator = Odds() | ||||
|     >>> next(iterator) | ||||
|     1 | ||||
|     >>> next(iterator) | ||||
|     3 | ||||
|  | ||||
| If you are defining your own custom iterator class as above, it is preferable | ||||
| to explicitly decorate the class with the @implements_iterator decorator from | ||||
| ``future.utils`` as follows: | ||||
|  | ||||
|     >>> @implements_iterator | ||||
|     ... class Odds(object): | ||||
|     ...     # etc | ||||
|     ...     pass | ||||
|  | ||||
| This next() function is primarily for consuming iterators defined in Python 3 | ||||
| code elsewhere that we would like to run on Python 2 or 3. | ||||
| ''' | ||||
|  | ||||
| _builtin_next = next | ||||
|  | ||||
| _SENTINEL = object() | ||||
|  | ||||
| def newnext(iterator, default=_SENTINEL): | ||||
|     """ | ||||
|     next(iterator[, default]) | ||||
|  | ||||
|     Return the next item from the iterator. If default is given and the iterator | ||||
|     is exhausted, it is returned instead of raising StopIteration. | ||||
|     """ | ||||
|  | ||||
|     # args = [] | ||||
|     # if default is not _SENTINEL: | ||||
|     #     args.append(default) | ||||
|     try: | ||||
|         try: | ||||
|             return iterator.__next__() | ||||
|         except AttributeError: | ||||
|             try: | ||||
|                 return iterator.next() | ||||
|             except AttributeError: | ||||
|                 raise TypeError("'{0}' object is not an iterator".format( | ||||
|                                            iterator.__class__.__name__)) | ||||
|     except StopIteration as e: | ||||
|         if default is _SENTINEL: | ||||
|             raise e | ||||
|         else: | ||||
|             return default | ||||
|  | ||||
|  | ||||
| __all__ = ['newnext'] | ||||
							
								
								
									
										105
									
								
								venv/lib/python3.12/site-packages/future/builtins/newround.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								venv/lib/python3.12/site-packages/future/builtins/newround.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,105 @@ | ||||
| """ | ||||
| ``python-future``: pure Python implementation of Python 3 round(). | ||||
| """ | ||||
|  | ||||
| from __future__ import division | ||||
| from future.utils import PYPY, PY26, bind_method | ||||
|  | ||||
| # Use the decimal module for simplicity of implementation (and | ||||
| # hopefully correctness). | ||||
| from decimal import Decimal, ROUND_HALF_EVEN | ||||
|  | ||||
|  | ||||
| def newround(number, ndigits=None): | ||||
|     """ | ||||
|     See Python 3 documentation: uses Banker's Rounding. | ||||
|  | ||||
|     Delegates to the __round__ method if for some reason this exists. | ||||
|  | ||||
|     If not, rounds a number to a given precision in decimal digits (default | ||||
|     0 digits). This returns an int when called with one argument, | ||||
|     otherwise the same type as the number. ndigits may be negative. | ||||
|  | ||||
|     See the test_round method in future/tests/test_builtins.py for | ||||
|     examples. | ||||
|     """ | ||||
|     return_int = False | ||||
|     if ndigits is None: | ||||
|         return_int = True | ||||
|         ndigits = 0 | ||||
|     if hasattr(number, '__round__'): | ||||
|         return number.__round__(ndigits) | ||||
|  | ||||
|     exponent = Decimal('10') ** (-ndigits) | ||||
|  | ||||
|     # Work around issue #24: round() breaks on PyPy with NumPy's types | ||||
|     # Also breaks on CPython with NumPy's specialized int types like uint64 | ||||
|     if 'numpy' in repr(type(number)): | ||||
|         number = float(number) | ||||
|  | ||||
|     if isinstance(number, Decimal): | ||||
|         d = number | ||||
|     else: | ||||
|         if not PY26: | ||||
|             d = Decimal.from_float(number) | ||||
|         else: | ||||
|             d = from_float_26(number) | ||||
|  | ||||
|     if ndigits < 0: | ||||
|         result = newround(d / exponent) * exponent | ||||
|     else: | ||||
|         result = d.quantize(exponent, rounding=ROUND_HALF_EVEN) | ||||
|  | ||||
|     if return_int: | ||||
|         return int(result) | ||||
|     else: | ||||
|         return float(result) | ||||
|  | ||||
|  | ||||
| ### From Python 2.7's decimal.py. Only needed to support Py2.6: | ||||
|  | ||||
| def from_float_26(f): | ||||
|     """Converts a float to a decimal number, exactly. | ||||
|  | ||||
|     Note that Decimal.from_float(0.1) is not the same as Decimal('0.1'). | ||||
|     Since 0.1 is not exactly representable in binary floating point, the | ||||
|     value is stored as the nearest representable value which is | ||||
|     0x1.999999999999ap-4.  The exact equivalent of the value in decimal | ||||
|     is 0.1000000000000000055511151231257827021181583404541015625. | ||||
|  | ||||
|     >>> Decimal.from_float(0.1) | ||||
|     Decimal('0.1000000000000000055511151231257827021181583404541015625') | ||||
|     >>> Decimal.from_float(float('nan')) | ||||
|     Decimal('NaN') | ||||
|     >>> Decimal.from_float(float('inf')) | ||||
|     Decimal('Infinity') | ||||
|     >>> Decimal.from_float(-float('inf')) | ||||
|     Decimal('-Infinity') | ||||
|     >>> Decimal.from_float(-0.0) | ||||
|     Decimal('-0') | ||||
|  | ||||
|     """ | ||||
|     import math as _math | ||||
|     from decimal import _dec_from_triple    # only available on Py2.6 and Py2.7 (not 3.3) | ||||
|  | ||||
|     if isinstance(f, (int, long)):        # handle integer inputs | ||||
|         return Decimal(f) | ||||
|     if _math.isinf(f) or _math.isnan(f):  # raises TypeError if not a float | ||||
|         return Decimal(repr(f)) | ||||
|     if _math.copysign(1.0, f) == 1.0: | ||||
|         sign = 0 | ||||
|     else: | ||||
|         sign = 1 | ||||
|     n, d = abs(f).as_integer_ratio() | ||||
|     # int.bit_length() method doesn't exist on Py2.6: | ||||
|     def bit_length(d): | ||||
|         if d != 0: | ||||
|             return len(bin(abs(d))) - 2 | ||||
|         else: | ||||
|             return 0 | ||||
|     k = bit_length(d) - 1 | ||||
|     result = _dec_from_triple(sign, str(n*5**k), -k) | ||||
|     return result | ||||
|  | ||||
|  | ||||
| __all__ = ['newround'] | ||||
							
								
								
									
										113
									
								
								venv/lib/python3.12/site-packages/future/builtins/newsuper.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								venv/lib/python3.12/site-packages/future/builtins/newsuper.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,113 @@ | ||||
| ''' | ||||
| This module provides a newsuper() function in Python 2 that mimics the | ||||
| behaviour of super() in Python 3. It is designed to be used as follows: | ||||
|  | ||||
|     from __future__ import division, absolute_import, print_function | ||||
|     from future.builtins import super | ||||
|  | ||||
| And then, for example: | ||||
|  | ||||
|     class VerboseList(list): | ||||
|         def append(self, item): | ||||
|             print('Adding an item') | ||||
|             super().append(item)        # new simpler super() function | ||||
|  | ||||
| Importing this module on Python 3 has no effect. | ||||
|  | ||||
| This is based on (i.e. almost identical to) Ryan Kelly's magicsuper | ||||
| module here: | ||||
|  | ||||
|     https://github.com/rfk/magicsuper.git | ||||
|  | ||||
| Excerpts from Ryan's docstring: | ||||
|  | ||||
|   "Of course, you can still explicitly pass in the arguments if you want | ||||
|   to do something strange.  Sometimes you really do want that, e.g. to | ||||
|   skip over some classes in the method resolution order. | ||||
|  | ||||
|   "How does it work?  By inspecting the calling frame to determine the | ||||
|   function object being executed and the object on which it's being | ||||
|   called, and then walking the object's __mro__ chain to find out where | ||||
|   that function was defined.  Yuck, but it seems to work..." | ||||
| ''' | ||||
|  | ||||
| from __future__ import absolute_import | ||||
| import sys | ||||
| from types import FunctionType | ||||
|  | ||||
| from future.utils import PY3, PY26 | ||||
|  | ||||
|  | ||||
| _builtin_super = super | ||||
|  | ||||
| _SENTINEL = object() | ||||
|  | ||||
| def newsuper(typ=_SENTINEL, type_or_obj=_SENTINEL, framedepth=1): | ||||
|     '''Like builtin super(), but capable of magic. | ||||
|  | ||||
|     This acts just like the builtin super() function, but if called | ||||
|     without any arguments it attempts to infer them at runtime. | ||||
|     ''' | ||||
|     #  Infer the correct call if used without arguments. | ||||
|     if typ is _SENTINEL: | ||||
|         # We'll need to do some frame hacking. | ||||
|         f = sys._getframe(framedepth) | ||||
|  | ||||
|         try: | ||||
|             # Get the function's first positional argument. | ||||
|             type_or_obj = f.f_locals[f.f_code.co_varnames[0]] | ||||
|         except (IndexError, KeyError,): | ||||
|             raise RuntimeError('super() used in a function with no args') | ||||
|  | ||||
|         try: | ||||
|             typ = find_owner(type_or_obj, f.f_code) | ||||
|         except (AttributeError, RuntimeError, TypeError): | ||||
|             # see issues #160, #267 | ||||
|             try: | ||||
|                 typ = find_owner(type_or_obj.__class__, f.f_code) | ||||
|             except AttributeError: | ||||
|                 raise RuntimeError('super() used with an old-style class') | ||||
|             except TypeError: | ||||
|                 raise RuntimeError('super() called outside a method') | ||||
|  | ||||
|     #  Dispatch to builtin super(). | ||||
|     if type_or_obj is not _SENTINEL: | ||||
|         return _builtin_super(typ, type_or_obj) | ||||
|     return _builtin_super(typ) | ||||
|  | ||||
|  | ||||
| def find_owner(cls, code): | ||||
|     '''Find the class that owns the currently-executing method. | ||||
|     ''' | ||||
|     for typ in cls.__mro__: | ||||
|         for meth in typ.__dict__.values(): | ||||
|             # Drill down through any wrappers to the underlying func. | ||||
|             # This handles e.g. classmethod() and staticmethod(). | ||||
|             try: | ||||
|                 while not isinstance(meth,FunctionType): | ||||
|                     if isinstance(meth, property): | ||||
|                         # Calling __get__ on the property will invoke | ||||
|                         # user code which might throw exceptions or have | ||||
|                         # side effects | ||||
|                         meth = meth.fget | ||||
|                     else: | ||||
|                         try: | ||||
|                             meth = meth.__func__ | ||||
|                         except AttributeError: | ||||
|                             meth = meth.__get__(cls, typ) | ||||
|             except (AttributeError, TypeError): | ||||
|                 continue | ||||
|             if meth.func_code is code: | ||||
|                 return typ   # Aha!  Found you. | ||||
|         #  Not found! Move onto the next class in MRO. | ||||
|  | ||||
|     raise TypeError | ||||
|  | ||||
|  | ||||
| def superm(*args, **kwds): | ||||
|     f = sys._getframe(1) | ||||
|     nm = f.f_code.co_name | ||||
|     return getattr(newsuper(framedepth=2),nm)(*args, **kwds) | ||||
|  | ||||
|  | ||||
| __all__ = ['newsuper'] | ||||
		Reference in New Issue
	
	Block a user