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

49 statements  

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

1"""Events and church finder data models.""" 

2 

3from datetime import datetime 

4from typing import Any, Protocol 

5 

6try: 

7 from typing import TypeAlias 

8except ImportError: 

9 # Python < 3.10 compatibility 

10 from typing import TypeAlias 

11 

12 

13class EventLocationProtocol(Protocol): 

14 """Protocol for event location information.""" 

15 

16 name: str 

17 address: str | None 

18 city: str | None 

19 state: str | None 

20 country: str | None 

21 latitude: float | None 

22 longitude: float | None 

23 

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

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

26 class_name = self.__class__.__name__ 

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

28 

29 

30# Type alias for convenience 

31EventLocation: TypeAlias = EventLocationProtocol 

32 

33 

34class EventTimeProtocol(Protocol): 

35 """Protocol for event time information.""" 

36 

37 start_time: datetime | None 

38 end_time: datetime | None 

39 timezone: str | None 

40 recurring: str | None 

41 

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

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

44 class_name = self.__class__.__name__ 

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

46 

47 

48# Type alias for convenience 

49EventTime: TypeAlias = EventTimeProtocol 

50 

51 

52class EventContentProtocol(Protocol): 

53 """Protocol for event content information.""" 

54 

55 title: str 

56 description: str | None 

57 image_url: str | None 

58 website_url: str | None 

59 

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

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

62 class_name = self.__class__.__name__ 

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

64 

65 

66# Type alias for convenience 

67EventContent: TypeAlias = EventContentProtocol 

68 

69 

70class EventProtocol(Protocol): 

71 """Protocol for event information.""" 

72 

73 id: int 

74 content: EventContent 

75 location: EventLocation 

76 time: EventTime 

77 created_dt: datetime | None 

78 updated_dt: datetime | None 

79 

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

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

82 class_name = self.__class__.__name__ 

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

84 

85 

86# Type alias for convenience 

87Event: TypeAlias = EventProtocol 

88 

89 

90class SavedEventProtocol(Protocol): 

91 """Protocol for saved event information.""" 

92 

93 event: Event 

94 saved_dt: datetime | None 

95 comments: dict[str, Any] | None 

96 

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

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

99 class_name = self.__class__.__name__ 

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

101 

102 

103# Type alias for convenience 

104SavedEvent: TypeAlias = SavedEventProtocol 

105 

106 

107class SavedEventsProtocol(Protocol): 

108 """Protocol for saved events list.""" 

109 

110 events: list[SavedEvent] 

111 total: int 

112 

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

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

115 class_name = self.__class__.__name__ 

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

117 

118 

119# Type alias for convenience 

120SavedEvents: TypeAlias = SavedEventsProtocol 

121 

122 

123class SearchEventProtocol(Protocol): 

124 """Protocol for search event result.""" 

125 

126 event: Event 

127 distance: float | None 

128 relevance_score: float | None 

129 

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

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

132 class_name = self.__class__.__name__ 

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

134 

135 

136# Type alias for convenience 

137SearchEvent: TypeAlias = SearchEventProtocol 

138 

139 

140class SearchEventsProtocol(Protocol): 

141 """Protocol for search events results.""" 

142 

143 events: list[SearchEvent] 

144 total: int 

145 query: str | None 

146 

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

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

149 class_name = self.__class__.__name__ 

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

151 

152 

153# Type alias for convenience 

154SearchEvents: TypeAlias = SearchEventsProtocol 

155 

156 

157class EventConfigurationProtocol(Protocol): 

158 """Protocol for event configuration.""" 

159 

160 categories: list[dict[str, Any]] 

161 filters: list[dict[str, Any]] 

162 sort_options: list[dict[str, Any]] 

163 

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

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

166 class_name = self.__class__.__name__ 

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

168 

169 

170# Type alias for convenience 

171EventConfiguration: TypeAlias = EventConfigurationProtocol