diff options
-rw-r--r-- | Doc/lib/libmimetypes.tex | 25 | ||||
-rw-r--r-- | Lib/mimetypes.py | 162 | ||||
-rw-r--r-- | Misc/NEWS | 5 |
3 files changed, 154 insertions, 38 deletions
diff --git a/Doc/lib/libmimetypes.tex b/Doc/lib/libmimetypes.tex index 3747fe1..64296f0 100644 --- a/Doc/lib/libmimetypes.tex +++ b/Doc/lib/libmimetypes.tex @@ -47,6 +47,20 @@ IANA types are supported; when \var{strict} is false, some additional non-standard but commonly used MIME types are also recognized. \end{funcdesc} +\begin{funcdesc}{guess_all_extensions}{type\optional{, strict}} +Guess the extensions for a file based on its MIME type, given by +\var{type}. +The return value is a list of strings giving all possible filename extensions, +including the leading dot (\character{.}). The extensions are not guaranteed +to have been associated with any particular data stream, but would be mapped +to the MIME type \var{type} by \function{guess_type()}. If no extension can +be guessed for \var{type}, \code{None} is returned. + +Optional \var{strict} has the same meaning as with the +\function{guess_type()} function. +\end{funcdesc} + + \begin{funcdesc}{guess_extension}{type\optional{, strict}} Guess the extension for a file based on its MIME type, given by \var{type}. @@ -83,6 +97,17 @@ not exist or cannot be read, \code{None} is returned. \end{funcdesc} +\begin{funcdesc}{add_type}{type, ext\optional{, strict}} +Add a mapping from the mimetype \var{type} to the extension \var{ext}. +When the extension is already known, the new type will replace the old +one. When the type is already known the extension will be added +to the list of known extensions. + +When \var{strict} is the mapping will added to the official +MIME types, otherwise to the non-standard ones. +\end{funcdesc} + + \begin{datadesc}{inited} Flag indicating whether or not the global data structures have been initialized. This is set to true by \function{init()}. diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py index ad13be3..846d56b 100644 --- a/Lib/mimetypes.py +++ b/Lib/mimetypes.py @@ -26,16 +26,20 @@ import os import posixpath import urllib -__all__ = ["guess_type","guess_extension","read_mime_types","init"] +__all__ = [ + "guess_type","guess_extension","guess_all_extensions", + "add_type","read_mime_types","init" +] knownfiles = [ + "/etc/mime.types", "/usr/local/etc/httpd/conf/mime.types", "/usr/local/lib/netscape/mime.types", "/usr/local/etc/httpd/conf/mime.types", # Apache 1.2 "/usr/local/etc/mime.types", # Apache 1.3 ] -inited = 0 +inited = False class MimeTypes: @@ -46,17 +50,38 @@ class MimeTypes: URL, and can guess a reasonable extension given a MIME type. """ - def __init__(self, filenames=()): + def __init__(self, filenames=(), strict=True): if not inited: init() self.encodings_map = encodings_map.copy() self.suffix_map = suffix_map.copy() - self.types_map = types_map.copy() - self.common_types = common_types.copy() + self.types_map = ({}, {}) # dict for (non-strict, strict) + self.types_map_inv = ({}, {}) + for (ext, type) in types_map.items(): + self.add_type(type, ext, True) + for (ext, type) in common_types.items(): + self.add_type(type, ext, False) for name in filenames: - self.read(name) + self.read(name, strict) - def guess_type(self, url, strict=1): + def add_type(self, type, ext, strict=True): + """Add a mapping between a type and and extension. + + When the extension is already known, the new + type will replace the old one. When the type + is already known the extension will be added + to the list of known extensions. + + If strict is true, information will be added to + list of standard types, else to the list of non-standard + types. + """ + self.types_map[strict][ext] = type + exts = self.types_map_inv[strict].setdefault(type, []) + if ext not in exts: + exts.append(ext) + + def guess_type(self, url, strict=True): """Guess the type of a file based on its URL. Return value is a tuple (type, encoding) where type is None if @@ -72,7 +97,7 @@ class MimeTypes: mapped to '.tar.gz'. (This is table-driven too, using the dictionary suffix_map.) - Optional `strict' argument when false adds a bunch of commonly found, + Optional `strict' argument when False adds a bunch of commonly found, but non-standard types. """ scheme, url = urllib.splittype(url) @@ -103,22 +128,44 @@ class MimeTypes: base, ext = posixpath.splitext(base) else: encoding = None - types_map = self.types_map - common_types = self.common_types + types_map = self.types_map[True] if ext in types_map: return types_map[ext], encoding elif ext.lower() in types_map: return types_map[ext.lower()], encoding elif strict: return None, encoding - elif ext in common_types: - return common_types[ext], encoding - elif ext.lower() in common_types: - return common_types[ext.lower()], encoding + types_map = self.types_map[False] + if ext in types_map: + return types_map[ext], encoding + elif ext.lower() in types_map: + return types_map[ext.lower()], encoding else: return None, encoding - def guess_extension(self, type, strict=1): + def guess_all_extensions(self, type, strict=True): + """Guess the extensions for a file based on its MIME type. + + Return value is a list of strings giving the possible filename + extensions, including the leading dot ('.'). The extension is not + guaranteed to have been associated with any particular data + stream, but would be mapped to the MIME type `type' by + guess_type(). If no extension can be guessed for `type', None + is returned. + + Optional `strict' argument when false adds a bunch of commonly found, + but non-standard types. + """ + type = type.lower() + extensions = self.types_map_inv[True].get(type, []) + if not strict: + for ext in self.types_map_inv[False].get(type, []): + if ext not in extensions: + extensions.append(ext) + if len(extensions): + return extensions + + def guess_extension(self, type, strict=True): """Guess the extension for a file based on its MIME type. Return value is a string giving a filename extension, @@ -131,25 +178,31 @@ class MimeTypes: Optional `strict' argument when false adds a bunch of commonly found, but non-standard types. """ - type = type.lower() - for ext, stype in self.types_map.items(): - if type == stype: - return ext - if not strict: - for ext, stype in common_types.items(): - if type == stype: - return ext - return None + extensions = self.guess_all_extensions(type, strict) + if extensions is not None: + extensions = extensions[0] + return extensions + + def read(self, filename, strict=True): + """ + Read a single mime.types-format file, specified by pathname. - def read(self, filename): - """Read a single mime.types-format file, specified by pathname.""" + If strict is true, information will be added to + list of standard types, else to the list of non-standard + types. + """ fp = open(filename) self.readfp(fp) fp.close() - def readfp(self, fp): - """Read a single mime.types-format file.""" - map = self.types_map + def readfp(self, fp, strict=True): + """ + Read a single mime.types-format file. + + If strict is true, information will be added to + list of standard types, else to the list of non-standard + types. + """ while 1: line = fp.readline() if not line: @@ -162,11 +215,11 @@ class MimeTypes: if not words: continue type, suffixes = words[0], words[1:] + suffixes = [ '.' + suff for suff in suffixes ] for suff in suffixes: - map['.' + suff] = type - + self.add_type(type, suff, strict) -def guess_type(url, strict=1): +def guess_type(url, strict=True): """Guess the type of a file based on its URL. Return value is a tuple (type, encoding) where type is None if the @@ -188,7 +241,23 @@ def guess_type(url, strict=1): return guess_type(url, strict) -def guess_extension(type, strict=1): +def guess_all_extensions(type, strict=True): + """Guess the extensions for a file based on its MIME type. + + Return value is a list of strings giving the possible filename + extensions, including the leading dot ('.'). The extension is not + guaranteed to have been associated with any particular data + stream, but would be mapped to the MIME type `type' by + guess_type(). If no extension can be guessed for `type', None + is returned. + + Optional `strict' argument when false adds a bunch of commonly found, + but non-standard types. + """ + init() + return guess_all_extensions(type, strict) + +def guess_extension(type, strict=True): """Guess the extension for a file based on its MIME type. Return value is a string giving a filename extension, including the @@ -203,12 +272,27 @@ def guess_extension(type, strict=1): init() return guess_extension(type, strict) +def add_type(self, type, ext, strict=True): + """Add a mapping between a type and and extension. + + When the extension is already known, the new + type will replace the old one. When the type + is already known the extension will be added + to the list of known extensions. + + If strict is true, information will be added to + list of standard types, else to the list of non-standard + types. + """ + init() + return add_type(type, ext, strict) + def init(files=None): - global guess_extension, guess_type + global guess_all_extensions, guess_extension, guess_type global suffix_map, types_map, encodings_map, common_types - global inited - inited = 1 + global add_type, inited + inited = True db = MimeTypes() if files is None: files = knownfiles @@ -217,10 +301,12 @@ def init(files=None): db.readfp(open(file)) encodings_map = db.encodings_map suffix_map = db.suffix_map - types_map = db.types_map + types_map = db.types_map[True] + guess_all_extensions = db.guess_all_extensions guess_extension = db.guess_extension guess_type = db.guess_type - common_types = db.common_types + add_type = db.add_type + common_types = db.types_map[False] def read_mime_types(file): @@ -321,6 +321,11 @@ Extension modules Library +- mimetypes has two new functions: guess_all_extensions() which + returns a list of all known extensions for a mime type, and + add_type() which adds one mapping between a mime type and + an extension to the database. + - New module: sets, defines the class Set that implements a mutable set type using the keys of a dict to represent the set. There's also a class ImmutableSet which is useful when you need sets of sets |