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