moraes / appengine

appengine utilities

Clone this repository (size: 78.4 KB): HTTPS / SSH
$ hg clone http://bitbucket.org/moraes/appengine/
commit 51: 547310a6324c
parent 50: 5abed6a4b570
branch: default
tags: tip
Added support for ReferenceProperty and StringProperty, and added get_bookmark(). Thanks, slamm. Fixes #6 #7 #8
rodrigo moraes / moraes
6 months ago
appengine / gaefy / jinja2 / compiler.py
r51:547310a6324c 115 loc 4.1 KB embed / history / annotate / raw /
# -*- coding: utf-8 -*-
"""
    gaefy.jinja2.compiler
    ~~~~~~~~~~~~~~~~~~~~~

    Helper functions to parse Jinja2 templates and store them as Python code.
    The compiled templates can be loaded using gaefy.jinja2.code_loaders,
    avoiding all the parsing process.

    To compile a whole dir:

        from jinja2 import Environment
        from gaefy.jinja2.compiler import compile_dir

        env = Environment()
        src_path = '/path/to/templates'
        dst_path = '/path/to/templates_compiled'

        compile_dir(env, src_path, dst_path)

    :copyright: 2009 by tipfy.org.
    :license: BSD, see LICENSE.txt for more details.
"""
import re
from os import path, listdir, mkdir

name_re = re.compile('^[a-zA-Z0-9_]+$')

def compile_file(env, src_path, dst_path, encoding='utf-8', base_dir='',
    as_module=False):
    """Compiles a Jinja2 template to python code.
    Params:
        `env`: a Jinja2 Environment instance.
        `src_path`: path to the source file.
        `dst_path`: path to the destination file.
        `encoding`: template encoding.
        `base_dir`: the base path to be removed from the compiled template
            filename.
        `as_module`: if True, saves the compiled code with a .py extension.
    """
    # Read the template file.
    src_file = file(src_path, 'r')
    source = src_file.read().decode(encoding)
    src_file.close()

    # Compile the template to raw Python code..
    name = src_path.replace(base_dir, '')
    raw = env.compile(source, name=name, filename=name, raw=True)

    if as_module:
        # Save as .py
        name, ext = path.splitext(dst_path)
        dst_path = name + '.py'

    # Save to the destination.
    dst_file = open(dst_path, 'w')
    dst_file.write(raw)
    dst_file.close()


def compile_dir(env, src_path, dst_path, pattern=r'^.*\.html$',
    encoding='utf-8', base_dir=None, as_module=False):
    """Compiles a directory of Jinja2 templates to python code.
    Params:
        `env`: a Jinja2 Environment instance.
        `src_path`: path to the source directory.
        `dst_path`: path to the destination directory.
        `encoding`: template encoding.
        `pattern`: a regular expression to match template file names.
        `base_dir`: the base path to be removed from the compiled template
            filename.
        `as_module`: if True, creates __init__.py for each directory and saves
            the compiled code with a .py extension.
     """
    if base_dir is None:
        # In the first call, store the base dir.
        base_dir = src_path

    if as_module and path.isdir(dst_path):
        # Create a __init__.py if not already there.
        init = path.join(dst_path, '__init__.py')
        if not path.exists(init):
            open(init, 'w').close()

    for filename in listdir(src_path):
        if filename.startswith('.'):
            continue

        src_name = path.join(src_path, filename)
        dst_name = path.join(dst_path, filename)

        if as_module:
            # Check that the file/dir are valid Python identifiers.
            if path.isfile(src_name):
                name, ext = path.splitext(filename)
                # Disallow template if a directory with the same name exists.
                module_dir = path.join(src_path, name)
                if path.isdir(module_dir):
                    raise ValueError("Template name conflict: %s is a module "
                        "directory, so %s can't exist as a template." %
                        (module_dir, src_name))
            else:
                name = filename

            if not name_re.match(name):
                raise ValueError('Invalid template name: "%s". Use only '
                    'letters, numbers and underscores.' % src_name)

        if path.isdir(src_name):
            mkdir(dst_name)
            compile_dir(env, src_name, dst_name, encoding=encoding,
                base_dir=base_dir, as_module=as_module)
        elif path.isfile(src_name) and re.match(pattern, filename):
            compile_file(env, src_name, dst_name, encoding=encoding,
                base_dir=base_dir, as_module=as_module)