Source code for wheezy.template.ext.determined
"""
"""
import re
from wheezy.template.utils import find_balanced
RE_ARGS = re.compile(
r'\s*(?P<expr>(([\'"]).*?\3|.+?))\s*\,')
RE_KWARGS = re.compile(
r'\s*(?P<name>\w+)\s*=\s*(?P<expr>([\'"].*?[\'"]|.+?))\s*\,')
RE_STR_VALUE = re.compile(
r'^[\'"](?P<value>.+)[\'"]$')
RE_INT_VALUE = re.compile(
r'^(?P<value>(\d+))$')
# region: core extension
class DeterminedExtension(object):
[docs] """ Tranlates function calls between template engines.
Strictly determined known calls are converted to preprocessor
calls, e.g.::
@_('Name:')
@path_for('default')
@path_for('static', path='/static/css/site.css')
Those that are not strictly determined are ignored and processed
by runtime engine.
"""
def __init__(self, known_calls, runtime_token_start='@',
token_start='#'):
self.token_start = token_start
self.pattern = re.compile(r'%s(%s)(?=\()' % (
runtime_token_start, '|'.join(known_calls)))
self.preprocessors = [self.preprocess]
def preprocess(self, source):
result = []
start = 0
for m in self.pattern.finditer(source):
pstart = m.end()
pend = find_balanced(source, pstart)
if determined(source[pstart + 1:pend - 1]):
name = m.group(1)
result.append(source[start:m.start()])
result.append(self.token_start + "ctx['" + name + "']")
start = pstart
if start:
result.append(source[start:])
return ''.join(result)
else:
return source
def determined(expression):
[docs] """ Checks if expresion is strictly determined.
>>> determined("'default'")
True
>>> determined('name')
False
>>> determined("'default', id=id")
False
>>> determined("'default', lang=100")
True
>>> determined('')
True
"""
args, kwargs = parse_params(expression)
for arg in args:
if not str_or_int(arg):
return False
for arg in kwargs.values():
if not str_or_int(arg):
return False
return True
def parse_kwargs(text):
[docs] """ Parses key-value type of parameters.
>>> parse_kwargs('id=item.id')
{'id': 'item.id'}
>>> sorted(parse_kwargs('lang="en", id=12').items())
[('id', '12'), ('lang', '"en"')]
"""
kwargs = {}
for m in RE_KWARGS.finditer(text + ','):
groups = m.groupdict()
kwargs[groups['name'].rstrip('_')] = groups['expr']
return kwargs
def parse_args(text):
[docs] """ Parses argument type of parameters.
>>> parse_args('')
[]
>>> parse_args('10, "x"')
['10', '"x"']
>>> parse_args("'x', 100")
["'x'", '100']
>>> parse_args('"default"')
['"default"']
"""
args = []
for m in RE_ARGS.finditer(text + ','):
args.append(m.group('expr'))
return args
def parse_params(text):
[docs] """ Parses function parameters.
>>> parse_params('')
([], {})
>>> parse_params('id=item.id')
([], {'id': 'item.id'})
>>> parse_params('"default"')
(['"default"'], {})
>>> parse_params('"default", lang="en"')
(['"default"'], {'lang': '"en"'})
"""
if '=' in text:
args = text.split('=')[0]
if ',' in args:
args = args.rsplit(',', 1)[0]
kwargs = text[len(args):]
return parse_args(args), parse_kwargs(kwargs)
else:
return [], parse_kwargs(text)
else:
return parse_args(text), {}
def str_or_int(text):
[docs] """ Ensures ``text`` as string or int expression.
>>> str_or_int('"default"')
True
>>> str_or_int("'Hello'")
True
>>> str_or_int('100')
True
>>> str_or_int('item.id')
False
"""
m = RE_STR_VALUE.match(text)
if m:
return True
else:
m = RE_INT_VALUE.match(text)
if m:
return True
return False