Coverage for gws-app/gws/lib/mime/__init__.py: 96%
70 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-05 13:35 +0200
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-05 13:35 +0200
1"""MIME types.
3Defines constants for the MIME types used in the application (``PNG``, ``JSON``, ``GML3``
4and so on) and functions to normalize MIME types and to map them to and from file extensions.
6``get`` accepts a MIME type, a content type with parameters, a known alias (e.g.
7``application/vnd.ogc.gml`` or ``image/jpg``) or a file extension, and returns a normalized
8MIME type. Lookups that are not covered by the built-in tables fall back to the standard
9``mimetypes`` module.
11Example::
13 gws.lib.mime.get('image/jpg') # 'image/jpeg'
14 gws.lib.mime.get('png') # 'image/png'
15 gws.lib.mime.for_path('/data/report.pdf') # 'application/pdf'
16 gws.lib.mime.extension_for(gws.lib.mime.JPEG) # 'jpeg'
17"""
19from typing import Optional
21import mimetypes
23BIN = 'application/octet-stream'
24CSS = 'text/css'
25CSV = 'text/csv'
26DOC = 'application/msword'
27GEOJSON = 'application/geo+json'
28GIF = 'image/gif'
29GML = 'application/gml+xml'
30GML2 = 'application/gml+xml;version=2'
31GML3 = 'application/gml+xml;version=3'
32GZIP = 'application/gzip'
33HTML = 'text/html'
34JPEG = 'image/jpeg'
35JS = 'application/javascript'
36JSON = 'application/json'
37KML = 'application/vnd.google-earth.kml+xml'
38PDF = 'application/pdf'
39PNG = 'image/png'
40PPT = 'application/vnd.ms-powerpoint'
41SVG = 'image/svg+xml'
42TTF = 'application/x-font-ttf'
43TXT = 'text/plain'
44WEBP = 'image/webp'
45XLS = 'application/vnd.ms-excel'
46XML = 'text/xml'
47ZIP = 'application/zip'
50_common = {
51 BIN,
52 CSS,
53 CSV,
54 DOC,
55 GEOJSON,
56 GIF,
57 GML,
58 GML2,
59 GML3,
60 GZIP,
61 HTML,
62 JPEG,
63 JS,
64 JSON,
65 KML,
66 PDF,
67 PNG,
68 PPT,
69 SVG,
70 TTF,
71 TXT,
72 XLS,
73 XML,
74 ZIP,
75}
77_common_extensions = {
78 'css': CSS,
79 'csv': CSV,
80 'doc': DOC,
81 'gif': GIF,
82 'gml': GML,
83 'gml2': GML2,
84 'html': HTML,
85 'jpeg': JPEG,
86 'jpg': JPEG,
87 'js': JS,
88 'json': JSON,
89 'kml': KML,
90 'pdf': PDF,
91 'png': PNG,
92 'ppt': PPT,
93 'svg': SVG,
94 'ttf': TTF,
95 'txt': TXT,
96 'xls': XLS,
97 'xml': XML,
98 'zip': ZIP,
99}
101_aliases = {
102 'application/vnd.ogc.gml': GML2,
103 'application/vnd.ogc.gml/3.1.1': GML,
104 'application/gml:3': GML,
105 'application/xml;subtype=gml/2': GML2,
106 'application/xml;subtype=gml/3': GML,
107 'application/html': HTML,
108 'application/x-gzip': GZIP,
109 'application/x-pdf': PDF,
110 'image/jpg': JPEG,
111 'text/xhtml': HTML,
112 'application/xml': XML,
113 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': DOC,
114 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': XLS,
115 'application/vnd.openxmlformats-officedocument.presentationml.presentation': PPT,
116}
119def get(mt: str) -> Optional[str]:
120 """Return the normalized MIME type.
122 Args:
123 mt: MIME type, content type, alias or file extension. Case and spaces are ignored.
125 Returns:
126 The normalized MIME type, or ``None`` if it is unknown.
127 """
129 if not mt:
130 return None
132 mt = mt.strip().replace(' ', '').lower()
134 s = _get_quick(mt)
135 if s:
136 return s
138 for s, m in _aliases.items():
139 if mt.startswith(s):
140 return m
142 if ';' in mt:
143 p = mt.partition(';')
144 s = _get_quick(p[0].strip())
145 if s:
146 return s
148 if '/' in mt and mimetypes.guess_extension(mt):
149 return mt
151 t, _ = mimetypes.guess_type('x.' + mt)
152 return t
155def _get_quick(mt):
156 """Look up a MIME type, an extension or an alias in the built-in tables."""
157 if mt in _common:
158 return mt
159 if mt in _common_extensions:
160 return _common_extensions[mt]
161 if mt in _aliases:
162 return _aliases[mt]
165def for_path(path: str) -> str:
166 """Return the MIME type for a file path, based on its extension.
168 Args:
169 path: File path or name.
171 Returns:
172 The MIME type, or ``BIN`` if it is unknown.
173 """
174 _, _, e = path.rpartition('.')
175 if e in _common_extensions:
176 return _common_extensions[e]
177 t, _ = mimetypes.guess_type(path)
178 return t or BIN
181def extension_for(mt: str, default: str = 'bin') -> str:
182 """Return the file extension for a MIME type.
184 Args:
185 mt: Normalized MIME type.
186 default: Extension to return if the MIME type is unknown.
188 Returns:
189 The extension, without a dot.
190 """
192 for ext, rt in _common_extensions.items():
193 if rt == mt:
194 return ext
195 s = mimetypes.guess_extension(mt)
196 if s:
197 return s[1:]
198 return default