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

18 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2026-05-01 16:57 +0200

1""" 

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

3""" 

4 

5from typing import Any, Never, Optional 

6 

7from .errors import IsPostponedError 

8from .singleton import Singleton 

9 

10 

11class Postponed(Singleton): 

12 """ 

13 Class returned by `postpone` below. 

14 """ 

15 

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

17 """ 

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

19 """ 

20 if not instance: # pragma: no cover 

21 return None 

22 

23 # instance: the instance the descriptor is accessed from 

24 # owner: the class that owns the descriptor 

25 property_name = None 

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

27 if attr_value is self: 

28 property_name = attr_name 

29 break 

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

31 return property_name 

32 

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

34 """ 

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

36 

37 Example: 

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

39 

40 Args: 

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

42 owner: `SingletonMeta` 

43 """ 

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

45 

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

47 msg += f".{name}" 

48 

49 raise IsPostponedError(msg) 

50 

51 

52def postpone() -> Any: 

53 """ 

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

55 

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

57 """ 

58 return Postponed()