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

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

22 from __future__ import annotations

23

24 from typing import TYPE_CHECKING, Any, Iterable, Literal

25

26 from paperap.const import ModelStatus

27

28 if TYPE_CHECKING:

29 from paperap.models.abstract import BaseModel

30

31

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