Permalink
Browse files

#. Improve template process:

    #. Add ``#uliweb-template-tag:<begin_tag>,<end_tag><newline>`` process to template
       file, and you can also pass ``begin_tag`` and ``end_tag`` to Template, and
       ``template_file()`` or ``template()``
    #. Add ``[TEMPLATE_PROCESSOR]`` section to ``default_settings.ini``, so that user
       can setup his own template processor, the option will look like::

            angularjs_template = {'file_exts':['.ahtml'],
                'processor':'uliweb.core.template.template_file',
                'args':{}}

       * the key is not very important, but you should keep it unique
       * ``file_exts`` will be the file extensions, it's a list, so the
         processor can match multiple filenames
       * ``processor`` will be the path of template function, uliweb will
         import it when needed
       * ``args`` will be a dict, and it will be passed to template function
    #. Add ``BEGIN_TAG`` and ``END_TAG`` to settings.ini, so user can change
       default tag name from ``{{`` and ``}}`` to other strings. But this
       appoach will effect globally, so if you are using other apps with
       templates which using old tag strings, will cause errors. So using
       ``#uliweb-template-tag`` or ``TEMPLATE_PROCESSOR`` maybe the good way,
       but you still need to set it in template file or set ``response.template``
       with other template extension, because the defult template file extension
       is ``.html``. For example::

            def index():
                response.template = 'index.ahtml'
                return {}

       Above code will override the default template filename from ``index.html``
       to ``index.ahtml``.

git-svn-id: https://uliweb.googlecode.com/svn/trunk@948 14287918-b64d-0410-abb6-a92efa0c2026
  • Loading branch information...
limodou
limodou committed Jul 1, 2012
1 parent ab0a7a6 commit d26cffb320fae45f915ef07a4a5e6f8b33835ca1
View
@@ -7,6 +7,39 @@ Uliweb Change Log
#. Fix loadtable bug for PickleType type, using inspecttable instead, so
PickleyType will be BLOB type.
+#. Improve template process:
+
+ #. Add ``#uliweb-template-tag:<begin_tag>,<end_tag><newline>`` process to template
+ file, and you can also pass ``begin_tag`` and ``end_tag`` to Template, and
+ ``template_file()`` or ``template()``
+ #. Add ``[TEMPLATE_PROCESSOR]`` section to ``default_settings.ini``, so that user
+ can setup his own template processor, the option will look like::
+
+ angularjs_template = {'file_exts':['.ahtml'],
+ 'processor':'uliweb.core.template.template_file',
+ 'args':{}}
+
+ * the key is not very important, but you should keep it unique
+ * ``file_exts`` will be the file extensions, it's a list, so the
+ processor can match multiple filenames
+ * ``processor`` will be the path of template function, uliweb will
+ import it when needed
+ * ``args`` will be a dict, and it will be passed to template function
+ #. Add ``BEGIN_TAG`` and ``END_TAG`` to settings.ini, so user can change
+ default tag name from ``{{`` and ``}}`` to other strings. But this
+ appoach will effect globally, so if you are using other apps with
+ templates which using old tag strings, will cause errors. So using
+ ``#uliweb-template-tag`` or ``TEMPLATE_PROCESSOR`` maybe the good way,
+ but you still need to set it in template file or set ``response.template``
+ with other template extension, because the defult template file extension
+ is ``.html``. For example::
+
+ def index():
+ response.template = 'index.ahtml'
+ return {}
+
+ Above code will override the default template filename from ``index.html``
+ to ``index.ahtml``.
0.1.2 Version
-----------------
@@ -8,3 +8,6 @@ def startup_installed(sender):
template.register_node('link', LinkNode)
template.register_node('use', UseNode)
+ template.BEGIN_TAG = sender.settings.TEMPLATE.BEGIN_TAG
+ template.END_TAG = sender.settings.TEMPLATE.END_TAG
+
@@ -2,6 +2,9 @@
USE_TEMPLATE_TEMP_DIR = False
TEMPLATE_TEMP_DIR = 'tmp/templates_temp'
RAISE_USE_EXCEPTION = True
+BEGIN_TAG = '{{'
+END_TAG = '}}'
[BINDS]
-template.startup_installed = 'startup_installed', 'uliweb.contrib.template.startup_installed'
+template.startup_installed = 'startup_installed', 'uliweb.contrib.template.startup_installed'
+
View
@@ -369,6 +369,8 @@ def init(self, project_dir, apps_dir):
Dispatcher.env = self._prepare_env()
Dispatcher.template_dirs = self.get_template_dirs()
+ Dispatcher.template_processors = {}
+ self.install_template_processors()
#begin to start apps
self.install_apps()
@@ -492,12 +494,21 @@ def get_file(self, filename, dir='static'):
if os.path.exists(path):
return path
return None
+
+ def get_template_processor(self, filename):
+ ext = os.path.splitext(filename)[1]
+ if ext in self.template_processors:
+ return self.template_processors[ext]['func'], self.template_processors[ext]['args']
+ else:
+ return template.template_file, {}
def template(self, filename, vars=None, env=None, dirs=None, default_template=None):
vars = vars or {}
dirs = dirs or self.template_dirs
env = env or self.get_view_env()
+ func, kwargs = self.get_template_processor(filename)
+
if self.debug:
def _compile(code, filename, action, env, Loader=Loader):
env['__loader__'] = Loader(filename, vars, env, dirs, notest=True)
@@ -507,9 +518,9 @@ def _compile(code, filename, action, env, Loader=Loader):
# file('out.html', 'w').write(code)
raise
- return template.template_file(filename, vars, env, dirs, default_template, compile=_compile)
+ return func(filename, vars, env, dirs, default_template, compile=_compile, **kwargs)
else:
- return template.template_file(filename, vars, env, dirs, default_template)
+ return func(filename, vars, env, dirs, default_template, **kwargs)
def render_text(self, text, vars=None, env=None, dirs=None, default_template=None):
vars = vars or {}
@@ -805,6 +816,11 @@ def install_apps(self):
except BaseException, e:
log.exception(e)
+ def install_template_processors(self):
+ for v in settings.TEMPLATE_PROCESSORS.values():
+ for ext in v.get('file_exts', []):
+ self.template_processors[ext] = {'func':import_attr(v['processor']), 'args':v.get('args', {})}
+
def install_settings(self, s):
# settings = pyini.Ini()
for v in s:
@@ -56,3 +56,5 @@ format_package = "[%(levelname)s %(name)] %(message)s"
[MIDDLEWARES]
+[TEMPLATE_PROCESSORS]
+#default = {'file_exts':['*'], 'processor':'uliweb.core.template.template_file', 'args':{}}
View
@@ -10,6 +10,9 @@
__options__ = {'use_temp_dir':False}
__nodes__ = {} #user defined nodes
+BEGIN_TAG = '{{'
+END_TAG = '}}'
+
class TemplateException(Exception): pass
class ContextPopException(TemplateException):
"pop() has been called more times than push()"
@@ -119,7 +122,11 @@ def eval_vars(vs, vars, env):
else:
return eval(vs, vars, env)
-r_tag = re.compile(r'(\{\{.*?\}\})', re.DOTALL|re.M)
+def get_tag(begin_tag, end_tag):
+ r = '(' + re.escape(begin_tag) + '.*?' + re.escape(end_tag) + ')'
+ return re.compile(r, re.DOTALL|re.M)
+
+r_tag = re.compile('^#uliweb-template-tag:(.+?),(.+?)(:\r|\n|\r\n)')
class Node(object):
block = 0
@@ -361,7 +368,8 @@ def getvalue(self):
class Template(object):
def __init__(self, text='', vars=None, env=None, dirs=None,
- default_template=None, use_temp=False, compile=None, skip_error=False, encoding='utf-8'):
+ default_template=None, use_temp=False, compile=None, skip_error=False,
+ encoding='utf-8', begin_tag=None, end_tag=None):
self.text = text
self.filename = None
self.vars = vars or {}
@@ -381,6 +389,8 @@ def __init__(self, text='', vars=None, env=None, dirs=None,
self.root = self
self.skip_error = skip_error
self.encoding = encoding
+ self.begin_tag = begin_tag or BEGIN_TAG
+ self.end_tag = end_tag or END_TAG
for k, v in __nodes__.iteritems():
if hasattr(v, 'init'):
@@ -420,7 +430,7 @@ def parse(self):
text = self.text
in_tag = False
extend = None #if need to process extend node
- for i in r_tag.split(text):
+ for i in get_tag(self.begin_tag, self.end_tag).split(text):
if i:
if len(self.stack) == 0:
raise TemplateException, "The 'end' tag is unmatched, please check if you have more '{{end}}'"
@@ -429,10 +439,6 @@ def parse(self):
line = i[2:-2].strip()
if not line:
continue
-# if line.startswith('T='):
-# name, value = 'T=', line[2:].strip()
-# elif line.startswith('T<<'):
-# name, value = 'T<<', line[3:].strip()
elif line.startswith('='):
name, value = '=', line[1:].strip()
elif line.startswith('<<'):
@@ -480,14 +486,14 @@ def parse(self):
elif name == '<<':
buf = "%s(%s, escape=False)\n" % (self.writer, value)
top.add(buf)
- elif name == 'T=':
- if not self._parse_template(top, value):
- buf = "%s(%s)\n" % (self.writer, value)
- top.add(buf)
- elif name == 'T<<':
- if not self._parse_template(top, value):
- buf = "%s(%s, escape=False)\n" % (self.writer, value)
- top.add(buf)
+# elif name == 'T=':
+# if not self._parse_template(top, value):
+# buf = "%s(%s)\n" % (self.writer, value)
+# top.add(buf)
+# elif name == 'T<<':
+# if not self._parse_template(top, value):
+# buf = "%s(%s, escape=False)\n" % (self.writer, value)
+# top.add(buf)
elif name == 'include':
self._parse_include(top, value)
elif name == 'embed':
@@ -555,9 +561,9 @@ def _parse_include(self, content, value):
self.depend_files.append(fname)
f = open(fname, 'rb')
- text = f.read()
+ text, begin_tag, end_tag = self.get_text(f.read())
f.close()
- t = Template(text, self.vars, self.env, self.dirs)
+ t = Template(text, self.vars, self.env, self.dirs, begin_tag=begin_tag, end_tag=end_tag)
t.add_root(self)
t.parse()
content.merge(t.content)
@@ -577,9 +583,9 @@ def _parse_extend(self, value):
self.depend_files.append(fname)
f = open(fname, 'rb')
- text = f.read()
+ text, begin_tag, end_tag = self.get_text(f.read())
f.close()
- t = Template(text, self.vars, self.env, self.dirs)
+ t = Template(text, self.vars, self.env, self.dirs, begin_tag=begin_tag, end_tag=end_tag)
t.add_root(self)
t.parse()
self.content.clear_content()
@@ -612,9 +618,22 @@ def get_parsed_code(self):
return True, f, text
if self.filename and not self.text:
- self.text = file(self.filename, 'rb').read()
+ self.text, self.begin_tag, self.end_tag = self.get_text(file(self.filename, 'rb').read())
return False, self.filename, self.parse()
+ def get_text(self, text):
+ """
+ Detect template tag definition in the text
+ """
+ b = r_tag.search(text)
+ if b:
+ begin_tag, end_tag = b.group(1), b.group(2)
+ text = text[b.end():]
+ else:
+ begin_tag = self.begin_tag
+ end_tag = self.end_tag
+ return text, begin_tag, end_tag
+
def __call__(self):
use_temp_flag, filename, code = self.get_parsed_code()
@@ -671,13 +690,13 @@ def defined(v, default=None):
return text
-def template_file(filename, vars=None, env=None, dirs=None, default_template=None, compile=None):
- t = Template('', vars, env, dirs, default_template, use_temp=__options__['use_temp_dir'], compile=compile)
+def template_file(filename, vars=None, env=None, dirs=None, default_template=None, compile=None, **kwargs):
+ t = Template('', vars, env, dirs, default_template, use_temp=__options__['use_temp_dir'], compile=compile, **kwargs)
t.set_filename(filename)
return t()
-def template(text, vars=None, env=None, dirs=None, default_template=None):
- t = Template(text, vars, env, dirs, default_template)
+def template(text, vars=None, env=None, dirs=None, default_template=None, **kwargs):
+ t = Template(text, vars, env, dirs, default_template, **kwargs)
return t()

0 comments on commit d26cffb

Please sign in to comment.