[Cvs-annodex] commit (annodex): cmmlwiki/trunk/README cmmlwiki/trunk/cmmlwiki/request.py +cmmlwiki/trunk/cmmlwiki/clearsilver.py +cmmlwiki/trunk/cmmlwiki/css.py +cmmlwiki/trunk/cmmlwiki/template.py

conrad nobody at lists.annodex.net
Tue Sep 12 03:15:40 UTC 2006


Update of /var/local/lib/svn/annodex (new revision 2455)

Added files:
   cmmlwiki/trunk/cmmlwiki/clearsilver.py
   cmmlwiki/trunk/cmmlwiki/css.py
   cmmlwiki/trunk/cmmlwiki/template.py

Modified files:
   cmmlwiki/trunk/README
   cmmlwiki/trunk/cmmlwiki/request.py

Log Message:
add Clearsilver templating, a general Template class, a CSS class, and a
handler for Special:CSS which munges in the current CSS skin with appropriate
substitutions


Modified: cmmlwiki/trunk/README
===================================================================
--- cmmlwiki/trunk/README	2006-09-12 00:38:29 UTC (rev 2454)
+++ cmmlwiki/trunk/README	2006-09-12 03:15:40 UTC (rev 2455)
@@ -8,6 +8,8 @@
 
 pyannodex: http://benno.id.au/code/pyannodex.pml
 
+Clearsilver, and its Python bindings: http://www.clearsilver.net/
+
 Additionally, the following commandline tools are required:
 
   oggzinfo, oggz-scan
@@ -19,7 +21,7 @@
     Available from http://www.mplayerhq.hu/
 
 On Debian, the oggz tools and required python packages are:
-  oggz-tools python-xml python-sqlite
+  oggz-tools python-xml python-sqlite python-clearsilver
 in addition to
   python apache2
 To use GStreamer for frame extraction, you also need:

Added: cmmlwiki/trunk/cmmlwiki/clearsilver.py
===================================================================
--- cmmlwiki/trunk/cmmlwiki/clearsilver.py	2006-09-12 00:38:29 UTC (rev 2454)
+++ cmmlwiki/trunk/cmmlwiki/clearsilver.py	2006-09-12 03:15:40 UTC (rev 2455)
@@ -0,0 +1,337 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2005 Edgewall Software
+# Copyright (C) 2005 Christopher Lenz <cmlenz at gmx.de>
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://trac.edgewall.com/license.html.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://projects.edgewall.com/trac/.
+#
+# Author: Christopher Lenz <cmlenz at gmx.de>
+
+# Adapted from Trac
+# We don't use Trac's Markup, Fragment objects
+
+#from trac.core import TracError
+#from trac.util.markup import Markup, Fragment, escape
+#from trac.util.text import to_unicode
+
+from xml.sax.saxutils import escape
+
+def to_unicode(text, charset=None, lossy=True):
+    """Convert a `str` object to an `unicode` object.
+
+    If `charset` is not specified, we'll make some guesses,
+    first trying the UTF-8 encoding then trying the locale
+    preferred encoding (this differs from the `unicode` function
+    which only tries with the locale preferred encoding, in 'strict'
+    mode).
+
+    If the `lossy` argument is `True`, which is the default, then
+    we use the 'replace' mode:
+
+    If the `lossy` argument is `False`, we fallback to the 'iso-8859-15'
+    charset in case of an error (encoding a `str` using 'iso-8859-15'
+    will always work, as there's one Unicode character for each byte of
+    the input).
+    """
+    if not isinstance(text, str):
+        if isinstance(text, Exception):
+            # two possibilities for storing unicode strings in exception data:
+            try:
+                # custom __str__ method on the exception (e.g. PermissionError)
+                return unicode(text)
+            except UnicodeError:
+                # unicode arguments given to the exception (e.g. parse_date)
+                return ' '.join([to_unicode(arg) for arg in text.args])
+        return unicode(text)
+    errors = lossy and 'replace' or 'strict'
+    try:
+        if charset:
+            return unicode(text, charset, errors)
+        else:
+            try:
+                return unicode(text, 'utf-8')
+            except UnicodeError:
+                return unicode(text, locale.getpreferredencoding(), errors)
+    except UnicodeError:
+        return unicode(text, 'iso-8859-15')
+
+class HDFWrapper:
+    """
+    Convenience layer on top of the low-level ClearSilver python bindings
+    for HDF manipulation. This class makes the HDF look and behave more
+    like a standard Python dict.
+
+    >>> hdf = HDFWrapper()
+    >>> hdf['trac.url'] = 'http://projects.edgewall.com/trac/'
+    >>> hdf['trac.version'] = '1.0'
+    >>> print hdf
+    trac {
+      url = http://projects.edgewall.com/trac/
+      version = 1.0
+    }
+
+    HDFWrapper can also assign Python lists and dicts to HDF nodes,
+    automatically expanding them into the corresponding HDF structure.
+
+    A dictionary is mapped to a HDF node with named children:
+
+    >>> hdf = HDFWrapper()
+    >>> hdf['item'] = {'name': 'An item', 'value': '0'}
+    >>> print hdf
+    item {
+      name = An item
+      value = 0
+    }
+
+    A sequence is mapped to a HDF node with children whose names are
+    the indexes of the elements:
+
+    >>> hdf = HDFWrapper()
+    >>> hdf['items'] = ['Item 1', 'Item 2']
+    >>> print hdf
+    items {
+      0 = Item 1
+      1 = Item 2
+    }
+
+    Simple values can also be easily retrieved using the same syntax.
+
+    >>> hdf = HDFWrapper()
+    >>> hdf['time'] = 42
+    >>> hdf['time']
+    u'42'
+    >>> hdf['name'] = 'Foo'
+    >>> hdf['name']
+    u'Foo'
+
+    An attempt to retrieve a value that hasn't been set will raise a KeyError,
+    just like a standard dictionary:
+
+    >>> hdf['undef']
+    Traceback (most recent call last):
+        ...
+    KeyError: 'undef'
+    
+    It may be preferable to return a default value if the given key does not exit.
+    It will return 'None' when the specified key is not present:
+
+    >>> hdf.get('time')
+    u'42'
+    >>> hdf.get('undef')
+
+    A second argument may be passed to specify the default return value:
+
+    >>> hdf.get('time', 'Undefined Key')
+    u'42'
+    >>> hdf.get('undef', 'Undefined Key')
+    'Undefined Key'
+
+    The 'in' and 'not in' operators can be used to test whether the HDF contains
+    a value with a given name.
+
+    >>> 'name' in hdf
+    True
+    >>> 'undef' in hdf
+    False
+
+    has_key() performs the same function:
+
+    >>> hdf.has_key('name')
+    True
+    >>> hdf.has_key('undef')
+    False
+    """
+
+    def __init__(self, loadpaths=[]):
+        """Create a new HDF dataset.
+        
+        The loadpaths parameter can be used to specify a sequence of paths under
+        which ClearSilver will search for template files:
+
+        >>> hdf = HDFWrapper(loadpaths=['/etc/templates',
+        ...                             '/home/john/templates'])
+        >>> print hdf
+        hdf {
+          loadpaths {
+            0 = /etc/templates
+            1 = /home/john/templates
+          }
+        }
+        """
+        #try:
+        import neo_cgi
+        # The following line is needed so that ClearSilver can be loaded when
+        # we are being run in multiple interpreters under mod_python
+        neo_cgi.update()
+        import neo_util
+        self.hdf = neo_util.HDF()
+        #except ImportError, e:
+        #    raise TracError, "ClearSilver not installed (%s)" % e
+        
+        self['hdf.loadpaths'] = loadpaths
+
+    def __getattr__(self, name):
+        # For backwards compatibility, expose the interface of the underlying HDF
+        # object
+        return getattr(self.hdf, name)
+
+    def __contains__(self, name):
+        return self.hdf.getObj(str(name)) != None
+    has_key = __contains__
+
+    def get(self, name, default=None):
+        value = self.hdf.getValue(str(name), '<<NONE>>')
+        if value == '<<NONE>>':
+            return default
+        return value.decode('utf-8')
+
+    def __getitem__(self, name):
+        value = self.get(name, None)
+        if value == None:
+            raise KeyError, name
+        return value
+
+    def __setitem__(self, name, value):
+        """Add data to the HDF dataset.
+        
+        The `name` parameter is the path of the node in dotted syntax. The
+        `value` parameter can be a simple value such as a string or number, but
+        also data structures such as dicts and lists.
+
+        >>> hdf = HDFWrapper()
+
+        Adding a simple value results in that value being inserted into the HDF
+        after being converted to a string.
+
+        >>> hdf['test.num'] = 42
+        >>> hdf['test.num']
+        u'42'
+        >>> hdf['test.str'] = 'foo'
+        >>> hdf['test.str']
+        u'foo'
+
+        The boolean literals `True` and `False` are converted to there integer
+        representation before being added:
+
+        >>> hdf['test.true'] = True
+        >>> hdf['test.true']
+        u'1'
+        >>> hdf['test.false'] = False
+        >>> hdf['test.false']
+        u'0'
+
+        If value is `None`, nothing is added to the HDF:
+
+        >>> hdf['test.true'] = None
+        >>> hdf['test.none']
+        Traceback (most recent call last):
+            ...
+        KeyError: 'test.none'
+        """
+        self.set_value(name, value, True)
+        
+    def set_unescaped(self, name, value):
+        """
+        Add data to the HDF dataset.
+        
+        This method works the same way as `__setitem__` except that `value`
+        is not escaped if it is a string.
+        """
+        self.set_value(name, value, False)
+        
+    def set_value(self, name, value, do_escape=True):
+        """
+        Add data to the HDF dataset.
+        """
+        def set_unicode(prefix, value):
+            self.hdf.setValue(prefix.encode('utf-8'), value.encode('utf-8'))
+        def set_str(prefix, value):
+            self.hdf.setValue(prefix.encode('utf-8'), str(value))
+            
+        def add_value(prefix, value):
+            if value is None:
+                return
+            if value in (True, False):
+                set_str(prefix, int(value))
+            #elif isinstance(value, (Markup, Fragment)):
+            #    set_unicode(prefix, unicode(value))
+            elif isinstance(value, str):
+                if do_escape:
+                    # Assume UTF-8 here, for backward compatibility reasons
+                    set_unicode(prefix, escape(to_unicode(value)))
+                else:
+                    set_str(prefix, value)
+            elif isinstance(value, unicode):
+                if do_escape:
+                    set_unicode(prefix, escape(value))
+                else:
+                    set_unicode(prefix, value)
+            elif isinstance(value, dict):
+                for k in value.keys():
+                    add_value('%s.%s' % (prefix, k), value[k])
+            else:
+                if hasattr(value, '__iter__') or \
+                        isinstance(value, (list, tuple)):
+                    for idx, item in enumerate(value):
+                        add_value('%s.%d' % (prefix, idx), item)
+                else:
+                    set_str(prefix, value)
+        add_value(name, value)
+
+    def __str__(self):
+        from StringIO import StringIO
+        buf = StringIO()
+        def hdf_tree_walk(node, prefix=''):
+            while node:
+                name = node.name() or ''
+                buf.write('%s%s' % (prefix, name))
+                value = node.value()
+                if value or not node.child():
+                    if value.find('\n') == -1:
+                        buf.write(' = %s' % value)
+                    else:
+                        buf.write(' = << EOM\n%s\nEOM' % value)
+                if node.child():
+                    buf.write(' {\n')
+                    hdf_tree_walk(node.child(), prefix + '  ')
+                    buf.write('%s}\n' % prefix)
+                else:
+                    buf.write('\n')
+                node = node.next()
+        hdf_tree_walk(self.hdf.child())
+        return buf.getvalue().strip()
+
+    def parse(self, string):
+        """Parse the given string as template text, and returns a neo_cs.CS
+        object.
+        """
+        import neo_cs
+        cs = neo_cs.CS(self.hdf)
+        cs.parseStr(string)
+        return cs
+
+    def render(self, template):
+        """Render the HDF using the given template.
+
+        The template parameter can be either an already parse neo_cs.CS
+        object, or a string. In the latter case it is interpreted as name of the
+        template file.
+        """
+        if isinstance(template, basestring):
+            filename = template
+            import neo_cs
+            template = neo_cs.CS(self.hdf)
+            template.parseFile(filename)
+        return template.render()
+
+
+if __name__ == '__main__':
+    import doctest, sys
+    doctest.testmod(sys.modules[__name__])

Added: cmmlwiki/trunk/cmmlwiki/css.py
===================================================================
--- cmmlwiki/trunk/cmmlwiki/css.py	2006-09-12 00:38:29 UTC (rev 2454)
+++ cmmlwiki/trunk/cmmlwiki/css.py	2006-09-12 03:15:40 UTC (rev 2455)
@@ -0,0 +1,27 @@
+# -*- coding: iso8859-1 -*-
+#
+# Copyright (C) 2006 CSIRO Australia
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For exact contribution history, see the revision
+# history and logs.
+#
+# Author: Conrad Parker <conrad at annodex.net>
+
+from cmmlwiki.template import Template
+
+class CSS:
+    def content_type(self):
+        return "text/css"
+    
+    def template(self, vars):
+        main_css = "/usr/share/cmmlwiki/htdocs/stylesheets/main.css"
+        video_monitor_css = "/usr/share/cmmlwiki/htdocs/stylesheets/video-monitor.css"
+        s = Template(main_css).template(vars)
+        s += Template(video_monitor_css).template(vars)
+
+        return s

Modified: cmmlwiki/trunk/cmmlwiki/request.py
===================================================================
--- cmmlwiki/trunk/cmmlwiki/request.py	2006-09-12 00:38:29 UTC (rev 2454)
+++ cmmlwiki/trunk/cmmlwiki/request.py	2006-09-12 03:15:40 UTC (rev 2455)
@@ -18,6 +18,7 @@
 import sys
 
 from cmmlwiki.response import Response
+from cmmlwiki.css import CSS
 from cmmlwiki.rssfeed import RSSFeed
 from cmmlwiki.htmlpage import HTMLPage
 from cmmlwiki.channel import Channel
@@ -153,6 +154,8 @@
         o = HTMLPage(s)
     elif (command == "RSS"):
         o = RSSFeed(handler)
+    elif (command == "CSS"):
+        o = CSS()
     else:
         o = handler.error ('Invalid request %s' % (command))
 

Added: cmmlwiki/trunk/cmmlwiki/template.py
===================================================================
--- cmmlwiki/trunk/cmmlwiki/template.py	2006-09-12 00:38:29 UTC (rev 2454)
+++ cmmlwiki/trunk/cmmlwiki/template.py	2006-09-12 03:15:40 UTC (rev 2455)
@@ -0,0 +1,26 @@
+# -*- coding: iso8859-1 -*-
+#
+# Copyright (C) 2006 CSIRO Australia
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For exact contribution history, see the revision
+# history and logs.
+#
+# Author: Conrad Parker <conrad at annodex.net>
+
+from cmmlwiki.clearsilver import HDFWrapper
+from cmmlwiki.location import WikiURL
+
+class Template:
+    def __init__(self, tfile):
+        self.tfile = tfile
+        self.hdf = HDFWrapper()
+
+    def template(self, vars):
+        self.hdf['vars'] = vars
+        self.hdf['StaticURL'] = WikiURL(htdocs=True).template(vars)
+        return self.hdf.render(self.tfile)


-- 
conrad



More information about the cvs-annodex mailing list