Source code for orion.core.utils.singleton

"""
Singleton helpers and boilerplate
=================================

"""
from abc import ABCMeta

from orion.core.utils import Factory, GenericFactory


[docs]class SingletonAlreadyInstantiatedError(ValueError): """Exception to be raised when someone provides arguments to build an object from a already-instantiated `SingletonType` class. """ def __init__(self, name): """Pass the same constant message to ValueError underneath.""" super().__init__( f"A singleton instance of (type: {name}) has already been instantiated." )
[docs]class SingletonNotInstantiatedError(TypeError): """Exception to be raised when someone try to access an instance of a singleton that has not been instantiated yet """ def __init__(self, name): """Pass the same constant message to TypeError underneath.""" super().__init__(f"No singleton instance of (type: {name}) was created")
[docs]class SingletonType(type): """Metaclass that implements the singleton pattern for a Python class.""" def __init__(cls, name, bases, dictionary): """Create a class instance variable and initiate it to None object.""" super().__init__(name, bases, dictionary) cls.instance = None
[docs] def __call__(cls, *args, **kwargs): """Create an object if does not already exist, otherwise return what there is.""" if cls.instance is None: try: cls.instance = super().__call__(*args, **kwargs) except TypeError as exception: raise SingletonNotInstantiatedError(cls.__name__) from exception elif args or kwargs: raise SingletonAlreadyInstantiatedError(cls.__name__) return cls.instance
[docs]class AbstractSingletonType(SingletonType, ABCMeta): """This will create singleton base classes, that need to be subclassed and implemented."""
[docs]class SingletonFactory(AbstractSingletonType, Factory): """Wrapping `orion.core.utils.Factory` with `SingletonType`. Keep compatibility with `AbstractSingletonType`."""
[docs]class GenericSingletonFactory(GenericFactory): """Factory to create singleton instances of classes inheriting a given ``base`` class. .. seealso:: :py:class:`orion.core.utils.GenericFactory` """ def __init__(self, base): super().__init__(base=base) self.instance = None
[docs] def create(self, of_type=None, *args, **kwargs): """Create an object, instance of ``self.base`` If the instance is already created, ``self.create`` can only be called without arguments and will return the singleton. Cannot be called without arguments if the singleton was not already created. Parameters ---------- of_type: str, optional Name of class, subclass of ``self.base``. Capitalization insensitive. args: * Positional arguments to construct the givin class. kwargs: ** Keyword arguments to construct the givin class. Raises ------ `SingletonNotInstantiatedError` - If ``self.create()`` was never called and is called without arguments for the first time. - If ``self.create()`` was never called and the current call raises an error. `SingletonAlreadyInstantiatedError` If ``self.create()`` was already called with arguments (the singleton exist) and is called again with arguments. """ if self.instance is None and of_type is None: raise SingletonNotInstantiatedError(self.base.__name__) elif self.instance is None: try: self.instance = super().create(of_type, *args, **kwargs) except TypeError as exception: raise SingletonNotInstantiatedError(self.base.__name__) from exception elif of_type or args or kwargs: raise SingletonAlreadyInstantiatedError(self.base.__name__) return self.instance