Source code for graphenecommon.aio.blockchainobject

# -*- coding: utf-8 -*-
from asyncinit import asyncinit

from .instance import AbstractBlockchainInstanceProvider
from ..blockchainobject import (
    Caching as SyncCaching,
    BlockchainObjects as SyncBlockchainObjects,
    BlockchainObject as SyncBlockchainObject,
)


class Caching(SyncCaching):
    def __getitem__(self, key):
        """ This method overrides synchronous version to avoid calling
            self.refresh()
        """
        return dict.__getitem__(self, key)

    async def items(self):
        """ This overrides items() so that refresh() is called if the
            object is not already fetched
        """
        if not self._fetched:
            await self.refresh()
        return dict.items(self)

    def __contains__(self, key):
        """ This method overrides synchronous version to avoid calling
            self.refresh()
        """
        return dict.__contains__(self, key)


@asyncinit
class BlockchainObjects(Caching, list):
    async def __init__(self, *args, **kwargs):
        Caching.__init__(self, *args, **kwargs)
        # Some lists are specific to some key value that is then provided as
        # first argument
        if len(args) > 0 and isinstance(args[0], str):
            key = self._cache_key(args[0])
        else:
            key = self._cache_key()
        if self.incached(key):
            list.__init__(self, self.getfromcache(key))
        else:
            if kwargs.get("refresh", True):
                await self.refresh(*args, **kwargs)

    def __getitem__(self, key):
        """ Since we've overwriten __getitem__ in cache and inherit from there,
            we need to make sure we use `list` here instead of `dict`.

            This method overrides synchronous version to avoid calling
            self.refresh()
        """
        return list.__getitem__(self, key)


@asyncinit
class BlockchainObject(Caching, SyncBlockchainObject):
    async def __init__(
        self, data, klass=None, lazy=False, use_cache=True, *args, **kwargs
    ):
        Caching.__init__(self, *args, **kwargs)
        self._use_cache = use_cache
        if self.perform_id_tests:
            assert self.type_id or self.type_ids, "Need type_id or type_ids"
        self._fetched = False
        self._lazy = lazy

        if "_cache_expiration" in kwargs:
            self.set_expiration(kwargs["_cache_expiration"])

        # We don't read lists, sets, or tuples
        if isinstance(data, (list, set, tuple)):
            raise ValueError(
                "Cannot interpret lists! Please load elements individually!"
            )

        if klass and isinstance(data, klass):
            self.identifier = data.get("id")
            dict.__init__(self, data)
        elif isinstance(data, dict):
            self.identifier = data.get("id")
            dict.__init__(self, data)
        elif isinstance(data, int):
            # This is only for block number bascially
            self.identifier = data
            if self.incached(str(data)):
                dict.__init__(self, self.getfromcache(str(data)))
                self._fetched = True
            if not self._lazy and not self._fetched:
                await self.refresh()
            # make sure to store the blocknumber for caching
            self["id"] = str(data)
            # Set identifier again as it is overwritten in super() in refresh()
            self.identifier = data
        else:
            self.identifier = data
            if self.perform_id_tests and self.test_valid_objectid(self.identifier):
                # Here we assume we deal with an id
                self.testid(self.identifier)

            if self.incached(data):
                dict.__init__(self, dict(self.getfromcache(data)))
            elif not self._lazy and not self._fetched:
                await self.refresh()

        if self._use_cache and not self._lazy:
            self._store_item()


class Object(BlockchainObject, AbstractBlockchainInstanceProvider):
    """ This class is a basic class that allows to obtain any object
        from the blockchyin by fetching it through the API
    """

[docs] async def refresh(self): """ This is the refresh method that overloads the prototype in BlockchainObject. """ dict.__init__( self, await self.blockchain.rpc.get_object(self.identifier), blockchain_instance=self.blockchain, )