Coverage for src/configuraptor/postpone.py: 47%

19 statements  

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

1""" 

2File contains logic to do with the 'postpone' feature. 

3""" 

4 

5from typing import Any, Optional 

6 

7from typing_extensions import Never 

8 

9from .errors import IsPostponedError 

10from .singleton import Singleton 

11 

12 

13class Postponed(Singleton): 

14 """ 

15 Class returned by `postpone` below. 

16 """ 

17 

18 def __get_property_name__(self, instance: type[Any], owner: type[Any]) -> Optional[str]: 

19 """ 

20 Internal method to get the property name of the class this descriptor is being used on. 

21 """ 

22 if not instance: # pragma: no cover 

23 return None 

24 

25 # instance: the instance the descriptor is accessed from 

26 # owner: the class that owns the descriptor 

27 property_name = None 

28 for attr_name, attr_value in owner.__dict__.items(): 

29 if attr_value is self: 

30 property_name = attr_name 

31 break 

32 # return instance.__dict__.get(property_name, None) 

33 return property_name 

34 

35 def __get__(self, instance: type[Any], owner: type[Any]) -> Never: 

36 """ 

37 This magic method is called when a property is accessed. 

38 

39 Example: 

40 someclass.someprop will trigger the __get__ of `someprop` 

41 

42 Args: 

43 instance: the class on which the postponed property is defined, 

44 owner: `SingletonMeta` 

45 """ 

46 msg = f"Err: Using postponed property on {owner.__name__}" 

47 

48 if name := self.__get_property_name__(instance, owner): 

49 msg += f".{name}" 

50 

51 raise IsPostponedError(msg) 

52 

53 

54def postpone() -> Any: 

55 """ 

56 Can be used to mark a property as postponed, meaning the user will fill it in later (they promose). 

57 

58 If they don't fill it in and still try to use it, they will be met with a IsPostponedError. 

59 """ 

60 return Postponed()