From 35f8d2de76c61cb4f52b1e4f4a8125ce17b77355 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Tue, 16 Sep 2008 10:59:03 +0200 Subject: [PATCH] Added first code for a django-to-jinja converter --HG-- branch : trunk --- ext/django2jinja/django2jinja.py | 258 +++++++++++++++++++++++++ ext/django2jinja/templates/index.html | 16 ++ ext/django2jinja/templates/layout.html | 4 + 3 files changed, 278 insertions(+) create mode 100644 ext/django2jinja/django2jinja.py create mode 100644 ext/django2jinja/templates/index.html create mode 100644 ext/django2jinja/templates/layout.html diff --git a/ext/django2jinja/django2jinja.py b/ext/django2jinja/django2jinja.py new file mode 100644 index 0000000..1c9130d --- /dev/null +++ b/ext/django2jinja/django2jinja.py @@ -0,0 +1,258 @@ +# -*- coding: utf-8 -*- +""" + Django to Jinja + ~~~~~~~~~~~~~~~ + + Helper module that can convert django templates into Jinja2 templates. + + :copyright: Copyright 2008 by Armin Ronacher. + :license: BSD. +""" +import sys +import re +from jinja2.defaults import * +from django.conf import settings +settings.configure(TEMPLATE_DEBUG=True, TEMPLATE_DIRS=['templates']) +from django.template import defaulttags as core_tags, loader, TextNode, \ + FilterExpression, libraries, Variable, loader_tags +from django.template.debug import DebugVariableNode as VariableNode +from StringIO import StringIO + + +node_handlers = {} +_resolved_filters = {} + + +_newline_re = re.compile(r'(?:\r\n|\r|\n)') + + +def node(cls): + def proxy(f): + node_handlers[cls] = f + return f + return proxy + + +def translate_variable_name(var): + if var == 'forloop': + return 'loop' + return var + + +def get_filter_name(filter): + if filter not in _resolved_filters: + for library in libraries.values(): + for key, value in library.filters.iteritems(): + _resolved_filters[value] = key + return _resolved_filters.get(filter, None) + + +class Writer(object): + + def __init__(self, stream=None, + block_start_string=BLOCK_START_STRING, + block_end_string=BLOCK_END_STRING, + variable_start_string=VARIABLE_START_STRING, + variable_end_string=VARIABLE_END_STRING, + comment_start_string=COMMENT_START_STRING, + comment_end_string=COMMENT_END_STRING): + if stream is None: + stream = sys.stdout + self.stream = stream + self.block_start_string = block_start_string + self.block_end_string = block_end_string + self.variable_start_string = variable_start_string + self.variable_end_string = variable_end_string + self.comment_start_string = comment_start_string + self.comment_end_string = comment_end_string + + def write(self, s): + self.stream.write(s) + + def print_expr(self, expr): + self.start_variable() + self.write(expr) + self.end_variable() + + def start_variable(self): + self.write(self.variable_start_string + ' ') + + def end_variable(self): + self.write(' ' + self.variable_end_string) + + def start_block(self): + self.write(self.block_start_string + ' ') + + def end_block(self): + self.write(' ' + self.block_end_string) + + def tag(self, name): + self.start_block() + self.write(name) + self.end_block() + + def variable(self, name): + self.write(translate_variable_name(name)) + + def literal(self, value): + value = repr(value) + if value[:2] in ('u"', "u'"): + value = value[1:] + self.write(value) + + def warn(self, message, node=None): + if node is not None and hasattr(node, 'source'): + message = '[%s:%d] %s' % ( + node.source[0].name.replace('<', '<') \ + .replace('>', '>'), + len(_newline_re.findall(node.source[0].source + [:node.source[1][0]])), + message + ) + print >> sys.stderr, message + + def node(self, node): + for cls, handler in node_handlers.iteritems(): + if type(node) is cls: + handler(node, self) + break + else: + self.warn('Untranslatable node %s.%s found' % ( + node.__module__, + node.__class__.__name__ + ), node) + + def body(self, nodes): + for node in nodes: + self.node(node) + + +@node(TextNode) +def text_node(node, writer): + writer.write(node.s) + + +@node(Variable) +def variable(node, writer): + if node.literal is not None: + writer.literal(node.literal) + else: + writer.variable(node.var) + + +@node(VariableNode) +def variable_node(node, writer): + writer.start_variable() + writer.node(node.filter_expression) + writer.end_variable() + + +@node(FilterExpression) +def filter_expression(node, writer): + writer.node(node.var) + for filter, args in node.filters: + name = get_filter_name(filter) + if name is None: + writer.warn('Could not find filter %s' % name, node) + writer.write('|%s' % name) + if args: + writer.write('(') + for idx, (is_var, value) in enumerate(args): + if idx: + writer.write(', ') + if is_var: + writer.node(value) + else: + writer.literal(value) + writer.write(')') + + +@node(core_tags.CommentNode) +def comment_tag(node, writer): + pass + + +@node(core_tags.DebugNode) +def comment_tag(node, writer): + writer.warn('Debug tag detected. Make sure to add a global function ' + 'called debug to the namespace.', node=node) + writer.print_expr('debug()') + + +@node(core_tags.ForNode) +def for_loop(node, writer): + writer.start_block() + writer.write('for ') + for idx, var in enumerate(node.loopvars): + if idx: + writer.write(', ') + writer.variable(var) + writer.write(' in ') + if node.is_reversed: + writer.write('(') + writer.node(node.sequence) + if node.is_reversed: + writer.write(')|reverse') + writer.end_block() + writer.body(node.nodelist_loop) + writer.tag('endfor') + + +@node(core_tags.IfNode) +def if_condition(node, writer): + writer.start_block() + writer.write('if ') + join_with = core_tags.IfNode.LinkTypes.or_ and 'or' or 'and' + for idx, (ifnot, expr) in enumerate(node.bool_exprs): + if idx: + writer.write(' %s ' % join_with) + if ifnot: + writer.write('not ') + writer.node(expr) + writer.end_block() + writer.body(node.nodelist_true) + if node.nodelist_false: + writer.tag('else') + writer.body(node.nodelist_false) + writer.tag('endif') + + +@node(core_tags.IfEqualNode) +def if_equal(node, writer): + writer.start_block() + writer.write('if ') + writer.node(node.var1) + writer.write(' == ') + writer.node(node.var2) + writer.end_block() + writer.body(node.nodelist_true) + if node.nodelist_false: + writer.tag('else') + writer.body(node.nodelist_false) + writer.tag('endif') + + +@node(loader_tags.BlockNode) +def block(node, writer): + writer.tag('block ' + node.name.replace('-', '_')) + node = node + while node.parent is not None: + node = node.parent + writer.body(node.nodelist) + writer.tag('endblock') + + +@node(loader_tags.ExtendsNode) +def extends(node, writer): + writer.start_block() + writer.write('extends ') + if node.parent_name_expr: + writer.node(node.parent_name_expr) + else: + writer.literal(node.parent_name) + writer.end_block() + writer.body(node.nodelist) + + +if __name__ == '__main__': + Writer().body(loader.get_template('index.html')) diff --git a/ext/django2jinja/templates/index.html b/ext/django2jinja/templates/index.html new file mode 100644 index 0000000..a335b66 --- /dev/null +++ b/ext/django2jinja/templates/index.html @@ -0,0 +1,16 @@ +{% extends "layout.html" %} +{% block title %}Foo{% endblock %} +{% block page-body %} + Hello {{ name|cut:"d"|escape }}! + + {% for item in seq reversed %} + {% if forloop.index|divisibleby:2 %} +
  • {{ item }}
  • + {% endif %} + {% endfor %} + {% ifequal foo bar %} + haha + {% else %} + hmm + {% endifequal %} +{% endblock %} diff --git a/ext/django2jinja/templates/layout.html b/ext/django2jinja/templates/layout.html new file mode 100644 index 0000000..3f21a12 --- /dev/null +++ b/ext/django2jinja/templates/layout.html @@ -0,0 +1,4 @@ +{% block title %}{% endblock %} +
    + {% block page-body %}{% endblock %} +
    -- 2.26.2