wheezy.template-0.1.167/0000750000014600001520000000000012524064206016432 5ustar buildbotbuildbot00000000000000wheezy.template-0.1.167/MANIFEST.in0000640000014600001520000000003312524064143020165 0ustar buildbotbuildbot00000000000000include LICENSE README.rst wheezy.template-0.1.167/PKG-INFO0000640000014600001520000001067712524064206017543 0ustar buildbotbuildbot00000000000000Metadata-Version: 1.1 Name: wheezy.template Version: 0.1.167 Summary: A lightweight template library Home-page: https://bitbucket.org/akorn/wheezy.template Author: Andriy Kornatskyy Author-email: andriy.kornatskyy at live.com License: MIT Description: `wheezy.template`_ is a `python`_ package written in pure Python code. It is a lightweight template library. The design goals achived: * **Compact, Expressive, Clean:** Minimizes the number of keystrokes required to build a template. Enables fast and well read coding. You do not need to explicitly denote statement blocks within HTML (unlike other template systems), the parser is smart enough to understand your code. This enables a compact and expressive syntax which is really clean and just pleasure to type. * **Intuitive, No time to Learn:** Basic Python programming skills plus HTML markup. You are productive just from start. Use full power of Python with minimal markup required to denote python statements. * **Do Not Repeat Yourself:** Master layout templates for inheritance; include and import directives for maximum reuse. * **Blazingly Fast:** Maximum rendering performance: ultimate speed and context preprocessor features. Simple template:: @require(user, items) Welcome, @user.name! @if items: @for i in items: @i.name: @i.price!s. @end @else: No items found. @end It is optimized for performance, well tested and documented. Resources: * `source code`_, `examples`_ and `issues`_ tracker are available on `bitbucket`_ * `documentation`_, `readthedocs`_ * `eggs`_ on `pypi`_ Install ------- `wheezy.template`_ requires `python`_ version 2.4 to 2.7 or 3.2+. It is independent of operating system. You can install it from `pypi`_ site using `setuptools`_:: $ easy_install wheezy.template If you are using `virtualenv`_:: $ virtualenv env $ env/bin/easy_install wheezy.template If you run into any issue or have comments, go ahead and add on `bitbucket`_. .. _`bitbucket`: http://bitbucket.org/akorn/wheezy.template .. _`doctest`: http://docs.python.org/library/doctest.html .. _`documentation`: http://packages.python.org/wheezy.template .. _`eggs`: http://pypi.python.org/pypi/wheezy.template .. _`examples`: http://bitbucket.org/akorn/wheezy.template/src/tip/demos .. _`issues`: http://bitbucket.org/akorn/wheezy.template/issues .. _`pypi`: http://pypi.python.org/pypi/wheezy.template .. _`python`: http://www.python.org .. _`readthedocs`: http://readthedocs.org/builds/wheezytemplate .. _`setuptools`: http://pypi.python.org/pypi/setuptools .. _`source code`: http://bitbucket.org/akorn/wheezy.template/src .. _`virtualenv`: http://pypi.python.org/pypi/virtualenv .. _`wheezy.template`: http://pypi.python.org/pypi/wheezy.template Keywords: html markup template preprocessor Platform: any Classifier: Development Status :: 4 - Beta Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.4 Classifier: Programming Language :: Python :: 2.5 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.2 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Topic :: Internet :: WWW/HTTP Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: Software Development :: Widget Sets Classifier: Topic :: Text Processing :: Markup :: HTML wheezy.template-0.1.167/setup.cfg0000640000014600001520000000024412524064206020254 0ustar buildbotbuildbot00000000000000[egg_info] tag_build = .167 tag_date = 0 tag_svn_revision = 0 [bdist_egg] exclude-source-files = 0 [upload_docs] upload-dir = doc/_build [pytest] pep8ignore = wheezy.template-0.1.167/README.rst0000640000014600001520000000477012524064143020132 0ustar buildbotbuildbot00000000000000`wheezy.template`_ is a `python`_ package written in pure Python code. It is a lightweight template library. The design goals achived: * **Compact, Expressive, Clean:** Minimizes the number of keystrokes required to build a template. Enables fast and well read coding. You do not need to explicitly denote statement blocks within HTML (unlike other template systems), the parser is smart enough to understand your code. This enables a compact and expressive syntax which is really clean and just pleasure to type. * **Intuitive, No time to Learn:** Basic Python programming skills plus HTML markup. You are productive just from start. Use full power of Python with minimal markup required to denote python statements. * **Do Not Repeat Yourself:** Master layout templates for inheritance; include and import directives for maximum reuse. * **Blazingly Fast:** Maximum rendering performance: ultimate speed and context preprocessor features. Simple template:: @require(user, items) Welcome, @user.name! @if items: @for i in items: @i.name: @i.price!s. @end @else: No items found. @end It is optimized for performance, well tested and documented. Resources: * `source code`_, `examples`_ and `issues`_ tracker are available on `bitbucket`_ * `documentation`_, `readthedocs`_ * `eggs`_ on `pypi`_ Install ------- `wheezy.template`_ requires `python`_ version 2.4 to 2.7 or 3.2+. It is independent of operating system. You can install it from `pypi`_ site using `setuptools`_:: $ easy_install wheezy.template If you are using `virtualenv`_:: $ virtualenv env $ env/bin/easy_install wheezy.template If you run into any issue or have comments, go ahead and add on `bitbucket`_. .. _`bitbucket`: http://bitbucket.org/akorn/wheezy.template .. _`doctest`: http://docs.python.org/library/doctest.html .. _`documentation`: http://packages.python.org/wheezy.template .. _`eggs`: http://pypi.python.org/pypi/wheezy.template .. _`examples`: http://bitbucket.org/akorn/wheezy.template/src/tip/demos .. _`issues`: http://bitbucket.org/akorn/wheezy.template/issues .. _`pypi`: http://pypi.python.org/pypi/wheezy.template .. _`python`: http://www.python.org .. _`readthedocs`: http://readthedocs.org/builds/wheezytemplate .. _`setuptools`: http://pypi.python.org/pypi/setuptools .. _`source code`: http://bitbucket.org/akorn/wheezy.template/src .. _`virtualenv`: http://pypi.python.org/pypi/virtualenv .. _`wheezy.template`: http://pypi.python.org/pypi/wheezy.template wheezy.template-0.1.167/setup.py0000640000014600001520000000503112524064143020144 0ustar buildbotbuildbot00000000000000#!/usr/bin/env python import os try: from setuptools import setup except: from distutils.core import setup # noqa extra = {} try: from Cython.Build import cythonize p = os.path.join('src', 'wheezy', 'template') extra['ext_modules'] = cythonize( [os.path.join(p, '*.py'), os.path.join(p, 'ext', '*.py')], exclude=[os.path.join(p, '__init__.py'), os.path.join(p, 'ext', '__init__.py')], nthreads=2, quiet=True) except ImportError: pass README = open(os.path.join(os.path.dirname(__file__), 'README.rst')).read() setup( name='wheezy.template', version='0.1', description='A lightweight template library', long_description=README, url='https://bitbucket.org/akorn/wheezy.template', author='Andriy Kornatskyy', author_email='andriy.kornatskyy at live.com', license='MIT', classifiers=[ 'Development Status :: 4 - Beta', 'Environment :: Web Environment', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Natural Language :: English', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.4', 'Programming Language :: Python :: 2.5', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Software Development :: Widget Sets', 'Topic :: Text Processing :: Markup :: HTML' ], keywords='html markup template preprocessor', packages=['wheezy', 'wheezy.template', 'wheezy.template.ext'], package_dir={'': 'src'}, namespace_packages=['wheezy'], zip_safe=False, install_requires=[ ], extras_require={ 'dev': [ 'coverage', 'nose', 'pytest', 'pytest-pep8', 'pytest-cov', ] }, entry_points={ 'console_scripts': [ 'wheezy.template=wheezy.template.console:main' ] }, platforms='any', **extra ) wheezy.template-0.1.167/src/0000750000014600001520000000000012524064206017221 5ustar buildbotbuildbot00000000000000wheezy.template-0.1.167/src/wheezy/0000750000014600001520000000000012524064206020534 5ustar buildbotbuildbot00000000000000wheezy.template-0.1.167/src/wheezy/__init__.py0000640000014600001520000000036612524064143022653 0ustar buildbotbuildbot00000000000000# See # http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages try: __import__('pkg_resources').declare_namespace(__name__) except ImportError: from pkgutil import extend_path __path__ = extend_path(__path__, __name__) wheezy.template-0.1.167/src/wheezy/template/0000750000014600001520000000000012524064206022347 5ustar buildbotbuildbot00000000000000wheezy.template-0.1.167/src/wheezy/template/builder.py0000640000014600001520000000610712524064143024354 0ustar buildbotbuildbot00000000000000 """ """ def builder_scan(extensions): builder_rules = {} for extension in extensions: if hasattr(extension, 'builder_rules'): rules = extension.builder_rules for token, builder in rules: builder_rules.setdefault(token, []).append(builder) return { 'builder_rules': builder_rules } class BlockBuilder(object): __slots__ = ('rules', 'indent', 'lineno', 'buf') def __init__(self, rules, indent='', lineno=0): self.rules = rules self.indent = indent self.lineno = lineno self.buf = [] def start_block(self): self.indent += ' ' def end_block(self): if len(self.indent) < 4: raise SyntaxError('Unexpected end of block.') self.indent = self.indent[:-4] def add(self, lineno, code): if lineno < self.lineno: raise SyntaxError('Inconsistence at %s : %s' % (self.lineno, lineno)) if lineno == self.lineno: line = self.buf[-1] if code: if line: if line[-1:] == ':': self.buf[-1] = line + code else: self.buf[-1] = line + '; ' + code else: self.buf[-1] = self.indent + code else: pad = lineno - self.lineno - 1 if pad > 0: self.buf.extend([''] * pad) if code: self.buf.append(self.indent + code) else: self.buf.append('') self.lineno = lineno + code.count('\n') def build_block(self, nodes): for lineno, token, value in nodes: self.build_token(lineno, token, value) def build_token(self, lineno, token, value): if token in self.rules: for rule in self.rules[token]: if rule(self, lineno, token, value): break else: raise SyntaxError('No rule to build "%s" token at line %d.' % (token, lineno)) def to_string(self): return '\n'.join(self.buf) class SourceBuilder(object): __slots__ = ('rules', 'lineno') def __init__(self, builder_rules, builder_offset=2, **ignore): self.rules = builder_rules self.lineno = 0 - builder_offset def build_source(self, nodes): builder = BlockBuilder(self.rules) builder.build_block(nodes) return builder.to_string() def build_render(self, nodes): builder = BlockBuilder(self.rules, lineno=self.lineno) builder.add(self.lineno + 1, 'def render(ctx, local_defs, super_defs):') builder.start_block() builder.build_token(self.lineno + 2, 'render', nodes) return builder.to_string() def build_module(self, nodes): builder = BlockBuilder(self.rules, lineno=self.lineno) builder.add(self.lineno + 1, 'local_defs = {}; super_defs = {}') builder.build_token(self.lineno + 2, 'module', nodes) return builder.to_string() wheezy.template-0.1.167/src/wheezy/template/preprocessor.py0000640000014600001520000000602612524064143025454 0ustar buildbotbuildbot00000000000000 """ """ from wheezy.template.comp import allocate_lock from wheezy.template.loader import ChainLoader from wheezy.template.loader import DictLoader class Preprocessor(object): """ Preprocess templates with ``engine`` and vary runtime templates by ``key_factory`` function using ``runtime_engine_factory``. """ def __init__(self, runtime_engine_factory, engine, key_factory): self.lock = allocate_lock() self.runtime_engines = {} self.runtime_engine_factory = runtime_engine_factory self.engine = engine self.loader = engine.loader self.key_factory = key_factory template_class = self.engine.template_class self.engine.template_class = lambda name, render_template: \ template_class(name, lambda ctx, local_defs, super_defs: self.render(name, ctx, local_defs, super_defs)) def get_template(self, name): return self.engine.get_template(name) def render(self, name, ctx, local_defs, super_defs): try: runtime_engine = self.runtime_engines[ self.key_factory(ctx)] except KeyError: runtime_engine = self.ensure_runtime_engine( self.key_factory(ctx)) try: return runtime_engine.renders[name](ctx, local_defs, super_defs) except KeyError: self.preprocess_template(runtime_engine, name, ctx) return runtime_engine.renders[name](ctx, local_defs, super_defs) def remove(self, name): self.lock.acquire(1) try: self.engine.remove(name) for runtime_engine in self.runtime_engines.values(): runtime_engine.remove(name) finally: self.lock.release() # region: internal details def ensure_runtime_engine(self, key): self.lock.acquire(1) try: engines = self.runtime_engines if key in engines: # pragma: nocover return engines[key] engine = engines[key] = self.runtime_engine_factory( loader=ChainLoader([DictLoader({}), self.engine.loader])) def render(name, ctx, local_defs, super_defs): try: return engine.renders[name](ctx, local_defs, super_defs) except KeyError: self.preprocess_template(engine, name, ctx) return engine.renders[name](ctx, local_defs, super_defs) engine.global_vars['_r'] = render return engine finally: self.lock.release() def preprocess_template(self, runtime_engine, name, ctx): self.lock.acquire(1) try: if name not in runtime_engine.renders: source = self.engine.render(name, ctx, {}, {}) loader = runtime_engine.loader.loaders[0] loader.templates[name] = source runtime_engine.compile_template(name) del loader.templates[name] finally: self.lock.release() wheezy.template-0.1.167/src/wheezy/template/ext/0000750000014600001520000000000012524064206023147 5ustar buildbotbuildbot00000000000000wheezy.template-0.1.167/src/wheezy/template/ext/determined.py0000640000014600001520000001006212524064143025641 0ustar buildbotbuildbot00000000000000 """ """ import re from wheezy.template.utils import find_balanced RE_ARGS = re.compile( r'\s*(?P(([\'"]).*?\3|.+?))\s*\,') RE_KWARGS = re.compile( r'\s*(?P\w+)\s*=\s*(?P([\'"].*?[\'"]|.+?))\s*\,') RE_STR_VALUE = re.compile( r'^[\'"](?P.+)[\'"]$') RE_INT_VALUE = re.compile( r'^(?P(\d+))$') # region: core extension class DeterminedExtension(object): """ 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): """ 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): """ 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): """ 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): """ 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): """ 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 wheezy.template-0.1.167/src/wheezy/template/ext/__init__.py0000640000014600001520000000000012524064143025247 0ustar buildbotbuildbot00000000000000wheezy.template-0.1.167/src/wheezy/template/ext/code.py0000640000014600001520000000214112524064143024432 0ustar buildbotbuildbot00000000000000 """ """ import re from wheezy.template.utils import find_balanced # region: lexer extensions def code_token(m): source = m.string start = m.end() end = find_balanced(source, start) if source[end::1] == '\n': end += 1 return end, 'code', source[start:end] # region: parser def parse_code(value): lines = value.rstrip('\n')[1:-1].split('\n') lines[0] = lines[0].lstrip() if len(lines) == 1: return lines line = lines[1] n = len(line) - len(line.lstrip()) return [l[:n].lstrip() + l[n:] for l in lines] # region: block_builders def build_code(builder, lineno, token, lines): for line in lines: builder.add(lineno, line) lineno += 1 return True # region: core extension class CodeExtension(object): """ Includes support for embedded python code. """ def __init__(self, token_start='@'): self.lexer_rules = { 300: (re.compile(r'\s*%s(?=\()' % token_start), code_token), } parser_rules = { 'code': parse_code } builder_rules = [ ('code', build_code) ] wheezy.template-0.1.167/src/wheezy/template/ext/core.py0000640000014600001520000002623312524064143024460 0ustar buildbotbuildbot00000000000000 """ """ import re from wheezy.template.comp import PY3 from wheezy.template.utils import find_all_balanced # region: config end_tokens = ['end'] continue_tokens = ['else:', 'elif '] compound_tokens = ['for ', 'if ', 'def ', 'extends'] + continue_tokens reserved_tokens = ['require', '#', 'include', 'import ', 'from '] all_tokens = end_tokens + compound_tokens + reserved_tokens out_tokens = ['markup', 'var', 'include'] extends_tokens = ['def ', 'require', 'import ', 'from '] known_var_filters = { 's': PY3 and 'str' or 'unicode' } WRITER_DECLARE = '_b = []; w = _b.append' WRITER_RETURN = "return ''.join(_b)" # region: lexer extensions def stmt_token(m): """ Produces statement token. """ return m.end(), str(m.group(2)), str(m.group(1)).replace('\\\n', '') RE_VAR = re.compile('(\.\w+)+') RE_VAR_FILTER = re.compile('(? 1: nested = nodes[:-1] + nested for lineno, token, value in nested: if token in extends_tokens: builder.build_token(lineno, token, value) builder.add(builder.lineno + 1, 'return _r(' + extends + ', ctx, local_defs, super_defs)') return True def build_module(builder, lineno, token, nodes): assert token == 'module' for lineno, token, value in nodes: if token == 'def ': builder.build_token(lineno, token, value) return True def build_import(builder, lineno, token, value): assert token == 'import ' name, var = value builder.add(lineno, var + ' = _i(' + name + ')') return True def build_from(builder, lineno, token, value): assert token == 'from ' name, var, alias = value builder.add(lineno, alias + ' = _i(' + name + ').local_defs[\'' + var + '\']') return True def build_render_single_markup(builder, lineno, token, nodes): assert lineno <= 0 assert token == 'render' if len(nodes) > 1: return False if len(nodes) == 0: builder.add(lineno, "return ''") return True ln, token, nodes = nodes[0] if token != 'out' or len(nodes) > 1: return False ln, token, value = nodes[0] if token != 'markup': return False if value: builder.add(ln, 'return ' + value) else: builder.add(ln, "return ''") return True def build_render(builder, lineno, token, nodes): assert lineno <= 0 assert token == 'render' builder.add(lineno, WRITER_DECLARE) builder.build_block(nodes) lineno = builder.lineno builder.add(lineno + 1, WRITER_RETURN) return True def build_def_syntax_check(builder, lineno, token, value): assert token == 'def ' stmt, nodes = value lineno, token, value = nodes[0] if token in compound_tokens: builder.add(lineno, stmt) builder.start_block() token = token.rstrip() error = """\ The compound statement '%s' is not allowed here. \ Add a line before it with @#ignore or leave it empty. %s @#ignore @%s ...""" % (token, stmt, token) builder.add(lineno, 'raise SyntaxError(%s)' % repr(error)) builder.end_block() return True elif len(nodes) > 1: # token before @end lineno, token, value = nodes[-2] if token == '#': del nodes[-2] return False def build_def_empty(builder, lineno, token, value): assert token == 'def ' stmt, nodes = value if len(nodes) > 1: return False def_name = stmt[4:stmt.index('(', 5)] builder.add(lineno, stmt) builder.start_block() builder.add(lineno, "return ''") builder.end_block() builder.add(lineno + 1, def_name.join([ "super_defs['", "'] = ", "; ", " = local_defs.setdefault('", "', ", ")" ])) return True def build_def_single_markup(builder, lineno, token, value): assert token == 'def ' stmt, nodes = value if len(nodes) > 2: return False ln, token, nodes = nodes[0] if token != 'out' or len(nodes) > 1: return False ln, token, value = nodes[0] if token != 'markup': return False def_name = stmt[4:stmt.index('(', 5)] builder.add(lineno, stmt) builder.start_block() builder.add(ln, "return " + value) builder.end_block() builder.add(ln + 1, def_name.join([ "super_defs['", "'] = ", "; ", " = local_defs.setdefault('", "', ", ")" ])) return True def build_def(builder, lineno, token, value): assert token == 'def ' stmt, nodes = value def_name = stmt[4:stmt.index('(', 5)] builder.add(lineno, stmt) builder.start_block() builder.add(lineno + 1, WRITER_DECLARE) builder.build_block(nodes) lineno = builder.lineno builder.add(lineno, WRITER_RETURN) builder.end_block() builder.add(lineno + 1, def_name.join([ "super_defs['", "'] = ", "; ", " = local_defs.setdefault('", "', ", ")" ])) return True def build_out(builder, lineno, token, nodes): assert token == 'out' builder.build_block(nodes) return True def build_include(builder, lineno, token, value): assert token == 'include' builder.add(lineno, 'w(_r(' + value + ', ctx, local_defs, super_defs))') return True def build_var(builder, lineno, token, value): assert token == 'var' var, var_filters = value if var_filters: for f in var_filters: var = known_var_filters.get(f, f) + '(' + var + ')' builder.add(lineno, 'w(' + var + ')') return True def build_markup(builder, lineno, token, value): assert token == 'markup' if value: builder.add(lineno, 'w(' + value + ')') return True def build_compound(builder, lineno, token, value): assert token in compound_tokens stmt, nodes = value builder.add(lineno, stmt) builder.start_block() builder.build_block(nodes) builder.end_block() return True def build_require(builder, lineno, token, variables): assert token == 'require' builder.add(lineno, '; '.join([ name + " = ctx['" + name + "']" for name in variables])) return True def build_comment(builder, lineno, token, comment): assert token == '#' builder.add(lineno, comment) return True def build_end(builder, lineno, token, value): if builder.lineno != lineno: builder.add(lineno - 1, '') return True # region: core extension class CoreExtension(object): """ Includes basic statements, variables processing and markup. """ def __init__(self, token_start='@', line_join='\\'): def markup_token(m): """ Produces markup token. """ return m.end(), 'markup', m.group().replace( token_start + token_start, token_start) self.lexer_rules = { 100: (re.compile(r'%s((%s).*?(?= 3 if PY3: # pragma: nocover from _thread import allocate_lock else: # pragma: nocover from thread import allocate_lock # noqa try: # pragma: nocover import ast def adjust_source_lineno(source, name, lineno): source = compile(source, name, 'exec', ast.PyCF_ONLY_AST) ast.increment_lineno(source, lineno) return source except ImportError: # pragma: nocover def adjust_source_lineno(source, name, lineno): # noqa return source wheezy.template-0.1.167/src/wheezy/template/__init__.py0000640000014600001520000000052412524064206024462 0ustar buildbotbuildbot00000000000000 """ """ # flake8: noqa from wheezy.template.engine import Engine from wheezy.template.ext.code import CodeExtension from wheezy.template.ext.core import CoreExtension from wheezy.template.loader import DictLoader from wheezy.template.loader import FileLoader from wheezy.template.loader import PreprocessLoader __version__ = '0.1.167' wheezy.template-0.1.167/src/wheezy/template/loader.py0000640000014600001520000001276312524064143024201 0ustar buildbotbuildbot00000000000000 """ """ import os import os.path import stat from time import time class FileLoader(object): """ Loads templates from file system. ``directories`` - search path of directories to scan for template. ``encoding`` - decode template content per encoding. """ def __init__(self, directories, encoding='UTF-8'): searchpath = [] for path in directories: abspath = os.path.abspath(path) assert os.path.exists(abspath) assert os.path.isdir(abspath) searchpath.append(abspath) self.searchpath = searchpath self.encoding = encoding def list_names(self): """ Return a list of names relative to directories. Ignores any files and directories that start with dot. """ names = [] for path in self.searchpath: pathlen = len(path) + 1 for dirpath, dirnames, filenames in os.walk(path): for i in [i for i, name in enumerate(dirnames) if name.startswith('.')]: del dirnames[i] for filename in filenames: if filename.startswith('.'): continue name = os.path.join(dirpath, filename)[pathlen:] name = name.replace('\\', '/') names.append(name) return tuple(sorted(names)) def get_fullname(self, name): """ Returns a full path by a template name. """ for path in self.searchpath: filename = os.path.join(path, name) if not os.path.exists(filename): continue if not os.path.isfile(filename): continue return filename else: None def load(self, name): """ Loads a template by name from file system. """ filename = self.get_fullname(name) if filename: f = open(filename, 'rb') try: return f.read().decode(self.encoding) finally: f.close() return None class DictLoader(object): """ Loads templates from python dictionary. ``templates`` - a dict where key corresponds to template name and value to template content. """ def __init__(self, templates): self.templates = templates def list_names(self): """ List all keys from internal dict. """ return tuple(sorted(self.templates.keys())) def load(self, name): """ Returns template by name. """ if name not in self.templates: return None return self.templates[name] class ChainLoader(object): """ Loads templates from ``loaders`` until first succeed. """ def __init__(self, loaders): self.loaders = loaders def list_names(self): """ Returns as list of names from all loaders. """ names = set() for loader in self.loaders: names |= set(loader.list_names()) return tuple(sorted(names)) def load(self, name): """ Returns template by name from the first loader that succeed. """ for loader in self.loaders: source = loader.load(name) if source is not None: return source return None class PreprocessLoader(object): """ Performs preprocessing of loaded template. """ def __init__(self, engine, ctx=None): self.engine = engine self.ctx = ctx or {} def list_names(self): return self.engine.loader.list_names() def load(self, name): return self.engine.render(name, self.ctx, {}, {}) def autoreload(engine, enabled=True): """ Auto reload template if changes are detected in file. Limitation: master (inherited), imported and preprocessed templates. It is recommended to use application server that supports file reload instead. """ if not enabled: return engine return AutoReloadProxy(engine) # region: internal details class AutoReloadProxy(object): def __init__(self, engine): from warnings import warn self.engine = engine self.names = {} warn('autoreload limitation: master (inherited), imported ' 'and preprocessed templates. It is recommended to use ' 'application server that supports file reload instead.', stacklevel=3) def get_template(self, name): if self.file_changed(name): self.remove(name) return self.engine.get_template(name) def render(self, name, ctx, local_defs, super_defs): if self.file_changed(name): self.remove(name) return self.engine.render(name, ctx, local_defs, super_defs) def remove(self, name): self.engine.remove(name) # region: internal details def __getattr__(self, name): return getattr(self.engine, name) def file_changed(self, name): try: last_known_stamp = self.names[name] current_time = int(time()) if current_time - last_known_stamp <= 2: return False except KeyError: last_known_stamp = 0 abspath = self.engine.loader.get_fullname(name) if not abspath: return False last_modified_stamp = os.stat(abspath)[stat.ST_MTIME] if last_modified_stamp <= last_known_stamp: return False self.names[name] = last_modified_stamp return True wheezy.template-0.1.167/src/wheezy/template/lexer.py0000640000014600001520000000432612524064143024046 0ustar buildbotbuildbot00000000000000 """ """ def lexer_scan(extensions): """ Scans extensions for ``lexer_rules`` and ``preprocessors`` attributes. """ lexer_rules = {} preprocessors = [] postprocessors = [] for extension in extensions: if hasattr(extension, 'lexer_rules'): lexer_rules.update(extension.lexer_rules) if hasattr(extension, 'preprocessors'): preprocessors.extend(extension.preprocessors) if hasattr(extension, 'postprocessors'): postprocessors.extend(extension.postprocessors) return { 'lexer_rules': [lexer_rules[k] for k in sorted(lexer_rules.keys())], 'preprocessors': preprocessors, 'postprocessors': postprocessors } class Lexer(object): """ Tokenizes input source per rules supplied. """ def __init__(self, lexer_rules, preprocessors=None, postprocessors=None, **ignore): """ Initializes with ``rules``. Rules must be a list of two elements tuple: ``(regex, tokenizer)`` where tokenizer if a callable of the following contract:: def tokenizer(match): return end_index, token, value """ self.rules = lexer_rules self.preprocessors = preprocessors or [] self.postprocessors = postprocessors or [] def tokenize(self, source): """ Translates ``source`` accoring to lexer rules into an iteratable of tokens. """ for preprocessor in self.preprocessors: source = preprocessor(source) tokens = [] append = tokens.append pos = 0 lineno = 1 end = len(source) while pos < end: for regex, tokenizer in self.rules: m = regex.match(source, pos, end) if m: npos, token, value = tokenizer(m) assert npos > pos append((lineno, token, value)) lineno += source[pos:npos].count('\n') pos = npos break else: assert False, 'Lexer pattern mismatch.' for postprocessor in self.postprocessors: postprocessor(tokens) return tokens wheezy.template-0.1.167/src/wheezy/template/utils.py0000640000014600001520000000231712524064143024065 0ustar buildbotbuildbot00000000000000 """ """ def find_all_balanced(text, start=0): """ Finds balanced ``([`` with ``])`` assuming that ``start`` is pointing to ``(`` or ``[`` in ``text``. """ if start >= len(text) or text[start] not in '([': return start while(1): pos = find_balanced(text, start) pos = find_balanced(text, pos, '[', ']') if pos != start: start = pos else: return pos def find_balanced(text, start=0, start_sep='(', end_sep=')'): """ Finds balanced ``start_sep`` with ``end_sep`` assuming that ``start`` is pointing to ``start_sep`` in ``text``. """ if start >= len(text) or start_sep != text[start]: return start balanced = 1 pos = start + 1 while pos < len(text): token = text[pos] pos += 1 if token == end_sep: if balanced == 1: return pos balanced -= 1 elif token == start_sep: balanced += 1 return start def print_source(source, lineno=1): # pragma: nocover lines = [] for line in source.split('\n'): lines.append("%02d " % lineno + line) lineno += line.count('\n') + 1 print('\n'.join(lines)) wheezy.template-0.1.167/src/wheezy/template/parser.py0000640000014600001520000000424012524064143024216 0ustar buildbotbuildbot00000000000000 """ """ def parser_scan(extensions): parser_rules = {} parser_configs = [] for extension in extensions: if hasattr(extension, 'parser_rules'): parser_rules.update(extension.parser_rules) if hasattr(extension, 'parser_configs'): parser_configs.extend(extension.parser_configs) return { 'parser_rules': parser_rules, 'parser_configs': parser_configs, } class Parser(object): """ ``continue_tokens`` are used to insert ``end`` node right before them to simulate a block end. Such nodes have token value ``None``. ``out_tokens`` are combined together into a single node. """ def __init__(self, parser_rules, parser_configs=None, **ignore): self.end_tokens = [] self.continue_tokens = [] self.compound_tokens = [] self.out_tokens = [] self.rules = parser_rules if parser_configs: for config in parser_configs: config(self) def end_continue(self, tokens): """ If token is in ``continue_tokens`` prepend it with end token so it simulate a closed block. """ for t in tokens: if t[1] in self.continue_tokens: yield (t[0], 'end', None) yield t def parse_iter(self, tokens): operands = [] for lineno, token, value in tokens: if token in self.rules: value = self.rules[token](value) if token in self.out_tokens: operands.append((lineno, token, value)) else: if operands: yield operands[0][0], 'out', operands operands = [] if token in self.compound_tokens: yield lineno, token, ( value, list(self.parse_iter(tokens))) else: yield lineno, token, value if token in self.end_tokens: break if operands: yield operands[0][0], 'out', operands def parse(self, tokens): return list(self.parse_iter(self.end_continue(tokens))) wheezy.template-0.1.167/src/wheezy.template.egg-info/0000750000014600001520000000000012524064206024040 5ustar buildbotbuildbot00000000000000wheezy.template-0.1.167/src/wheezy.template.egg-info/requires.txt0000640000014600001520000000006312524064206026440 0ustar buildbotbuildbot00000000000000 [dev] coverage nose pytest pytest-pep8 pytest-covwheezy.template-0.1.167/src/wheezy.template.egg-info/dependency_links.txt0000640000014600001520000000000112524064206030107 0ustar buildbotbuildbot00000000000000 wheezy.template-0.1.167/src/wheezy.template.egg-info/PKG-INFO0000640000014600001520000001067712524064206025151 0ustar buildbotbuildbot00000000000000Metadata-Version: 1.1 Name: wheezy.template Version: 0.1.167 Summary: A lightweight template library Home-page: https://bitbucket.org/akorn/wheezy.template Author: Andriy Kornatskyy Author-email: andriy.kornatskyy at live.com License: MIT Description: `wheezy.template`_ is a `python`_ package written in pure Python code. It is a lightweight template library. The design goals achived: * **Compact, Expressive, Clean:** Minimizes the number of keystrokes required to build a template. Enables fast and well read coding. You do not need to explicitly denote statement blocks within HTML (unlike other template systems), the parser is smart enough to understand your code. This enables a compact and expressive syntax which is really clean and just pleasure to type. * **Intuitive, No time to Learn:** Basic Python programming skills plus HTML markup. You are productive just from start. Use full power of Python with minimal markup required to denote python statements. * **Do Not Repeat Yourself:** Master layout templates for inheritance; include and import directives for maximum reuse. * **Blazingly Fast:** Maximum rendering performance: ultimate speed and context preprocessor features. Simple template:: @require(user, items) Welcome, @user.name! @if items: @for i in items: @i.name: @i.price!s. @end @else: No items found. @end It is optimized for performance, well tested and documented. Resources: * `source code`_, `examples`_ and `issues`_ tracker are available on `bitbucket`_ * `documentation`_, `readthedocs`_ * `eggs`_ on `pypi`_ Install ------- `wheezy.template`_ requires `python`_ version 2.4 to 2.7 or 3.2+. It is independent of operating system. You can install it from `pypi`_ site using `setuptools`_:: $ easy_install wheezy.template If you are using `virtualenv`_:: $ virtualenv env $ env/bin/easy_install wheezy.template If you run into any issue or have comments, go ahead and add on `bitbucket`_. .. _`bitbucket`: http://bitbucket.org/akorn/wheezy.template .. _`doctest`: http://docs.python.org/library/doctest.html .. _`documentation`: http://packages.python.org/wheezy.template .. _`eggs`: http://pypi.python.org/pypi/wheezy.template .. _`examples`: http://bitbucket.org/akorn/wheezy.template/src/tip/demos .. _`issues`: http://bitbucket.org/akorn/wheezy.template/issues .. _`pypi`: http://pypi.python.org/pypi/wheezy.template .. _`python`: http://www.python.org .. _`readthedocs`: http://readthedocs.org/builds/wheezytemplate .. _`setuptools`: http://pypi.python.org/pypi/setuptools .. _`source code`: http://bitbucket.org/akorn/wheezy.template/src .. _`virtualenv`: http://pypi.python.org/pypi/virtualenv .. _`wheezy.template`: http://pypi.python.org/pypi/wheezy.template Keywords: html markup template preprocessor Platform: any Classifier: Development Status :: 4 - Beta Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.4 Classifier: Programming Language :: Python :: 2.5 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.2 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Topic :: Internet :: WWW/HTTP Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: Software Development :: Widget Sets Classifier: Topic :: Text Processing :: Markup :: HTML wheezy.template-0.1.167/src/wheezy.template.egg-info/top_level.txt0000640000014600001520000000000712524064206026570 0ustar buildbotbuildbot00000000000000wheezy wheezy.template-0.1.167/src/wheezy.template.egg-info/not-zip-safe0000640000014600001520000000000112524064205026266 0ustar buildbotbuildbot00000000000000 wheezy.template-0.1.167/src/wheezy.template.egg-info/namespace_packages.txt0000640000014600001520000000000712524064206030371 0ustar buildbotbuildbot00000000000000wheezy wheezy.template-0.1.167/src/wheezy.template.egg-info/SOURCES.txt0000640000014600001520000000160612524064206025730 0ustar buildbotbuildbot00000000000000LICENSE MANIFEST.in README.rst setup.cfg setup.py src/wheezy/__init__.py src/wheezy.template.egg-info/PKG-INFO src/wheezy.template.egg-info/SOURCES.txt src/wheezy.template.egg-info/dependency_links.txt src/wheezy.template.egg-info/entry_points.txt src/wheezy.template.egg-info/namespace_packages.txt src/wheezy.template.egg-info/not-zip-safe src/wheezy.template.egg-info/requires.txt src/wheezy.template.egg-info/top_level.txt src/wheezy/template/__init__.py src/wheezy/template/builder.py src/wheezy/template/comp.py src/wheezy/template/compiler.py src/wheezy/template/console.py src/wheezy/template/engine.py src/wheezy/template/lexer.py src/wheezy/template/loader.py src/wheezy/template/parser.py src/wheezy/template/preprocessor.py src/wheezy/template/utils.py src/wheezy/template/ext/__init__.py src/wheezy/template/ext/code.py src/wheezy/template/ext/core.py src/wheezy/template/ext/determined.pywheezy.template-0.1.167/src/wheezy.template.egg-info/entry_points.txt0000640000014600001520000000010212524064206027330 0ustar buildbotbuildbot00000000000000[console_scripts] wheezy.template = wheezy.template.console:main wheezy.template-0.1.167/LICENSE0000640000014600001520000000205012524064143017435 0ustar buildbotbuildbot00000000000000Copyright (C) 2011 by Andriy Kornatskyy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.