Coverage for src/paperap/const.py: 92%

189 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-03-20 13:17 -0400

1""" 

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

3 

4 METADATA: 

5 

6 File: const.py 

7 Project: paperap 

8 Created: 2025-03-04 

9 Version: 0.0.8 

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-04 By Jess Mann 

19 

20""" 

21 

22from __future__ import annotations 

23 

24import logging 

25from datetime import datetime 

26from enum import Enum, IntEnum, StrEnum 

27from string import Template 

28from typing import ( 

29 Any, 

30 Iterator, 

31 Literal, 

32 NotRequired, 

33 Protocol, 

34 Required, 

35 Self, 

36 TypeAlias, 

37 TypedDict, 

38 override, 

39 runtime_checkable, 

40) 

41 

42import pydantic 

43from pydantic import ConfigDict, Field 

44 

45logger = logging.getLogger(__name__) 

46 

47 

48class ConstModel(pydantic.BaseModel): 

49 model_config = ConfigDict( 

50 from_attributes=True, 

51 extra="forbid", 

52 use_enum_values=True, 

53 validate_default=True, 

54 validate_assignment=True, 

55 ) 

56 

57 @override 

58 def __eq__(self, other: Any) -> bool: 

59 if isinstance(other, dict): 

60 # Ensure the dictionary keys match the model fields 

61 expected_keys = set(self.model_fields.keys()) 

62 if set(other.keys()) != expected_keys: 

63 return False 

64 return all(getattr(self, key) == other.get(key) for key in expected_keys) 

65 

66 # This check probably isn't necessary before calling super (TODO?) 

67 if isinstance(other, self.__class__): 

68 # Compare all fields of the model 

69 return self.model_dump() == other.model_dump() 

70 

71 return super().__eq__(other) 

72 

73 

74class URLS: 

75 index: Template = Template("/api/") 

76 token: Template = Template("/api/token/") 

77 list: Template = Template("/api/${resource}/") 

78 detail: Template = Template("/api/${resource}/${pk}/") 

79 create: Template = Template("/api/${resource}/") 

80 update: Template = Template("/api/${resource}/${pk}/") 

81 delete: Template = Template("/api/${resource}/${pk}/") 

82 meta: Template = Template("/api/document/${pk}/metadata/") 

83 next_asn: Template = Template("/api/document/next_asn/") 

84 notes: Template = Template("/api/document/${pk}/notes/") 

85 post: Template = Template("/api/document/post_document/") 

86 single: Template = Template("/api/document/${pk}/") 

87 suggestions: Template = Template("/api/${resource}/${pk}/suggestions/") 

88 preview: Template = Template("/api/${resource}/${pk}/preview/") 

89 thumbnail: Template = Template("/api/${resource}/${pk}/thumb/") 

90 download: Template = Template("/api/${resource}/${pk}/download/") 

91 

92 

93CommonEndpoints: TypeAlias = Literal["list", "detail", "create", "update", "delete"] 

94Endpoints: TypeAlias = dict[CommonEndpoints | str, Template] 

95 

96 

97class FilteringStrategies(StrEnum): 

98 WHITELIST = "whitelist" 

99 BLACKLIST = "blacklist" 

100 ALLOW_ALL = "allow_all" 

101 ALLOW_NONE = "allow_none" 

102 

103 

104class ModelStatus(StrEnum): 

105 INITIALIZING = "initializing" 

106 UPDATING = "updating" 

107 SAVING = "saving" 

108 READY = "ready" 

109 ERROR = "error" 

110 

111 

112class CustomFieldTypes(StrEnum): 

113 STRING = "string" 

114 BOOLEAN = "boolean" 

115 INTEGER = "integer" 

116 FLOAT = "float" 

117 MONETARY = "monetary" 

118 DATE = "date" 

119 URL = "url" 

120 DOCUMENT_LINK = "documentlink" 

121 UNKNOWN = "unknown" 

122 

123 @override 

124 @classmethod 

125 def _missing_(cls, value: object) -> "Literal[CustomFieldTypes.UNKNOWN]": 

126 logger.debug("Handling unknown enum value", extra={"enum_class": cls.__name__, "value": value}) 

127 return cls.UNKNOWN 

128 

129 

130class CustomFieldValues(ConstModel): 

131 field: int 

132 value: Any 

133 

134 

135class CustomFieldTypedDict(TypedDict): 

136 field: int 

137 value: Any 

138 

139 

140class DocumentMetadataType(ConstModel): 

141 namespace: str | None = None 

142 prefix: str | None = None 

143 key: str | None = None 

144 value: str | None = None 

145 

146 

147class DocumentSearchHitType(ConstModel): 

148 score: float | None = None 

149 highlights: str | None = None 

150 note_highlights: str | None = None 

151 rank: int | None = None 

152 

153 

154class MatchingAlgorithmType(IntEnum): 

155 NONE = 0 

156 ANY = 1 

157 ALL = 2 

158 LITERAL = 3 

159 REGEX = 4 

160 FUZZY = 5 

161 AUTO = 6 

162 UNKNOWN = -1 

163 

164 @override 

165 @classmethod 

166 def _missing_(cls, value: object) -> "Literal[MatchingAlgorithmType.UNKNOWN]": 

167 logger.debug("Handling unknown enum value", extra={"enum_class": cls.__name__, "value": value}) 

168 return cls.UNKNOWN 

169 

170 

171class PermissionSetType(ConstModel): 

172 users: list[int] = Field(default_factory=list) 

173 groups: list[int] = Field(default_factory=list) 

174 

175 

176class PermissionTableType(ConstModel): 

177 view: PermissionSetType = Field(default_factory=PermissionSetType) 

178 change: PermissionSetType = Field(default_factory=PermissionSetType) 

179 

180 

181class RetrieveFileMode(StrEnum): 

182 DOWNLOAD = "download" 

183 PREVIEW = "preview" 

184 THUMBNAIL = "thumb" 

185 

186 

187class SavedViewFilterRuleType(ConstModel): 

188 rule_type: int | None = None 

189 value: str | None = None 

190 

191 

192class ShareLinkFileVersionType(StrEnum): 

193 ARCHIVE = "archive" 

194 ORIGINAL = "original" 

195 UNKNOWN = "unknown" 

196 

197 @override 

198 @classmethod 

199 def _missing_(cls, value: object) -> "Literal[ShareLinkFileVersionType.UNKNOWN]": 

200 logger.debug("Handling unknown enum value", extra={"enum_class": cls.__name__, "value": value}) 

201 return cls.UNKNOWN 

202 

203 

204class StatusType(StrEnum): 

205 OK = "OK" 

206 ERROR = "ERROR" 

207 UNKNOWN = "UNKNOWN" 

208 

209 @override 

210 @classmethod 

211 def _missing_(cls, value: object) -> "Literal[StatusType.UNKNOWN]": 

212 logger.debug("Handling unknown enum value", extra={"enum_class": cls.__name__, "value": value}) 

213 return cls.UNKNOWN 

214 

215 

216class StatusDatabaseMigrationStatusType(ConstModel): 

217 latest_migration: str | None = None 

218 unapplied_migrations: list[str] = Field(default_factory=list) 

219 

220 

221class StatusDatabaseType(ConstModel): 

222 type: str | None = None 

223 url: str | None = None 

224 status: StatusType | None = None 

225 error: str | None = None 

226 migration_status: StatusDatabaseMigrationStatusType | None = None 

227 

228 

229class StatusStorageType(ConstModel): 

230 total: int | None = None 

231 available: int | None = None 

232 

233 

234class StatusTasksType(ConstModel): 

235 redis_url: str | None = None 

236 redis_status: StatusType | None = None 

237 redis_error: str | None = None 

238 celery_status: StatusType | None = None 

239 index_status: StatusType | None = None 

240 index_last_modified: datetime | None = None 

241 index_error: str | None = None 

242 classifier_status: StatusType | None = None 

243 classifier_last_trained: datetime | None = None 

244 classifier_error: str | None = None 

245 

246 

247class TaskStatusType(StrEnum): 

248 PENDING = "PENDING" 

249 STARTED = "STARTED" 

250 SUCCESS = "SUCCESS" 

251 FAILURE = "FAILURE" 

252 UNKNOWN = "UNKNOWN" 

253 

254 @override 

255 @classmethod 

256 def _missing_(cls, value: object) -> "Literal[TaskStatusType.UNKNOWN]": 

257 logger.debug("Handling unknown enum value", extra={"enum_class": cls.__name__, "value": value}) 

258 return cls.UNKNOWN 

259 

260 

261class WorkflowActionType(IntEnum): 

262 ASSIGNMENT = 1 

263 UNKNOWN = -1 

264 

265 @override 

266 @classmethod 

267 def _missing_(cls, value: object) -> "Literal[WorkflowActionType.UNKNOWN]": 

268 logger.debug("Handling unknown enum value", extra={"enum_class": cls.__name__, "value": value}) 

269 return cls.UNKNOWN 

270 

271 

272class WorkflowTriggerType(IntEnum): 

273 CONSUMPTION = 1 

274 DOCUMENT_ADDED = 2 

275 DOCUMENT_UPDATED = 3 

276 UNKNOWN = -1 

277 

278 @override 

279 @classmethod 

280 def _missing_(cls, value: object) -> "Literal[WorkflowTriggerType.UNKNOWN]": 

281 logger.debug("Handling unknown enum value", extra={"enum_class": cls.__name__, "value": value}) 

282 return cls.UNKNOWN 

283 

284 

285class WorkflowTriggerSourceType(IntEnum): 

286 CONSUME_FOLDER = 1 

287 API_UPLOAD = 2 

288 MAIL_FETCH = 3 

289 UNKNOWN = -1 

290 

291 @override 

292 @classmethod 

293 def _missing_(cls, value: object) -> "Literal[WorkflowTriggerSourceType.UNKNOWN]": 

294 logger.debug("Handling unknown enum value", extra={"enum_class": cls.__name__, "value": value}) 

295 return cls.UNKNOWN