Coverage for src/paperap/models/abstract/meta.py: 100%

31 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-03-12 23:40 -0400

1""" 

2---------------------------------------------------------------------------- 

3 

4 METADATA: 

5 

6 File: meta.py 

7 Project: paperap 

8 Created: 2025-03-07 

9 Version: 0.0.5 

10 Author: Jess Mann 

11 Email: jess@jmann.me 

12 Copyright (c) 2025 Jess Mann 

13 

14---------------------------------------------------------------------------- 

15 

16 LAST MODIFIED: 

17 

18 2025-03-07 By Jess Mann 

19 

20""" 

21 

22from __future__ import annotations 

23 

24from typing import TYPE_CHECKING, Any, Iterable, Literal 

25 

26from paperap.const import ModelStatus 

27 

28if TYPE_CHECKING: 

29 from paperap.models.abstract import BaseModel 

30 

31 

32class StatusContext: 

33 """ 

34 Context manager for safely updating model status. 

35 

36 Attributes: 

37 model (SomeModel): The model whose status is being updated. 

38 new_status (ModelStatus): The status to set within the context. 

39 previous_status (ModelStatus): The status before entering the context. 

40 

41 Examples: 

42 >>> class SomeModel(BaseModel): 

43 ... def perform_update(self): 

44 ... with StatusContext(self, ModelStatus.UPDATING): 

45 ... # Perform an update 

46 

47 """ 

48 

49 _model: "BaseModel" 

50 _new_status: ModelStatus 

51 _previous_status: ModelStatus | None 

52 

53 @property 

54 def model(self) -> "BaseModel": 

55 """Read-only access to the model.""" 

56 return self._model 

57 

58 @property 

59 def _meta(self) -> "BaseModel.Meta": 

60 """Read-only access to the model's meta.""" 

61 return self.model._meta # pyright: ignore[reportPrivateUsage] # pylint: disable=protected-access 

62 

63 @property 

64 def new_status(self) -> ModelStatus: 

65 """Read-only access to the new status.""" 

66 return self._new_status 

67 

68 @property 

69 def previous_status(self) -> ModelStatus | None: 

70 """Read-only access to the previous status.""" 

71 return self._previous_status 

72 

73 def __init__(self, model: "BaseModel", new_status: ModelStatus) -> None: 

74 self._model = model 

75 self._new_status = new_status 

76 self._previous_status = None 

77 super().__init__() 

78 

79 def __enter__(self) -> None: 

80 self._previous_status = self._meta.status 

81 self._meta.status = self.new_status 

82 # Do NOT return context manager, because we want to guarantee that the status is reverted 

83 # so we do not want to allow access to the context manager object 

84 

85 def __exit__( 

86 self, exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: Iterable[Any] 

87 ) -> None: 

88 if self.previous_status is not None: 

89 self._meta.status = self.previous_status 

90 else: 

91 self._meta.status = ModelStatus.ERROR