Source code for y.classes.singleton
import threading
from collections import defaultdict
from typing import DefaultDict, Generic, TypeVar
from a_sync.a_sync._meta import ASyncMeta
from checksum_dict import ChecksumAddressDict
from checksum_dict.base import AnyAddressOrContract
T = TypeVar("T", bound=object)
[docs]
class ChecksumASyncSingletonMeta(ASyncMeta, Generic[T]):
[docs]
def __init__(cls, name, bases, namespace):
super().__init__(name, bases, namespace)
cls.__instances: DefaultDict[bool, ChecksumAddressDict[T]] = defaultdict(ChecksumAddressDict)
cls.__locks = defaultdict(lambda: defaultdict(threading.Lock))
cls.__locks_lock: threading.Lock = threading.Lock()
[docs]
def __call__(cls, address: AnyAddressOrContract, *args, **kwargs) -> T: # type: ignore
# NOTE This will only work if you init your objects using a kwarg not a positional arg
# TODO Make it work with posiional args
address = str(address)
is_sync = cls.__a_sync_instance_will_be_sync__(args, kwargs)
try:
instance = cls.__instances[is_sync][address]
except KeyError:
with cls.__get_address_lock(address, is_sync):
# Try to get the instance again, in case it was added while waiting for the lock
try:
instance = cls.__instances[is_sync][address]
except KeyError:
instance = super().__call__(address, *args, **kwargs)
cls.__instances[is_sync][address] = instance
cls.__delete_address_lock(address, is_sync)
assert instance.asynchronous is not is_sync, f"You must initialize your objects with 'asynchronous' specified as a kwarg, not a positional arg. {instance} {kwargs} {is_sync} {instance.asynchronous} {args} {kwargs}"
return instance
def __get_address_lock(cls, address: AnyAddressOrContract, is_sync: bool) -> threading.Lock:
""" Makes sure the singleton is actually a singleton. """
with cls.__locks_lock:
return cls.__locks[is_sync][address]
def __delete_address_lock(cls, address: AnyAddressOrContract, is_sync: bool) -> None:
""" No need to maintain locks for initialized addresses. """
with cls.__locks_lock:
try:
del cls.__locks[is_sync][address]
except KeyError:
pass