Coverage for youversion/models/commons.py: 100%

33 statements  

« prev     ^ index     » next       coverage.py v7.14.3, created at 2026-06-26 11:31 +0100

1"""Common models for YouVersion API responses.""" 

2 

3from typing import Any, Protocol 

4 

5try: 

6 from typing import TypeAlias 

7except ImportError: 

8 # Python < 3.10 compatibility 

9 from typing import TypeAlias 

10 

11 

12class ReactionModelProtocol(Protocol): 

13 """Protocol for reaction-based models (comments, likes).""" 

14 

15 enabled: bool 

16 count: int 

17 strings: dict[str, Any] 

18 all: list[Any] 

19 

20 def __getattr__(self, name: str) -> Any: 

21 """Allow access to dynamically added fields.""" 

22 class_name = self.__class__.__name__ 

23 raise AttributeError(f"'{class_name}' has no attribute '{name}'") 

24 

25 

26# Type alias for convenience 

27ReactionModel: TypeAlias = ReactionModelProtocol 

28 

29 

30class BodyImageProtocol(Protocol): 

31 """Protocol for body image objects.""" 

32 

33 height: int 

34 width: int 

35 url: str 

36 

37 def __getattr__(self, name: str) -> Any: 

38 """Allow access to dynamically added fields.""" 

39 class_name = self.__class__.__name__ 

40 raise AttributeError(f"'{class_name}' has no attribute '{name}'") 

41 

42 

43# Type alias for convenience 

44BodyImage: TypeAlias = BodyImageProtocol 

45 

46 

47class ActionProtocol(Protocol): 

48 """Protocol for action objects.""" 

49 

50 deletable: bool 

51 editable: bool 

52 read: bool 

53 show: bool 

54 

55 def __getattr__(self, name: str) -> Any: 

56 """Allow access to dynamically added fields.""" 

57 class_name = self.__class__.__name__ 

58 raise AttributeError(f"'{class_name}' has no attribute '{name}'") 

59 

60 

61# Type alias for convenience 

62Action: TypeAlias = ActionProtocol 

63 

64 

65class UserProtocol(Protocol): 

66 """Protocol for user objects.""" 

67 

68 id: Any | None # Can be str or int 

69 path: str 

70 user_name: str | None 

71 

72 def __getattr__(self, name: str) -> Any: 

73 """Allow access to dynamically added fields.""" 

74 class_name = self.__class__.__name__ 

75 raise AttributeError(f"'{class_name}' has no attribute '{name}'") 

76 

77 

78# Type alias for convenience 

79User: TypeAlias = UserProtocol 

80 

81 

82class CommentProtocol(Protocol): 

83 """Protocol for comment objects.""" 

84 

85 enabled: bool 

86 count: int 

87 strings: dict[str, Any] 

88 all: list[Any] 

89 

90 def __getattr__(self, name: str) -> Any: 

91 """Allow access to dynamically added fields.""" 

92 class_name = self.__class__.__name__ 

93 raise AttributeError(f"'{class_name}' has no attribute '{name}'") 

94 

95 

96# Type alias for convenience 

97Comment: TypeAlias = CommentProtocol 

98 

99 

100class LikeProtocol(Protocol): 

101 """Protocol for like objects.""" 

102 

103 enabled: bool 

104 count: int 

105 strings: dict[str, Any] 

106 all: list[Any] 

107 is_liked: bool 

108 user_ids: list[int] | None 

109 

110 def __getattr__(self, name: str) -> Any: 

111 """Allow access to dynamically added fields.""" 

112 class_name = self.__class__.__name__ 

113 raise AttributeError(f"'{class_name}' has no attribute '{name}'") 

114 

115 

116# Type alias for convenience 

117Like: TypeAlias = LikeProtocol