Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
functools.py1166 linesDownload Raw Back to Lib
1"""functools.py - Tools for working with functions and callable objects2"""3# Python module wrapper for _functools C module4# to allow utilities written in Python to be added5# to the functools module.6# Written by Nick Coghlan <ncoghlan at gmail.com>,7# Raymond Hettinger <python at rcn.com>,8# and Łukasz Langa <lukasz at langa.pl>.9#   Copyright (C) 2006 Python Software Foundation.10# See C source code for _functools credits/copyright11 12__all__ = ['update_wrapper', 'wraps', 'WRAPPER_ASSIGNMENTS', 'WRAPPER_UPDATES',13           'total_ordering', 'cache', 'cmp_to_key', 'lru_cache', 'reduce',14           'partial', 'partialmethod', 'singledispatch', 'singledispatchmethod',15           'cached_property', 'Placeholder']16 17from abc import get_cache_token18from collections import namedtuple19# import weakref  # Deferred to single_dispatch()20from operator import itemgetter21from reprlib import recursive_repr22from types import GenericAlias, MethodType, MappingProxyType, UnionType23from _thread import RLock24 25################################################################################26### update_wrapper() and wraps() decorator27################################################################################28 29# update_wrapper() and wraps() are tools to help write30# wrapper functions that can handle naive introspection31 32WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__',33                       '__annotate__', '__type_params__')34WRAPPER_UPDATES = ('__dict__',)35def update_wrapper(wrapper,36                   wrapped,37                   assigned = WRAPPER_ASSIGNMENTS,38                   updated = WRAPPER_UPDATES):39    """Update a wrapper function to look like the wrapped function40 41       wrapper is the function to be updated42       wrapped is the original function43       assigned is a tuple naming the attributes assigned directly44       from the wrapped function to the wrapper function (defaults to45       functools.WRAPPER_ASSIGNMENTS)46       updated is a tuple naming the attributes of the wrapper that47       are updated with the corresponding attribute from the wrapped48       function (defaults to functools.WRAPPER_UPDATES)49    """50    for attr in assigned:51        try:52            value = getattr(wrapped, attr)53        except AttributeError:54            pass55        else:56            setattr(wrapper, attr, value)57    for attr in updated:58        getattr(wrapper, attr).update(getattr(wrapped, attr, {}))59    # Issue #17482: set __wrapped__ last so we don't inadvertently copy it60    # from the wrapped function when updating __dict__61    wrapper.__wrapped__ = wrapped62    # Return the wrapper so this can be used as a decorator via partial()63    return wrapper64 65def wraps(wrapped,66          assigned = WRAPPER_ASSIGNMENTS,67          updated = WRAPPER_UPDATES):68    """Decorator factory to apply update_wrapper() to a wrapper function69 70       Returns a decorator that invokes update_wrapper() with the decorated71       function as the wrapper argument and the arguments to wraps() as the72       remaining arguments. Default arguments are as for update_wrapper().73       This is a convenience function to simplify applying partial() to74       update_wrapper().75    """76    return partial(update_wrapper, wrapped=wrapped,77                   assigned=assigned, updated=updated)78 79 80################################################################################81### total_ordering class decorator82################################################################################83 84# The total ordering functions all invoke the root magic method directly85# rather than using the corresponding operator.  This avoids possible86# infinite recursion that could occur when the operator dispatch logic87# detects a NotImplemented result and then calls a reflected method.88 89def _gt_from_lt(self, other):90    'Return a > b.  Computed by @total_ordering from (not a < b) and (a != b).'91    op_result = type(self).__lt__(self, other)92    if op_result is NotImplemented:93        return op_result94    return not op_result and self != other95 96def _le_from_lt(self, other):97    'Return a <= b.  Computed by @total_ordering from (a < b) or (a == b).'98    op_result = type(self).__lt__(self, other)99    if op_result is NotImplemented:100        return op_result101    return op_result or self == other102 103def _ge_from_lt(self, other):104    'Return a >= b.  Computed by @total_ordering from (not a < b).'105    op_result = type(self).__lt__(self, other)106    if op_result is NotImplemented:107        return op_result108    return not op_result109 110def _ge_from_le(self, other):111    'Return a >= b.  Computed by @total_ordering from (not a <= b) or (a == b).'112    op_result = type(self).__le__(self, other)113    if op_result is NotImplemented:114        return op_result115    return not op_result or self == other116 117def _lt_from_le(self, other):118    'Return a < b.  Computed by @total_ordering from (a <= b) and (a != b).'119    op_result = type(self).__le__(self, other)120    if op_result is NotImplemented:121        return op_result122    return op_result and self != other123 124def _gt_from_le(self, other):125    'Return a > b.  Computed by @total_ordering from (not a <= b).'126    op_result = type(self).__le__(self, other)127    if op_result is NotImplemented:128        return op_result129    return not op_result130 131def _lt_from_gt(self, other):132    'Return a < b.  Computed by @total_ordering from (not a > b) and (a != b).'133    op_result = type(self).__gt__(self, other)134    if op_result is NotImplemented:135        return op_result136    return not op_result and self != other137 138def _ge_from_gt(self, other):139    'Return a >= b.  Computed by @total_ordering from (a > b) or (a == b).'140    op_result = type(self).__gt__(self, other)141    if op_result is NotImplemented:142        return op_result143    return op_result or self == other144 145def _le_from_gt(self, other):146    'Return a <= b.  Computed by @total_ordering from (not a > b).'147    op_result = type(self).__gt__(self, other)148    if op_result is NotImplemented:149        return op_result150    return not op_result151 152def _le_from_ge(self, other):153    'Return a <= b.  Computed by @total_ordering from (not a >= b) or (a == b).'154    op_result = type(self).__ge__(self, other)155    if op_result is NotImplemented:156        return op_result157    return not op_result or self == other158 159def _gt_from_ge(self, other):160    'Return a > b.  Computed by @total_ordering from (a >= b) and (a != b).'161    op_result = type(self).__ge__(self, other)162    if op_result is NotImplemented:163        return op_result164    return op_result and self != other165 166def _lt_from_ge(self, other):167    'Return a < b.  Computed by @total_ordering from (not a >= b).'168    op_result = type(self).__ge__(self, other)169    if op_result is NotImplemented:170        return op_result171    return not op_result172 173_convert = {174    '__lt__': [('__gt__', _gt_from_lt),175               ('__le__', _le_from_lt),176               ('__ge__', _ge_from_lt)],177    '__le__': [('__ge__', _ge_from_le),178               ('__lt__', _lt_from_le),179               ('__gt__', _gt_from_le)],180    '__gt__': [('__lt__', _lt_from_gt),181               ('__ge__', _ge_from_gt),182               ('__le__', _le_from_gt)],183    '__ge__': [('__le__', _le_from_ge),184               ('__gt__', _gt_from_ge),185               ('__lt__', _lt_from_ge)]186}187 188def total_ordering(cls):189    """Class decorator that fills in missing ordering methods"""190    # Find user-defined comparisons (not those inherited from object).191    roots = {op for op in _convert if getattr(cls, op, None) is not getattr(object, op, None)}192    if not roots:193        raise ValueError('must define at least one ordering operation: < > <= >=')194    root = max(roots)       # prefer __lt__ to __le__ to __gt__ to __ge__195    for opname, opfunc in _convert[root]:196        if opname not in roots:197            opfunc.__name__ = opname198            setattr(cls, opname, opfunc)199    return cls200 201 202################################################################################203### cmp_to_key() function converter204################################################################################205 206def cmp_to_key(mycmp):207    """Convert a cmp= function into a key= function"""208    class K(object):209        __slots__ = ['obj']210        def __init__(self, obj):211            self.obj = obj212        def __lt__(self, other):213            return mycmp(self.obj, other.obj) < 0214        def __gt__(self, other):215            return mycmp(self.obj, other.obj) > 0216        def __eq__(self, other):217            return mycmp(self.obj, other.obj) == 0218        def __le__(self, other):219            return mycmp(self.obj, other.obj) <= 0220        def __ge__(self, other):221            return mycmp(self.obj, other.obj) >= 0222        __hash__ = None223    return K224 225try:226    from _functools import cmp_to_key227except ImportError:228    pass229 230 231################################################################################232### reduce() sequence to a single item233################################################################################234 235_initial_missing = object()236 237def reduce(function, sequence, initial=_initial_missing):238    """239    reduce(function, iterable, /[, initial]) -> value240 241    Apply a function of two arguments cumulatively to the items of an iterable, from left to right.242 243    This effectively reduces the iterable to a single value.  If initial is present,244    it is placed before the items of the iterable in the calculation, and serves as245    a default when the iterable is empty.246 247    For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])248    calculates ((((1 + 2) + 3) + 4) + 5).249    """250 251    it = iter(sequence)252 253    if initial is _initial_missing:254        try:255            value = next(it)256        except StopIteration:257            raise TypeError(258                "reduce() of empty iterable with no initial value") from None259    else:260        value = initial261 262    for element in it:263        value = function(value, element)264 265    return value266 267 268################################################################################269### partial() argument application270################################################################################271 272 273class _PlaceholderType:274    """The type of the Placeholder singleton.275 276    Used as a placeholder for partial arguments.277    """278    __instance = None279    __slots__ = ()280 281    def __init_subclass__(cls, *args, **kwargs):282        raise TypeError(f"type '{cls.__name__}' is not an acceptable base type")283 284    def __new__(cls):285        if cls.__instance is None:286            cls.__instance = object.__new__(cls)287        return cls.__instance288 289    def __repr__(self):290        return 'Placeholder'291 292    def __reduce__(self):293        return 'Placeholder'294 295Placeholder = _PlaceholderType()296 297def _partial_prepare_merger(args):298    if not args:299        return 0, None300    nargs = len(args)301    order = []302    j = nargs303    for i, a in enumerate(args):304        if a is Placeholder:305            order.append(j)306            j += 1307        else:308            order.append(i)309    phcount = j - nargs310    merger = itemgetter(*order) if phcount else None311    return phcount, merger312 313def _partial_new(cls, func, /, *args, **keywords):314    if issubclass(cls, partial):315        base_cls = partial316        if not callable(func):317            raise TypeError("the first argument must be callable")318    else:319        base_cls = partialmethod320        # func could be a descriptor like classmethod which isn't callable321        if not callable(func) and not hasattr(func, "__get__"):322            raise TypeError(f"the first argument {func!r} must be a callable "323                            "or a descriptor")324    if args and args[-1] is Placeholder:325        raise TypeError("trailing Placeholders are not allowed")326    for value in keywords.values():327        if value is Placeholder:328            raise TypeError("Placeholder cannot be passed as a keyword argument")329    if isinstance(func, base_cls):330        pto_phcount = func._phcount331        tot_args = func.args332        if args:333            tot_args += args334            if pto_phcount:335                # merge args with args of `func` which is `partial`336                nargs = len(args)337                if nargs < pto_phcount:338                    tot_args += (Placeholder,) * (pto_phcount - nargs)339                tot_args = func._merger(tot_args)340                if nargs > pto_phcount:341                    tot_args += args[pto_phcount:]342            phcount, merger = _partial_prepare_merger(tot_args)343        else:   # works for both pto_phcount == 0 and != 0344            phcount, merger = pto_phcount, func._merger345        keywords = {**func.keywords, **keywords}346        func = func.func347    else:348        tot_args = args349        phcount, merger = _partial_prepare_merger(tot_args)350 351    self = object.__new__(cls)352    self.func = func353    self.args = tot_args354    self.keywords = keywords355    self._phcount = phcount356    self._merger = merger357    return self358 359def _partial_repr(self):360    cls = type(self)361    module = cls.__module__362    qualname = cls.__qualname__363    args = [repr(self.func)]364    args.extend(map(repr, self.args))365    args.extend(f"{k}={v!r}" for k, v in self.keywords.items())366    return f"{module}.{qualname}({', '.join(args)})"367 368# Purely functional, no descriptor behaviour369class partial:370    """New function with partial application of the given arguments371    and keywords.372    """373 374    __slots__ = ("func", "args", "keywords", "_phcount", "_merger",375                 "__dict__", "__weakref__")376 377    __new__ = _partial_new378    __repr__ = recursive_repr()(_partial_repr)379 380    def __call__(self, /, *args, **keywords):381        phcount = self._phcount382        if phcount:383            try:384                pto_args = self._merger(self.args + args)385                args = args[phcount:]386            except IndexError:387                raise TypeError("missing positional arguments "388                                "in 'partial' call; expected "389                                f"at least {phcount}, got {len(args)}")390        else:391            pto_args = self.args392        keywords = {**self.keywords, **keywords}393        return self.func(*pto_args, *args, **keywords)394 395    def __get__(self, obj, objtype=None):396        if obj is None:397            return self398        return MethodType(self, obj)399 400    def __reduce__(self):401        return type(self), (self.func,), (self.func, self.args,402               self.keywords or None, self.__dict__ or None)403 404    def __setstate__(self, state):405        if not isinstance(state, tuple):406            raise TypeError("argument to __setstate__ must be a tuple")407        if len(state) != 4:408            raise TypeError(f"expected 4 items in state, got {len(state)}")409        func, args, kwds, namespace = state410        if (not callable(func) or not isinstance(args, tuple) or411           (kwds is not None and not isinstance(kwds, dict)) or412           (namespace is not None and not isinstance(namespace, dict))):413            raise TypeError("invalid partial state")414 415        if args and args[-1] is Placeholder:416            raise TypeError("trailing Placeholders are not allowed")417        phcount, merger = _partial_prepare_merger(args)418 419        args = tuple(args) # just in case it's a subclass420        if kwds is None:421            kwds = {}422        elif type(kwds) is not dict: # XXX does it need to be *exactly* dict?423            kwds = dict(kwds)424        if namespace is None:425            namespace = {}426 427        self.__dict__ = namespace428        self.func = func429        self.args = args430        self.keywords = kwds431        self._phcount = phcount432        self._merger = merger433 434    __class_getitem__ = classmethod(GenericAlias)435 436 437try:438    from _functools import partial, Placeholder, _PlaceholderType439except ImportError:440    pass441 442# Descriptor version443class partialmethod:444    """Method descriptor with partial application of the given arguments445    and keywords.446 447    Supports wrapping existing descriptors and handles non-descriptor448    callables as instance methods.449    """450    __new__ = _partial_new451    __repr__ = _partial_repr452 453    def _make_unbound_method(self):454        def _method(cls_or_self, /, *args, **keywords):455            phcount = self._phcount456            if phcount:457                try:458                    pto_args = self._merger(self.args + args)459                    args = args[phcount:]460                except IndexError:461                    raise TypeError("missing positional arguments "462                                    "in 'partialmethod' call; expected "463                                    f"at least {phcount}, got {len(args)}")464            else:465                pto_args = self.args466            keywords = {**self.keywords, **keywords}467            return self.func(cls_or_self, *pto_args, *args, **keywords)468        _method.__isabstractmethod__ = self.__isabstractmethod__469        _method.__partialmethod__ = self470        return _method471 472    def __get__(self, obj, cls=None):473        get = getattr(self.func, "__get__", None)474        result = None475        if get is not None:476            new_func = get(obj, cls)477            if new_func is not self.func:478                # Assume __get__ returning something new indicates the479                # creation of an appropriate callable480                result = partial(new_func, *self.args, **self.keywords)481                try:482                    result.__self__ = new_func.__self__483                except AttributeError:484                    pass485        if result is None:486            # If the underlying descriptor didn't do anything, treat this487            # like an instance method488            result = self._make_unbound_method().__get__(obj, cls)489        return result490 491    @property492    def __isabstractmethod__(self):493        return getattr(self.func, "__isabstractmethod__", False)494 495    __class_getitem__ = classmethod(GenericAlias)496 497 498# Helper functions499 500def _unwrap_partial(func):501    while isinstance(func, partial):502        func = func.func503    return func504 505def _unwrap_partialmethod(func):506    prev = None507    while func is not prev:508        prev = func509        while isinstance(getattr(func, "__partialmethod__", None), partialmethod):510            func = func.__partialmethod__511        while isinstance(func, partialmethod):512            func = getattr(func, 'func')513        func = _unwrap_partial(func)514    return func515 516################################################################################517### LRU Cache function decorator518################################################################################519 520_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])521 522def _make_key(args, kwds, typed,523             kwd_mark = (object(),),524             fasttypes = {int, str},525             tuple=tuple, type=type, len=len):526    """Make a cache key from optionally typed positional and keyword arguments527 528    The key is constructed in a way that is flat as possible rather than529    as a nested structure that would take more memory.530 531    If there is only a single argument and its data type is known to cache532    its hash value, then that argument is returned without a wrapper.  This533    saves space and improves lookup speed.534 535    """536    # All of code below relies on kwds preserving the order input by the user.537    # Formerly, we sorted() the kwds before looping.  The new way is *much*538    # faster; however, it means that f(x=1, y=2) will now be treated as a539    # distinct call from f(y=2, x=1) which will be cached separately.540    key = args541    if kwds:542        key += kwd_mark543        for item in kwds.items():544            key += item545    if typed:546        key += tuple(type(v) for v in args)547        if kwds:548            key += tuple(type(v) for v in kwds.values())549    elif len(key) == 1 and type(key[0]) in fasttypes:550        return key[0]551    return key552 553def lru_cache(maxsize=128, typed=False):554    """Least-recently-used cache decorator.555 556    If *maxsize* is set to None, the LRU features are disabled and the cache557    can grow without bound.558 559    If *typed* is True, arguments of different types will be cached separately.560    For example, f(decimal.Decimal("3.0")) and f(3.0) will be treated as561    distinct calls with distinct results. Some types such as str and int may562    be cached separately even when typed is false.563 564    Arguments to the cached function must be hashable.565 566    View the cache statistics named tuple (hits, misses, maxsize, currsize)567    with f.cache_info().  Clear the cache and statistics with f.cache_clear().568    Access the underlying function with f.__wrapped__.569 570    See:  https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU)571 572    """573 574    # Users should only access the lru_cache through its public API:575    #       cache_info, cache_clear, and f.__wrapped__576    # The internals of the lru_cache are encapsulated for thread safety and577    # to allow the implementation to change (including a possible C version).578 579    if isinstance(maxsize, int):580        # Negative maxsize is treated as 0581        if maxsize < 0:582            maxsize = 0583    elif callable(maxsize) and isinstance(typed, bool):584        # The user_function was passed in directly via the maxsize argument585        user_function, maxsize = maxsize, 128586        wrapper = _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo)587        wrapper.cache_parameters = lambda : {'maxsize': maxsize, 'typed': typed}588        return update_wrapper(wrapper, user_function)589    elif maxsize is not None:590        raise TypeError(591            'Expected first argument to be an integer, a callable, or None')592 593    def decorating_function(user_function):594        wrapper = _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo)595        wrapper.cache_parameters = lambda : {'maxsize': maxsize, 'typed': typed}596        return update_wrapper(wrapper, user_function)597 598    return decorating_function599 600def _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo):601    # Constants shared by all lru cache instances:602    sentinel = object()          # unique object used to signal cache misses603    make_key = _make_key         # build a key from the function arguments604    PREV, NEXT, KEY, RESULT = 0, 1, 2, 3   # names for the link fields605 606    cache = {}607    hits = misses = 0608    full = False609    cache_get = cache.get    # bound method to lookup a key or return None610    cache_len = cache.__len__  # get cache size without calling len()611    lock = RLock()           # because linkedlist updates aren't threadsafe612    root = []                # root of the circular doubly linked list613    root[:] = [root, root, None, None]     # initialize by pointing to self614 615    if maxsize == 0:616 617        def wrapper(*args, **kwds):618            # No caching -- just a statistics update619            nonlocal misses620            misses += 1621            result = user_function(*args, **kwds)622            return result623 624    elif maxsize is None:625 626        def wrapper(*args, **kwds):627            # Simple caching without ordering or size limit628            nonlocal hits, misses629            key = make_key(args, kwds, typed)630            result = cache_get(key, sentinel)631            if result is not sentinel:632                hits += 1633                return result634            misses += 1635            result = user_function(*args, **kwds)636            cache[key] = result637            return result638 639    else:640 641        def wrapper(*args, **kwds):642            # Size limited caching that tracks accesses by recency643            nonlocal root, hits, misses, full644            key = make_key(args, kwds, typed)645            with lock:646                link = cache_get(key)647                if link is not None:648                    # Move the link to the front of the circular queue649                    link_prev, link_next, _key, result = link650                    link_prev[NEXT] = link_next651                    link_next[PREV] = link_prev652                    last = root[PREV]653                    last[NEXT] = root[PREV] = link654                    link[PREV] = last655                    link[NEXT] = root656                    hits += 1657                    return result658                misses += 1659            result = user_function(*args, **kwds)660            with lock:661                if key in cache:662                    # Getting here means that this same key was added to the663                    # cache while the lock was released.  Since the link664                    # update is already done, we need only return the665                    # computed result and update the count of misses.666                    pass667                elif full:668                    # Use the old root to store the new key and result.669                    oldroot = root670                    oldroot[KEY] = key671                    oldroot[RESULT] = result672                    # Empty the oldest link and make it the new root.673                    # Keep a reference to the old key and old result to674                    # prevent their ref counts from going to zero during the675                    # update. That will prevent potentially arbitrary object676                    # clean-up code (i.e. __del__) from running while we're677                    # still adjusting the links.678                    root = oldroot[NEXT]679                    oldkey = root[KEY]680                    oldresult = root[RESULT]681                    root[KEY] = root[RESULT] = None682                    # Now update the cache dictionary.683                    del cache[oldkey]684                    # Save the potentially reentrant cache[key] assignment685                    # for last, after the root and links have been put in686                    # a consistent state.687                    cache[key] = oldroot688                else:689                    # Put result in a new link at the front of the queue.690                    last = root[PREV]691                    link = [last, root, key, result]692                    last[NEXT] = root[PREV] = cache[key] = link693                    # Use the cache_len bound method instead of the len() function694                    # which could potentially be wrapped in an lru_cache itself.695                    full = (cache_len() >= maxsize)696            return result697 698    def cache_info():699        """Report cache statistics"""700        with lock:701            return _CacheInfo(hits, misses, maxsize, cache_len())702 703    def cache_clear():704        """Clear the cache and cache statistics"""705        nonlocal hits, misses, full706        with lock:707            cache.clear()708            root[:] = [root, root, None, None]709            hits = misses = 0710            full = False711 712    wrapper.cache_info = cache_info713    wrapper.cache_clear = cache_clear714    return wrapper715 716try:717    from _functools import _lru_cache_wrapper718except ImportError:719    pass720 721 722################################################################################723### cache -- simplified access to the infinity cache724################################################################################725 726def cache(user_function, /):727    'Simple lightweight unbounded cache.  Sometimes called "memoize".'728    return lru_cache(maxsize=None)(user_function)729 730 731################################################################################732### singledispatch() - single-dispatch generic function decorator733################################################################################734 735def _c3_merge(sequences):736    """Merges MROs in *sequences* to a single MRO using the C3 algorithm.737 738    Adapted from https://docs.python.org/3/howto/mro.html.739 740    """741    result = []742    while True:743        sequences = [s for s in sequences if s]   # purge empty sequences744        if not sequences:745            return result746        for s1 in sequences:   # find merge candidates among seq heads747            candidate = s1[0]748            for s2 in sequences:749                if candidate in s2[1:]:750                    candidate = None751                    break      # reject the current head, it appears later752            else:753                break754        if candidate is None:755            raise RuntimeError("Inconsistent hierarchy")756        result.append(candidate)757        # remove the chosen candidate758        for seq in sequences:759            if seq[0] == candidate:760                del seq[0]761 762def _c3_mro(cls, abcs=None):763    """Computes the method resolution order using extended C3 linearization.764 765    If no *abcs* are given, the algorithm works exactly like the built-in C3766    linearization used for method resolution.767 768    If given, *abcs* is a list of abstract base classes that should be inserted769    into the resulting MRO. Unrelated ABCs are ignored and don't end up in the770    result. The algorithm inserts ABCs where their functionality is introduced,771    i.e. issubclass(cls, abc) returns True for the class itself but returns772    False for all its direct base classes. Implicit ABCs for a given class773    (either registered or inferred from the presence of a special method like774    __len__) are inserted directly after the last ABC explicitly listed in the775    MRO of said class. If two implicit ABCs end up next to each other in the776    resulting MRO, their ordering depends on the order of types in *abcs*.777 778    """779    for i, base in enumerate(reversed(cls.__bases__)):780        if hasattr(base, '__abstractmethods__'):781            boundary = len(cls.__bases__) - i782            break   # Bases up to the last explicit ABC are considered first.783    else:784        boundary = 0785    abcs = list(abcs) if abcs else []786    explicit_bases = list(cls.__bases__[:boundary])787    abstract_bases = []788    other_bases = list(cls.__bases__[boundary:])789    for base in abcs:790        if issubclass(cls, base) and not any(791                issubclass(b, base) for b in cls.__bases__792            ):793            # If *cls* is the class that introduces behaviour described by794            # an ABC *base*, insert said ABC to its MRO.795            abstract_bases.append(base)796    for base in abstract_bases:797        abcs.remove(base)798    explicit_c3_mros = [_c3_mro(base, abcs=abcs) for base in explicit_bases]799    abstract_c3_mros = [_c3_mro(base, abcs=abcs) for base in abstract_bases]800    other_c3_mros = [_c3_mro(base, abcs=abcs) for base in other_bases]801    return _c3_merge(802        [[cls]] +803        explicit_c3_mros + abstract_c3_mros + other_c3_mros +804        [explicit_bases] + [abstract_bases] + [other_bases]805    )806 807def _compose_mro(cls, types):808    """Calculates the method resolution order for a given class *cls*.809 810    Includes relevant abstract base classes (with their respective bases) from811    the *types* iterable. Uses a modified C3 linearization algorithm.812 813    """814    bases = set(cls.__mro__)815    # Remove entries which are already present in the __mro__ or unrelated.816    def is_related(typ):817        return (typ not in bases and hasattr(typ, '__mro__')818                                 and not isinstance(typ, GenericAlias)819                                 and issubclass(cls, typ))820    types = [n for n in types if is_related(n)]821    # Remove entries which are strict bases of other entries (they will end up822    # in the MRO anyway.823    def is_strict_base(typ):824        for other in types:825            if typ != other and typ in other.__mro__:826                return True827        return False828    types = [n for n in types if not is_strict_base(n)]829    # Subclasses of the ABCs in *types* which are also implemented by830    # *cls* can be used to stabilize ABC ordering.831    type_set = set(types)832    mro = []833    for typ in types:834        found = []835        for sub in typ.__subclasses__():836            if sub not in bases and issubclass(cls, sub):837                found.append([s for s in sub.__mro__ if s in type_set])838        if not found:839            mro.append(typ)840            continue841        # Favor subclasses with the biggest number of useful bases842        found.sort(key=len, reverse=True)843        for sub in found:844            for subcls in sub:845                if subcls not in mro:846                    mro.append(subcls)847    return _c3_mro(cls, abcs=mro)848 849def _find_impl(cls, registry):850    """Returns the best matching implementation from *registry* for type *cls*.851 852    Where there is no registered implementation for a specific type, its method853    resolution order is used to find a more generic implementation.854 855    Note: if *registry* does not contain an implementation for the base856    *object* type, this function may return None.857 858    """859    mro = _compose_mro(cls, registry.keys())860    match = None861    for t in mro:862        if match is not None:863            # If *match* is an implicit ABC but there is another unrelated,864            # equally matching implicit ABC, refuse the temptation to guess.865            if (t in registry and t not in cls.__mro__866                              and match not in cls.__mro__867                              and not issubclass(match, t)):868                raise RuntimeError("Ambiguous dispatch: {} or {}".format(869                    match, t))870            break871        if t in registry:872            match = t873    return registry.get(match)874 875def singledispatch(func):876    """Single-dispatch generic function decorator.877 878    Transforms a function into a generic function, which can have different879    behaviours depending upon the type of its first argument. The decorated880    function acts as the default implementation, and additional881    implementations can be registered using the register() attribute of the882    generic function.883    """884    # There are many programs that use functools without singledispatch, so we885    # trade-off making singledispatch marginally slower for the benefit of886    # making start-up of such applications slightly faster.887    import weakref888 889    registry = {}890    dispatch_cache = weakref.WeakKeyDictionary()891    cache_token = None892 893    def dispatch(cls):894        """generic_func.dispatch(cls) -> <function implementation>895 896        Runs the dispatch algorithm to return the best available implementation897        for the given *cls* registered on *generic_func*.898 899        """900        nonlocal cache_token901        if cache_token is not None:902            current_token = get_cache_token()903            if cache_token != current_token:904                dispatch_cache.clear()905                cache_token = current_token906        try:907            impl = dispatch_cache[cls]908        except KeyError:909            try:910                impl = registry[cls]911            except KeyError:912                impl = _find_impl(cls, registry)913            dispatch_cache[cls] = impl914        return impl915 916    def _is_valid_dispatch_type(cls):917        if isinstance(cls, type):918            return True919        return (isinstance(cls, UnionType) and920                all(isinstance(arg, type) for arg in cls.__args__))921 922    def register(cls, func=None):923        """generic_func.register(cls, func) -> func924 925        Registers a new implementation for the given *cls* on a *generic_func*.926 927        """928        nonlocal cache_token929        if _is_valid_dispatch_type(cls):930            if func is None:931                return lambda f: register(cls, f)932        else:933            if func is not None:934                raise TypeError(935                    f"Invalid first argument to `register()`. "936                    f"{cls!r} is not a class or union type."937                )938            ann = getattr(cls, '__annotate__', None)939            if ann is None:940                raise TypeError(941                    f"Invalid first argument to `register()`: {cls!r}. "942                    f"Use either `@register(some_class)` or plain `@register` "943                    f"on an annotated function."944                )945            func = cls946 947            # only import typing if annotation parsing is necessary948            from typing import get_type_hints949            from annotationlib import Format, ForwardRef950            argname, cls = next(iter(get_type_hints(func, format=Format.FORWARDREF).items()))951            if not _is_valid_dispatch_type(cls):952                if isinstance(cls, UnionType):953                    raise TypeError(954                        f"Invalid annotation for {argname!r}. "955                        f"{cls!r} not all arguments are classes."956                    )957                elif isinstance(cls, ForwardRef):958                    raise TypeError(959                        f"Invalid annotation for {argname!r}. "960                        f"{cls!r} is an unresolved forward reference."961                    )962                else:963                    raise TypeError(964                        f"Invalid annotation for {argname!r}. "965                        f"{cls!r} is not a class."966                    )967 968        if isinstance(cls, UnionType):969            for arg in cls.__args__:970                registry[arg] = func971        else:972            registry[cls] = func973        if cache_token is None and hasattr(cls, '__abstractmethods__'):974            cache_token = get_cache_token()975        dispatch_cache.clear()976        return func977 978    def wrapper(*args, **kw):979        if not args:980            raise TypeError(f'{funcname} requires at least '981                            '1 positional argument')982        return dispatch(args[0].__class__)(*args, **kw)983 984    funcname = getattr(func, '__name__', 'singledispatch function')985    registry[object] = func986    wrapper.register = register987    wrapper.dispatch = dispatch988    wrapper.registry = MappingProxyType(registry)989    wrapper._clear_cache = dispatch_cache.clear990    update_wrapper(wrapper, func)991    return wrapper992 993 994# Descriptor version995class singledispatchmethod:996    """Single-dispatch generic method descriptor.997 998    Supports wrapping existing descriptors.999    """1000 1001    def __init__(self, func):1002        if not callable(func) and not hasattr(func, "__get__"):1003            raise TypeError(f"{func!r} is not callable or a descriptor")1004 1005        self.dispatcher = singledispatch(func)1006        self.func = func1007 1008    def register(self, cls, method=None):1009        """generic_method.register(cls, func) -> func1010 1011        Registers a new implementation for the given *cls* on a *generic_method*.1012        """1013        return self.dispatcher.register(cls, func=method)1014 1015    def __get__(self, obj, cls=None):1016        return _singledispatchmethod_get(self, obj, cls)1017 1018    @property1019    def __isabstractmethod__(self):1020        return getattr(self.func, '__isabstractmethod__', False)1021 1022    def __repr__(self):1023        try:1024            name = self.func.__qualname__1025        except AttributeError:1026            try:1027                name = self.func.__name__1028            except AttributeError:1029                name = '?'1030        return f'<single dispatch method descriptor {name}>'1031 1032class _singledispatchmethod_get:1033    def __init__(self, unbound, obj, cls):1034        self._unbound = unbound1035        self._dispatch = unbound.dispatcher.dispatch1036        self._obj = obj1037        self._cls = cls1038        # Set instance attributes which cannot be handled in __getattr__()1039        # because they conflict with type descriptors.1040        func = unbound.func1041        try:1042            self.__module__ = func.__module__1043        except AttributeError:1044            pass1045        try:1046            self.__doc__ = func.__doc__1047        except AttributeError:1048            pass1049 1050    def __repr__(self):1051        try:1052            name = self.__qualname__1053        except AttributeError:1054            try:1055                name = self.__name__1056            except AttributeError:1057                name = '?'1058        if self._obj is not None:1059            return f'<bound single dispatch method {name} of {self._obj!r}>'1060        else:1061            return f'<single dispatch method {name}>'1062 1063    def __call__(self, /, *args, **kwargs):1064        if not args:1065            funcname = getattr(self._unbound.func, '__name__',1066                               'singledispatchmethod method')1067            raise TypeError(f'{funcname} requires at least '1068                            '1 positional argument')1069        return self._dispatch(args[0].__class__).__get__(self._obj, self._cls)(*args, **kwargs)1070 1071    def __getattr__(self, name):1072        # Resolve these attributes lazily to speed up creation of1073        # the _singledispatchmethod_get instance.1074        if name not in {'__name__', '__qualname__', '__isabstractmethod__',1075                        '__annotations__', '__type_params__'}:1076            raise AttributeError1077        return getattr(self._unbound.func, name)1078 1079    @property1080    def __wrapped__(self):1081        return self._unbound.func1082 1083    @property1084    def register(self):1085        return self._unbound.register1086 1087 1088################################################################################1089### cached_property() - property result cached as instance attribute1090################################################################################1091 1092_NOT_FOUND = object()1093 1094class cached_property:1095    def __init__(self, func):1096        self.func = func1097        self.attrname = None1098        self.__doc__ = func.__doc__1099        self.__module__ = func.__module__1100 1101    def __set_name__(self, owner, name):1102        if self.attrname is None:1103            self.attrname = name1104        elif name != self.attrname:1105            raise TypeError(1106                "Cannot assign the same cached_property to two different names "1107                f"({self.attrname!r} and {name!r})."1108            )1109 1110    def __get__(self, instance, owner=None):1111        if instance is None:1112            return self1113        if self.attrname is None:1114            raise TypeError(1115                "Cannot use cached_property instance without calling __set_name__ on it.")1116        try:1117            cache = instance.__dict__1118        except AttributeError:  # not all objects have __dict__ (e.g. class defines slots)1119            msg = (1120                f"No '__dict__' attribute on {type(instance).__name__!r} "1121                f"instance to cache {self.attrname!r} property."1122            )1123            raise TypeError(msg) from None1124        val = cache.get(self.attrname, _NOT_FOUND)1125        if val is _NOT_FOUND:1126            val = self.func(instance)1127            try:1128                cache[self.attrname] = val1129            except TypeError:1130                msg = (1131                    f"The '__dict__' attribute on {type(instance).__name__!r} instance "1132                    f"does not support item assignment for caching {self.attrname!r} property."1133                )1134                raise TypeError(msg) from None1135        return val1136 1137    __class_getitem__ = classmethod(GenericAlias)1138 1139def _warn_python_reduce_kwargs(py_reduce):1140    @wraps(py_reduce)1141    def wrapper(*args, **kwargs):1142        if 'function' in kwargs or 'sequence' in kwargs:1143            import os1144            import warnings1145            warnings.warn(1146                'Calling functools.reduce with keyword arguments '1147                '"function" or "sequence" '1148                'is deprecated in Python 3.14 and will be '1149                'forbidden in Python 3.16.',1150                DeprecationWarning,1151                skip_file_prefixes=(os.path.dirname(__file__),))1152        return py_reduce(*args, **kwargs)1153    return wrapper1154 1155reduce = _warn_python_reduce_kwargs(reduce)1156del _warn_python_reduce_kwargs1157 1158# The import of the C accelerated version of reduce() has been moved1159# here due to gh-121676. In Python 3.16, _warn_python_reduce_kwargs()1160# should be removed and the import block should be moved back right1161# after the definition of reduce().1162try:1163    from _functools import reduce1164except ImportError:1165    pass1166 
codekingpro/portable-devtools · Team Ai