diff MoinMoin/wikiutil.py @ 657:016a8a3ef354

wikiutil.MimeType class, renamed parsers to mimetype like module names
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Tue, 16 May 2006 20:12:29 +0200
parents a80a6c629bc3
children 68d93872d4c9 28de47f4ff1a
line wrap: on
line diff
--- a/MoinMoin/wikiutil.py	Tue May 16 13:10:13 2006 +0200
+++ b/MoinMoin/wikiutil.py	Tue May 16 20:12:29 2006 +0200
@@ -755,12 +755,140 @@
 
 def pagelinkmarkup(pagename):
     """ return markup that can be used as link to page <pagename> """
-    from MoinMoin.parser.wiki import Parser
+    from MoinMoin.parser.text_moin_wiki import Parser
     if re.match(Parser.word_rule + "$", pagename):
         return pagename
     else:
         return u'["%s"]' % pagename
 
+# mimetype stuff ------------------------------------------------------------
+class MimeType(object):
+    """ represents a mimetype like text/plain """
+    sanitize_mapping = {
+        # this stuff is text, but got application/* for unknown reasons
+        ('application', 'docbook+xml'): ('text', 'docbook'),
+        ('application', 'x-latex'): ('text', 'latex'),
+        ('application', 'x-tex'): ('text', 'tex'),
+        ('application', 'javascript'): ('text', 'javascript'),
+    }
+    spoil_mapping = {} # inverse mapping of above
+    
+    def __init__(self, mimestr=None, filename=None):
+        self.major = self.minor = None # sanitized mime type and subtype
+        self.params = {} # parameters like "charset" or others
+        self.charset = None # this stays None until we know for sure!
+
+        for key, value in self.sanitize_mapping.items():
+            self.spoil_mapping[value] = key
+
+        if mimestr:
+            self.parse_mimetype(mimestr)
+        elif filename:
+            self.parse_filename(filename)
+    
+    def parse_filename(self, filename):
+        import mimetypes
+        mtype, encoding = mimetypes.guess_type()
+        if mtype is None:
+            mtype = 'application/octet-stream'
+        self.parse_mimetype(mtype)
+        
+    def parse_mimetype(self, mimestr):
+        """ take a string like used in content-type and parse it into components,
+            alternatively it also can process some abbreviated string like "wiki"
+        """
+        parameters = mimestr.split(";")
+        parameters = [p.strip() for p in parameters]
+        mimetype, parameters = parameters[0], parameters[1:]
+        mimetype = mimetype.split('/')
+        if len(mimetype) >= 2:
+            major, minor = mimetype[:2] # we just ignore more than 2 parts
+        else:
+            major, minor = self.parse_format(mimetype[0])
+        self.major = major.lower()
+        self.minor = minor.lower()
+        for param in parameters:
+            key, value = param.split('=')
+            if value[0] == '"' and value[-1] == '"': # remove quotes
+                value = value[1:-1]
+            self.params[key.lower()] = value
+        if self.params.has_key('charset'):
+            self.charset = self.params['charset'].lower()
+        self.sanitize()
+            
+    def parse_format(self, format):
+        """ maps from what we currently use on-page in a #format xxx processing
+            instruction to a sanitized mimetype major, minor tuple.
+            can also be user later for easier entry by the user, so he can just
+            type "wiki" instead of "text/moin-wiki".
+        """
+        format = format.lower()
+        if format in ('plain', 'csv', 'rst', 'docbook', 'latex', 'tex', 'html', 'css',
+                      'xml', 'python', 'perl', 'php', 'ruby', 'javascript',
+                      'cplusplus', 'java', 'pascal', 'diff', 'gettext', 'xslt', ):
+            mimetype = 'text', format
+        else:
+            mapping = {
+                'wiki': ('text', 'moin-wiki'),
+                'irc': ('text', 'irssi'),
+            }
+            try:
+                mimetype = mapping[format]
+            except KeyError:
+                mimetype = 'text', 'x-%s' % format
+        return mimetype
+
+    def sanitize(self):
+        """ convert to some representation that makes sense - this is not necessarily
+            conformant to /etc/mime.types or IANA listing, but if something is
+            readable text, we will return some text/* mimetype, not application/*,
+            because we need text/plain as fallback and not application/octet-stream.
+        """
+        self.major, self.minor = self.sanitize_mapping.get((self.major, self.minor), (self.major, self.minor))
+
+    def spoil(self):
+        """ this returns something conformant to /etc/mime.type or IANA as a string,
+            kind of inverse operation of sanitize(), but doesn't change self
+        """
+        major, minor = self.spoil_mapping.get((self.major, self.minor), (self.major, self.minor))
+        return self.content_type(major, minor)
+
+    def content_type(self, major=None, minor=None, charset=None, params=None):
+        """ return a string suitable for Content-Type header
+        """
+        major = major or self.major
+        minor = minor or self.minor
+        params = params or self.params or {}
+        if major == 'text':
+            charset = charset or self.charset or params.get('charset', config.charset)
+            params['charset'] = charset
+        mimestr = "%s/%s" % (major, minor)
+        params = ['%s="%s"' % (key.lower(), value) for key, value in params.items()]
+        params.insert(0, mimestr)
+        return "; ".join(params)
+
+    def mime_type(self):
+        """ return a string major/minor only, no params """
+        return "%s/%s" % (self.major, self.minor)
+
+    def module_name(self):
+        """ convert this mimetype to a string useable as python module name,
+            we yield the exact module name first and then proceed to shorter
+            module names (useful for falling back to them, if the more special
+            module is not found) - e.g. first "text_python", next "text".
+            Finally, we yield "application_octet_stream" as the most general
+            mimetype we have.
+            Hint: the fallback handler module for text/* should be implemented
+                  in module "text" (not "text_plain")
+        """
+        mimetype = self.mime_type()
+        modname = mimetype.replace("/", "_").replace("-", "_").replace(".", "_")
+        fragments = modname.split('_')
+        for length in range(len(fragments), 0, -1):
+            yield "_".join(fragments[:length])
+        yield "application_octet_stream"
+
+
 #############################################################################
 ### Plugins
 #############################################################################