root/trunk/templess.py

Revision 139 (checked in by johnny, 2 years ago)

Pyflakes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision
Line 
1 # Copyright (c) 2005-2009 Guido Wesdorp. All rights reserved.
2 # This software is distributed under the terms of the Templess
3 # License. See LICENSE.txt for license text.
4 # E-mail: johnny@johnnydebris.net
5
6 """ A very compact, XML based templating system.
7
8     It has only 5 different directives, and doesn't allow any logic inside the
9     templates, instead it expects the application to provide a dict with all
10     the data (as strings or XML nodes) completely prepared. This makes it quite
11     restrictive, and harder to seperately work on design and logic (the
12     template has to very strictly adhere to the format of the dict), but makes
13     it an environment extremely suitable for developers (since all development
14     is done from code rather than from the template, and they don't have to
15     learn a new, quirky templating language) and for projects where HTML and
16     code development are strictly seperated.
17
18     Main features/advantages compared to other templating languages:
19
20       * templates are very clean
21       * it's easy to learn, and relatively simple code
22       * templates and results are well-formed XML, so processable
23       * proper unicode support
24       * proper generative rendering (so suitable for async environments)
25
26     Quick example:
27
28     >>> from templess.templess import template
29     >>> t = template('''
30     ...   <foo xmlns:t="http://johnnydebris.net/xmlns/templess">
31     ...     <bar t:content="bar" />
32     ...   </foo>
33     ... ''')
34     >>> print t.unicode({'bar': 'bar content'})
35     <foo>
36       <bar>bar content</bar>
37     </foo>
38 """
39
40 __appname__ = 'templess'
41 __version__ = '1.0 unreleased'
42 __author__ = 'Guido Wesdorp <johnny@johnnydebris.net>'
43 __last_modified_date__ = \
44     '$Date$'
45 __last_author__ = '$Author$'
46 __revision__ = '$Revision$'
47 __footer__ = '%s v%s, (c) %s 2005-2009' % (
48     __appname__, __version__, __author__)
49
50 # tree stuff
51 class nodebase(object):
52     """ node base
53     
54         very specific to Templess, the nodes contain as little functionality
55         as possible
56     """
57     # __slots__ = ()
58
59
60 class elnode(list, nodebase):
61     """ XML element
62     """
63     # __slots__ = ('name', 'attrs', 'parent', 'charset')
64
65     def __init__(self, name, attrs, parent, charset='UTF-8'):
66         self.name = name
67         self.attrs = dict(attrs)
68         self.parent = parent
69         self.charset = charset
70         if parent is not None:
71             parent.append(self)
72
73     def __repr__(self):
74         return '<%s "%s">' % (self.__class__.__name__, self.name)
75
76     def find(self, name):
77         buffer = [self]
78         while buffer:
79             current = buffer.pop(0)
80             if not isinstance(current, elnode):
81                 continue
82             buffer = list(current) + buffer
83             if current.name == name:
84                 yield current
85
86     @property
87     def children(self):
88         return self.__iter__()
89
90
91 class templessnode(elnode):
92     """ templess element node
93
94         has a special method 'convert' that makes it convert itself to a
95         normal elnode by processing all templess directives (returns a new
96         node, doesn't process in-place)
97     """
98
99     # __slots__ = ('name', 'attrs', 'parent', 'directives', 'charset')
100
101     def __init__(self, name, attrs, parent, directives, charset='UTF-8'):
102         self.name = name
103         self.attrs = dict(attrs)
104         self.parent = parent
105         self.directives = directives
106         self.charset = charset
107         if parent is not None:
108             parent.append(self)
109
110
111 class textnode(nodebase):
112     """ text element
113     """
114
115     # __slots__ = ('text', 'parent', 'charset')
116
117     def __init__(self, text, parent, charset='UTF-8'):
118         if not isinstance(text, unicode):
119             text = unicode(text, charset)
120         self.text = text
121         self.parent = parent
122         self.charset = charset
123         if parent is not None:
124             parent.append(self)
125
126     def __repr__(self):
127         reprtext = self.text[10:]
128         if reprtext and len(reprtext) < len(self.text):
129             reprtext += '...'
130         return '<%s "%s">' % (self.__class__.__name__, reprtext)
131
132
133 class cdatanode(textnode):
134     """ cdata node
135     """
136
137
138 class commentnode(textnode):
139     """ comment node
140     """
141
142
143 class template(object):
144     """ a Templess template
145
146         initialize takes 3 arguments:
147
148           * 'data' (mandatory) - the data from which to build the tree,
149             usually XML, 'data' can either be a plain string in UTF-8, or the
150             charset provided as second argument, a unicode object, or a
151             file-like object that contains data formatted using the charset
152             provided as second argument
153
154           * charset (optional, defaults to UTF-8) - character set used for
155             input (if the first argument is a plain string or a file) and
156             output (if 'render_to_string' is called), and also for converting
157             plain string items in the context dictionary on conversion
158
159           * parse (optional, defaults to parse.parse_from_xml) - a callable
160             that converts the data provided as first argument, or read from
161             the file provided as first argument, to a templess node tree
162
163         call 'unicode()' to get a unicode string, 'generate()' to get a
164         generator that yields bits of string, and 'render()' to get a node
165     """
166     def __init__(self, data, charset='UTF-8', parse=None):
167         if parse is None:
168             from parse import parse_from_xml as parse
169         self.charset = charset
170         if hasattr(data, 'read'):
171             data = data.read()
172         if charset != 'UTF-8':
173             data = unicode(data, charset)
174         if isinstance(data, unicode):
175             data = data.encode('UTF-8')
176         self.tree = parse(data, charset)
177
178     # some convenience methods to quickly render to XML
179     def render_to_string(self, context, charset='UTF-8', html=False):
180         """ returns a complete string with the rendered template as XML
181         """
182         # not preferred anymore... better use template.unicode()
183         return self.unicode(context, html=html).encode(charset)
184
185     def unicode(self, context, html=False):
186         """ returns a unicode XML rendering of the template
187         """
188         from convert import xmlserializer
189         s = xmlserializer(self.tree)
190         s.convert(context)
191         return s.unicode(html=html)
192
193     def generate(self, context, html=False):
194         """ returns a generator that generates bits of XML as unicode
195         """
196         from convert import xmlgenerator
197         s = xmlgenerator(self.tree)
198         return s.convert_generate(context, html=html)
199
200     def convert(self, context):
201         """ convert the tree to a 'normal' node
202         
203             processes all templess directives and returns the resulting tree
204             (a fresh copy, doesn't process in-place)
205         """
206         from convert import convertor
207         s = convertor(self.tree)
208         node = s.convert(context)
209         return node
210     # old name, I guess it should be removed
211     render = convert
Note: See TracBrowser for help on using the browser.