Cat Feeder  1.0.0
The Cat feeder project
Loading...
Searching...
No Matches
http_constants.py
Go to the documentation of this file.
1r"""
2# +==== BEGIN CatFeeder =================+
3# LOGO:
4# ..............(..../\
5# ...............)..(.')
6# ..............(../..)
7# ...............\‍(__)|
8# Inspired by Joan Stark
9# source https://www.asciiart.eu/
10# animals/cats
11# /STOP
12# PROJECT: CatFeeder
13# FILE: http_constants.py
14# CREATION DATE: 19-11-2025
15# LAST Modified: 22:21:27 23-01-2026
16# DESCRIPTION:
17# This is the backend server in charge of making the actual website work.
18# /STOP
19# COPYRIGHT: (c) Cat Feeder
20# PURPOSE:
21# File containing the constants that are used by the http codes class.
22# Central definitions for HTTP-related constants:
23# - Known status codes
24# - Known MIME types (DATA_TYPES)
25# - DataTypes Enum (auto-mapped from DATA_TYPES and sorted)
26# - Grouped categories: FILE_TYPES, HTML_TYPES, JSON_TYPES, PLAIN_TEXT_TYPES, etc.
27# - Redirect type added ("redirect")
28#
29# This file is designed to be:
30# - Alphabetically sorted
31# - Fully deduplicated
32# - Easy to maintain
33# /STOP
34# // AR
35# +==== END CatFeeder =================+
36"""
37
38from __future__ import annotations
39from enum import Enum
40from dataclasses import dataclass
41from typing import Dict, List, Tuple, ClassVar, Optional, Set
42
43
44# ============================================================
45# HTTP STATUS CODES (Authorised)
46# ============================================================
47
48AUTHORISED_STATUSES: List[int] = [
49 # 1xx - Informational
50 100, 101, 102, 103, 110,
51 # 2xx - Successful
52 200, 201, 202, 203, 204, 205, 206, 207, 208, 226,
53 # 3xx - Redirection
54 300, 301, 302, 303, 304, 305, 306, 307, 308,
55 # 4xx - Client error
56 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411,
57 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423,
58 424, 425, 426, 428, 429, 430, 431, 451, 498,
59 # 5xx - Server error
60 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511
61]
62
63# ============================================================
64# ENUM (alphabetically sorted)
65# ============================================================
66
67
68class DataTypes(str, Enum):
69 """Enumeration of common HTTP content (MIME) types.
70
71 Member names are uppercased, hyphen replaced by underscore, and
72 prefixed with an underscore if starting with a digit (e.g. _3GP).
73 The value of each member is the canonical MIME type string.
74
75 Example:
76 >>> DataTypes.JSON.value
77 'application/json'
78 >>> DataTypes.from_key('json') is DataTypes.JSON
79 True
80
81 Use `from_key()` to resolve a member from the original lower-case
82 dictionary key (case-insensitive, supports hyphenated keys).
83 """
84 # Python 3.10 compatibility: ignore cache variables so they're not treated as enum members
85 _ignore_ = ['_key_to_value_cache', '_value_to_member_cache']
86
87 # Archive / Binary formats
88 _7Z = 'application/x-7z-compressed'
89 DIGIT_7Z = 'application/x-7z-compressed'
90 BZ2 = 'application/x-bzip2'
91 DMG = 'application/x-apple-diskimage'
92 GZIP = 'application/gzip'
93 GZ = 'application/gzip'
94 ISO = 'application/x-iso9660-image'
95 OCTET_STREAM = 'application/octet-stream'
96 RAR = 'application/vnd.rar'
97 TAR = 'application/x-tar'
98 TAR_GZ = 'application/gzip'
99 TAR_BZ2 = 'application/x-bzip2'
100 TAR_XZ = 'application/x-xz'
101 XZ = 'application/x-xz'
102 ZIP = 'application/zip'
103
104 # Audio formats
105 AAC = 'audio/aac'
106 AIFF = 'audio/aiff'
107 AMR = 'audio/amr'
108 FLAC = 'audio/flac'
109 M4A = 'audio/mp4'
110 MID = 'audio/midi'
111 MIDI = 'audio/midi'
112 MP3 = 'audio/mpeg'
113 OGG_AUDIO = 'audio/ogg'
114 OPUS = 'audio/opus'
115 WAV = 'audio/wav'
116
117 # Document formats
118 CSV = 'text/csv'
119 DOC = 'application/msword'
120 DOCX = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
121 EPUB = 'application/epub+zip'
122 GEOJSON = 'application/geo+json'
123 ICS = 'text/calendar'
124 JSON = 'application/json'
125 JSONLD = 'application/ld+json'
126 JSONPATCH = 'application/json-patch+json'
127 JSONSCHEMA = 'application/schema+json'
128 MARKDOWN = 'text/markdown'
129 MD = 'text/markdown'
130 ODS = 'application/vnd.oasis.opendocument.spreadsheet'
131 ODT = 'application/vnd.oasis.opendocument.text'
132 ODP = 'application/vnd.oasis.opendocument.presentation'
133 PDF = 'application/pdf'
134 PLAIN = 'text/plain'
135 PPT = 'application/vnd.ms-powerpoint'
136 PPTX = 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
137 RTF = 'application/rtf'
138 TEXT = 'text/plain'
139 TOML = 'application/toml'
140 TXT = 'text/plain'
141 XLS = 'application/vnd.ms-excel'
142 XLSX = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
143 YAML = 'application/yaml'
144 YML = 'application/yaml'
145 XHTML = "application/xhtml+xml"
146 RSS = "application/rss+xml"
147 ATOM = "application/atom+xml"
148
149 # Font formats
150 EOT = 'application/vnd.ms-fontobject'
151 OTF = 'font/otf'
152 TTF = 'font/ttf'
153 WOFF = 'font/woff'
154 WOFF2 = 'font/woff2'
155
156 # HTML / CSS / JS / XML
157 CSS = 'text/css'
158 FORM = 'application/x-www-form-urlencoded'
159 FORM_DATA = 'multipart/form-data'
160 MULTIPART = 'multipart/form-data' # Alias for FORM_DATA
161 HTML = 'text/html'
162 JAVASCRIPT = 'application/javascript'
163 JS = 'application/javascript'
164 XML = 'application/xml'
165
166 # Image formats
167 AVIF = 'image/avif'
168 BMP = 'image/bmp'
169 GIF = 'image/gif'
170 HEIC = 'image/heic'
171 HEIF = 'image/heif'
172 ICO = 'image/vnd.microsoft.icon'
173 JPEG = 'image/jpeg'
174 JPE = 'image/jpe'
175 JPG = 'image/jpeg'
176 PNG = 'image/png'
177 SVG = 'image/svg+xml'
178 TIFF = 'image/tiff'
179 WEBP = 'image/webp'
180 XICON = 'image/x-icon'
181 # Less common image types
182 GRIB = 'application/grib'
183 HDR = 'image/vnd.radiance'
184 ICNS = 'image/icns'
185 H5 = 'application/x-hdf5'
186 HDF = 'application/x-hdf'
187 JP2 = 'image/jp2'
188 J2K = 'image/jp2'
189 JPC = 'image/jp2'
190 JPF = 'image/jp2'
191 JPX = 'image/jp2'
192 J2C = 'image/jp2'
193 IM = 'image/im'
194 IIM = 'application/x-iim'
195 JFIF = 'image/jpeg'
196 MPO = 'image/mpo'
197 MSP = 'image/x-mspaint'
198 PALM = 'image/x-palm'
199 PCD = 'image/x-photo-cd'
200 PXR = 'image/pxr'
201 PBM = 'image/portable-bitmap'
202 PGM = 'image/portable-graymap'
203 PPM = 'image/portable-pixmap'
204 PNM = 'image/portable-anymap'
205 PFM = 'image/portable-floatmap'
206 PSD = 'image/vnd.adobe.photoshop'
207 QOI = 'image/qoi'
208 BW = 'image/bw'
209 RGB = 'image/rgb'
210 RGBA = 'image/rgba'
211 SGI = 'image/sgi'
212 RAS = 'image/cmu-raster'
213 ICB = 'image/tga'
214 VDA = 'image/tga'
215 VST = 'image/tga'
216 WMF = 'image/wmf'
217 EMF = 'image/emf'
218 DIB = "image/bmp" # DIB is essentially BMP
219 CUR = "image/x-icon" # Cursor files
220 PCX = "image/pcx" # PCX
221 DDS = "image/vnd.ms-dds" # DirectDraw Surface
222 EPS = "application/postscript" # Encapsulated PostScript
223 FIT = "image/fits" # FITS (astronomical)
224 FITS = "image/fits"
225 FLI = "video/fli" # FLI animation
226 FLC = "video/flc" # FLC animation
227 GBR = "image/gbr" # GIMP brush / old graphics
228 APNG = "image/apng" # Animated PNG
229 TIF = "image/tiff" # TIFF alternate extension
230 XBM = "image/x-xbitmap" # X bitmap
231 XPM = "image/x-xpixmap" # X pixmap
232
233 # Redirect pseudo-type
234 REDIRECT = 'application/redirect'
235
236 # Streaming
237 STREAM = 'application/octet-stream'
238
239 # Video formats
240 _3G2 = 'video/3gpp2'
241 DIGIT_3G2 = 'video/3gpp2'
242 _3GP = 'video/3gpp'
243 DIGIT_3GP = 'video/3gpp'
244 _3GPP = 'video/3gpp'
245 DIGIT_3GPP = 'video/3gpp'
246 _3GPP2 = 'video/3gpp2'
247 DIGIT_3GPP2 = 'video/3gpp2'
248 AVI = 'video/x-msvideo'
249 FLV = 'video/x-flv'
250 MKV = 'video/x-matroska'
251 MOV = 'video/quicktime'
252 MP4 = 'video/mp4'
253 MPEG = 'video/mpeg'
254 WEBM = 'video/webm'
255 OGG_VIDEO = "video/ogg"
256 WMV = "video/x-ms-wmv"
257 M4v = "video/x-m4v"
258
259 # WASM
260 WASM = 'application/wasm'
261 OGG = 'application/ogg'
262
263 # Not a mime
264 BASE16 = 'application/base16'
265 BASE32 = 'application/base32'
266 BASE64 = 'application/base64'
267 BASE85 = 'application/base85'
268 BYTES = 'application/bytes'
269
270 # Class cleaning + optimisation
271 _key_to_value_cache: ClassVar[Dict[str, str]] = {}
272 _value_to_member_cache: ClassVar[Dict[str, "DataTypes"]] = {}
273
274 @classmethod
275 def _init_cache(cls) -> None:
276 """Initialize internal caches, called on first use."""
277 # Access via __dict__ to bypass enum's __getattr__ in Python 3.10
278 key_cache = cls.__dict__.get('_key_to_value_cache', {})
279 val_cache = cls.__dict__.get('_value_to_member_cache', {})
280
281 # Only build if caches are empty (dicts start empty by definition)
282 if key_cache and val_cache:
283 return
284
285 # build the key->value dict once
286 key_to_value: Dict[str, str] = {}
287 for name, member in cls.__members__.items():
288 key_to_value[cls._normalize_key(name)] = member.value
289 cls._key_to_value_cache = key_to_value
290
291 # build the value->member dict once
292 value_to_member: Dict[str, "DataTypes"] = {}
293 for member in cls.__members__.values():
294 value_to_member[member.value] = member
295 cls._value_to_member_cache = value_to_member
296
297 @staticmethod
298 def _normalize_key(name: str) -> str:
299 """Convert enum member name to dictionary key."""
300 if name.startswith("_"):
301 return name[1:].lower()
302 if name.startswith("DIGIT_"):
303 return name[6:].lower()
304 return name.lower()
305
306 @classmethod
307 def from_key(cls, key: str) -> Optional['DataTypes']:
308 """Return enum member matching original DATA_TYPES key (case-insensitive)."""
309 norm = key.strip().lower()
310 cls._init_cache()
311
312 # Access via __dict__ to bypass enum's __getattr__ in Python 3.10
313 key_cache = cls.__dict__.get('_key_to_value_cache', {})
314 if not key_cache:
315 return None
316
317 value = key_cache.get(norm)
318 if not value:
319 return None
320
321 val_cache = cls.__dict__.get('_value_to_member_cache', {})
322 if not val_cache:
323 return None
324
325 return val_cache.get(value)
326
327 @classmethod
328 def get_dict(cls) -> Dict[str, str]:
329 """
330 Return a dictionary mapping normalized lowercase keys to MIME type strings.
331
332 The keys correspond to the naming convention used in DATA_TYPES:
333 - enum names are lowercased
334 - a leading underscore becomes a leading digit key (e.g. _3GP -> "3gp")
335 - underscores become hyphens only if originally used to escape illegal names
336
337 Example:
338 >>> DataTypes.get_dict()["json"]
339 'application/json'
340
341 Returns:
342 Dict[str, str]: A mapping of normalized string keys to MIME type strings.
343 """
344 cls._init_cache()
345 # Access via __dict__ to bypass enum's __getattr__ in Python 3.10
346 return cls.__dict__.get('_key_to_value_cache', {})
347
348# ============================================================
349# BASE MIME-TYPE DEFINITIONS
350# Alphabetically sorted
351# ============================================================
352
353
354DATA_TYPES: Dict[str, str] = DataTypes.get_dict()
355
356# File-like responses
357FILE_TYPES: Tuple[DataTypes, ...] = (
358 # Archives / binaries
359 DataTypes.ZIP, DataTypes.GZIP, DataTypes.TAR,
360 DataTypes._7Z, DataTypes.DIGIT_7Z,
361 DataTypes.BZ2, DataTypes.DMG, DataTypes.ISO, DataTypes.OCTET_STREAM, DataTypes.RAR,
362 DataTypes.TAR_GZ, DataTypes.TAR_BZ2, DataTypes.TAR_XZ, DataTypes.XZ,
363 # Fonts
364 DataTypes.EOT, DataTypes.OTF, DataTypes.TTF, DataTypes.WOFF, DataTypes.WOFF2,
365 # Audio
366 DataTypes.MP3, DataTypes.WAV, DataTypes.FLAC, DataTypes.AAC, DataTypes.OGG_AUDIO, DataTypes.OPUS,
367 DataTypes.M4A, DataTypes.AIFF, DataTypes.AMR, DataTypes.MID, DataTypes.MIDI,
368 # Video
369 DataTypes.MP4, DataTypes.MPEG, DataTypes.AVI,
370 DataTypes._3GP, DataTypes.DIGIT_3GP,
371 DataTypes._3GPP, DataTypes.DIGIT_3GPP,
372 DataTypes._3G2, DataTypes.DIGIT_3G2,
373 DataTypes._3GPP2, DataTypes.DIGIT_3GPP2,
374 DataTypes.MOV, DataTypes.FLV, DataTypes.MKV, DataTypes.WEBM, DataTypes.OGG_VIDEO,
375 DataTypes.WMV, DataTypes.M4v,
376 # Documents
377 DataTypes.PDF, DataTypes.RTF, DataTypes.DOC, DataTypes.DOCX,
378 DataTypes.XLS, DataTypes.XLSX, DataTypes.PPT, DataTypes.PPTX,
379 DataTypes.ODT, DataTypes.ODS, DataTypes.ODP, DataTypes.EPUB,
380 DataTypes.ICS, DataTypes.CSV, DataTypes.GEOJSON,
381 # Images
382 DataTypes.JPEG, DataTypes.JPG, DataTypes.JPE, DataTypes.PNG, DataTypes.GIF, DataTypes.BMP,
383 DataTypes.TIFF, DataTypes.WEBP, DataTypes.ICO, DataTypes.SVG, DataTypes.XICON, DataTypes.GRIB,
384 DataTypes.HDR, DataTypes.ICNS, DataTypes.H5, DataTypes.HDF, DataTypes.JP2, DataTypes.J2K,
385 DataTypes.JPC, DataTypes.JPF, DataTypes.JPX, DataTypes.J2C, DataTypes.IM, DataTypes.IIM,
386 DataTypes.JFIF, DataTypes.MPO, DataTypes.MSP, DataTypes.PALM, DataTypes.PCD, DataTypes.PXR,
387 DataTypes.PBM, DataTypes.PGM, DataTypes.PPM, DataTypes.PNM, DataTypes.PFM, DataTypes.PSD,
388 DataTypes.QOI, DataTypes.BW, DataTypes.RGB, DataTypes.RGBA, DataTypes.SGI, DataTypes.RAS,
389 DataTypes.ICB, DataTypes.VDA, DataTypes.VST, DataTypes.WMF, DataTypes.EMF, DataTypes.DIB,
390 DataTypes.CUR, DataTypes.PCX, DataTypes.DDS, DataTypes.EPS, DataTypes.FIT, DataTypes.FITS,
391 DataTypes.FLI, DataTypes.FLC, DataTypes.GBR, DataTypes.APNG, DataTypes.TIF, DataTypes.XBM,
392 DataTypes.XPM,
393 # Streaming / others
394 DataTypes.OGG, DataTypes.STREAM,
395 # JavaScript files (served as files, not inline)
396 DataTypes.JAVASCRIPT, DataTypes.JS,
397 # Form data (for file uploads and mixed content)
398 DataTypes.FORM_DATA, DataTypes.MULTIPART
399)
400
401# HTML-like responses
402HTML_TYPES: Tuple[DataTypes, ...] = (
403 DataTypes.CSS,
404 DataTypes.HTML,
405 DataTypes.XML,
406 # Form data for simple form submissions (not file uploads)
407 DataTypes.FORM
408)
409
410# JSON responses
411JSON_TYPES: Tuple[DataTypes, ...] = (
412 DataTypes.JSON,
413 DataTypes.JSONLD,
414 DataTypes.GEOJSON,
415 DataTypes.JSONPATCH,
416 DataTypes.JSONSCHEMA
417)
418
419# Plain text responses
420PLAIN_TEXT_TYPES: Tuple[DataTypes, ...] = (
421 DataTypes.CSV,
422 DataTypes.MARKDOWN,
423 DataTypes.MD,
424 DataTypes.PLAIN,
425 DataTypes.TEXT,
426 DataTypes.TOML,
427 DataTypes.TXT,
428 DataTypes.YAML,
429 DataTypes.YML
430)
431
432# Redirect responses
433REDIRECT_TYPES: Tuple[DataTypes, ...] = (
434 DataTypes.REDIRECT,
435)
436
437# Streaming responses
438STREAMING_TYPES: Tuple[DataTypes, ...] = (
439 DataTypes.STREAM,
440 DataTypes.OCTET_STREAM
441)
442
443# JSON-optimized responses
444UJSON_TYPES: Tuple[DataTypes, ...] = JSON_TYPES
445ORJSON_TYPES: Tuple[DataTypes, ...] = JSON_TYPES
446
447# ============================================================
448# DERIVED MIME TYPE VALUE SETS (for quick membership checks)
449# ============================================================
450
451
452def _build_mime_set(group: Tuple[DataTypes, ...]) -> Set[str]:
453 """Return a set of MIME type strings for the provided DataTypes group.
454
455 Using an explicit loop for clarity and easier debugging instead of a
456 comprehension per user preference.
457 """
458 result: Set[str] = set()
459 for member in group:
460 result.add(member.value)
461 return result
462
463
464# Build MIME sets with explicit loops (no inline comprehensions)
465FILE_MIME_TYPES: Set[str] = _build_mime_set(FILE_TYPES)
466HTML_MIME_TYPES: Set[str] = _build_mime_set(HTML_TYPES)
467JSON_MIME_TYPES: Set[str] = _build_mime_set(JSON_TYPES)
468PLAIN_TEXT_MIME_TYPES: Set[str] = _build_mime_set(PLAIN_TEXT_TYPES)
469REDIRECT_MIME_TYPES: Set[str] = _build_mime_set(REDIRECT_TYPES)
470STREAMING_MIME_TYPES: Set[str] = _build_mime_set(STREAMING_TYPES)
471UJSON_MIME_TYPES: Set[str] = _build_mime_set(UJSON_TYPES)
472ORJSON_MIME_TYPES: Set[str] = _build_mime_set(ORJSON_TYPES)
473
474# ============================================================
475# Default values for the response
476# ============================================================
477
478DEFAULT_MESSAGE_CONTENT: Dict[str, str] = {'msg': 'message'}
479
480DEFAULT_MESSAGE_TYPE: str = DataTypes.JSON
481
482# ============================================================
483# Media type groupings
484
485# Image types
486IMAGE_TYPES_UNIVERSAL: Tuple[DataTypes, ...] = (
487 DataTypes.PNG, DataTypes.JPEG, DataTypes.JPE,
488 DataTypes.JPG, DataTypes.GIF, DataTypes.SVG,
489 DataTypes.ICO, DataTypes.WEBP, DataTypes.APNG
490)
491IMAGE_TYPES_NEED_CONVERTING: Tuple[DataTypes, ...] = (
492 DataTypes.BMP, DataTypes.HEIC, DataTypes.HEIF, DataTypes.XICON, DataTypes.AVIF,
493 DataTypes.GRIB, DataTypes.HDR, DataTypes.ICNS, DataTypes.H5, DataTypes.HDF,
494 DataTypes.JP2, DataTypes.J2K, DataTypes.JPC, DataTypes.JPF, DataTypes.JPX, DataTypes.J2C,
495 DataTypes.IM, DataTypes.IIM, DataTypes.JFIF, DataTypes.MPO, DataTypes.MSP,
496 DataTypes.PALM, DataTypes.PCD, DataTypes.PBM, DataTypes.PGM, DataTypes.PPM,
497 DataTypes.PNM, DataTypes.PFM, DataTypes.PSD, DataTypes.QOI, DataTypes.BW,
498 DataTypes.RGB, DataTypes.RGBA, DataTypes.SGI, DataTypes.RAS, DataTypes.ICB,
499 DataTypes.VDA, DataTypes.VST, DataTypes.WMF, DataTypes.EMF, DataTypes.DIB,
500 DataTypes.CUR, DataTypes.PCX, DataTypes.DDS, DataTypes.EPS, DataTypes.FIT,
501 DataTypes.FITS, DataTypes.FLI, DataTypes.FLC, DataTypes.GBR, DataTypes.TIF,
502 DataTypes.XBM, DataTypes.XPM
503)
504IMAGE_TYPES_HEAVY: Tuple[DataTypes, ...] = (
505 DataTypes.BMP,
506 DataTypes.TIFF,
507 DataTypes.PNG, # large for photos
508 DataTypes.HEIC,
509 DataTypes.HEIF,
510 DataTypes.HDR,
511 DataTypes.JP2,
512 DataTypes.J2K,
513 DataTypes.JPC,
514 DataTypes.JPF,
515 DataTypes.JPX,
516 DataTypes.J2C,
517 DataTypes.PSD,
518 DataTypes.TIF
519)
520
521IMAGE_CONVERSION_TARGET: Dict[DataTypes, DataTypes] = {
522 DataTypes.BMP: DataTypes.WEBP,
523 DataTypes.HEIC: DataTypes.WEBP,
524 DataTypes.HEIF: DataTypes.WEBP,
525 DataTypes.XICON: DataTypes.PNG,
526 DataTypes.AVIF: DataTypes.WEBP,
527 DataTypes.TIFF: DataTypes.WEBP,
528 DataTypes.JPE: DataTypes.JPEG,
529 DataTypes.JPG: DataTypes.JPEG,
530 DataTypes.GRIB: DataTypes.PNG,
531 DataTypes.HDR: DataTypes.PNG,
532 DataTypes.ICNS: DataTypes.PNG,
533 DataTypes.H5: DataTypes.PNG,
534 DataTypes.HDF: DataTypes.PNG,
535 DataTypes.JP2: DataTypes.JPEG,
536 DataTypes.J2K: DataTypes.JPEG,
537 DataTypes.JPC: DataTypes.JPEG,
538 DataTypes.JPF: DataTypes.JPEG,
539 DataTypes.JPX: DataTypes.JPEG,
540 DataTypes.J2C: DataTypes.JPEG,
541 DataTypes.IM: DataTypes.PNG,
542 DataTypes.IIM: DataTypes.PNG,
543 DataTypes.JFIF: DataTypes.JPEG,
544 DataTypes.MPO: DataTypes.JPEG,
545 DataTypes.MSP: DataTypes.PNG,
546 DataTypes.PALM: DataTypes.PNG,
547 DataTypes.PCD: DataTypes.JPEG,
548 DataTypes.PBM: DataTypes.PNG,
549 DataTypes.PGM: DataTypes.PNG,
550 DataTypes.PPM: DataTypes.PNG,
551 DataTypes.PNM: DataTypes.PNG,
552 DataTypes.PFM: DataTypes.PNG,
553 DataTypes.PSD: DataTypes.PNG,
554 DataTypes.QOI: DataTypes.PNG,
555 DataTypes.BW: DataTypes.PNG,
556 DataTypes.RGB: DataTypes.PNG,
557 DataTypes.RGBA: DataTypes.PNG,
558 DataTypes.SGI: DataTypes.PNG,
559 DataTypes.RAS: DataTypes.PNG,
560 DataTypes.ICB: DataTypes.PNG,
561 DataTypes.VDA: DataTypes.PNG,
562 DataTypes.VST: DataTypes.PNG,
563 DataTypes.WMF: DataTypes.PNG,
564 DataTypes.EMF: DataTypes.PNG,
565 DataTypes.DIB: DataTypes.PNG,
566 DataTypes.CUR: DataTypes.PNG,
567 DataTypes.PCX: DataTypes.PNG,
568 DataTypes.DDS: DataTypes.PNG,
569 DataTypes.EPS: DataTypes.PNG,
570 DataTypes.FIT: DataTypes.PNG,
571 DataTypes.FITS: DataTypes.PNG,
572 DataTypes.FLI: DataTypes.GIF,
573 DataTypes.FLC: DataTypes.GIF,
574 DataTypes.GBR: DataTypes.PNG,
575 DataTypes.TIF: DataTypes.WEBP,
576 DataTypes.XBM: DataTypes.PNG,
577 DataTypes.XPM: DataTypes.PNG
578}
579
580# Video types
581VIDEO_TYPES_UNIVERSAL: Tuple[DataTypes, ...] = (
582 DataTypes.MP4, # H.264 + AAC assumed
583 DataTypes.WEBM, # VP8/VP9 (modern-safe)
584)
585
586VIDEO_TYPES_NEED_CONVERTING: Tuple[DataTypes, ...] = (
587 DataTypes.MKV,
588 DataTypes.AVI,
589 DataTypes.FLV,
590 DataTypes.MOV,
591 DataTypes.MPEG,
592 DataTypes._3GP,
593 DataTypes._3G2,
594 DataTypes._3GPP,
595 DataTypes._3GPP2,
596)
597
598VIDEO_TYPES_HEAVY: Tuple[DataTypes, ...] = (
599 DataTypes.MKV,
600 DataTypes.AVI,
601 DataTypes.MOV,
602 DataTypes.MPEG,
603)
604
605VIDEO_CONVERSION_TARGET: Dict[DataTypes, DataTypes] = {
606 DataTypes.MKV: DataTypes.MP4,
607 DataTypes.AVI: DataTypes.MP4,
608 DataTypes.FLV: DataTypes.MP4,
609 DataTypes.MOV: DataTypes.MP4,
610 DataTypes.MPEG: DataTypes.MP4,
611 DataTypes._3GP: DataTypes.MP4,
612 DataTypes._3G2: DataTypes.MP4,
613 DataTypes._3GPP: DataTypes.MP4,
614 DataTypes._3GPP2: DataTypes.MP4,
615}
616
617# Audio types
618AUDIO_TYPES_UNIVERSAL: Tuple[DataTypes, ...] = (
619 DataTypes.MP3,
620 DataTypes.WAV,
621 DataTypes.AAC,
622)
623
624AUDIO_TYPES_NEED_CONVERTING: Tuple[DataTypes, ...] = (
625 DataTypes.FLAC,
626 DataTypes.AIFF,
627 DataTypes.OPUS,
628 DataTypes.OGG_AUDIO,
629 DataTypes.M4A,
630 DataTypes.AMR,
631 DataTypes.MID,
632 DataTypes.MIDI,
633)
634
635AUDIO_TYPES_HEAVY: Tuple[DataTypes, ...] = (
636 DataTypes.WAV,
637 DataTypes.AIFF,
638 DataTypes.FLAC,
639 DataTypes.MID,
640 DataTypes.MIDI,
641)
642
643AUDIO_CONVERSION_TARGET: Dict[DataTypes, DataTypes] = {
644 DataTypes.FLAC: DataTypes.MP3,
645 DataTypes.AIFF: DataTypes.MP3,
646 DataTypes.OPUS: DataTypes.MP3,
647 DataTypes.OGG_AUDIO: DataTypes.MP3,
648 DataTypes.M4A: DataTypes.MP3,
649 DataTypes.AMR: DataTypes.MP3,
650 DataTypes.MID: DataTypes.MP3,
651 DataTypes.MIDI: DataTypes.MP3,
652}
653
654# Document types
655DOCUMENT_TYPES_UNIVERSAL: Tuple[DataTypes, ...] = (
656 DataTypes.PDF,
657 DataTypes.JSON,
658 DataTypes.PLAIN,
659 DataTypes.TEXT,
660 DataTypes.TXT,
661 DataTypes.CSV,
662 DataTypes.HTML,
663 DataTypes.XML,
664)
665
666DOCUMENT_TYPES_NEED_CONVERTING: Tuple[DataTypes, ...] = (
667 DataTypes.DOC,
668 DataTypes.DOCX,
669 DataTypes.PPT,
670 DataTypes.PPTX,
671 DataTypes.XLS,
672 DataTypes.XLSX,
673 DataTypes.ODS,
674 DataTypes.ODT,
675 DataTypes.ODP,
676 DataTypes.EPUB,
677 DataTypes.MARKDOWN,
678 DataTypes.MD,
679 DataTypes.RTF,
680 DataTypes.TOML,
681 DataTypes.YAML,
682 DataTypes.YML,
683)
684
685DOCUMENT_TYPES_HEAVY: Tuple[DataTypes, ...] = (
686 DataTypes.PDF,
687 DataTypes.PPTX,
688 DataTypes.DOCX,
689 DataTypes.XLSX,
690)
691
692DOCUMENT_CONVERSION_TARGET: Dict[DataTypes, DataTypes] = {
693 DataTypes.DOC: DataTypes.PDF,
694 DataTypes.DOCX: DataTypes.PDF,
695 DataTypes.PPT: DataTypes.PDF,
696 DataTypes.PPTX: DataTypes.PDF,
697 DataTypes.XLS: DataTypes.PDF,
698 DataTypes.XLSX: DataTypes.PDF,
699 DataTypes.ODS: DataTypes.PDF,
700 DataTypes.ODT: DataTypes.PDF,
701 DataTypes.ODP: DataTypes.PDF,
702 DataTypes.EPUB: DataTypes.PDF,
703 DataTypes.MARKDOWN: DataTypes.HTML,
704 DataTypes.MD: DataTypes.HTML,
705 DataTypes.RTF: DataTypes.PDF,
706 DataTypes.TOML: DataTypes.JSON,
707 DataTypes.YAML: DataTypes.JSON,
708 DataTypes.YML: DataTypes.JSON,
709}
710
711# Archive types
712ARCHIVE_TYPES_UNIVERSAL: Tuple[DataTypes, ...] = (
713 DataTypes.ZIP,
714)
715
716ARCHIVE_TYPES_NEED_CONVERTING: Tuple[DataTypes, ...] = (
717 DataTypes.RAR,
718 DataTypes._7Z,
719 DataTypes.BZ2,
720 DataTypes.TAR,
721 DataTypes.TAR_GZ,
722 DataTypes.TAR_BZ2,
723 DataTypes.TAR_XZ,
724 DataTypes.XZ,
725 DataTypes.GZIP,
726 DataTypes.ISO,
727 DataTypes.DMG,
728)
729
730ARCHIVE_TYPES_HEAVY: Tuple[DataTypes, ...] = (
731 DataTypes.ISO,
732 DataTypes.DMG,
733 DataTypes.TAR,
734 DataTypes.TAR_GZ,
735 DataTypes.TAR_BZ2,
736 DataTypes.TAR_XZ,
737 DataTypes.XZ,
738)
739
740ARCHIVE_CONVERSION_TARGET: Dict[DataTypes, DataTypes] = {
741 DataTypes.RAR: DataTypes.ZIP,
742 DataTypes._7Z: DataTypes.ZIP,
743 DataTypes.BZ2: DataTypes.ZIP,
744 DataTypes.TAR: DataTypes.ZIP,
745 DataTypes.GZIP: DataTypes.ZIP,
746 DataTypes.ISO: DataTypes.ZIP,
747 DataTypes.DMG: DataTypes.ZIP,
748 DataTypes.TAR_GZ: DataTypes.ZIP,
749 DataTypes.TAR_BZ2: DataTypes.ZIP,
750 DataTypes.TAR_XZ: DataTypes.ZIP,
751}
752
753# Font types
754FONT_TYPES_UNIVERSAL: Tuple[DataTypes, ...] = (
755 DataTypes.WOFF,
756 DataTypes.WOFF2,
757)
758
759FONT_TYPES_NEED_CONVERTING: Tuple[DataTypes, ...] = (
760 DataTypes.TTF,
761 DataTypes.OTF,
762 DataTypes.EOT,
763)
764
765FONT_TYPES_HEAVY: Tuple[DataTypes, ...] = (
766 DataTypes.TTF,
767 DataTypes.OTF,
768)
769
770FONT_CONVERSION_TARGET: Dict[DataTypes, DataTypes] = {
771 DataTypes.TTF: DataTypes.WOFF2,
772 DataTypes.OTF: DataTypes.WOFF2,
773 DataTypes.EOT: DataTypes.WOFF2,
774}
775
776# Stream binary types
777BINARY_TYPES_UNIVERSAL: Tuple[DataTypes, ...] = (
778 DataTypes.OCTET_STREAM,
779 DataTypes.STREAM,
780)
781
782BINARY_TYPES_NEED_CONVERTING: Tuple[DataTypes, ...] = ()
783BINARY_TYPES_HEAVY: Tuple[DataTypes, ...] = ()
784BINARY_CONVERSION_TARGET: Dict[DataTypes, DataTypes] = {}
785
786# Base types
787BASE_TYPES_UNIVERSAL: Tuple[DataTypes, ...] = (
788 DataTypes.BASE16,
789 DataTypes.BASE32,
790 DataTypes.BASE64,
791 DataTypes.BASE85,
792)
793BASE_TYPES_NEED_CONVERTING: Tuple[DataTypes, ...] = ()
794BASE_TYPES_HEAVY: Tuple[DataTypes, ...] = ()
795BASE_TYPES_CONVERSION_TARGET: Dict[DataTypes, DataTypes] = {}
796
797# ============================================================
798
799# lookup conversion table
800CONVERSION_TARGETS: Dict[DataTypes, DataTypes] = {}
801for d in (
802 IMAGE_CONVERSION_TARGET, VIDEO_CONVERSION_TARGET,
803 AUDIO_CONVERSION_TARGET, DOCUMENT_CONVERSION_TARGET,
804 ARCHIVE_CONVERSION_TARGET, FONT_CONVERSION_TARGET,
805 BINARY_CONVERSION_TARGET, BASE_TYPES_CONVERSION_TARGET
806):
807 CONVERSION_TARGETS.update(d)
808
809# ============================================================
810
811# Media type lookup tables
812
813
814@dataclass(frozen=True)
816 """Registry of media type groupings and conversion targets."""
817 # Images
818 image_universal: Tuple[DataTypes, ...]
819 image_needs_converting: Tuple[DataTypes, ...]
820 image_heavy: Tuple[DataTypes, ...]
821 image_conversion_targets: Dict[DataTypes, DataTypes]
822
823 # Video
824 video_universal: Tuple[DataTypes, ...]
825 video_needs_converting: Tuple[DataTypes, ...]
826 video_heavy: Tuple[DataTypes, ...]
827 video_conversion_targets: Dict[DataTypes, DataTypes]
828
829 # Audio
830 audio_universal: Tuple[DataTypes, ...]
831 audio_needs_converting: Tuple[DataTypes, ...]
832 audio_heavy: Tuple[DataTypes, ...]
833 audio_conversion_targets: Dict[DataTypes, DataTypes]
834
835 # Documents
836 document_universal: Tuple[DataTypes, ...]
837 document_needs_converting: Tuple[DataTypes, ...]
838 document_heavy: Tuple[DataTypes, ...]
839 document_conversion_targets: Dict[DataTypes, DataTypes]
840
841 # Archives
842 archive_universal: Tuple[DataTypes, ...]
843 archive_needs_converting: Tuple[DataTypes, ...]
844 archive_heavy: Tuple[DataTypes, ...]
845 archive_conversion_targets: Dict[DataTypes, DataTypes]
846
847 # Fonts
848 font_universal: Tuple[DataTypes, ...]
849 font_needs_converting: Tuple[DataTypes, ...]
850 font_heavy: Tuple[DataTypes, ...]
851 font_conversion_targets: Dict[DataTypes, DataTypes]
852
853 # Binary
854 binary_universal: Tuple[DataTypes, ...]
855 binary_needs_converting: Tuple[DataTypes, ...]
856 binary_heavy: Tuple[DataTypes, ...]
857 binary_conversion_targets: Dict[DataTypes, DataTypes]
858
859 # Base type
860 base_types_universal: Tuple[DataTypes, ...]
861 base_types_need_converting: Tuple[DataTypes, ...]
862 base_types_heavy: Tuple[DataTypes, ...]
863 base_types_conversion_targets: Dict[DataTypes, DataTypes]
864
865 # Conversion lookup
866 conversion_targets: Dict[DataTypes, DataTypes]
867
868 def is_image(self, mime: DataTypes) -> bool:
869 """Check if the given MIME type is an image.
870 Args:
871 mime (DataTypes): The MIME type to check.
872 Returns:
873 bool: True if it's an image, False otherwise.
874 """
875 return mime in self.image_universal or mime in self.image_needs_converting
876
877 def is_video(self, mime: DataTypes) -> bool:
878 """Check if the given MIME type is a video.
879 Args:
880 mime (DataTypes): The MIME type to check.
881 Returns:
882 bool: True if it's a video, False otherwise.
883 """
884 return mime in self.video_universal or mime in self.video_needs_converting
885
886 def is_audio(self, mime: DataTypes) -> bool:
887 """Check if the given MIME type is an audio.
888 Args:
889 mime (DataTypes): The MIME type to check.
890 Returns:
891 bool: True if it's an audio, False otherwise.
892 """
893 return mime in self.audio_universal or mime in self.audio_needs_converting
894
895 def is_document(self, mime: DataTypes) -> bool:
896 """Check if the given MIME type is a document.
897 Args:
898 mime (DataTypes): The MIME type to check.
899 Returns:
900 bool: True if it's a document, False otherwise.
901 """
902 return mime in self.document_universal or mime in self.document_needs_converting
903
904 def is_archive(self, mime: DataTypes) -> bool:
905 """Check if the given MIME type is an archive.
906 Args:
907 mime (DataTypes): The MIME type to check.
908 Returns:
909 bool: True if it's an archive, False otherwise.
910 """
911 return mime in self.archive_universal or mime in self.archive_needs_converting
912
913 def is_font(self, mime: DataTypes) -> bool:
914 """Check if the given MIME type is a font.
915 Args:
916 mime (DataTypes): The MIME type to check.
917 Returns:
918 bool: True if it's a font, False otherwise.
919 """
920 return mime in self.font_universal or mime in self.font_needs_converting
921
922 def is_binary(self, mime: DataTypes) -> bool:
923 """Check if the given MIME type is a binary stream.
924 Args:
925 mime (DataTypes): The MIME type to check.
926 Returns:
927 bool: True if it's a binary stream, False otherwise.
928 """
929 return mime in self.binary_universal or mime in self.binary_needs_converting
930
931 def is_base_type(self, mime: DataTypes) -> bool:
932 """Check if the given MIME type is a base (universal) type.
933 Args:
934 mime (DataTypes): The MIME type to check.
935 Returns:
936 bool: True if it's a base type, False otherwise.
937 """
938 return mime in self.base_types_universal or mime in self.base_types_need_converting
939
940 def is_heavy(self, mime: DataTypes) -> bool:
941 """Check if the given MIME type is considered heavy.
942 Args:
943 mime (DataTypes): The MIME type to check.
944 Returns:
945 bool: True if it's heavy, False otherwise.
946 """
947 return (
948 mime in self.image_heavy or
949 mime in self.video_heavy or
950 mime in self.audio_heavy or
951 mime in self.document_heavy or
952 mime in self.archive_heavy or
953 mime in self.font_heavy or
954 mime in self.binary_heavy
955 )
956
957 def is_supported(self, mime: DataTypes) -> bool:
958 """Check if the given MIME type is supported in any category.
959 Args:
960 mime (DataTypes): The MIME type to check.
961 Returns:
962 bool: True if supported, False otherwise.
963 """
964 return (
965 self.is_image(mime) or
966 self.is_video(mime) or
967 self.is_audio(mime) or
968 self.is_document(mime) or
969 self.is_archive(mime) or
970 self.is_font(mime) or
971 self.is_binary(mime)
972 )
973
974 def needs_conversion(self, mime: DataTypes) -> bool:
975 """Check if the given MIME type requires conversion.
976 Args:
977 mime (DataTypes): The MIME type to check.
978 Returns:
979 bool: True if conversion is needed, False otherwise.
980 """
981 return mime in MEDIA_TYPES.conversion_targets
982
983 def get_conversion_target(self, mime: DataTypes) -> Optional[DataTypes]:
984 """Get the conversion target MIME type for the given MIME type.
985 Args:
986 mime (DataTypes): The MIME type to check.
987 Returns:
988 Optional[DataTypes]: The target MIME type if conversion is needed, None otherwise.
989 """
990 return MEDIA_TYPES.conversion_targets.get(mime)
991
992
993MEDIA_TYPES = MediaTypeRegistry(
994 image_universal=IMAGE_TYPES_UNIVERSAL,
995 image_needs_converting=IMAGE_TYPES_NEED_CONVERTING,
996 image_heavy=IMAGE_TYPES_HEAVY,
997 image_conversion_targets=IMAGE_CONVERSION_TARGET,
998
999 video_universal=VIDEO_TYPES_UNIVERSAL,
1000 video_needs_converting=VIDEO_TYPES_NEED_CONVERTING,
1001 video_heavy=VIDEO_TYPES_HEAVY,
1002 video_conversion_targets=VIDEO_CONVERSION_TARGET,
1003
1004 audio_universal=AUDIO_TYPES_UNIVERSAL,
1005 audio_needs_converting=AUDIO_TYPES_NEED_CONVERTING,
1006 audio_heavy=AUDIO_TYPES_HEAVY,
1007 audio_conversion_targets=AUDIO_CONVERSION_TARGET,
1008
1009 document_universal=DOCUMENT_TYPES_UNIVERSAL,
1010 document_needs_converting=DOCUMENT_TYPES_NEED_CONVERTING,
1011 document_heavy=DOCUMENT_TYPES_HEAVY,
1012 document_conversion_targets=DOCUMENT_CONVERSION_TARGET,
1013
1014 archive_universal=ARCHIVE_TYPES_UNIVERSAL,
1015 archive_needs_converting=ARCHIVE_TYPES_NEED_CONVERTING,
1016 archive_heavy=ARCHIVE_TYPES_HEAVY,
1017 archive_conversion_targets=ARCHIVE_CONVERSION_TARGET,
1018
1019 font_universal=FONT_TYPES_UNIVERSAL,
1020 font_needs_converting=FONT_TYPES_NEED_CONVERTING,
1021 font_heavy=FONT_TYPES_HEAVY,
1022 font_conversion_targets=FONT_CONVERSION_TARGET,
1023
1024 binary_universal=BINARY_TYPES_UNIVERSAL,
1025 binary_needs_converting=BINARY_TYPES_NEED_CONVERTING,
1026 binary_heavy=BINARY_TYPES_HEAVY,
1027 binary_conversion_targets=BINARY_CONVERSION_TARGET,
1028
1029 base_types_universal=BASE_TYPES_UNIVERSAL,
1030 base_types_need_converting=BASE_TYPES_NEED_CONVERTING,
1031 base_types_heavy=BASE_TYPES_HEAVY,
1032 base_types_conversion_targets=BASE_TYPES_CONVERSION_TARGET,
1033
1034 conversion_targets=CONVERSION_TARGETS,
1035)
Optional[ 'DataTypes'] from_key(cls, str key)
Optional[DataTypes] get_conversion_target(self, DataTypes mime)
Set[str] _build_mime_set(Tuple[DataTypes,...] group)