Coverage for src/configuraptor/singleton.py: 100%

1"""

2 Singleton mixin/metaclass.

3"""

4

5 import typing

6

7

8 class SingletonMeta(type):

9 """

10 Every instance of a singleton shares the same object underneath.

11

12 Can be used as a metaclass:

13 Example:

14 class AbstractConfig(metaclass=Singleton):

15

16 Source: https://stackoverflow.com/questions/6760685/creating-a-singleton-in-python

17 """

18

19 _instances: typing.ClassVar[dict[typing.Type[typing.Any], typing.Type[typing.Any]]] = {}

20

21 def __call__(self, *args: typing.Any, **kwargs: typing.Any) -> typing.Type[typing.Any]:

22 """

23 When a class is instantiated (e.g. `AbstractConfig()`), __call__ is called. This overrides the default behavior.

24 """

25 if self not in self._instances:

26 self._instances[self] = super(SingletonMeta, self).__call__(*args, **kwargs)

27

28 return self._instances[self]

29

30 @staticmethod

31 def clear(instance: "Singleton" = None) -> None:

32 """

33 Use to remove old instances.

34

35 (otherwise e.g. pytest will crash)

36 """

37 if instance:

38 SingletonMeta._instances.pop(instance.__class__, None)

39 else:

40 SingletonMeta._instances.clear()

41

42

43 class Singleton(metaclass=SingletonMeta):

44 """

45 Mixin to make a class a singleton.

46 """