Source code for graphenecommon.instance

# -*- coding: utf-8 -*-
import types


class SharedInstance:
    """ This class merely offers a singelton for the Blockchain Instance
    """

    instance = None
    config = {}


class AbstractBlockchainInstanceProvider:
    """ This is a class that allows compatibility with previous
        naming conventions. It will extract 'blockchain_instance'
        from the key word arguments and ensure that self.blockchain
        contains an instance of the main chain instance
    """

    _sharedInstance = SharedInstance

    def __init__(self, *args, **kwargs):
        self._blockchain = None
        if kwargs.get("blockchain_instance"):
            self._blockchain = kwargs["blockchain_instance"]
        else:
            self._blockchain = self.shared_blockchain_instance()

    @classmethod
    def inject(slf, cls):
        class NewClass(slf, cls):
            blockchain_instance_class = slf

            def __init__(self, *args, **kwargs):
                slf.__init__(self, *args, **kwargs)
                cls.__init__(self, *args, **kwargs)

        NewClass.__name__ = cls.__name__
        NewClass.__qualname__ = cls.__qualname__
        NewClass.__doc__ = cls.__doc__
        NewClass.__module__ = cls.__module__
        return NewClass

    def get_instance_class(self):
        """ Should return the Chain instance class, e.g. `bitshares.BitShares`
        """
        raise NotImplementedError

    def define_classes(self):
        """ Needs to define instance variables that provide classes
        """
        raise NotImplementedError

    @property
    def blockchain(self):
        if hasattr(self, "_blockchain") and self._blockchain:
            # This shouldn't happen except for legacy libraries
            return self._blockchain
        else:
            return self.shared_blockchain_instance()

    @property
    def chain(self):
        """ Short form for blockchain (for the lazy)
        """
        return self.blockchain

    def shared_blockchain_instance(self):
        """ This method will initialize ``SharedInstance.instance`` and return it.
            The purpose of this method is to have offer single default
            instance that can be reused by multiple classes.
        """
        if not self._sharedInstance.instance:
            klass = self.get_instance_class()
            self._sharedInstance.instance = klass(**self._sharedInstance.config)
        return self._sharedInstance.instance

    @classmethod
    def set_shared_blockchain_instance(cls, instance):
        """ This method allows us to override default instance for all
            users of ``SharedInstance.instance``.

            :param chaininstance instance: Chain instance
        """
        cls._sharedInstance.instance = instance

    # -------------------------------------------------------------------------
    # Shared instance interface
    # -------------------------------------------------------------------------
    def set_shared_instance(self):
        """ This method allows to set the current instance as default
        """
        self._sharedInstance.instance = self

    @classmethod
    def set_shared_config(cls, config):
        """ This allows to set a config that will be used when calling
            ``shared_blockchain_instance`` and allows to define the configuration
            without requiring to actually create an instance
        """
        assert isinstance(config, dict)
        cls._sharedInstance.config.update(config)
        # if one is already set, delete
        if cls._sharedInstance.instance:
            cls._sharedInstance.instance = None


def shared_blockchain_instance():
    return BlockchainInstance().shared_blockchain_instance()


def set_shared_blockchain_instance(instance):
    instance.clear_cache()
    BlockchainInstance.set_shared_blockchain_instance(instance)


def set_shared_config(config):
    BlockchainInstance.set_shared_config(config)


# Legacy alias
BlockchainInstance = AbstractBlockchainInstanceProvider