Commit 38a7b6de authored by Walter Dörwald's avatar Walter Dörwald

Apply diff3.txt (plus additional documentation)

from SF patch http://www.python.org/sf/554192

This adds two new functions to mimetypes:
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.
parent 95ae3dda
...@@ -47,6 +47,20 @@ IANA types are supported; when \var{strict} is false, some additional ...@@ -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. non-standard but commonly used MIME types are also recognized.
\end{funcdesc} \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}} \begin{funcdesc}{guess_extension}{type\optional{, strict}}
Guess the extension for a file based on its MIME type, given by Guess the extension for a file based on its MIME type, given by
\var{type}. \var{type}.
...@@ -83,6 +97,17 @@ not exist or cannot be read, \code{None} is returned. ...@@ -83,6 +97,17 @@ not exist or cannot be read, \code{None} is returned.
\end{funcdesc} \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} \begin{datadesc}{inited}
Flag indicating whether or not the global data structures have been Flag indicating whether or not the global data structures have been
initialized. This is set to true by \function{init()}. initialized. This is set to true by \function{init()}.
......
...@@ -26,16 +26,20 @@ import os ...@@ -26,16 +26,20 @@ import os
import posixpath import posixpath
import urllib 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 = [ knownfiles = [
"/etc/mime.types",
"/usr/local/etc/httpd/conf/mime.types", "/usr/local/etc/httpd/conf/mime.types",
"/usr/local/lib/netscape/mime.types", "/usr/local/lib/netscape/mime.types",
"/usr/local/etc/httpd/conf/mime.types", # Apache 1.2 "/usr/local/etc/httpd/conf/mime.types", # Apache 1.2
"/usr/local/etc/mime.types", # Apache 1.3 "/usr/local/etc/mime.types", # Apache 1.3
] ]
inited = 0 inited = False
class MimeTypes: class MimeTypes:
...@@ -46,17 +50,38 @@ class MimeTypes: ...@@ -46,17 +50,38 @@ class MimeTypes:
URL, and can guess a reasonable extension given a MIME type. URL, and can guess a reasonable extension given a MIME type.
""" """
def __init__(self, filenames=()): def __init__(self, filenames=(), strict=True):
if not inited: if not inited:
init() init()
self.encodings_map = encodings_map.copy() self.encodings_map = encodings_map.copy()
self.suffix_map = suffix_map.copy() self.suffix_map = suffix_map.copy()
self.types_map = types_map.copy() self.types_map = ({}, {}) # dict for (non-strict, strict)
self.common_types = common_types.copy() 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: 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. """Guess the type of a file based on its URL.
Return value is a tuple (type, encoding) where type is None if Return value is a tuple (type, encoding) where type is None if
...@@ -72,7 +97,7 @@ class MimeTypes: ...@@ -72,7 +97,7 @@ class MimeTypes:
mapped to '.tar.gz'. (This is table-driven too, using the mapped to '.tar.gz'. (This is table-driven too, using the
dictionary suffix_map.) 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. but non-standard types.
""" """
scheme, url = urllib.splittype(url) scheme, url = urllib.splittype(url)
...@@ -103,22 +128,44 @@ class MimeTypes: ...@@ -103,22 +128,44 @@ class MimeTypes:
base, ext = posixpath.splitext(base) base, ext = posixpath.splitext(base)
else: else:
encoding = None encoding = None
types_map = self.types_map types_map = self.types_map[True]
common_types = self.common_types
if ext in types_map: if ext in types_map:
return types_map[ext], encoding return types_map[ext], encoding
elif ext.lower() in types_map: elif ext.lower() in types_map:
return types_map[ext.lower()], encoding return types_map[ext.lower()], encoding
elif strict: elif strict:
return None, encoding return None, encoding
elif ext in common_types: types_map = self.types_map[False]
return common_types[ext], encoding if ext in types_map:
elif ext.lower() in common_types: return types_map[ext], encoding
return common_types[ext.lower()], encoding elif ext.lower() in types_map:
return types_map[ext.lower()], encoding
else: else:
return None, encoding 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. """Guess the extension for a file based on its MIME type.
Return value is a string giving a filename extension, Return value is a string giving a filename extension,
...@@ -131,25 +178,31 @@ class MimeTypes: ...@@ -131,25 +178,31 @@ class MimeTypes:
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. but non-standard types.
""" """
type = type.lower() extensions = self.guess_all_extensions(type, strict)
for ext, stype in self.types_map.items(): if extensions is not None:
if type == stype: extensions = extensions[0]
return ext return extensions
if not strict:
for ext, stype in common_types.items(): def read(self, filename, strict=True):
if type == stype: """
return ext Read a single mime.types-format file, specified by pathname.
return None
def read(self, filename): If strict is true, information will be added to
"""Read a single mime.types-format file, specified by pathname.""" list of standard types, else to the list of non-standard
types.
"""
fp = open(filename) fp = open(filename)
self.readfp(fp) self.readfp(fp)
fp.close() fp.close()
def readfp(self, fp): def readfp(self, fp, strict=True):
"""Read a single mime.types-format file.""" """
map = self.types_map 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: while 1:
line = fp.readline() line = fp.readline()
if not line: if not line:
...@@ -162,11 +215,11 @@ class MimeTypes: ...@@ -162,11 +215,11 @@ class MimeTypes:
if not words: if not words:
continue continue
type, suffixes = words[0], words[1:] type, suffixes = words[0], words[1:]
suffixes = [ '.' + suff for suff in suffixes ]
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. """Guess the type of a file based on its URL.
Return value is a tuple (type, encoding) where type is None if the Return value is a tuple (type, encoding) where type is None if the
...@@ -188,7 +241,23 @@ def guess_type(url, strict=1): ...@@ -188,7 +241,23 @@ def guess_type(url, strict=1):
return guess_type(url, strict) 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. """Guess the extension for a file based on its MIME type.
Return value is a string giving a filename extension, including the Return value is a string giving a filename extension, including the
...@@ -203,12 +272,27 @@ def guess_extension(type, strict=1): ...@@ -203,12 +272,27 @@ def guess_extension(type, strict=1):
init() init()
return guess_extension(type, strict) 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): 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 suffix_map, types_map, encodings_map, common_types
global inited global add_type, inited
inited = 1 inited = True
db = MimeTypes() db = MimeTypes()
if files is None: if files is None:
files = knownfiles files = knownfiles
...@@ -217,10 +301,12 @@ def init(files=None): ...@@ -217,10 +301,12 @@ def init(files=None):
db.readfp(open(file)) db.readfp(open(file))
encodings_map = db.encodings_map encodings_map = db.encodings_map
suffix_map = db.suffix_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_extension = db.guess_extension
guess_type = db.guess_type 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): def read_mime_types(file):
......
...@@ -321,6 +321,11 @@ Extension modules ...@@ -321,6 +321,11 @@ Extension modules
Library 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 - 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 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 also a class ImmutableSet which is useful when you need sets of sets
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment