# A singleton class decorator, based on http://stackoverflow.com/a/7346105/3301902
[docs]class Singleton(object):
"""
A non-thread-safe helper class to ease implementing singletons.
This should be used as a **decorator** -- not a metaclass -- to the class that should be a singleton.
The decorated class can define one `__init__` function that takes an arbitrary list of parameters.
To get the singleton instance, use the :py:meth:`instance` method. Trying to use `__call__` will result in a `TypeError` being raised.
Limitations:
* The decorated class cannot be inherited from.
* The documentation of the decorated class is replaced with the documentation of this class.
"""
def __init__(self, decorated):
self._decorated = decorated
# see: functools.WRAPPER_ASSIGNMENTS:
self.__doc__ = decorated.__doc__
self.__name__ = decorated.__name__
self.__module__ = decorated.__module__
self.__mro__ = decorated.__mro__
self.__bases__ = []
self._instance = None
[docs] def create(self, *args, **kwargs):
"""Creates the singleton instance, by passing the given parameters to the class' constructor."""
self._instance = self._decorated(*args, **kwargs)
[docs] def instance(self):
"""Returns the singleton instance.
The function :py:meth:`create` must have been called before."""
if self._instance is None:
raise RuntimeError("The class has not yet been instantiated using the 'create' method.")
return self._instance
def __call__(self):
raise TypeError('Singletons must be accessed through the `instance()` method.')
def __instancecheck__(self, inst):
return isinstance(inst, self._decorated)