clearsilver.py :  » Project-Management » Trac » Trac-0.11.7 » trac » web » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Project Management » Trac 
Trac » Trac 0.11.7 » trac » web » clearsilver.py
# -*- coding: utf-8 -*-
#
# Copyright (C)2005-2009 Edgewall Software
# Copyright (C) 2005 Christopher Lenz <cmlenz@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.org/wiki/TracLicense.
#
# This software consists of voluntary contributions made by many
# individuals. For the exact contribution history, see the revision
# history and logs, available at http://trac.edgewall.org/log/.
#
# Author: Christopher Lenz <cmlenz@gmx.de>

from HTMLParser import HTMLParser

from trac.core import TracError
from trac.util.html import Markup,Fragment,escape
from trac.util.text import to_unicode


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://trac.edgewall.org/'
    >>> hdf['trac.version'] = '1.0'
    >>> print hdf
    trac {
      url = http://trac.edgewall.org/
      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
    """

    has_clearsilver = None
    
    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()
            self.has_clearsilver = True
        except ImportError, e:
            self.has_clearsilver = False
        
        self['hdf.loadpaths'] = loadpaths

    def __repr__(self):
        return '<HDFWrapper 0x%x>' % id(self)

    def __nonzero__(self):
        return self.has_clearsilver

    def __getattr__(self, name):
        # For backwards compatibility, expose the interface of the underlying HDF
        # object
        if self.has_clearsilver:
            return getattr(self.hdf, name)
        else:
            return None

    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.
        """
        if not self.has_clearsilver:
            return
        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, to_unicode(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, form_token=None):
        """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
            try:
                import neo_cs
            except ImportError:
                raise TracError("You're using a plugin which requires "
                                "the Clearsilver template engine and "
                                "Clearsilver is not installed. "
                                "Either disable that plugin or install "
                                "Clearsilver.")
            template = neo_cs.CS(self.hdf)
            template.parseFile(filename)

        if form_token:
            from cStringIO import StringIO
            out = StringIO()
            injector = FormTokenInjector(form_token, out)
            injector.feed(template.render())
            return out.getvalue()
        else:
            return template.render()


class FormTokenInjector(HTMLParser):
    """Identify and protect forms from CSRF attacks

    This filter works by adding a input type=hidden field to POST forms.
    """
    def __init__(self, form_token, out):
        HTMLParser.__init__(self)
        self.out = out
        self.token = form_token

    def handle_starttag(self, tag, attrs):
        self.out.write(self.get_starttag_text())
        if tag.lower() == 'form':
            for name, value in attrs:
                if name.lower() == 'method' and value.lower() == 'post':
                    self.out.write('<input type="hidden" name="__FORM_TOKEN"'
                                   ' value="%s"/>' % self.token)
                    break
                    
    def handle_startendtag(self, tag, attrs):
        self.out.write(self.get_starttag_text())
        
    def handle_charref(self, name):
        self.out.write('&#%s;' % name)

    def handle_entityref(self, name):
        self.out.write('&%s;' % name)

    def handle_comment(self, data):
        self.out.write('<!--%s-->' % data)

    def handle_decl(self, data):
        self.out.write('<!%s>' % data)

    def handle_pi(self, data):
        self.out.write('<?%s?>' % data)

    def handle_data(self, data):
        self.out.write(data)

    def handle_endtag(self, tag):
        self.out.write('</' + tag + '>')


if __name__ == '__main__':
    import doctest, sys
    doctest.testmod(sys.modules[__name__])
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.