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

13 statements  

« prev     ^ index     » next       coverage.py v7.6.10, created at 2025-01-09 20:12 +0100

1""" 

2Singleton mixin/metaclass. 

3""" 

4 

5import typing 

6 

7 

8class 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 

43class Singleton(metaclass=SingletonMeta): 

44 """ 

45 Mixin to make a class a singleton. 

46 """