Last active
December 16, 2015 11:59
-
-
Save raphigaziano/5431016 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Hello, my name is {{ name }}! | |
I'm {{ age }} years old, yay! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
#-*- coding:utf-8 -*- | |
''' | |
Testing for a simple template ENGINE. | |
Tested: py2.7, py3.2 on win7 | |
Author: raphi <r.gaziano@gmail.com> | |
Created: 18/04/2013 | |
Version: 0.1 | |
''' | |
from __future__ import print_function | |
from __future__ import unicode_literals | |
import sys, os | |
import re | |
import logging | |
# DEBUG IMPORTS # | |
from pprint import pprint; from pdb import set_trace | |
if sys.version > '3': | |
unicode = str | |
_logger = logging.getLogger(__name__) | |
#~ _logger.addHandler(logging.NullHandler()) | |
_logger.addHandler(logging.StreamHandler()) | |
_logger.setLevel(logging.INFO) | |
# <external module> | |
### Regex Helpers ### | |
##################### | |
# ... | |
### Default Callbacks Processors ### | |
#################################### | |
def sub(m, **kwargs): | |
tag = m.group(1) if m.groups() else m.group() | |
val = str( kwargs.get(tag, "") ) # notenough... default err string ? | |
_logger.info("%s\t=> %s" % (tag, val)) | |
return val | |
def comment(m, **kwargs): | |
#~ print("Processing comments: %s" % m.group(0)) | |
return '' # avoid empty lines? | |
def include(m, **kwargs): | |
# if "in memory templs" can be registered somewhere, then | |
# we could name them and include them as well... | |
# but for now only works with a file path | |
path = m.group(1) | |
t = Template(path) | |
return t(**kwargs) | |
# ... | |
# </external module> | |
class Tag(object): | |
""" Class doc """ | |
def __init__ (self, regexp, f=sub): | |
""" Class initialiser """ | |
self.regexp = re.compile(regexp) | |
self.process = f | |
def render(self, tmpl, **kwargs): | |
''' ''' | |
out = tmpl | |
#~ _logger.info("Subs for %s..." % self) | |
#~ for m in re.finditer(self.pattern, tmpl): | |
for m in self.finditer(tmpl): | |
sub_pattern = re.escape(m.group(0)) | |
out = re.sub(sub_pattern, self.process(m, **kwargs), out) | |
return out | |
def __repr__(self): | |
return "<Tag> %s" % self.regexp.pattern | |
# <???> | |
def __getattr__(self, attr): return getattr(self.regexp, attr) | |
# </???> | |
# Rather useless for now... | |
class _TagManager(object): | |
""" """ | |
tags = [] | |
@classmethod | |
def add(cls, p): | |
""" """ | |
cls.tags.append(p) | |
@classmethod | |
def clear(cls): | |
""" """ | |
cls.tags = [] | |
class Template(object): | |
""" """ | |
def __init__(self, tmpl): | |
""" """ | |
if os.path.exists(tmpl): | |
tmpl = open(tmpl, 'r').read() | |
# unicode checks? | |
self.tmpl = tmpl | |
def __call__(self, *args, **kwargs): | |
# instead of a render method ? | |
# idea from pyratemp | |
out = self.tmpl | |
for t in _TagManager.tags: | |
out = t.render(out, **kwargs) | |
return out | |
### Top Level, Convenience functions ### | |
######################################## | |
def register(*tags): | |
""" """ | |
for t in tags: | |
#~ print("registering tag %s, %s instance" % (t, type(t))) | |
if isinstance(t, unicode): | |
_TagManager.add(Tag(t)) | |
elif isinstance(t, Tag): | |
_TagManager.add(t) | |
#~ print("Registered tags: %s" % ", ".join([str(t) | |
#~ for t in _TagManager.tags])) | |
def render(tmpl, **kwargs): | |
"""Not used, kept for tests""" | |
out = tmpl | |
for p in _TagManager.tags: | |
_logger.info("Subs for %s..." % p) | |
for m in re.finditer(p.pattern, tmpl): | |
tag = m.group(1) if m.groups() else m.group() | |
val = str( kwargs.get(tag, "") ) # notenough... default err string ? | |
_logger.info("%s => %s" % (tag, val)) | |
# 2nd arg can be a func acting on the match obj... | |
out = re.sub(m.group(0), val, out) | |
return out | |
### Pseudo Testing ### | |
###################### | |
if __name__ == '__main__': | |
register( | |
"popo", | |
"papa", | |
"pipi" | |
) | |
def testing(s): | |
hashes = '#' * (9 + len(s)) | |
print("\n%s\n%s\n%s\n" % (hashes, "Testing: " + s, hashes)) | |
testing("Tag Registration and Retrieval") | |
from pprint import pprint | |
pprint(_TagManager.tags) | |
testing("Stoopid, Individual Tag sub") | |
for t in _TagManager.tags: | |
tag = t.regexp.pattern | |
print("%s => %s" % (t, t.regexp.sub("pwal", "test_%s" % tag))) | |
_TagManager.clear() | |
assert(_TagManager.tags == []) | |
register( | |
"_name", | |
"_age" | |
) | |
testing("Simple Text Processing") | |
tmpl = """ | |
Hello, my name is _name! | |
I'm _age years old, yay! | |
""" | |
print(render(tmpl, _name="raphi", _age="26")) | |
testing("Simple Text Processing - repated tags") | |
tmpl = """ | |
Hello, my name is _name! | |
I'm _age years old, yay! | |
Did i say my name was _name? | |
""" | |
print(render(tmpl, _name="raphi", _age="26")) | |
_TagManager.clear() | |
#~ testing("Verbose tag definition") | |
_TagManager.clear() | |
register( | |
'{{ ?(?P<tag>\w+) ?}}' | |
#~ '{{ ?(\w+) ?}}' | |
) | |
testing("Moar \"complex\" regex (single group)") | |
tmpl = """ | |
Hello, my name is {{ name }}! | |
I'm {{ age }} years old, yay! | |
""" | |
print(render(tmpl, name="bob", age="32")) | |
testing("Missing var => blank (tempo: should raise a warning or fail)") | |
print(render(tmpl, name="marylou")) | |
testing("Int converted to Str") | |
print(render(tmpl, name="Joe", age=17)) | |
testing("Template Object rendering") | |
tmpl = Template(""" | |
Hello, my name is {{ name}}! | |
I'm {{ age }} years old, yay! | |
""" | |
) | |
print(tmpl(name="Bill", age=78)) | |
testing("Registering Tag instances directly") | |
_TagManager.clear() | |
register( | |
Tag("{{ ?(\w+) ?}}") | |
) | |
print("Ok") | |
testing("Custom Tag Function - no args") | |
def custom_func(m, **kwargs): | |
return sub(m, customtag="custom func called") | |
t = Tag("customtag", custom_func) | |
register(t) | |
print(Template("test test customtag test")()) | |
_TagManager.tags.remove(t) | |
testing("Custom Tag Function - lambda") | |
t = Tag("customtag", | |
lambda m, **kwargs: \ | |
sub(m, customtag="lambda custom func called") | |
) | |
register(t) | |
print(Template("test customtag test customtag test")()) | |
_TagManager.tags.remove(t) | |
#~ Tag.process = basic_substitute # Onoes.... custom funcs overides default one | |
testing("Load Template from File") | |
t = Template("tmpl.txt") | |
print(t(name="zoulou", age=65)) | |
testing("Comment Tag") | |
# (?s): flag to make . match newlines | |
#~ register(Tag(r"""(?xs) # flags: verbose, dotall | |
#~ {\# # start tag | |
#~ (.*?) # any character, anytime (including newlines) | |
#~ \#} # end tag | |
#~ """, comment)) | |
register(Tag(r"(?s){#(.*)#}", comment)) | |
tmpl = Template(""" | |
{# This is a comment #} | |
Hello, my name is {{ name}}! | |
I'm {{ age }} years old, yay! | |
""" | |
) | |
print(tmpl(name="suzy", age=3)) | |
testing("Multiline Comment") | |
tmpl = Template(""" | |
{# This is | |
a multiline | |
comment #} | |
Hello, my name is {{ name}}! | |
I'm {{ age }} years old, yay! | |
""" | |
) | |
print(tmpl(name="lilly", age=33)) | |
testing("Include Tag") | |
register(Tag(r"(?s){%\s?include\((.*)\)\s?%}", include)) | |
tmpl = Template(""" | |
{{ title }} | |
In base template | |
{% include(tmpl.txt) %} | |
Back in base tmpl | |
""" | |
) | |
print(tmpl(title="INCLUDE TEST", name="jojo", age=98)) | |
# TEST TAG __getattr__ ! | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment