1*cda5da8dSAndroid Build Coastguard Worker"""functools.py - Tools for working with functions and callable objects 2*cda5da8dSAndroid Build Coastguard Worker""" 3*cda5da8dSAndroid Build Coastguard Worker# Python module wrapper for _functools C module 4*cda5da8dSAndroid Build Coastguard Worker# to allow utilities written in Python to be added 5*cda5da8dSAndroid Build Coastguard Worker# to the functools module. 6*cda5da8dSAndroid Build Coastguard Worker# Written by Nick Coghlan <ncoghlan at gmail.com>, 7*cda5da8dSAndroid Build Coastguard Worker# Raymond Hettinger <python at rcn.com>, 8*cda5da8dSAndroid Build Coastguard Worker# and Łukasz Langa <lukasz at langa.pl>. 9*cda5da8dSAndroid Build Coastguard Worker# Copyright (C) 2006-2013 Python Software Foundation. 10*cda5da8dSAndroid Build Coastguard Worker# See C source code for _functools credits/copyright 11*cda5da8dSAndroid Build Coastguard Worker 12*cda5da8dSAndroid Build Coastguard Worker__all__ = ['update_wrapper', 'wraps', 'WRAPPER_ASSIGNMENTS', 'WRAPPER_UPDATES', 13*cda5da8dSAndroid Build Coastguard Worker 'total_ordering', 'cache', 'cmp_to_key', 'lru_cache', 'reduce', 14*cda5da8dSAndroid Build Coastguard Worker 'partial', 'partialmethod', 'singledispatch', 'singledispatchmethod', 15*cda5da8dSAndroid Build Coastguard Worker 'cached_property'] 16*cda5da8dSAndroid Build Coastguard Worker 17*cda5da8dSAndroid Build Coastguard Workerfrom abc import get_cache_token 18*cda5da8dSAndroid Build Coastguard Workerfrom collections import namedtuple 19*cda5da8dSAndroid Build Coastguard Worker# import types, weakref # Deferred to single_dispatch() 20*cda5da8dSAndroid Build Coastguard Workerfrom reprlib import recursive_repr 21*cda5da8dSAndroid Build Coastguard Workerfrom _thread import RLock 22*cda5da8dSAndroid Build Coastguard Workerfrom types import GenericAlias 23*cda5da8dSAndroid Build Coastguard Worker 24*cda5da8dSAndroid Build Coastguard Worker 25*cda5da8dSAndroid Build Coastguard Worker################################################################################ 26*cda5da8dSAndroid Build Coastguard Worker### update_wrapper() and wraps() decorator 27*cda5da8dSAndroid Build Coastguard Worker################################################################################ 28*cda5da8dSAndroid Build Coastguard Worker 29*cda5da8dSAndroid Build Coastguard Worker# update_wrapper() and wraps() are tools to help write 30*cda5da8dSAndroid Build Coastguard Worker# wrapper functions that can handle naive introspection 31*cda5da8dSAndroid Build Coastguard Worker 32*cda5da8dSAndroid Build Coastguard WorkerWRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__', 33*cda5da8dSAndroid Build Coastguard Worker '__annotations__') 34*cda5da8dSAndroid Build Coastguard WorkerWRAPPER_UPDATES = ('__dict__',) 35*cda5da8dSAndroid Build Coastguard Workerdef update_wrapper(wrapper, 36*cda5da8dSAndroid Build Coastguard Worker wrapped, 37*cda5da8dSAndroid Build Coastguard Worker assigned = WRAPPER_ASSIGNMENTS, 38*cda5da8dSAndroid Build Coastguard Worker updated = WRAPPER_UPDATES): 39*cda5da8dSAndroid Build Coastguard Worker """Update a wrapper function to look like the wrapped function 40*cda5da8dSAndroid Build Coastguard Worker 41*cda5da8dSAndroid Build Coastguard Worker wrapper is the function to be updated 42*cda5da8dSAndroid Build Coastguard Worker wrapped is the original function 43*cda5da8dSAndroid Build Coastguard Worker assigned is a tuple naming the attributes assigned directly 44*cda5da8dSAndroid Build Coastguard Worker from the wrapped function to the wrapper function (defaults to 45*cda5da8dSAndroid Build Coastguard Worker functools.WRAPPER_ASSIGNMENTS) 46*cda5da8dSAndroid Build Coastguard Worker updated is a tuple naming the attributes of the wrapper that 47*cda5da8dSAndroid Build Coastguard Worker are updated with the corresponding attribute from the wrapped 48*cda5da8dSAndroid Build Coastguard Worker function (defaults to functools.WRAPPER_UPDATES) 49*cda5da8dSAndroid Build Coastguard Worker """ 50*cda5da8dSAndroid Build Coastguard Worker for attr in assigned: 51*cda5da8dSAndroid Build Coastguard Worker try: 52*cda5da8dSAndroid Build Coastguard Worker value = getattr(wrapped, attr) 53*cda5da8dSAndroid Build Coastguard Worker except AttributeError: 54*cda5da8dSAndroid Build Coastguard Worker pass 55*cda5da8dSAndroid Build Coastguard Worker else: 56*cda5da8dSAndroid Build Coastguard Worker setattr(wrapper, attr, value) 57*cda5da8dSAndroid Build Coastguard Worker for attr in updated: 58*cda5da8dSAndroid Build Coastguard Worker getattr(wrapper, attr).update(getattr(wrapped, attr, {})) 59*cda5da8dSAndroid Build Coastguard Worker # Issue #17482: set __wrapped__ last so we don't inadvertently copy it 60*cda5da8dSAndroid Build Coastguard Worker # from the wrapped function when updating __dict__ 61*cda5da8dSAndroid Build Coastguard Worker wrapper.__wrapped__ = wrapped 62*cda5da8dSAndroid Build Coastguard Worker # Return the wrapper so this can be used as a decorator via partial() 63*cda5da8dSAndroid Build Coastguard Worker return wrapper 64*cda5da8dSAndroid Build Coastguard Worker 65*cda5da8dSAndroid Build Coastguard Workerdef wraps(wrapped, 66*cda5da8dSAndroid Build Coastguard Worker assigned = WRAPPER_ASSIGNMENTS, 67*cda5da8dSAndroid Build Coastguard Worker updated = WRAPPER_UPDATES): 68*cda5da8dSAndroid Build Coastguard Worker """Decorator factory to apply update_wrapper() to a wrapper function 69*cda5da8dSAndroid Build Coastguard Worker 70*cda5da8dSAndroid Build Coastguard Worker Returns a decorator that invokes update_wrapper() with the decorated 71*cda5da8dSAndroid Build Coastguard Worker function as the wrapper argument and the arguments to wraps() as the 72*cda5da8dSAndroid Build Coastguard Worker remaining arguments. Default arguments are as for update_wrapper(). 73*cda5da8dSAndroid Build Coastguard Worker This is a convenience function to simplify applying partial() to 74*cda5da8dSAndroid Build Coastguard Worker update_wrapper(). 75*cda5da8dSAndroid Build Coastguard Worker """ 76*cda5da8dSAndroid Build Coastguard Worker return partial(update_wrapper, wrapped=wrapped, 77*cda5da8dSAndroid Build Coastguard Worker assigned=assigned, updated=updated) 78*cda5da8dSAndroid Build Coastguard Worker 79*cda5da8dSAndroid Build Coastguard Worker 80*cda5da8dSAndroid Build Coastguard Worker################################################################################ 81*cda5da8dSAndroid Build Coastguard Worker### total_ordering class decorator 82*cda5da8dSAndroid Build Coastguard Worker################################################################################ 83*cda5da8dSAndroid Build Coastguard Worker 84*cda5da8dSAndroid Build Coastguard Worker# The total ordering functions all invoke the root magic method directly 85*cda5da8dSAndroid Build Coastguard Worker# rather than using the corresponding operator. This avoids possible 86*cda5da8dSAndroid Build Coastguard Worker# infinite recursion that could occur when the operator dispatch logic 87*cda5da8dSAndroid Build Coastguard Worker# detects a NotImplemented result and then calls a reflected method. 88*cda5da8dSAndroid Build Coastguard Worker 89*cda5da8dSAndroid Build Coastguard Workerdef _gt_from_lt(self, other): 90*cda5da8dSAndroid Build Coastguard Worker 'Return a > b. Computed by @total_ordering from (not a < b) and (a != b).' 91*cda5da8dSAndroid Build Coastguard Worker op_result = type(self).__lt__(self, other) 92*cda5da8dSAndroid Build Coastguard Worker if op_result is NotImplemented: 93*cda5da8dSAndroid Build Coastguard Worker return op_result 94*cda5da8dSAndroid Build Coastguard Worker return not op_result and self != other 95*cda5da8dSAndroid Build Coastguard Worker 96*cda5da8dSAndroid Build Coastguard Workerdef _le_from_lt(self, other): 97*cda5da8dSAndroid Build Coastguard Worker 'Return a <= b. Computed by @total_ordering from (a < b) or (a == b).' 98*cda5da8dSAndroid Build Coastguard Worker op_result = type(self).__lt__(self, other) 99*cda5da8dSAndroid Build Coastguard Worker if op_result is NotImplemented: 100*cda5da8dSAndroid Build Coastguard Worker return op_result 101*cda5da8dSAndroid Build Coastguard Worker return op_result or self == other 102*cda5da8dSAndroid Build Coastguard Worker 103*cda5da8dSAndroid Build Coastguard Workerdef _ge_from_lt(self, other): 104*cda5da8dSAndroid Build Coastguard Worker 'Return a >= b. Computed by @total_ordering from (not a < b).' 105*cda5da8dSAndroid Build Coastguard Worker op_result = type(self).__lt__(self, other) 106*cda5da8dSAndroid Build Coastguard Worker if op_result is NotImplemented: 107*cda5da8dSAndroid Build Coastguard Worker return op_result 108*cda5da8dSAndroid Build Coastguard Worker return not op_result 109*cda5da8dSAndroid Build Coastguard Worker 110*cda5da8dSAndroid Build Coastguard Workerdef _ge_from_le(self, other): 111*cda5da8dSAndroid Build Coastguard Worker 'Return a >= b. Computed by @total_ordering from (not a <= b) or (a == b).' 112*cda5da8dSAndroid Build Coastguard Worker op_result = type(self).__le__(self, other) 113*cda5da8dSAndroid Build Coastguard Worker if op_result is NotImplemented: 114*cda5da8dSAndroid Build Coastguard Worker return op_result 115*cda5da8dSAndroid Build Coastguard Worker return not op_result or self == other 116*cda5da8dSAndroid Build Coastguard Worker 117*cda5da8dSAndroid Build Coastguard Workerdef _lt_from_le(self, other): 118*cda5da8dSAndroid Build Coastguard Worker 'Return a < b. Computed by @total_ordering from (a <= b) and (a != b).' 119*cda5da8dSAndroid Build Coastguard Worker op_result = type(self).__le__(self, other) 120*cda5da8dSAndroid Build Coastguard Worker if op_result is NotImplemented: 121*cda5da8dSAndroid Build Coastguard Worker return op_result 122*cda5da8dSAndroid Build Coastguard Worker return op_result and self != other 123*cda5da8dSAndroid Build Coastguard Worker 124*cda5da8dSAndroid Build Coastguard Workerdef _gt_from_le(self, other): 125*cda5da8dSAndroid Build Coastguard Worker 'Return a > b. Computed by @total_ordering from (not a <= b).' 126*cda5da8dSAndroid Build Coastguard Worker op_result = type(self).__le__(self, other) 127*cda5da8dSAndroid Build Coastguard Worker if op_result is NotImplemented: 128*cda5da8dSAndroid Build Coastguard Worker return op_result 129*cda5da8dSAndroid Build Coastguard Worker return not op_result 130*cda5da8dSAndroid Build Coastguard Worker 131*cda5da8dSAndroid Build Coastguard Workerdef _lt_from_gt(self, other): 132*cda5da8dSAndroid Build Coastguard Worker 'Return a < b. Computed by @total_ordering from (not a > b) and (a != b).' 133*cda5da8dSAndroid Build Coastguard Worker op_result = type(self).__gt__(self, other) 134*cda5da8dSAndroid Build Coastguard Worker if op_result is NotImplemented: 135*cda5da8dSAndroid Build Coastguard Worker return op_result 136*cda5da8dSAndroid Build Coastguard Worker return not op_result and self != other 137*cda5da8dSAndroid Build Coastguard Worker 138*cda5da8dSAndroid Build Coastguard Workerdef _ge_from_gt(self, other): 139*cda5da8dSAndroid Build Coastguard Worker 'Return a >= b. Computed by @total_ordering from (a > b) or (a == b).' 140*cda5da8dSAndroid Build Coastguard Worker op_result = type(self).__gt__(self, other) 141*cda5da8dSAndroid Build Coastguard Worker if op_result is NotImplemented: 142*cda5da8dSAndroid Build Coastguard Worker return op_result 143*cda5da8dSAndroid Build Coastguard Worker return op_result or self == other 144*cda5da8dSAndroid Build Coastguard Worker 145*cda5da8dSAndroid Build Coastguard Workerdef _le_from_gt(self, other): 146*cda5da8dSAndroid Build Coastguard Worker 'Return a <= b. Computed by @total_ordering from (not a > b).' 147*cda5da8dSAndroid Build Coastguard Worker op_result = type(self).__gt__(self, other) 148*cda5da8dSAndroid Build Coastguard Worker if op_result is NotImplemented: 149*cda5da8dSAndroid Build Coastguard Worker return op_result 150*cda5da8dSAndroid Build Coastguard Worker return not op_result 151*cda5da8dSAndroid Build Coastguard Worker 152*cda5da8dSAndroid Build Coastguard Workerdef _le_from_ge(self, other): 153*cda5da8dSAndroid Build Coastguard Worker 'Return a <= b. Computed by @total_ordering from (not a >= b) or (a == b).' 154*cda5da8dSAndroid Build Coastguard Worker op_result = type(self).__ge__(self, other) 155*cda5da8dSAndroid Build Coastguard Worker if op_result is NotImplemented: 156*cda5da8dSAndroid Build Coastguard Worker return op_result 157*cda5da8dSAndroid Build Coastguard Worker return not op_result or self == other 158*cda5da8dSAndroid Build Coastguard Worker 159*cda5da8dSAndroid Build Coastguard Workerdef _gt_from_ge(self, other): 160*cda5da8dSAndroid Build Coastguard Worker 'Return a > b. Computed by @total_ordering from (a >= b) and (a != b).' 161*cda5da8dSAndroid Build Coastguard Worker op_result = type(self).__ge__(self, other) 162*cda5da8dSAndroid Build Coastguard Worker if op_result is NotImplemented: 163*cda5da8dSAndroid Build Coastguard Worker return op_result 164*cda5da8dSAndroid Build Coastguard Worker return op_result and self != other 165*cda5da8dSAndroid Build Coastguard Worker 166*cda5da8dSAndroid Build Coastguard Workerdef _lt_from_ge(self, other): 167*cda5da8dSAndroid Build Coastguard Worker 'Return a < b. Computed by @total_ordering from (not a >= b).' 168*cda5da8dSAndroid Build Coastguard Worker op_result = type(self).__ge__(self, other) 169*cda5da8dSAndroid Build Coastguard Worker if op_result is NotImplemented: 170*cda5da8dSAndroid Build Coastguard Worker return op_result 171*cda5da8dSAndroid Build Coastguard Worker return not op_result 172*cda5da8dSAndroid Build Coastguard Worker 173*cda5da8dSAndroid Build Coastguard Worker_convert = { 174*cda5da8dSAndroid Build Coastguard Worker '__lt__': [('__gt__', _gt_from_lt), 175*cda5da8dSAndroid Build Coastguard Worker ('__le__', _le_from_lt), 176*cda5da8dSAndroid Build Coastguard Worker ('__ge__', _ge_from_lt)], 177*cda5da8dSAndroid Build Coastguard Worker '__le__': [('__ge__', _ge_from_le), 178*cda5da8dSAndroid Build Coastguard Worker ('__lt__', _lt_from_le), 179*cda5da8dSAndroid Build Coastguard Worker ('__gt__', _gt_from_le)], 180*cda5da8dSAndroid Build Coastguard Worker '__gt__': [('__lt__', _lt_from_gt), 181*cda5da8dSAndroid Build Coastguard Worker ('__ge__', _ge_from_gt), 182*cda5da8dSAndroid Build Coastguard Worker ('__le__', _le_from_gt)], 183*cda5da8dSAndroid Build Coastguard Worker '__ge__': [('__le__', _le_from_ge), 184*cda5da8dSAndroid Build Coastguard Worker ('__gt__', _gt_from_ge), 185*cda5da8dSAndroid Build Coastguard Worker ('__lt__', _lt_from_ge)] 186*cda5da8dSAndroid Build Coastguard Worker} 187*cda5da8dSAndroid Build Coastguard Worker 188*cda5da8dSAndroid Build Coastguard Workerdef total_ordering(cls): 189*cda5da8dSAndroid Build Coastguard Worker """Class decorator that fills in missing ordering methods""" 190*cda5da8dSAndroid Build Coastguard Worker # Find user-defined comparisons (not those inherited from object). 191*cda5da8dSAndroid Build Coastguard Worker roots = {op for op in _convert if getattr(cls, op, None) is not getattr(object, op, None)} 192*cda5da8dSAndroid Build Coastguard Worker if not roots: 193*cda5da8dSAndroid Build Coastguard Worker raise ValueError('must define at least one ordering operation: < > <= >=') 194*cda5da8dSAndroid Build Coastguard Worker root = max(roots) # prefer __lt__ to __le__ to __gt__ to __ge__ 195*cda5da8dSAndroid Build Coastguard Worker for opname, opfunc in _convert[root]: 196*cda5da8dSAndroid Build Coastguard Worker if opname not in roots: 197*cda5da8dSAndroid Build Coastguard Worker opfunc.__name__ = opname 198*cda5da8dSAndroid Build Coastguard Worker setattr(cls, opname, opfunc) 199*cda5da8dSAndroid Build Coastguard Worker return cls 200*cda5da8dSAndroid Build Coastguard Worker 201*cda5da8dSAndroid Build Coastguard Worker 202*cda5da8dSAndroid Build Coastguard Worker################################################################################ 203*cda5da8dSAndroid Build Coastguard Worker### cmp_to_key() function converter 204*cda5da8dSAndroid Build Coastguard Worker################################################################################ 205*cda5da8dSAndroid Build Coastguard Worker 206*cda5da8dSAndroid Build Coastguard Workerdef cmp_to_key(mycmp): 207*cda5da8dSAndroid Build Coastguard Worker """Convert a cmp= function into a key= function""" 208*cda5da8dSAndroid Build Coastguard Worker class K(object): 209*cda5da8dSAndroid Build Coastguard Worker __slots__ = ['obj'] 210*cda5da8dSAndroid Build Coastguard Worker def __init__(self, obj): 211*cda5da8dSAndroid Build Coastguard Worker self.obj = obj 212*cda5da8dSAndroid Build Coastguard Worker def __lt__(self, other): 213*cda5da8dSAndroid Build Coastguard Worker return mycmp(self.obj, other.obj) < 0 214*cda5da8dSAndroid Build Coastguard Worker def __gt__(self, other): 215*cda5da8dSAndroid Build Coastguard Worker return mycmp(self.obj, other.obj) > 0 216*cda5da8dSAndroid Build Coastguard Worker def __eq__(self, other): 217*cda5da8dSAndroid Build Coastguard Worker return mycmp(self.obj, other.obj) == 0 218*cda5da8dSAndroid Build Coastguard Worker def __le__(self, other): 219*cda5da8dSAndroid Build Coastguard Worker return mycmp(self.obj, other.obj) <= 0 220*cda5da8dSAndroid Build Coastguard Worker def __ge__(self, other): 221*cda5da8dSAndroid Build Coastguard Worker return mycmp(self.obj, other.obj) >= 0 222*cda5da8dSAndroid Build Coastguard Worker __hash__ = None 223*cda5da8dSAndroid Build Coastguard Worker return K 224*cda5da8dSAndroid Build Coastguard Worker 225*cda5da8dSAndroid Build Coastguard Workertry: 226*cda5da8dSAndroid Build Coastguard Worker from _functools import cmp_to_key 227*cda5da8dSAndroid Build Coastguard Workerexcept ImportError: 228*cda5da8dSAndroid Build Coastguard Worker pass 229*cda5da8dSAndroid Build Coastguard Worker 230*cda5da8dSAndroid Build Coastguard Worker 231*cda5da8dSAndroid Build Coastguard Worker################################################################################ 232*cda5da8dSAndroid Build Coastguard Worker### reduce() sequence to a single item 233*cda5da8dSAndroid Build Coastguard Worker################################################################################ 234*cda5da8dSAndroid Build Coastguard Worker 235*cda5da8dSAndroid Build Coastguard Worker_initial_missing = object() 236*cda5da8dSAndroid Build Coastguard Worker 237*cda5da8dSAndroid Build Coastguard Workerdef reduce(function, sequence, initial=_initial_missing): 238*cda5da8dSAndroid Build Coastguard Worker """ 239*cda5da8dSAndroid Build Coastguard Worker reduce(function, iterable[, initial]) -> value 240*cda5da8dSAndroid Build Coastguard Worker 241*cda5da8dSAndroid Build Coastguard Worker Apply a function of two arguments cumulatively to the items of a sequence 242*cda5da8dSAndroid Build Coastguard Worker or iterable, from left to right, so as to reduce the iterable to a single 243*cda5da8dSAndroid Build Coastguard Worker value. For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates 244*cda5da8dSAndroid Build Coastguard Worker ((((1+2)+3)+4)+5). If initial is present, it is placed before the items 245*cda5da8dSAndroid Build Coastguard Worker of the iterable in the calculation, and serves as a default when the 246*cda5da8dSAndroid Build Coastguard Worker iterable is empty. 247*cda5da8dSAndroid Build Coastguard Worker """ 248*cda5da8dSAndroid Build Coastguard Worker 249*cda5da8dSAndroid Build Coastguard Worker it = iter(sequence) 250*cda5da8dSAndroid Build Coastguard Worker 251*cda5da8dSAndroid Build Coastguard Worker if initial is _initial_missing: 252*cda5da8dSAndroid Build Coastguard Worker try: 253*cda5da8dSAndroid Build Coastguard Worker value = next(it) 254*cda5da8dSAndroid Build Coastguard Worker except StopIteration: 255*cda5da8dSAndroid Build Coastguard Worker raise TypeError( 256*cda5da8dSAndroid Build Coastguard Worker "reduce() of empty iterable with no initial value") from None 257*cda5da8dSAndroid Build Coastguard Worker else: 258*cda5da8dSAndroid Build Coastguard Worker value = initial 259*cda5da8dSAndroid Build Coastguard Worker 260*cda5da8dSAndroid Build Coastguard Worker for element in it: 261*cda5da8dSAndroid Build Coastguard Worker value = function(value, element) 262*cda5da8dSAndroid Build Coastguard Worker 263*cda5da8dSAndroid Build Coastguard Worker return value 264*cda5da8dSAndroid Build Coastguard Worker 265*cda5da8dSAndroid Build Coastguard Workertry: 266*cda5da8dSAndroid Build Coastguard Worker from _functools import reduce 267*cda5da8dSAndroid Build Coastguard Workerexcept ImportError: 268*cda5da8dSAndroid Build Coastguard Worker pass 269*cda5da8dSAndroid Build Coastguard Worker 270*cda5da8dSAndroid Build Coastguard Worker 271*cda5da8dSAndroid Build Coastguard Worker################################################################################ 272*cda5da8dSAndroid Build Coastguard Worker### partial() argument application 273*cda5da8dSAndroid Build Coastguard Worker################################################################################ 274*cda5da8dSAndroid Build Coastguard Worker 275*cda5da8dSAndroid Build Coastguard Worker# Purely functional, no descriptor behaviour 276*cda5da8dSAndroid Build Coastguard Workerclass partial: 277*cda5da8dSAndroid Build Coastguard Worker """New function with partial application of the given arguments 278*cda5da8dSAndroid Build Coastguard Worker and keywords. 279*cda5da8dSAndroid Build Coastguard Worker """ 280*cda5da8dSAndroid Build Coastguard Worker 281*cda5da8dSAndroid Build Coastguard Worker __slots__ = "func", "args", "keywords", "__dict__", "__weakref__" 282*cda5da8dSAndroid Build Coastguard Worker 283*cda5da8dSAndroid Build Coastguard Worker def __new__(cls, func, /, *args, **keywords): 284*cda5da8dSAndroid Build Coastguard Worker if not callable(func): 285*cda5da8dSAndroid Build Coastguard Worker raise TypeError("the first argument must be callable") 286*cda5da8dSAndroid Build Coastguard Worker 287*cda5da8dSAndroid Build Coastguard Worker if hasattr(func, "func"): 288*cda5da8dSAndroid Build Coastguard Worker args = func.args + args 289*cda5da8dSAndroid Build Coastguard Worker keywords = {**func.keywords, **keywords} 290*cda5da8dSAndroid Build Coastguard Worker func = func.func 291*cda5da8dSAndroid Build Coastguard Worker 292*cda5da8dSAndroid Build Coastguard Worker self = super(partial, cls).__new__(cls) 293*cda5da8dSAndroid Build Coastguard Worker 294*cda5da8dSAndroid Build Coastguard Worker self.func = func 295*cda5da8dSAndroid Build Coastguard Worker self.args = args 296*cda5da8dSAndroid Build Coastguard Worker self.keywords = keywords 297*cda5da8dSAndroid Build Coastguard Worker return self 298*cda5da8dSAndroid Build Coastguard Worker 299*cda5da8dSAndroid Build Coastguard Worker def __call__(self, /, *args, **keywords): 300*cda5da8dSAndroid Build Coastguard Worker keywords = {**self.keywords, **keywords} 301*cda5da8dSAndroid Build Coastguard Worker return self.func(*self.args, *args, **keywords) 302*cda5da8dSAndroid Build Coastguard Worker 303*cda5da8dSAndroid Build Coastguard Worker @recursive_repr() 304*cda5da8dSAndroid Build Coastguard Worker def __repr__(self): 305*cda5da8dSAndroid Build Coastguard Worker qualname = type(self).__qualname__ 306*cda5da8dSAndroid Build Coastguard Worker args = [repr(self.func)] 307*cda5da8dSAndroid Build Coastguard Worker args.extend(repr(x) for x in self.args) 308*cda5da8dSAndroid Build Coastguard Worker args.extend(f"{k}={v!r}" for (k, v) in self.keywords.items()) 309*cda5da8dSAndroid Build Coastguard Worker if type(self).__module__ == "functools": 310*cda5da8dSAndroid Build Coastguard Worker return f"functools.{qualname}({', '.join(args)})" 311*cda5da8dSAndroid Build Coastguard Worker return f"{qualname}({', '.join(args)})" 312*cda5da8dSAndroid Build Coastguard Worker 313*cda5da8dSAndroid Build Coastguard Worker def __reduce__(self): 314*cda5da8dSAndroid Build Coastguard Worker return type(self), (self.func,), (self.func, self.args, 315*cda5da8dSAndroid Build Coastguard Worker self.keywords or None, self.__dict__ or None) 316*cda5da8dSAndroid Build Coastguard Worker 317*cda5da8dSAndroid Build Coastguard Worker def __setstate__(self, state): 318*cda5da8dSAndroid Build Coastguard Worker if not isinstance(state, tuple): 319*cda5da8dSAndroid Build Coastguard Worker raise TypeError("argument to __setstate__ must be a tuple") 320*cda5da8dSAndroid Build Coastguard Worker if len(state) != 4: 321*cda5da8dSAndroid Build Coastguard Worker raise TypeError(f"expected 4 items in state, got {len(state)}") 322*cda5da8dSAndroid Build Coastguard Worker func, args, kwds, namespace = state 323*cda5da8dSAndroid Build Coastguard Worker if (not callable(func) or not isinstance(args, tuple) or 324*cda5da8dSAndroid Build Coastguard Worker (kwds is not None and not isinstance(kwds, dict)) or 325*cda5da8dSAndroid Build Coastguard Worker (namespace is not None and not isinstance(namespace, dict))): 326*cda5da8dSAndroid Build Coastguard Worker raise TypeError("invalid partial state") 327*cda5da8dSAndroid Build Coastguard Worker 328*cda5da8dSAndroid Build Coastguard Worker args = tuple(args) # just in case it's a subclass 329*cda5da8dSAndroid Build Coastguard Worker if kwds is None: 330*cda5da8dSAndroid Build Coastguard Worker kwds = {} 331*cda5da8dSAndroid Build Coastguard Worker elif type(kwds) is not dict: # XXX does it need to be *exactly* dict? 332*cda5da8dSAndroid Build Coastguard Worker kwds = dict(kwds) 333*cda5da8dSAndroid Build Coastguard Worker if namespace is None: 334*cda5da8dSAndroid Build Coastguard Worker namespace = {} 335*cda5da8dSAndroid Build Coastguard Worker 336*cda5da8dSAndroid Build Coastguard Worker self.__dict__ = namespace 337*cda5da8dSAndroid Build Coastguard Worker self.func = func 338*cda5da8dSAndroid Build Coastguard Worker self.args = args 339*cda5da8dSAndroid Build Coastguard Worker self.keywords = kwds 340*cda5da8dSAndroid Build Coastguard Worker 341*cda5da8dSAndroid Build Coastguard Workertry: 342*cda5da8dSAndroid Build Coastguard Worker from _functools import partial 343*cda5da8dSAndroid Build Coastguard Workerexcept ImportError: 344*cda5da8dSAndroid Build Coastguard Worker pass 345*cda5da8dSAndroid Build Coastguard Worker 346*cda5da8dSAndroid Build Coastguard Worker# Descriptor version 347*cda5da8dSAndroid Build Coastguard Workerclass partialmethod(object): 348*cda5da8dSAndroid Build Coastguard Worker """Method descriptor with partial application of the given arguments 349*cda5da8dSAndroid Build Coastguard Worker and keywords. 350*cda5da8dSAndroid Build Coastguard Worker 351*cda5da8dSAndroid Build Coastguard Worker Supports wrapping existing descriptors and handles non-descriptor 352*cda5da8dSAndroid Build Coastguard Worker callables as instance methods. 353*cda5da8dSAndroid Build Coastguard Worker """ 354*cda5da8dSAndroid Build Coastguard Worker 355*cda5da8dSAndroid Build Coastguard Worker def __init__(self, func, /, *args, **keywords): 356*cda5da8dSAndroid Build Coastguard Worker if not callable(func) and not hasattr(func, "__get__"): 357*cda5da8dSAndroid Build Coastguard Worker raise TypeError("{!r} is not callable or a descriptor" 358*cda5da8dSAndroid Build Coastguard Worker .format(func)) 359*cda5da8dSAndroid Build Coastguard Worker 360*cda5da8dSAndroid Build Coastguard Worker # func could be a descriptor like classmethod which isn't callable, 361*cda5da8dSAndroid Build Coastguard Worker # so we can't inherit from partial (it verifies func is callable) 362*cda5da8dSAndroid Build Coastguard Worker if isinstance(func, partialmethod): 363*cda5da8dSAndroid Build Coastguard Worker # flattening is mandatory in order to place cls/self before all 364*cda5da8dSAndroid Build Coastguard Worker # other arguments 365*cda5da8dSAndroid Build Coastguard Worker # it's also more efficient since only one function will be called 366*cda5da8dSAndroid Build Coastguard Worker self.func = func.func 367*cda5da8dSAndroid Build Coastguard Worker self.args = func.args + args 368*cda5da8dSAndroid Build Coastguard Worker self.keywords = {**func.keywords, **keywords} 369*cda5da8dSAndroid Build Coastguard Worker else: 370*cda5da8dSAndroid Build Coastguard Worker self.func = func 371*cda5da8dSAndroid Build Coastguard Worker self.args = args 372*cda5da8dSAndroid Build Coastguard Worker self.keywords = keywords 373*cda5da8dSAndroid Build Coastguard Worker 374*cda5da8dSAndroid Build Coastguard Worker def __repr__(self): 375*cda5da8dSAndroid Build Coastguard Worker args = ", ".join(map(repr, self.args)) 376*cda5da8dSAndroid Build Coastguard Worker keywords = ", ".join("{}={!r}".format(k, v) 377*cda5da8dSAndroid Build Coastguard Worker for k, v in self.keywords.items()) 378*cda5da8dSAndroid Build Coastguard Worker format_string = "{module}.{cls}({func}, {args}, {keywords})" 379*cda5da8dSAndroid Build Coastguard Worker return format_string.format(module=self.__class__.__module__, 380*cda5da8dSAndroid Build Coastguard Worker cls=self.__class__.__qualname__, 381*cda5da8dSAndroid Build Coastguard Worker func=self.func, 382*cda5da8dSAndroid Build Coastguard Worker args=args, 383*cda5da8dSAndroid Build Coastguard Worker keywords=keywords) 384*cda5da8dSAndroid Build Coastguard Worker 385*cda5da8dSAndroid Build Coastguard Worker def _make_unbound_method(self): 386*cda5da8dSAndroid Build Coastguard Worker def _method(cls_or_self, /, *args, **keywords): 387*cda5da8dSAndroid Build Coastguard Worker keywords = {**self.keywords, **keywords} 388*cda5da8dSAndroid Build Coastguard Worker return self.func(cls_or_self, *self.args, *args, **keywords) 389*cda5da8dSAndroid Build Coastguard Worker _method.__isabstractmethod__ = self.__isabstractmethod__ 390*cda5da8dSAndroid Build Coastguard Worker _method._partialmethod = self 391*cda5da8dSAndroid Build Coastguard Worker return _method 392*cda5da8dSAndroid Build Coastguard Worker 393*cda5da8dSAndroid Build Coastguard Worker def __get__(self, obj, cls=None): 394*cda5da8dSAndroid Build Coastguard Worker get = getattr(self.func, "__get__", None) 395*cda5da8dSAndroid Build Coastguard Worker result = None 396*cda5da8dSAndroid Build Coastguard Worker if get is not None: 397*cda5da8dSAndroid Build Coastguard Worker new_func = get(obj, cls) 398*cda5da8dSAndroid Build Coastguard Worker if new_func is not self.func: 399*cda5da8dSAndroid Build Coastguard Worker # Assume __get__ returning something new indicates the 400*cda5da8dSAndroid Build Coastguard Worker # creation of an appropriate callable 401*cda5da8dSAndroid Build Coastguard Worker result = partial(new_func, *self.args, **self.keywords) 402*cda5da8dSAndroid Build Coastguard Worker try: 403*cda5da8dSAndroid Build Coastguard Worker result.__self__ = new_func.__self__ 404*cda5da8dSAndroid Build Coastguard Worker except AttributeError: 405*cda5da8dSAndroid Build Coastguard Worker pass 406*cda5da8dSAndroid Build Coastguard Worker if result is None: 407*cda5da8dSAndroid Build Coastguard Worker # If the underlying descriptor didn't do anything, treat this 408*cda5da8dSAndroid Build Coastguard Worker # like an instance method 409*cda5da8dSAndroid Build Coastguard Worker result = self._make_unbound_method().__get__(obj, cls) 410*cda5da8dSAndroid Build Coastguard Worker return result 411*cda5da8dSAndroid Build Coastguard Worker 412*cda5da8dSAndroid Build Coastguard Worker @property 413*cda5da8dSAndroid Build Coastguard Worker def __isabstractmethod__(self): 414*cda5da8dSAndroid Build Coastguard Worker return getattr(self.func, "__isabstractmethod__", False) 415*cda5da8dSAndroid Build Coastguard Worker 416*cda5da8dSAndroid Build Coastguard Worker __class_getitem__ = classmethod(GenericAlias) 417*cda5da8dSAndroid Build Coastguard Worker 418*cda5da8dSAndroid Build Coastguard Worker 419*cda5da8dSAndroid Build Coastguard Worker# Helper functions 420*cda5da8dSAndroid Build Coastguard Worker 421*cda5da8dSAndroid Build Coastguard Workerdef _unwrap_partial(func): 422*cda5da8dSAndroid Build Coastguard Worker while isinstance(func, partial): 423*cda5da8dSAndroid Build Coastguard Worker func = func.func 424*cda5da8dSAndroid Build Coastguard Worker return func 425*cda5da8dSAndroid Build Coastguard Worker 426*cda5da8dSAndroid Build Coastguard Worker################################################################################ 427*cda5da8dSAndroid Build Coastguard Worker### LRU Cache function decorator 428*cda5da8dSAndroid Build Coastguard Worker################################################################################ 429*cda5da8dSAndroid Build Coastguard Worker 430*cda5da8dSAndroid Build Coastguard Worker_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"]) 431*cda5da8dSAndroid Build Coastguard Worker 432*cda5da8dSAndroid Build Coastguard Workerclass _HashedSeq(list): 433*cda5da8dSAndroid Build Coastguard Worker """ This class guarantees that hash() will be called no more than once 434*cda5da8dSAndroid Build Coastguard Worker per element. This is important because the lru_cache() will hash 435*cda5da8dSAndroid Build Coastguard Worker the key multiple times on a cache miss. 436*cda5da8dSAndroid Build Coastguard Worker 437*cda5da8dSAndroid Build Coastguard Worker """ 438*cda5da8dSAndroid Build Coastguard Worker 439*cda5da8dSAndroid Build Coastguard Worker __slots__ = 'hashvalue' 440*cda5da8dSAndroid Build Coastguard Worker 441*cda5da8dSAndroid Build Coastguard Worker def __init__(self, tup, hash=hash): 442*cda5da8dSAndroid Build Coastguard Worker self[:] = tup 443*cda5da8dSAndroid Build Coastguard Worker self.hashvalue = hash(tup) 444*cda5da8dSAndroid Build Coastguard Worker 445*cda5da8dSAndroid Build Coastguard Worker def __hash__(self): 446*cda5da8dSAndroid Build Coastguard Worker return self.hashvalue 447*cda5da8dSAndroid Build Coastguard Worker 448*cda5da8dSAndroid Build Coastguard Workerdef _make_key(args, kwds, typed, 449*cda5da8dSAndroid Build Coastguard Worker kwd_mark = (object(),), 450*cda5da8dSAndroid Build Coastguard Worker fasttypes = {int, str}, 451*cda5da8dSAndroid Build Coastguard Worker tuple=tuple, type=type, len=len): 452*cda5da8dSAndroid Build Coastguard Worker """Make a cache key from optionally typed positional and keyword arguments 453*cda5da8dSAndroid Build Coastguard Worker 454*cda5da8dSAndroid Build Coastguard Worker The key is constructed in a way that is flat as possible rather than 455*cda5da8dSAndroid Build Coastguard Worker as a nested structure that would take more memory. 456*cda5da8dSAndroid Build Coastguard Worker 457*cda5da8dSAndroid Build Coastguard Worker If there is only a single argument and its data type is known to cache 458*cda5da8dSAndroid Build Coastguard Worker its hash value, then that argument is returned without a wrapper. This 459*cda5da8dSAndroid Build Coastguard Worker saves space and improves lookup speed. 460*cda5da8dSAndroid Build Coastguard Worker 461*cda5da8dSAndroid Build Coastguard Worker """ 462*cda5da8dSAndroid Build Coastguard Worker # All of code below relies on kwds preserving the order input by the user. 463*cda5da8dSAndroid Build Coastguard Worker # Formerly, we sorted() the kwds before looping. The new way is *much* 464*cda5da8dSAndroid Build Coastguard Worker # faster; however, it means that f(x=1, y=2) will now be treated as a 465*cda5da8dSAndroid Build Coastguard Worker # distinct call from f(y=2, x=1) which will be cached separately. 466*cda5da8dSAndroid Build Coastguard Worker key = args 467*cda5da8dSAndroid Build Coastguard Worker if kwds: 468*cda5da8dSAndroid Build Coastguard Worker key += kwd_mark 469*cda5da8dSAndroid Build Coastguard Worker for item in kwds.items(): 470*cda5da8dSAndroid Build Coastguard Worker key += item 471*cda5da8dSAndroid Build Coastguard Worker if typed: 472*cda5da8dSAndroid Build Coastguard Worker key += tuple(type(v) for v in args) 473*cda5da8dSAndroid Build Coastguard Worker if kwds: 474*cda5da8dSAndroid Build Coastguard Worker key += tuple(type(v) for v in kwds.values()) 475*cda5da8dSAndroid Build Coastguard Worker elif len(key) == 1 and type(key[0]) in fasttypes: 476*cda5da8dSAndroid Build Coastguard Worker return key[0] 477*cda5da8dSAndroid Build Coastguard Worker return _HashedSeq(key) 478*cda5da8dSAndroid Build Coastguard Worker 479*cda5da8dSAndroid Build Coastguard Workerdef lru_cache(maxsize=128, typed=False): 480*cda5da8dSAndroid Build Coastguard Worker """Least-recently-used cache decorator. 481*cda5da8dSAndroid Build Coastguard Worker 482*cda5da8dSAndroid Build Coastguard Worker If *maxsize* is set to None, the LRU features are disabled and the cache 483*cda5da8dSAndroid Build Coastguard Worker can grow without bound. 484*cda5da8dSAndroid Build Coastguard Worker 485*cda5da8dSAndroid Build Coastguard Worker If *typed* is True, arguments of different types will be cached separately. 486*cda5da8dSAndroid Build Coastguard Worker For example, f(3.0) and f(3) will be treated as distinct calls with 487*cda5da8dSAndroid Build Coastguard Worker distinct results. 488*cda5da8dSAndroid Build Coastguard Worker 489*cda5da8dSAndroid Build Coastguard Worker Arguments to the cached function must be hashable. 490*cda5da8dSAndroid Build Coastguard Worker 491*cda5da8dSAndroid Build Coastguard Worker View the cache statistics named tuple (hits, misses, maxsize, currsize) 492*cda5da8dSAndroid Build Coastguard Worker with f.cache_info(). Clear the cache and statistics with f.cache_clear(). 493*cda5da8dSAndroid Build Coastguard Worker Access the underlying function with f.__wrapped__. 494*cda5da8dSAndroid Build Coastguard Worker 495*cda5da8dSAndroid Build Coastguard Worker See: https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU) 496*cda5da8dSAndroid Build Coastguard Worker 497*cda5da8dSAndroid Build Coastguard Worker """ 498*cda5da8dSAndroid Build Coastguard Worker 499*cda5da8dSAndroid Build Coastguard Worker # Users should only access the lru_cache through its public API: 500*cda5da8dSAndroid Build Coastguard Worker # cache_info, cache_clear, and f.__wrapped__ 501*cda5da8dSAndroid Build Coastguard Worker # The internals of the lru_cache are encapsulated for thread safety and 502*cda5da8dSAndroid Build Coastguard Worker # to allow the implementation to change (including a possible C version). 503*cda5da8dSAndroid Build Coastguard Worker 504*cda5da8dSAndroid Build Coastguard Worker if isinstance(maxsize, int): 505*cda5da8dSAndroid Build Coastguard Worker # Negative maxsize is treated as 0 506*cda5da8dSAndroid Build Coastguard Worker if maxsize < 0: 507*cda5da8dSAndroid Build Coastguard Worker maxsize = 0 508*cda5da8dSAndroid Build Coastguard Worker elif callable(maxsize) and isinstance(typed, bool): 509*cda5da8dSAndroid Build Coastguard Worker # The user_function was passed in directly via the maxsize argument 510*cda5da8dSAndroid Build Coastguard Worker user_function, maxsize = maxsize, 128 511*cda5da8dSAndroid Build Coastguard Worker wrapper = _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo) 512*cda5da8dSAndroid Build Coastguard Worker wrapper.cache_parameters = lambda : {'maxsize': maxsize, 'typed': typed} 513*cda5da8dSAndroid Build Coastguard Worker return update_wrapper(wrapper, user_function) 514*cda5da8dSAndroid Build Coastguard Worker elif maxsize is not None: 515*cda5da8dSAndroid Build Coastguard Worker raise TypeError( 516*cda5da8dSAndroid Build Coastguard Worker 'Expected first argument to be an integer, a callable, or None') 517*cda5da8dSAndroid Build Coastguard Worker 518*cda5da8dSAndroid Build Coastguard Worker def decorating_function(user_function): 519*cda5da8dSAndroid Build Coastguard Worker wrapper = _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo) 520*cda5da8dSAndroid Build Coastguard Worker wrapper.cache_parameters = lambda : {'maxsize': maxsize, 'typed': typed} 521*cda5da8dSAndroid Build Coastguard Worker return update_wrapper(wrapper, user_function) 522*cda5da8dSAndroid Build Coastguard Worker 523*cda5da8dSAndroid Build Coastguard Worker return decorating_function 524*cda5da8dSAndroid Build Coastguard Worker 525*cda5da8dSAndroid Build Coastguard Workerdef _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo): 526*cda5da8dSAndroid Build Coastguard Worker # Constants shared by all lru cache instances: 527*cda5da8dSAndroid Build Coastguard Worker sentinel = object() # unique object used to signal cache misses 528*cda5da8dSAndroid Build Coastguard Worker make_key = _make_key # build a key from the function arguments 529*cda5da8dSAndroid Build Coastguard Worker PREV, NEXT, KEY, RESULT = 0, 1, 2, 3 # names for the link fields 530*cda5da8dSAndroid Build Coastguard Worker 531*cda5da8dSAndroid Build Coastguard Worker cache = {} 532*cda5da8dSAndroid Build Coastguard Worker hits = misses = 0 533*cda5da8dSAndroid Build Coastguard Worker full = False 534*cda5da8dSAndroid Build Coastguard Worker cache_get = cache.get # bound method to lookup a key or return None 535*cda5da8dSAndroid Build Coastguard Worker cache_len = cache.__len__ # get cache size without calling len() 536*cda5da8dSAndroid Build Coastguard Worker lock = RLock() # because linkedlist updates aren't threadsafe 537*cda5da8dSAndroid Build Coastguard Worker root = [] # root of the circular doubly linked list 538*cda5da8dSAndroid Build Coastguard Worker root[:] = [root, root, None, None] # initialize by pointing to self 539*cda5da8dSAndroid Build Coastguard Worker 540*cda5da8dSAndroid Build Coastguard Worker if maxsize == 0: 541*cda5da8dSAndroid Build Coastguard Worker 542*cda5da8dSAndroid Build Coastguard Worker def wrapper(*args, **kwds): 543*cda5da8dSAndroid Build Coastguard Worker # No caching -- just a statistics update 544*cda5da8dSAndroid Build Coastguard Worker nonlocal misses 545*cda5da8dSAndroid Build Coastguard Worker misses += 1 546*cda5da8dSAndroid Build Coastguard Worker result = user_function(*args, **kwds) 547*cda5da8dSAndroid Build Coastguard Worker return result 548*cda5da8dSAndroid Build Coastguard Worker 549*cda5da8dSAndroid Build Coastguard Worker elif maxsize is None: 550*cda5da8dSAndroid Build Coastguard Worker 551*cda5da8dSAndroid Build Coastguard Worker def wrapper(*args, **kwds): 552*cda5da8dSAndroid Build Coastguard Worker # Simple caching without ordering or size limit 553*cda5da8dSAndroid Build Coastguard Worker nonlocal hits, misses 554*cda5da8dSAndroid Build Coastguard Worker key = make_key(args, kwds, typed) 555*cda5da8dSAndroid Build Coastguard Worker result = cache_get(key, sentinel) 556*cda5da8dSAndroid Build Coastguard Worker if result is not sentinel: 557*cda5da8dSAndroid Build Coastguard Worker hits += 1 558*cda5da8dSAndroid Build Coastguard Worker return result 559*cda5da8dSAndroid Build Coastguard Worker misses += 1 560*cda5da8dSAndroid Build Coastguard Worker result = user_function(*args, **kwds) 561*cda5da8dSAndroid Build Coastguard Worker cache[key] = result 562*cda5da8dSAndroid Build Coastguard Worker return result 563*cda5da8dSAndroid Build Coastguard Worker 564*cda5da8dSAndroid Build Coastguard Worker else: 565*cda5da8dSAndroid Build Coastguard Worker 566*cda5da8dSAndroid Build Coastguard Worker def wrapper(*args, **kwds): 567*cda5da8dSAndroid Build Coastguard Worker # Size limited caching that tracks accesses by recency 568*cda5da8dSAndroid Build Coastguard Worker nonlocal root, hits, misses, full 569*cda5da8dSAndroid Build Coastguard Worker key = make_key(args, kwds, typed) 570*cda5da8dSAndroid Build Coastguard Worker with lock: 571*cda5da8dSAndroid Build Coastguard Worker link = cache_get(key) 572*cda5da8dSAndroid Build Coastguard Worker if link is not None: 573*cda5da8dSAndroid Build Coastguard Worker # Move the link to the front of the circular queue 574*cda5da8dSAndroid Build Coastguard Worker link_prev, link_next, _key, result = link 575*cda5da8dSAndroid Build Coastguard Worker link_prev[NEXT] = link_next 576*cda5da8dSAndroid Build Coastguard Worker link_next[PREV] = link_prev 577*cda5da8dSAndroid Build Coastguard Worker last = root[PREV] 578*cda5da8dSAndroid Build Coastguard Worker last[NEXT] = root[PREV] = link 579*cda5da8dSAndroid Build Coastguard Worker link[PREV] = last 580*cda5da8dSAndroid Build Coastguard Worker link[NEXT] = root 581*cda5da8dSAndroid Build Coastguard Worker hits += 1 582*cda5da8dSAndroid Build Coastguard Worker return result 583*cda5da8dSAndroid Build Coastguard Worker misses += 1 584*cda5da8dSAndroid Build Coastguard Worker result = user_function(*args, **kwds) 585*cda5da8dSAndroid Build Coastguard Worker with lock: 586*cda5da8dSAndroid Build Coastguard Worker if key in cache: 587*cda5da8dSAndroid Build Coastguard Worker # Getting here means that this same key was added to the 588*cda5da8dSAndroid Build Coastguard Worker # cache while the lock was released. Since the link 589*cda5da8dSAndroid Build Coastguard Worker # update is already done, we need only return the 590*cda5da8dSAndroid Build Coastguard Worker # computed result and update the count of misses. 591*cda5da8dSAndroid Build Coastguard Worker pass 592*cda5da8dSAndroid Build Coastguard Worker elif full: 593*cda5da8dSAndroid Build Coastguard Worker # Use the old root to store the new key and result. 594*cda5da8dSAndroid Build Coastguard Worker oldroot = root 595*cda5da8dSAndroid Build Coastguard Worker oldroot[KEY] = key 596*cda5da8dSAndroid Build Coastguard Worker oldroot[RESULT] = result 597*cda5da8dSAndroid Build Coastguard Worker # Empty the oldest link and make it the new root. 598*cda5da8dSAndroid Build Coastguard Worker # Keep a reference to the old key and old result to 599*cda5da8dSAndroid Build Coastguard Worker # prevent their ref counts from going to zero during the 600*cda5da8dSAndroid Build Coastguard Worker # update. That will prevent potentially arbitrary object 601*cda5da8dSAndroid Build Coastguard Worker # clean-up code (i.e. __del__) from running while we're 602*cda5da8dSAndroid Build Coastguard Worker # still adjusting the links. 603*cda5da8dSAndroid Build Coastguard Worker root = oldroot[NEXT] 604*cda5da8dSAndroid Build Coastguard Worker oldkey = root[KEY] 605*cda5da8dSAndroid Build Coastguard Worker oldresult = root[RESULT] 606*cda5da8dSAndroid Build Coastguard Worker root[KEY] = root[RESULT] = None 607*cda5da8dSAndroid Build Coastguard Worker # Now update the cache dictionary. 608*cda5da8dSAndroid Build Coastguard Worker del cache[oldkey] 609*cda5da8dSAndroid Build Coastguard Worker # Save the potentially reentrant cache[key] assignment 610*cda5da8dSAndroid Build Coastguard Worker # for last, after the root and links have been put in 611*cda5da8dSAndroid Build Coastguard Worker # a consistent state. 612*cda5da8dSAndroid Build Coastguard Worker cache[key] = oldroot 613*cda5da8dSAndroid Build Coastguard Worker else: 614*cda5da8dSAndroid Build Coastguard Worker # Put result in a new link at the front of the queue. 615*cda5da8dSAndroid Build Coastguard Worker last = root[PREV] 616*cda5da8dSAndroid Build Coastguard Worker link = [last, root, key, result] 617*cda5da8dSAndroid Build Coastguard Worker last[NEXT] = root[PREV] = cache[key] = link 618*cda5da8dSAndroid Build Coastguard Worker # Use the cache_len bound method instead of the len() function 619*cda5da8dSAndroid Build Coastguard Worker # which could potentially be wrapped in an lru_cache itself. 620*cda5da8dSAndroid Build Coastguard Worker full = (cache_len() >= maxsize) 621*cda5da8dSAndroid Build Coastguard Worker return result 622*cda5da8dSAndroid Build Coastguard Worker 623*cda5da8dSAndroid Build Coastguard Worker def cache_info(): 624*cda5da8dSAndroid Build Coastguard Worker """Report cache statistics""" 625*cda5da8dSAndroid Build Coastguard Worker with lock: 626*cda5da8dSAndroid Build Coastguard Worker return _CacheInfo(hits, misses, maxsize, cache_len()) 627*cda5da8dSAndroid Build Coastguard Worker 628*cda5da8dSAndroid Build Coastguard Worker def cache_clear(): 629*cda5da8dSAndroid Build Coastguard Worker """Clear the cache and cache statistics""" 630*cda5da8dSAndroid Build Coastguard Worker nonlocal hits, misses, full 631*cda5da8dSAndroid Build Coastguard Worker with lock: 632*cda5da8dSAndroid Build Coastguard Worker cache.clear() 633*cda5da8dSAndroid Build Coastguard Worker root[:] = [root, root, None, None] 634*cda5da8dSAndroid Build Coastguard Worker hits = misses = 0 635*cda5da8dSAndroid Build Coastguard Worker full = False 636*cda5da8dSAndroid Build Coastguard Worker 637*cda5da8dSAndroid Build Coastguard Worker wrapper.cache_info = cache_info 638*cda5da8dSAndroid Build Coastguard Worker wrapper.cache_clear = cache_clear 639*cda5da8dSAndroid Build Coastguard Worker return wrapper 640*cda5da8dSAndroid Build Coastguard Worker 641*cda5da8dSAndroid Build Coastguard Workertry: 642*cda5da8dSAndroid Build Coastguard Worker from _functools import _lru_cache_wrapper 643*cda5da8dSAndroid Build Coastguard Workerexcept ImportError: 644*cda5da8dSAndroid Build Coastguard Worker pass 645*cda5da8dSAndroid Build Coastguard Worker 646*cda5da8dSAndroid Build Coastguard Worker 647*cda5da8dSAndroid Build Coastguard Worker################################################################################ 648*cda5da8dSAndroid Build Coastguard Worker### cache -- simplified access to the infinity cache 649*cda5da8dSAndroid Build Coastguard Worker################################################################################ 650*cda5da8dSAndroid Build Coastguard Worker 651*cda5da8dSAndroid Build Coastguard Workerdef cache(user_function, /): 652*cda5da8dSAndroid Build Coastguard Worker 'Simple lightweight unbounded cache. Sometimes called "memoize".' 653*cda5da8dSAndroid Build Coastguard Worker return lru_cache(maxsize=None)(user_function) 654*cda5da8dSAndroid Build Coastguard Worker 655*cda5da8dSAndroid Build Coastguard Worker 656*cda5da8dSAndroid Build Coastguard Worker################################################################################ 657*cda5da8dSAndroid Build Coastguard Worker### singledispatch() - single-dispatch generic function decorator 658*cda5da8dSAndroid Build Coastguard Worker################################################################################ 659*cda5da8dSAndroid Build Coastguard Worker 660*cda5da8dSAndroid Build Coastguard Workerdef _c3_merge(sequences): 661*cda5da8dSAndroid Build Coastguard Worker """Merges MROs in *sequences* to a single MRO using the C3 algorithm. 662*cda5da8dSAndroid Build Coastguard Worker 663*cda5da8dSAndroid Build Coastguard Worker Adapted from https://www.python.org/download/releases/2.3/mro/. 664*cda5da8dSAndroid Build Coastguard Worker 665*cda5da8dSAndroid Build Coastguard Worker """ 666*cda5da8dSAndroid Build Coastguard Worker result = [] 667*cda5da8dSAndroid Build Coastguard Worker while True: 668*cda5da8dSAndroid Build Coastguard Worker sequences = [s for s in sequences if s] # purge empty sequences 669*cda5da8dSAndroid Build Coastguard Worker if not sequences: 670*cda5da8dSAndroid Build Coastguard Worker return result 671*cda5da8dSAndroid Build Coastguard Worker for s1 in sequences: # find merge candidates among seq heads 672*cda5da8dSAndroid Build Coastguard Worker candidate = s1[0] 673*cda5da8dSAndroid Build Coastguard Worker for s2 in sequences: 674*cda5da8dSAndroid Build Coastguard Worker if candidate in s2[1:]: 675*cda5da8dSAndroid Build Coastguard Worker candidate = None 676*cda5da8dSAndroid Build Coastguard Worker break # reject the current head, it appears later 677*cda5da8dSAndroid Build Coastguard Worker else: 678*cda5da8dSAndroid Build Coastguard Worker break 679*cda5da8dSAndroid Build Coastguard Worker if candidate is None: 680*cda5da8dSAndroid Build Coastguard Worker raise RuntimeError("Inconsistent hierarchy") 681*cda5da8dSAndroid Build Coastguard Worker result.append(candidate) 682*cda5da8dSAndroid Build Coastguard Worker # remove the chosen candidate 683*cda5da8dSAndroid Build Coastguard Worker for seq in sequences: 684*cda5da8dSAndroid Build Coastguard Worker if seq[0] == candidate: 685*cda5da8dSAndroid Build Coastguard Worker del seq[0] 686*cda5da8dSAndroid Build Coastguard Worker 687*cda5da8dSAndroid Build Coastguard Workerdef _c3_mro(cls, abcs=None): 688*cda5da8dSAndroid Build Coastguard Worker """Computes the method resolution order using extended C3 linearization. 689*cda5da8dSAndroid Build Coastguard Worker 690*cda5da8dSAndroid Build Coastguard Worker If no *abcs* are given, the algorithm works exactly like the built-in C3 691*cda5da8dSAndroid Build Coastguard Worker linearization used for method resolution. 692*cda5da8dSAndroid Build Coastguard Worker 693*cda5da8dSAndroid Build Coastguard Worker If given, *abcs* is a list of abstract base classes that should be inserted 694*cda5da8dSAndroid Build Coastguard Worker into the resulting MRO. Unrelated ABCs are ignored and don't end up in the 695*cda5da8dSAndroid Build Coastguard Worker result. The algorithm inserts ABCs where their functionality is introduced, 696*cda5da8dSAndroid Build Coastguard Worker i.e. issubclass(cls, abc) returns True for the class itself but returns 697*cda5da8dSAndroid Build Coastguard Worker False for all its direct base classes. Implicit ABCs for a given class 698*cda5da8dSAndroid Build Coastguard Worker (either registered or inferred from the presence of a special method like 699*cda5da8dSAndroid Build Coastguard Worker __len__) are inserted directly after the last ABC explicitly listed in the 700*cda5da8dSAndroid Build Coastguard Worker MRO of said class. If two implicit ABCs end up next to each other in the 701*cda5da8dSAndroid Build Coastguard Worker resulting MRO, their ordering depends on the order of types in *abcs*. 702*cda5da8dSAndroid Build Coastguard Worker 703*cda5da8dSAndroid Build Coastguard Worker """ 704*cda5da8dSAndroid Build Coastguard Worker for i, base in enumerate(reversed(cls.__bases__)): 705*cda5da8dSAndroid Build Coastguard Worker if hasattr(base, '__abstractmethods__'): 706*cda5da8dSAndroid Build Coastguard Worker boundary = len(cls.__bases__) - i 707*cda5da8dSAndroid Build Coastguard Worker break # Bases up to the last explicit ABC are considered first. 708*cda5da8dSAndroid Build Coastguard Worker else: 709*cda5da8dSAndroid Build Coastguard Worker boundary = 0 710*cda5da8dSAndroid Build Coastguard Worker abcs = list(abcs) if abcs else [] 711*cda5da8dSAndroid Build Coastguard Worker explicit_bases = list(cls.__bases__[:boundary]) 712*cda5da8dSAndroid Build Coastguard Worker abstract_bases = [] 713*cda5da8dSAndroid Build Coastguard Worker other_bases = list(cls.__bases__[boundary:]) 714*cda5da8dSAndroid Build Coastguard Worker for base in abcs: 715*cda5da8dSAndroid Build Coastguard Worker if issubclass(cls, base) and not any( 716*cda5da8dSAndroid Build Coastguard Worker issubclass(b, base) for b in cls.__bases__ 717*cda5da8dSAndroid Build Coastguard Worker ): 718*cda5da8dSAndroid Build Coastguard Worker # If *cls* is the class that introduces behaviour described by 719*cda5da8dSAndroid Build Coastguard Worker # an ABC *base*, insert said ABC to its MRO. 720*cda5da8dSAndroid Build Coastguard Worker abstract_bases.append(base) 721*cda5da8dSAndroid Build Coastguard Worker for base in abstract_bases: 722*cda5da8dSAndroid Build Coastguard Worker abcs.remove(base) 723*cda5da8dSAndroid Build Coastguard Worker explicit_c3_mros = [_c3_mro(base, abcs=abcs) for base in explicit_bases] 724*cda5da8dSAndroid Build Coastguard Worker abstract_c3_mros = [_c3_mro(base, abcs=abcs) for base in abstract_bases] 725*cda5da8dSAndroid Build Coastguard Worker other_c3_mros = [_c3_mro(base, abcs=abcs) for base in other_bases] 726*cda5da8dSAndroid Build Coastguard Worker return _c3_merge( 727*cda5da8dSAndroid Build Coastguard Worker [[cls]] + 728*cda5da8dSAndroid Build Coastguard Worker explicit_c3_mros + abstract_c3_mros + other_c3_mros + 729*cda5da8dSAndroid Build Coastguard Worker [explicit_bases] + [abstract_bases] + [other_bases] 730*cda5da8dSAndroid Build Coastguard Worker ) 731*cda5da8dSAndroid Build Coastguard Worker 732*cda5da8dSAndroid Build Coastguard Workerdef _compose_mro(cls, types): 733*cda5da8dSAndroid Build Coastguard Worker """Calculates the method resolution order for a given class *cls*. 734*cda5da8dSAndroid Build Coastguard Worker 735*cda5da8dSAndroid Build Coastguard Worker Includes relevant abstract base classes (with their respective bases) from 736*cda5da8dSAndroid Build Coastguard Worker the *types* iterable. Uses a modified C3 linearization algorithm. 737*cda5da8dSAndroid Build Coastguard Worker 738*cda5da8dSAndroid Build Coastguard Worker """ 739*cda5da8dSAndroid Build Coastguard Worker bases = set(cls.__mro__) 740*cda5da8dSAndroid Build Coastguard Worker # Remove entries which are already present in the __mro__ or unrelated. 741*cda5da8dSAndroid Build Coastguard Worker def is_related(typ): 742*cda5da8dSAndroid Build Coastguard Worker return (typ not in bases and hasattr(typ, '__mro__') 743*cda5da8dSAndroid Build Coastguard Worker and not isinstance(typ, GenericAlias) 744*cda5da8dSAndroid Build Coastguard Worker and issubclass(cls, typ)) 745*cda5da8dSAndroid Build Coastguard Worker types = [n for n in types if is_related(n)] 746*cda5da8dSAndroid Build Coastguard Worker # Remove entries which are strict bases of other entries (they will end up 747*cda5da8dSAndroid Build Coastguard Worker # in the MRO anyway. 748*cda5da8dSAndroid Build Coastguard Worker def is_strict_base(typ): 749*cda5da8dSAndroid Build Coastguard Worker for other in types: 750*cda5da8dSAndroid Build Coastguard Worker if typ != other and typ in other.__mro__: 751*cda5da8dSAndroid Build Coastguard Worker return True 752*cda5da8dSAndroid Build Coastguard Worker return False 753*cda5da8dSAndroid Build Coastguard Worker types = [n for n in types if not is_strict_base(n)] 754*cda5da8dSAndroid Build Coastguard Worker # Subclasses of the ABCs in *types* which are also implemented by 755*cda5da8dSAndroid Build Coastguard Worker # *cls* can be used to stabilize ABC ordering. 756*cda5da8dSAndroid Build Coastguard Worker type_set = set(types) 757*cda5da8dSAndroid Build Coastguard Worker mro = [] 758*cda5da8dSAndroid Build Coastguard Worker for typ in types: 759*cda5da8dSAndroid Build Coastguard Worker found = [] 760*cda5da8dSAndroid Build Coastguard Worker for sub in typ.__subclasses__(): 761*cda5da8dSAndroid Build Coastguard Worker if sub not in bases and issubclass(cls, sub): 762*cda5da8dSAndroid Build Coastguard Worker found.append([s for s in sub.__mro__ if s in type_set]) 763*cda5da8dSAndroid Build Coastguard Worker if not found: 764*cda5da8dSAndroid Build Coastguard Worker mro.append(typ) 765*cda5da8dSAndroid Build Coastguard Worker continue 766*cda5da8dSAndroid Build Coastguard Worker # Favor subclasses with the biggest number of useful bases 767*cda5da8dSAndroid Build Coastguard Worker found.sort(key=len, reverse=True) 768*cda5da8dSAndroid Build Coastguard Worker for sub in found: 769*cda5da8dSAndroid Build Coastguard Worker for subcls in sub: 770*cda5da8dSAndroid Build Coastguard Worker if subcls not in mro: 771*cda5da8dSAndroid Build Coastguard Worker mro.append(subcls) 772*cda5da8dSAndroid Build Coastguard Worker return _c3_mro(cls, abcs=mro) 773*cda5da8dSAndroid Build Coastguard Worker 774*cda5da8dSAndroid Build Coastguard Workerdef _find_impl(cls, registry): 775*cda5da8dSAndroid Build Coastguard Worker """Returns the best matching implementation from *registry* for type *cls*. 776*cda5da8dSAndroid Build Coastguard Worker 777*cda5da8dSAndroid Build Coastguard Worker Where there is no registered implementation for a specific type, its method 778*cda5da8dSAndroid Build Coastguard Worker resolution order is used to find a more generic implementation. 779*cda5da8dSAndroid Build Coastguard Worker 780*cda5da8dSAndroid Build Coastguard Worker Note: if *registry* does not contain an implementation for the base 781*cda5da8dSAndroid Build Coastguard Worker *object* type, this function may return None. 782*cda5da8dSAndroid Build Coastguard Worker 783*cda5da8dSAndroid Build Coastguard Worker """ 784*cda5da8dSAndroid Build Coastguard Worker mro = _compose_mro(cls, registry.keys()) 785*cda5da8dSAndroid Build Coastguard Worker match = None 786*cda5da8dSAndroid Build Coastguard Worker for t in mro: 787*cda5da8dSAndroid Build Coastguard Worker if match is not None: 788*cda5da8dSAndroid Build Coastguard Worker # If *match* is an implicit ABC but there is another unrelated, 789*cda5da8dSAndroid Build Coastguard Worker # equally matching implicit ABC, refuse the temptation to guess. 790*cda5da8dSAndroid Build Coastguard Worker if (t in registry and t not in cls.__mro__ 791*cda5da8dSAndroid Build Coastguard Worker and match not in cls.__mro__ 792*cda5da8dSAndroid Build Coastguard Worker and not issubclass(match, t)): 793*cda5da8dSAndroid Build Coastguard Worker raise RuntimeError("Ambiguous dispatch: {} or {}".format( 794*cda5da8dSAndroid Build Coastguard Worker match, t)) 795*cda5da8dSAndroid Build Coastguard Worker break 796*cda5da8dSAndroid Build Coastguard Worker if t in registry: 797*cda5da8dSAndroid Build Coastguard Worker match = t 798*cda5da8dSAndroid Build Coastguard Worker return registry.get(match) 799*cda5da8dSAndroid Build Coastguard Worker 800*cda5da8dSAndroid Build Coastguard Workerdef singledispatch(func): 801*cda5da8dSAndroid Build Coastguard Worker """Single-dispatch generic function decorator. 802*cda5da8dSAndroid Build Coastguard Worker 803*cda5da8dSAndroid Build Coastguard Worker Transforms a function into a generic function, which can have different 804*cda5da8dSAndroid Build Coastguard Worker behaviours depending upon the type of its first argument. The decorated 805*cda5da8dSAndroid Build Coastguard Worker function acts as the default implementation, and additional 806*cda5da8dSAndroid Build Coastguard Worker implementations can be registered using the register() attribute of the 807*cda5da8dSAndroid Build Coastguard Worker generic function. 808*cda5da8dSAndroid Build Coastguard Worker """ 809*cda5da8dSAndroid Build Coastguard Worker # There are many programs that use functools without singledispatch, so we 810*cda5da8dSAndroid Build Coastguard Worker # trade-off making singledispatch marginally slower for the benefit of 811*cda5da8dSAndroid Build Coastguard Worker # making start-up of such applications slightly faster. 812*cda5da8dSAndroid Build Coastguard Worker import types, weakref 813*cda5da8dSAndroid Build Coastguard Worker 814*cda5da8dSAndroid Build Coastguard Worker registry = {} 815*cda5da8dSAndroid Build Coastguard Worker dispatch_cache = weakref.WeakKeyDictionary() 816*cda5da8dSAndroid Build Coastguard Worker cache_token = None 817*cda5da8dSAndroid Build Coastguard Worker 818*cda5da8dSAndroid Build Coastguard Worker def dispatch(cls): 819*cda5da8dSAndroid Build Coastguard Worker """generic_func.dispatch(cls) -> <function implementation> 820*cda5da8dSAndroid Build Coastguard Worker 821*cda5da8dSAndroid Build Coastguard Worker Runs the dispatch algorithm to return the best available implementation 822*cda5da8dSAndroid Build Coastguard Worker for the given *cls* registered on *generic_func*. 823*cda5da8dSAndroid Build Coastguard Worker 824*cda5da8dSAndroid Build Coastguard Worker """ 825*cda5da8dSAndroid Build Coastguard Worker nonlocal cache_token 826*cda5da8dSAndroid Build Coastguard Worker if cache_token is not None: 827*cda5da8dSAndroid Build Coastguard Worker current_token = get_cache_token() 828*cda5da8dSAndroid Build Coastguard Worker if cache_token != current_token: 829*cda5da8dSAndroid Build Coastguard Worker dispatch_cache.clear() 830*cda5da8dSAndroid Build Coastguard Worker cache_token = current_token 831*cda5da8dSAndroid Build Coastguard Worker try: 832*cda5da8dSAndroid Build Coastguard Worker impl = dispatch_cache[cls] 833*cda5da8dSAndroid Build Coastguard Worker except KeyError: 834*cda5da8dSAndroid Build Coastguard Worker try: 835*cda5da8dSAndroid Build Coastguard Worker impl = registry[cls] 836*cda5da8dSAndroid Build Coastguard Worker except KeyError: 837*cda5da8dSAndroid Build Coastguard Worker impl = _find_impl(cls, registry) 838*cda5da8dSAndroid Build Coastguard Worker dispatch_cache[cls] = impl 839*cda5da8dSAndroid Build Coastguard Worker return impl 840*cda5da8dSAndroid Build Coastguard Worker 841*cda5da8dSAndroid Build Coastguard Worker def _is_union_type(cls): 842*cda5da8dSAndroid Build Coastguard Worker from typing import get_origin, Union 843*cda5da8dSAndroid Build Coastguard Worker return get_origin(cls) in {Union, types.UnionType} 844*cda5da8dSAndroid Build Coastguard Worker 845*cda5da8dSAndroid Build Coastguard Worker def _is_valid_dispatch_type(cls): 846*cda5da8dSAndroid Build Coastguard Worker if isinstance(cls, type): 847*cda5da8dSAndroid Build Coastguard Worker return True 848*cda5da8dSAndroid Build Coastguard Worker from typing import get_args 849*cda5da8dSAndroid Build Coastguard Worker return (_is_union_type(cls) and 850*cda5da8dSAndroid Build Coastguard Worker all(isinstance(arg, type) for arg in get_args(cls))) 851*cda5da8dSAndroid Build Coastguard Worker 852*cda5da8dSAndroid Build Coastguard Worker def register(cls, func=None): 853*cda5da8dSAndroid Build Coastguard Worker """generic_func.register(cls, func) -> func 854*cda5da8dSAndroid Build Coastguard Worker 855*cda5da8dSAndroid Build Coastguard Worker Registers a new implementation for the given *cls* on a *generic_func*. 856*cda5da8dSAndroid Build Coastguard Worker 857*cda5da8dSAndroid Build Coastguard Worker """ 858*cda5da8dSAndroid Build Coastguard Worker nonlocal cache_token 859*cda5da8dSAndroid Build Coastguard Worker if _is_valid_dispatch_type(cls): 860*cda5da8dSAndroid Build Coastguard Worker if func is None: 861*cda5da8dSAndroid Build Coastguard Worker return lambda f: register(cls, f) 862*cda5da8dSAndroid Build Coastguard Worker else: 863*cda5da8dSAndroid Build Coastguard Worker if func is not None: 864*cda5da8dSAndroid Build Coastguard Worker raise TypeError( 865*cda5da8dSAndroid Build Coastguard Worker f"Invalid first argument to `register()`. " 866*cda5da8dSAndroid Build Coastguard Worker f"{cls!r} is not a class or union type." 867*cda5da8dSAndroid Build Coastguard Worker ) 868*cda5da8dSAndroid Build Coastguard Worker ann = getattr(cls, '__annotations__', {}) 869*cda5da8dSAndroid Build Coastguard Worker if not ann: 870*cda5da8dSAndroid Build Coastguard Worker raise TypeError( 871*cda5da8dSAndroid Build Coastguard Worker f"Invalid first argument to `register()`: {cls!r}. " 872*cda5da8dSAndroid Build Coastguard Worker f"Use either `@register(some_class)` or plain `@register` " 873*cda5da8dSAndroid Build Coastguard Worker f"on an annotated function." 874*cda5da8dSAndroid Build Coastguard Worker ) 875*cda5da8dSAndroid Build Coastguard Worker func = cls 876*cda5da8dSAndroid Build Coastguard Worker 877*cda5da8dSAndroid Build Coastguard Worker # only import typing if annotation parsing is necessary 878*cda5da8dSAndroid Build Coastguard Worker from typing import get_type_hints 879*cda5da8dSAndroid Build Coastguard Worker argname, cls = next(iter(get_type_hints(func).items())) 880*cda5da8dSAndroid Build Coastguard Worker if not _is_valid_dispatch_type(cls): 881*cda5da8dSAndroid Build Coastguard Worker if _is_union_type(cls): 882*cda5da8dSAndroid Build Coastguard Worker raise TypeError( 883*cda5da8dSAndroid Build Coastguard Worker f"Invalid annotation for {argname!r}. " 884*cda5da8dSAndroid Build Coastguard Worker f"{cls!r} not all arguments are classes." 885*cda5da8dSAndroid Build Coastguard Worker ) 886*cda5da8dSAndroid Build Coastguard Worker else: 887*cda5da8dSAndroid Build Coastguard Worker raise TypeError( 888*cda5da8dSAndroid Build Coastguard Worker f"Invalid annotation for {argname!r}. " 889*cda5da8dSAndroid Build Coastguard Worker f"{cls!r} is not a class." 890*cda5da8dSAndroid Build Coastguard Worker ) 891*cda5da8dSAndroid Build Coastguard Worker 892*cda5da8dSAndroid Build Coastguard Worker if _is_union_type(cls): 893*cda5da8dSAndroid Build Coastguard Worker from typing import get_args 894*cda5da8dSAndroid Build Coastguard Worker 895*cda5da8dSAndroid Build Coastguard Worker for arg in get_args(cls): 896*cda5da8dSAndroid Build Coastguard Worker registry[arg] = func 897*cda5da8dSAndroid Build Coastguard Worker else: 898*cda5da8dSAndroid Build Coastguard Worker registry[cls] = func 899*cda5da8dSAndroid Build Coastguard Worker if cache_token is None and hasattr(cls, '__abstractmethods__'): 900*cda5da8dSAndroid Build Coastguard Worker cache_token = get_cache_token() 901*cda5da8dSAndroid Build Coastguard Worker dispatch_cache.clear() 902*cda5da8dSAndroid Build Coastguard Worker return func 903*cda5da8dSAndroid Build Coastguard Worker 904*cda5da8dSAndroid Build Coastguard Worker def wrapper(*args, **kw): 905*cda5da8dSAndroid Build Coastguard Worker if not args: 906*cda5da8dSAndroid Build Coastguard Worker raise TypeError(f'{funcname} requires at least ' 907*cda5da8dSAndroid Build Coastguard Worker '1 positional argument') 908*cda5da8dSAndroid Build Coastguard Worker 909*cda5da8dSAndroid Build Coastguard Worker return dispatch(args[0].__class__)(*args, **kw) 910*cda5da8dSAndroid Build Coastguard Worker 911*cda5da8dSAndroid Build Coastguard Worker funcname = getattr(func, '__name__', 'singledispatch function') 912*cda5da8dSAndroid Build Coastguard Worker registry[object] = func 913*cda5da8dSAndroid Build Coastguard Worker wrapper.register = register 914*cda5da8dSAndroid Build Coastguard Worker wrapper.dispatch = dispatch 915*cda5da8dSAndroid Build Coastguard Worker wrapper.registry = types.MappingProxyType(registry) 916*cda5da8dSAndroid Build Coastguard Worker wrapper._clear_cache = dispatch_cache.clear 917*cda5da8dSAndroid Build Coastguard Worker update_wrapper(wrapper, func) 918*cda5da8dSAndroid Build Coastguard Worker return wrapper 919*cda5da8dSAndroid Build Coastguard Worker 920*cda5da8dSAndroid Build Coastguard Worker 921*cda5da8dSAndroid Build Coastguard Worker# Descriptor version 922*cda5da8dSAndroid Build Coastguard Workerclass singledispatchmethod: 923*cda5da8dSAndroid Build Coastguard Worker """Single-dispatch generic method descriptor. 924*cda5da8dSAndroid Build Coastguard Worker 925*cda5da8dSAndroid Build Coastguard Worker Supports wrapping existing descriptors and handles non-descriptor 926*cda5da8dSAndroid Build Coastguard Worker callables as instance methods. 927*cda5da8dSAndroid Build Coastguard Worker """ 928*cda5da8dSAndroid Build Coastguard Worker 929*cda5da8dSAndroid Build Coastguard Worker def __init__(self, func): 930*cda5da8dSAndroid Build Coastguard Worker if not callable(func) and not hasattr(func, "__get__"): 931*cda5da8dSAndroid Build Coastguard Worker raise TypeError(f"{func!r} is not callable or a descriptor") 932*cda5da8dSAndroid Build Coastguard Worker 933*cda5da8dSAndroid Build Coastguard Worker self.dispatcher = singledispatch(func) 934*cda5da8dSAndroid Build Coastguard Worker self.func = func 935*cda5da8dSAndroid Build Coastguard Worker 936*cda5da8dSAndroid Build Coastguard Worker def register(self, cls, method=None): 937*cda5da8dSAndroid Build Coastguard Worker """generic_method.register(cls, func) -> func 938*cda5da8dSAndroid Build Coastguard Worker 939*cda5da8dSAndroid Build Coastguard Worker Registers a new implementation for the given *cls* on a *generic_method*. 940*cda5da8dSAndroid Build Coastguard Worker """ 941*cda5da8dSAndroid Build Coastguard Worker return self.dispatcher.register(cls, func=method) 942*cda5da8dSAndroid Build Coastguard Worker 943*cda5da8dSAndroid Build Coastguard Worker def __get__(self, obj, cls=None): 944*cda5da8dSAndroid Build Coastguard Worker def _method(*args, **kwargs): 945*cda5da8dSAndroid Build Coastguard Worker method = self.dispatcher.dispatch(args[0].__class__) 946*cda5da8dSAndroid Build Coastguard Worker return method.__get__(obj, cls)(*args, **kwargs) 947*cda5da8dSAndroid Build Coastguard Worker 948*cda5da8dSAndroid Build Coastguard Worker _method.__isabstractmethod__ = self.__isabstractmethod__ 949*cda5da8dSAndroid Build Coastguard Worker _method.register = self.register 950*cda5da8dSAndroid Build Coastguard Worker update_wrapper(_method, self.func) 951*cda5da8dSAndroid Build Coastguard Worker return _method 952*cda5da8dSAndroid Build Coastguard Worker 953*cda5da8dSAndroid Build Coastguard Worker @property 954*cda5da8dSAndroid Build Coastguard Worker def __isabstractmethod__(self): 955*cda5da8dSAndroid Build Coastguard Worker return getattr(self.func, '__isabstractmethod__', False) 956*cda5da8dSAndroid Build Coastguard Worker 957*cda5da8dSAndroid Build Coastguard Worker 958*cda5da8dSAndroid Build Coastguard Worker################################################################################ 959*cda5da8dSAndroid Build Coastguard Worker### cached_property() - computed once per instance, cached as attribute 960*cda5da8dSAndroid Build Coastguard Worker################################################################################ 961*cda5da8dSAndroid Build Coastguard Worker 962*cda5da8dSAndroid Build Coastguard Worker_NOT_FOUND = object() 963*cda5da8dSAndroid Build Coastguard Worker 964*cda5da8dSAndroid Build Coastguard Worker 965*cda5da8dSAndroid Build Coastguard Workerclass cached_property: 966*cda5da8dSAndroid Build Coastguard Worker def __init__(self, func): 967*cda5da8dSAndroid Build Coastguard Worker self.func = func 968*cda5da8dSAndroid Build Coastguard Worker self.attrname = None 969*cda5da8dSAndroid Build Coastguard Worker self.__doc__ = func.__doc__ 970*cda5da8dSAndroid Build Coastguard Worker self.lock = RLock() 971*cda5da8dSAndroid Build Coastguard Worker 972*cda5da8dSAndroid Build Coastguard Worker def __set_name__(self, owner, name): 973*cda5da8dSAndroid Build Coastguard Worker if self.attrname is None: 974*cda5da8dSAndroid Build Coastguard Worker self.attrname = name 975*cda5da8dSAndroid Build Coastguard Worker elif name != self.attrname: 976*cda5da8dSAndroid Build Coastguard Worker raise TypeError( 977*cda5da8dSAndroid Build Coastguard Worker "Cannot assign the same cached_property to two different names " 978*cda5da8dSAndroid Build Coastguard Worker f"({self.attrname!r} and {name!r})." 979*cda5da8dSAndroid Build Coastguard Worker ) 980*cda5da8dSAndroid Build Coastguard Worker 981*cda5da8dSAndroid Build Coastguard Worker def __get__(self, instance, owner=None): 982*cda5da8dSAndroid Build Coastguard Worker if instance is None: 983*cda5da8dSAndroid Build Coastguard Worker return self 984*cda5da8dSAndroid Build Coastguard Worker if self.attrname is None: 985*cda5da8dSAndroid Build Coastguard Worker raise TypeError( 986*cda5da8dSAndroid Build Coastguard Worker "Cannot use cached_property instance without calling __set_name__ on it.") 987*cda5da8dSAndroid Build Coastguard Worker try: 988*cda5da8dSAndroid Build Coastguard Worker cache = instance.__dict__ 989*cda5da8dSAndroid Build Coastguard Worker except AttributeError: # not all objects have __dict__ (e.g. class defines slots) 990*cda5da8dSAndroid Build Coastguard Worker msg = ( 991*cda5da8dSAndroid Build Coastguard Worker f"No '__dict__' attribute on {type(instance).__name__!r} " 992*cda5da8dSAndroid Build Coastguard Worker f"instance to cache {self.attrname!r} property." 993*cda5da8dSAndroid Build Coastguard Worker ) 994*cda5da8dSAndroid Build Coastguard Worker raise TypeError(msg) from None 995*cda5da8dSAndroid Build Coastguard Worker val = cache.get(self.attrname, _NOT_FOUND) 996*cda5da8dSAndroid Build Coastguard Worker if val is _NOT_FOUND: 997*cda5da8dSAndroid Build Coastguard Worker with self.lock: 998*cda5da8dSAndroid Build Coastguard Worker # check if another thread filled cache while we awaited lock 999*cda5da8dSAndroid Build Coastguard Worker val = cache.get(self.attrname, _NOT_FOUND) 1000*cda5da8dSAndroid Build Coastguard Worker if val is _NOT_FOUND: 1001*cda5da8dSAndroid Build Coastguard Worker val = self.func(instance) 1002*cda5da8dSAndroid Build Coastguard Worker try: 1003*cda5da8dSAndroid Build Coastguard Worker cache[self.attrname] = val 1004*cda5da8dSAndroid Build Coastguard Worker except TypeError: 1005*cda5da8dSAndroid Build Coastguard Worker msg = ( 1006*cda5da8dSAndroid Build Coastguard Worker f"The '__dict__' attribute on {type(instance).__name__!r} instance " 1007*cda5da8dSAndroid Build Coastguard Worker f"does not support item assignment for caching {self.attrname!r} property." 1008*cda5da8dSAndroid Build Coastguard Worker ) 1009*cda5da8dSAndroid Build Coastguard Worker raise TypeError(msg) from None 1010*cda5da8dSAndroid Build Coastguard Worker return val 1011*cda5da8dSAndroid Build Coastguard Worker 1012*cda5da8dSAndroid Build Coastguard Worker __class_getitem__ = classmethod(GenericAlias) 1013