[docs]@classmethoddefreset(cls)->None:"""Reset the singleton callable class."""with_LOCK_SINGLETON_CALLABLE:cls._has_run={}cls._responses={}
[docs]@classmethoddefrun_once(cls,f:Callable[PARAM_SPEC_TYPE,ANY_GENERIC_TYPE]# type: ignore)->Callable[PARAM_SPEC_TYPE,ANY_GENERIC_TYPE]:# type: ignore"""A decorator to make a function run only once."""@functools.wraps(f)defwrapper(*args:PARAM_SPEC_TYPE.args,**kwargs:PARAM_SPEC_TYPE.kwargs)->ANY_GENERIC_TYPE:with_LOCK_SINGLETON_CALLABLE:ifnotcls._has_run.get(f,False):cls._has_run[f]=Trueoutput=f(*args,**kwargs)cls._responses[f]=outputreturnoutputelse:returncls._responses.get(f,None)cls._has_run[f]=Falsereturnwrapper
[docs]@classmethoddefrun_once_async(cls,f:Callable[PARAM_SPEC_TYPE,Awaitable[ANY_GENERIC_TYPE]]# type: ignore)->Callable[PARAM_SPEC_TYPE,Awaitable[ANY_GENERIC_TYPE]]:# type: ignore"""A decorator to make a function run only once asynchronously."""@functools.wraps(f)defwrapper(*args:PARAM_SPEC_TYPE.args,**kwargs:PARAM_SPEC_TYPE.kwargs)->Awaitable[ANY_GENERIC_TYPE]:with_LOCK_SINGLETON_CALLABLE:ifnotcls._has_run.get(f,False):cls._has_run[f.__name__]=Truereturnf(*args,**kwargs)else:returnasyncio.sleep(0)cls._has_run[f]=Falsereturnwrapper
[docs]classSingletonCachedByKey(type):"""Singleton metaclass with key caching."""_instances:Any={}@classmethoddef_get_key(cls,mro,**kwargs:Any)->tuple[str,...]|None:singleton_key=f'{kwargs.get("id")}'forbaseinmro:ifbase.__module__.startswith("pylav.storage.models"):key_name=base.__name__ifkey_namein("PlayerState","NodeMock","Equalizer"):returnifkey_namein("PlayerConfig","Config"):singleton_key+=f".{kwargs.get('bot')}"returnsingleton_key,key_namedef__call__(cls,*args:Any,**kwargs:Any)->Any:# sourcery skip: instance-method-first-arg-namekey=cls._get_key(cls.mro(),**kwargs)ifkeynotincls._instances:rps=cls._locked_call(*args,**kwargs)ifkeyisNone:returnrpsreturncls._instances[key]def_locked_call(cls,*args:Any,**kwargs:Any)->Any:ifsuper().__class__.__name__notin_LOCKS_SINGLETON_CACHE:_LOCKS_SINGLETON_CACHE[super().__class__.__name__]=threading.Lock()with_LOCKS_SINGLETON_CACHE[super().__class__.__name__]:key=cls._get_key(cls.mro(),**kwargs)ifkeynotincls._instances:singleton=super().__call__(*args,**kwargs)ifkeyisnotNone:cls._instances[key]=singletonelse:returnsingleton