Package template3k
[hide private]
[frames] | no frames]

Source Code for Package template3k

  1  #coding: utf8; 
  2  ############################################################################ 
  3  #                                                                          # 
  4  #    This file 'template3k/__init__.py'                                    # 
  5  #    is part of 'dom3k'                                                    # 
  6  #    Copyright (C) 2004-2005 by Eric Sadit Téllez Avila                    # 
  7  #    Copyright (C) 2006      by Eric Sadit Téllez Avila                    # 
  8  #    Copyright (C) 2007      by Eric Sadit Téllez Avila                    # 
  9  #    Copyright (C) 2008      by Eric Sadit Téllez Avila                    # 
 10  #    sadit@lsc.fie.umich.mx or donsadit@gmail.com                          # 
 11  #                                                                          # 
 12  #    This program is free software; you can redistribute it and#or modify  # 
 13  #    it under the terms of the GNU General Public License as published by  # 
 14  #    the Free Software Foundation; either version 2 of the License, or     # 
 15  #    (at your option) any later version.                                   # 
 16  #                                                                          # 
 17  #    This program is distributed in the hope that it will be useful,       # 
 18  #    but WITHOUT ANY WARRANTY; without even the implied warranty of        # 
 19  #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         # 
 20  #    GNU General Public License for more details.                          # 
 21  #                                                                          # 
 22  #    You should have received a copy of the GNU General Public License     # 
 23  #    along with this program; if not, write to the                         # 
 24  #    Free Software Foundation, Inc.,                                       # 
 25  #    59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             # 
 26  ############################################################################ 
 27   
 28  __doc__ = """ 
 29  This module provides support for simple but powerful templates.  
 30  template3k is a template regular language based on substitution of 
 31  commands for their evaluation. 
 32   
 33  There exists two levels of execution: 
 34   
 35  Static level (substitution on template compilation time) or dynamic substitution 
 36  (executed on running time). 
 37   
 38  The entire template a python living code, so you can define python classes or 
 39  functions inside and use them at any time in the template. 
 40   
 41  It's based on commands that looks like simple html tags (to be easily used with 
 42  graphical html design applications).  The templates could not be an xml document, 
 43  but the commands will be named in the same way. 
 44   
 45  A template is executed with the method 'merge(values)' where values is a dictionary 
 46  with values to be used by the commands. Functions and lambdas in dynamic substitutions 
 47  receives as argument the merge's dictvalues as a dictionary 
 48   
 49  Commands: 
 50   
 51  python:keyword 
 52     <python:keyword id="Name" /> 
 53         Replaces the command with values["Name"] 
 54     <python:keyword id="Name">Default text</python:keyword> 
 55         Replaces the command with values["Name"], with optionally default text 
 56   
 57  python:exec 
 58     <python:exec id="Name"> 
 59     ...Python Code... 
 60     </python:exec> 
 61         Replaces the command with the result of compute the python code inside the command 
 62         and whose varname is Name. 
 63         If Name variable is a function or lambda it will be a dynamic substitution 
 64   
 65  python:code 
 66     <python:code id="Name"> 
 67     ...Python Code... 
 68     </python:code> 
 69         Replaces the command with an empty string but the code is saved in the environment of 
 70         the template, so its definitions could be used later 
 71   
 72  python:include 
 73     <python:include id="Name">TemplatePath</python:include> 
 74         Replaces the command with the template substituion of TemplatePath template. If must exists an special 
 75         keyword |template_pool| in the merge dictionary to be used to get the template. If this key is not 
 76         given in the merge, the default module get_template will be used. The arguments in the merge will be 
 77         passed to this new template merge. 
 78          
 79  python:eval 
 80     <python:eval id="Name">...Python Expression...</python:eval> 
 81         Replaces the command with the result of the evaluation of the Python Expression inside the command tags. 
 82         If Name is send to merge it will be replaced for the merge argument. 
 83         If the result of the expression is a function or a lambda, it will be a dynamic substitution, a string 
 84         otherwise. If Name is send to merge, the expression will not be executed. There is a implicit argument 
 85         in the environment named dictvalues, is not needed in the Python Expression, but can be used in the 
 86         Python Expression as well. 
 87   
 88  python:call 
 89     <python:call id="Name">...Python Expression...</python:call> 
 90         Replaces the command with the result of the evaluation of the Python Expression inside the command tags. 
 91         If Name is send to merge it will be replaced for the merge argument. 
 92         This expression will be always executed. If Name is send to merge, the expression will not be executed. 
 93   
 94  """ 
 95   
 96  import re 
 97  import warn 
 98  import os 
 99   
100  _pool = None 
101  _template_pattern=re.compile(r""" 
102       <python:(?P<command>\w+) \s+ 
103       id\s*=\s*["'](?P<id>\w+)["'] 
104       \s* 
105       ( (/\>) | 
106         (\> (?P<defaultvalue>.*?) </python:(?P<endcommand>\w+)\s*\>) ) 
107       """, re.IGNORECASE | re.DOTALL | re.MULTILINE | re.VERBOSE ) #" 
108   
109 -class UnknownTemplateCommand(Exception): pass
110
111 -class Template:
112 - def __init__(self, name, data):
113 self.name = name 114 self.defaultvalues = {} 115 self.vars = {} 116 self.template = self._compile_template(data)
117
118 - def _replace_keywords(self, d):
119 x = d.groupdict() 120 comm = x['command'] 121 xid = x['id'] 122 # print dir(d), d.start(), d.end(), d.span() 123 if comm == 'keyword': 124 if x['defaultvalue'] is None: 125 pass 126 else: 127 self.defaultvalues[xid] = x['defaultvalue'] 128 elif comm in ('exec','code'): 129 c = compile(x['defaultvalue'].replace('%%','%')+"\n",self.name + ':id:' + xid,'exec') 130 exec c in self.vars, self.vars 131 if comm == 'code': 132 return '' 133 self.defaultvalues[xid] = self.vars[xid] 134 elif comm == 'eval': 135 self.defaultvalues[xid] = eval(x['defaultvalue'], self.vars, self.vars) 136 elif comm == 'call': 137 self.defaultvalues[xid] = eval("lambda dictvalues: (%s)"%x['defaultvalue'], self.vars, self.vars) 138 elif comm == 'include': 139 def include_template(dictvalues): 140 try: 141 g = dictvalues['template_pool'].get_template 142 except KeyError: 143 g = get_template 144 return g(x['defaultvalue']).merge(dictvalues)
145 self.defaultvalues[xid] = include_template 146 else: 147 raise UnknownTemplateCommand('Unknown Template Command %s'%repr(comm)) 148 return '%%(%(id)s)s'%x
149
150 - def _compile_template(self, data):
151 return _template_pattern.sub(self._replace_keywords, re.sub("%","%%", data)) 152
153 - def merge(self, dictvalues=None, **kwargs):
154 """ Merge the template with a set of values |dictvalues| """ 155 if dictvalues is None: 156 dictvalues = kwargs 157 for k,v in self.defaultvalues.items(): 158 try: 159 dictvalues[k] 160 except KeyError: 161 if callable(v): 162 v = v(dictvalues) 163 dictvalues.setdefault(k,v) 164 return self.template%dictvalues
165
166 -class Pool:
167 - def __init__(self, path="."):
168 self.path = path 169 self._CACHE = {} # name => mtime, template
170
171 - def get_template(self, template):
172 _CACHE = self._CACHE 173 filename = os.path.join(self.path,template) 174 try: 175 s = os.stat(filename) 176 except OSError: 177 warn.debug("Template %s don't exists"%repr(filename)) 178 raise 179 try: 180 _mtime, _temp = _CACHE[template] 181 if _mtime == s.st_mtime: 182 return _temp 183 except KeyError: 184 pass 185 f = file(filename) 186 data = f.read() 187 f.close() 188 c = Template(filename, data) 189 _CACHE[template] = (s.st_mtime, c) 190 return c
191
192 -def get_template(temname):
193 global _pool 194 if _pool is None: 195 _pool = Pool() 196 return _pool.get_template(temname)
197