Re: GSoc : Templates Compilation , draft 2
Hello, Russell Keith-Magee Thanks for your advices. *1. Detailed Timeline :* - Designing concept : this step requires fully design writing for achieving BACKWARD compatibility for all tags, and filters. Providing backward-compatibility is a simple task. I've described it earlier by using FilterExpression class. - Coding "template compilation" subsystem : - 4 days term - django.template.loader, django.template.loaders.* - adding support for importing already compiled templates. - 1 week term - implementing 'compile' method to django.template.Template class, in this method will be processed calling of child nodelist compiling and writing to compiled template file. - 2 weeks term - implementing 'compile' method to django.templates - 1 weeks term - implementing 'compile' method to django.template.loader_tags Node-derived classes. - 3 days term - implementing support in django.template.FilterExpression and django.template.Variable.In 5 weeks term will be produced such possibilities : 1. compiling, writing, importing compiled tempaltes files 2. support for compilation of default filters from django.template.defaultfilters, and default tags from django.template.defaulttags : , Node, Node-derived classes : TextNode, VariableNode, BlockNode, ExtendsNode, ConstantIncludeNode, IncludeNode, AutoEscapeNode, CommentNode, CsrfTokenNode, CycleNode, FilterNode, FirstOfNode, ForNode, IfChangedNode, IfEqualNode, RegroupNode, SsiNode, LoadNode, NowNode, SpacelessNode, URLNode, WidthRatioNode, WithNode. - 5 days term - implementing 'compile' method for django.template.defaulttags.IfNode and implementing compilation support for django.template.smartif. - Writing unit-tests : - 1 week term - writing unit-tests for compilation process for django.template.defaultfilters. - 2 week term - writing unit-tests for django.template.defaulttags. - 4 days term - writing unit-tests for django.template.loader_tags. - 1 week term - writing unit-tests for compilation process for django.template.Template, django.template.loader, django.template.loaders.*. Testing compiled tempates writing,import'ing and raw template compiling. - 1-2 weeks term - resolving all errors founded by using unit-tests. By this step I will produce fully tested template compilation code. - 3-5 weeks term - optimization of written code *2. Armin Ronacher has good template engine that supports template compilation, and other features. I can not argue against his template engine solution. But, society should be pointed on :* - The default syntax of Jinja2 matches Django syntax in many ways. However this similarity doesn’t mean that you can use a Django template unmodified in Jinja2. For example filter arguments use a function call syntax rather than a colon to separate filter name and arguments. Additionally the extension interface in Jinja is fundamentally different from the Django one which means that your custom tags won’t work any longer. - Armin Ronacher wrote about backward-compatibilty: > Are you planning on keeping the API for registering template tags > compatible? (django.template.Library.register.tag) It will be supported because otherwise upgrading won't be possible, but how well this works in detail would have to be investigated and what a cleaner implementation looks like. Jinja2 has an expression parser and encourages people to create a AST that does what they want in extensions. However in Jinja2 I never encouraged people to write custom tags so the API is very limited there. As for me, he haven't made decision how it would be looked like in Django. I have already proposed solution of template subsystem's improvement. - My solution will come with django 'out of the box' against Armin Ronacher solution. On Fri, Apr 8, 2011 at 4:23 AM, Russell Keith-Mageewrote: > On Fri, Apr 8, 2011 at 9:15 AM, Andrey Zubko wrote: > > Hello, > > I'm Andrey Zubko, student faculty of Computer Science in Zaporozhye > > State Engineering Academy. I'm senior chief developer of a local > > Internet Service Provider "Telza" which provides Internet and > > telephony services. My responsibilities includes enhancing, improving > > existent Billing system that is written by myself. > > > > In GSOC program I want to improve template subsystem by integrating > > template compilation into python bytecode. > > > > Goals and challenges > > Integrating of template compilation has 2 goals. The first goal and > > the chief goal is to provide backward-compatibility to templates, > > custom tags, custom filters that are already written. The second > > goal is to minimize modifications of Django sources to provide more > > stability and faster
Re: GSoc : Templates Compilation , draft 2
On Fri, Apr 8, 2011 at 9:15 AM, Andrey Zubkowrote: > Hello, > I'm Andrey Zubko, student faculty of Computer Science in Zaporozhye > State Engineering Academy. I'm senior chief developer of a local > Internet Service Provider "Telza" which provides Internet and > telephony services. My responsibilities includes enhancing, improving > existent Billing system that is written by myself. > > In GSOC program I want to improve template subsystem by integrating > template compilation into python bytecode. > > Goals and challenges > Integrating of template compilation has 2 goals. The first goal and > the chief goal is to provide backward-compatibility to templates, > custom tags, custom filters that are already written. The second > goal is to minimize modifications of Django sources to provide more > stability and faster integrating in trunk. > Implementation > Support of template compilation can be achieved by adding method > 'compile' to every Node-derived class, and some other classes, > functions, such as django.template.Variable, > django.template.FilterExpression, django.template.NodeList, and others > described further. > > 1. Node and Node-derived classes modifications > Class Node and derived from it classes should have optional method – > compile, it returns list of python bytecode commands for write in > compiled template. It receives parameter parent_name that will > contains name of uppermost tag/block. Parent_name is a name of > uppermost tag/block that identifies entry in hash blocks_output that > is used for caching all outputs. Only one case can provide parent_name > to be overridden – meet of the '{% block %}' tag in a parent tag, this > tag should override parent_name to its unique name. Approach for > caching all output is used for providing template inheritance ability. > Use of template Inheritance provides following cases : > child template has one sequence of blocks, but parent template has > another sequence of blocks > child template has blocks that haven't specified in parent's template > > For solving this cases I provided list blocks_sequence_output that > keeps sequence of blocks outputting. Implementation of 'compile' > method in Node class : > def compile(self,parent_name): > self.generate_name(parent_name) > compiled_code = ["t = Template('%s')" % self.template, > "blocks_output['%s'] = blocks_output['%s'] + > t._render(context)" % (self.parent_name,self.parent_name)] > return compiled_code > > As you saw, in purposes of providing backward-compatibility all Node- > derived classes, that haven't implemented 'compile' method, will use > current rendering approach. > Node-derived classes with implemented 'compile' method will be looked > like : > class TextNode(Node): > def compile(self,parent_name): > return ["blocks_output['%s'] = blocks_output['%s'] + \"\"\"%s > \"\"\"" % (self.parent_name, > > self.parent_name, > > self.s)] > > As shown before 'compile' method is not so difficult to implement. > To recursively compilation of Node-derived classes is used method > 'compile' in the class NodeList : > class NodeList(list): > def generate_name(self,node): > return id(node) > > def compile(self, parent_name=None): > bits = [] > for node in self: > if isinstance(node, Node): > if parent_name is None or isinstance(node, > BlockNode) : > if isinstance(node, BlockNode) : > parent_name_new = node.name > else : > parent_name_new = self.generate_name(node) > > bits.append("blocks_output['%s']=''" % > parent_name_new) > else : > parent_name_new = parent_name > > bits.append(self.compile_node(node, parent_name_new)) > else: > bits.append(node) > return mark_safe(''.join([force_unicode(b) for b in bits])) > > Also this function is used for initialising blocks_output hashes for > uppermost nodes. > > 2. Blocks and dynamical inheritance > I have described before Node-derived classes improvements, but > django.template.loader_tags.BlockNode, django.template.loader_tags, > django.template.loader_tages.ExtendsNode and others have big influence > on compiled template architecture design, that's why I have allocated > whole section for them. Internal variables blocks_output, > blocks_output_sequence are used for providing support of dynamic > inheritance. They specify the way how template should be rendered, in > what sequence, what blocks should be outputted to user. > 'blocks_output' hash collects blocks or tags outputs, and > blocks_output_sequence saves sequence of block outputting. Because > parent template can contain its own sequence of blocks that is saved > in blocks_output_sequence, we must update the child > blocks_output_sequence without right of overriding it.
GSoc : Templates Compilation , draft 2
Hello, I'm Andrey Zubko, student faculty of Computer Science in Zaporozhye State Engineering Academy. I'm senior chief developer of a local Internet Service Provider "Telza" which provides Internet and telephony services. My responsibilities includes enhancing, improving existent Billing system that is written by myself. In GSOC program I want to improve template subsystem by integrating template compilation into python bytecode. Goals and challenges Integrating of template compilation has 2 goals. The first goal and the chief goal is to provide backward-compatibility to templates, custom tags, custom filters that are already written. The second goal is to minimize modifications of Django sources to provide more stability and faster integrating in trunk. Implementation Support of template compilation can be achieved by adding method 'compile' to every Node-derived class, and some other classes, functions, such as django.template.Variable, django.template.FilterExpression, django.template.NodeList, and others described further. 1. Node and Node-derived classes modifications Class Node and derived from it classes should have optional method – compile, it returns list of python bytecode commands for write in compiled template. It receives parameter parent_name that will contains name of uppermost tag/block. Parent_name is a name of uppermost tag/block that identifies entry in hash blocks_output that is used for caching all outputs. Only one case can provide parent_name to be overridden – meet of the '{% block %}' tag in a parent tag, this tag should override parent_name to its unique name. Approach for caching all output is used for providing template inheritance ability. Use of template Inheritance provides following cases : child template has one sequence of blocks, but parent template has another sequence of blocks child template has blocks that haven't specified in parent's template For solving this cases I provided list blocks_sequence_output that keeps sequence of blocks outputting. Implementation of 'compile' method in Node class : def compile(self,parent_name): self.generate_name(parent_name) compiled_code = ["t = Template('%s')" % self.template, "blocks_output['%s'] = blocks_output['%s'] + t._render(context)" % (self.parent_name,self.parent_name)] return compiled_code As you saw, in purposes of providing backward-compatibility all Node- derived classes, that haven't implemented 'compile' method, will use current rendering approach. Node-derived classes with implemented 'compile' method will be looked like : class TextNode(Node): def compile(self,parent_name): return ["blocks_output['%s'] = blocks_output['%s'] + \"\"\"%s \"\"\"" % (self.parent_name, self.parent_name, self.s)] As shown before 'compile' method is not so difficult to implement. To recursively compilation of Node-derived classes is used method 'compile' in the class NodeList : class NodeList(list): def generate_name(self,node): return id(node) def compile(self, parent_name=None): bits = [] for node in self: if isinstance(node, Node): if parent_name is None or isinstance(node, BlockNode) : if isinstance(node, BlockNode) : parent_name_new = node.name else : parent_name_new = self.generate_name(node) bits.append("blocks_output['%s']=''" % parent_name_new) else : parent_name_new = parent_name bits.append(self.compile_node(node, parent_name_new)) else: bits.append(node) return mark_safe(''.join([force_unicode(b) for b in bits])) Also this function is used for initialising blocks_output hashes for uppermost nodes. 2. Blocks and dynamical inheritance I have described before Node-derived classes improvements, but django.template.loader_tags.BlockNode, django.template.loader_tags, django.template.loader_tages.ExtendsNode and others have big influence on compiled template architecture design, that's why I have allocated whole section for them. Internal variables blocks_output, blocks_output_sequence are used for providing support of dynamic inheritance. They specify the way how template should be rendered, in what sequence, what blocks should be outputted to user. 'blocks_output' hash collects blocks or tags outputs, and blocks_output_sequence saves sequence of block outputting. Because parent template can contain its own sequence of blocks that is saved in blocks_output_sequence, we must update the child blocks_output_sequence without right of overriding it. Because parent template can contain own blocks that is not present in child template, we must update child blocks_output hash with not existing items in it. By solving this requirements class BlockNode will be looked like : class BlockNode(Node):
Re: GSoc : Templates Compilation
Hi, Jonathan I was considering two approaches : template compilation with static inheritance and template compilation with static and dynamic inheritance. The first one approach has simple way of compilation : 1.Reading template in string 2.Tokenizing 3.Parsing — creating NodeList structure 4.Recuirsive NodeList tree compiling. Note: parent templatea already in this tree. And my task is to repeat this structure in python bytecode. E.g. Template ('TextNodePart\n{% block some_block %}BlockNode 'some_block'{% if True %}IfNode{% endif %}{%endblock%}') : from ... import ... def render(context): print "TextNodePart" print "BlockNode 'some_block'" if True : print "IfNode" or, e.g. With static inheritance Template('{% extends 'base.html' %} SomeTextNode{% block some_block %}{% if True %}ifNode{% endif %}{% endblock%}'), where base.html — Template('{% block some_block %}{% endblock %}{% block other_block %}TextNode{% endblock %}') will be looked : from … import … def render(context): if True : print "ifNode" print "TextNode" But template compilation with dynamic inheritance is a bit more complicated. Real template structure isn't known at compilation time of template, because it isn't known what template it will be. At runtime i tried to find template, compile it, or just import already compiled template. Structure of final template will be known also at runtime - thats why I'm collecting blocks output sequence - to output in this sequence. E.g. : child.html : {% extends parent %} {% block first_block %} {% if True %} some_info {% endif %} {% endblock %} {% block second_block %} {% endblock %} parent.html : TextNode {% block first_block %} {% endblock %} In this example child template has 2 block : first_block and second_block, but parent template has only 1 block : first_block. And in this situation I have to print only first_block output... Compiled child template : from ... import ... blocks_output = Template_BlockOutput() blocks_output_sequence = list() def output(): for block_name in blocks_output_sequence : if blocks_output.has_key(block_name) : print blocks_output[block_name] def render(context,no_output=False): blocks_output['first_block'] = '' # entering block tag blocks_sequence_output.append('first_block') if True : blocks_output['first_block'] = blocks_output['first_block'] + "some_info" blocks_output['second_block'] = '' # entering block tag extenal_blocks_output, external_blocks_sequence_output = get_compiled_template_or_create(context.parent,no_output=True) blocks_output.append(external_blocks_output) blocks_sequence_output = external_blocks_sequence_output """ function footer """ if no_output : return blocks_output, blocks_output_sequence else : output() Compiled parent template : from ... import ... blocks_output = Template_BlockOutput() blocks_output_sequence = list() def output(): for block_name in blocks_output_sequence : if blocks_output.has_key(block_name) : print blocks_output[block_name] def render(context,no_output=False): blocks_output['first_block'] = '' # entering block tag blocks_sequence_output.append('first_block') """ function footer """ if no_output : return blocks_output, blocks_output_sequence else : output() This is draft version of compilation, it has number of defects. I'm solving them now. On Apr 1, 12:50 am, Jonathan Slenderswrote: > Another one: > > Instead of: > def has_key(self,key): > for level in xrange(0,len(self._levels)) : > if self._levels[level].has_key(key) : > return True > return False > > do: > def has_key(self,key): > return any((key in l) for l in self._levels) > > Ony one "self" reference, and any-through-iterator is very fast, as > it's native python code (probably implemented in C). And lazy > evaluating. > > It's challenging to understand your code. Maybe it's easier if you > explain in words-only how you want to implement inheritance. > > - > > My approach would be like this > > For a template called 'x', create a dictionary 'x' with maps the block > names for this template to a func with it's matching implementation > code. > Somehow, a method render_block(name) should be made available. So when > a blocks are nested, one block should be able to call > render_block(other_name). The render_block method should do a lookup > in the dictionary for a block with this name, and call it. > > Dynamic inheritance can easily be realized by replacing key/value > pairs in this dict by other implementations. Pass the original > implementation to the new implementation as an additional function > parameter. (As a curry.) > > I guess it's fast, and can be cached in memory. For each rendering, > only a
Re: GSoc : Templates Compilation
Another one: Instead of: def has_key(self,key): for level in xrange(0,len(self._levels)) : if self._levels[level].has_key(key) : return True return False do: def has_key(self,key): return any((key in l) for l in self._levels) Ony one "self" reference, and any-through-iterator is very fast, as it's native python code (probably implemented in C). And lazy evaluating. It's challenging to understand your code. Maybe it's easier if you explain in words-only how you want to implement inheritance. - My approach would be like this For a template called 'x', create a dictionary 'x' with maps the block names for this template to a func with it's matching implementation code. Somehow, a method render_block(name) should be made available. So when a blocks are nested, one block should be able to call render_block(other_name). The render_block method should do a lookup in the dictionary for a block with this name, and call it. Dynamic inheritance can easily be realized by replacing key/value pairs in this dict by other implementations. Pass the original implementation to the new implementation as an additional function parameter. (As a curry.) I guess it's fast, and can be cached in memory. For each rendering, only a copy of the required template dictionaries have to be made. (Not even a deep copy.) --- Cheers, Jonathan -- You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to django-developers@googlegroups.com. To unsubscribe from this group, send email to django-developers+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
Re: GSoc : Templates Compilation
Hi Andrey I haven't yet looked through all of your code, but already a little feedback. Remember that every dot operator requires a dictionary lookup or getattr call. Also the [ ]-operator is another level of redirection. I think using 'self' inside a for-loop is not a good idea. If you're going to compile, you really want to optimize every possible detail. On Mar 31, 6:00 pm, Andrey Zubkowrote: > ... > def super(self,key): > if len(self._levels) > 1 : > for level in xrange(1,len(self._levels)) : > if self._levels[level].has_key(key) : > return self._levels[level][key] > else : > if self._levels[0].has_key(key) : > return self._levels[key] ### You mean: return > self._levels[0][key] > else : > return "" Maybe turn it into this: > def super(self,key): > levels = self._levels > if len(levels) > 1 : > iter = levels.__iter__() > iter.next() # Ignore first item > for level in iter: > if level.has_key(key) : > return level[key] > else : > return levels[0].get(key, "") Now you have only one lookup in 'self', half the amount of index operators (has_key counts as index operator), no additional xrange iterator, and only one call of "len". Gaining probably twice the speed. But is it really necessary to use classes and instance methods instead of just plain methods in a module? A template should be stateless. (we have render_context for the state when required.) Classes always have overhead compared to methods. -- You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to django-developers@googlegroups.com. To unsubscribe from this group, send email to django-developers+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
Re: GSoc : Templates Compilation
Hello, Jonathan > How exactly do you want to solve dynamic inheritance? It seems that > some people are still interested in dynamic inheritance, by using {% > extends variable %}. (Which is still dirty in my opinion, but anyway.) > Block information has to be kept somehow. For supporting dynamic inheritance compiled template will be looked more complicated. To resolve this i should : 1.Create class Template_BlockOutput similiar to ContextRender : class Template_BlockOutput(object): def __init__(self): self._levels = [{}] def __getitem__(self,key): for level in xrange(0,len(self._levels)) : if self._levels[level].has_key(key) : return self._levels[level][key] raise AttributeError() def super(self,key): if len(self._levels) > 1 : for level in xrange(1,len(self._levels)) : if self._levels[level].has_key(key) : return self._levels[level][key] else : if self._levels[0].has_key(key) : return self._levels[key] else : return "" def has_key(self,key): for level in xrange(0,len(self._levels)) : if self._levels[level].has_key(key) : return True return False def __setitem__(self,key,value): self._levels[0][key] = value def append(self,d): if isinstance(d, Template_BlockOutput) : for level in d._levels : self._levels.append(level) elif isinstance(d,list) : for level in d : self._levels.append(level) elif isinstance(d,dict) : self._levels.append(d) The instance of this class will be named as «blocks_output». Saving all blocks output is used for block.super expression. 2.Add list named blocks_sequence_output, that will contain blocks output sequence. Every time parser will find «extends» tag — the list will be overridden by parent blocks output sequence. 3.Add get_compiled_template_or_create function to django.template.loader that will be imported in compiled template for compiling and importing external template. To support all that requirements classes BlockNode, ExtendsNode should contain compile functions like : class BlockNode(Node): def super_compile(self): compiled_code = ["blocks_output.super('%s')" % self.name] return compiled_code def compile(self,parent_name): compiled_childs = self.nodelist.compile(self.name) compiled_code = ["blocks_output['%s'] = %s" % (self.name,compiled_childs), "blocks_sequence_output.append('%s')" % self.name] return compiled_code class ExtendsNode(Node): def get_parent_compiled(self): if self.parent_name_expr: parent = self.parent_name_expr.compile() else : parent = self.parent_name if not parent: error_msg = "Invalid template name in 'extends' tag: %r." % parent if self.parent_name_expr: error_msg += " Got this from the '%s' variable." % self.parent_name_expr.token raise TemplateSyntaxError(error_msg) if hasattr(parent, 'compile'): return parent.compile() # parent is a Template object code = ["extenal_blocks_output, external_blocks_sequence_output = get_compiled_template_or_create(%s,no_output=True)" % self.parent_name, "blocks_output.append(external_blocks_output)", "blocks_sequence_output = external_blocks_sequence_output"] return code def compile(self): compiled_parent = self.get_compiled_parent() return compiled_parent And compiled template structure for supporting dynamic template extending : from ... import ... def resolve(context,var_name): """ should be looked like method _resolve_lookup in django.template.Variable """ blocks_output = Template_BlockOutput() blocks_output_sequence = list() def output(): for block_name in blocks_output_sequence : if blocks_output.has_key(block_name) : print blocks_output[block_name] def render(context,no_output=False): """ compiled template will be here """ """ function footer """ if no_output : return blocks_output, blocks_output_sequence else : output() Yours Suggestion : > Maybe one small improvement. Isn't the following > > date(context.variable or "Default value"),"Y-m-d") faster than this? > > date(default(resolve(context,variable),"Default value"),"Y-m-d") Yes, it will be good to add to every filter function additional «compile» function that will generate optimesed code. E.g. : def default_compiled(value, arg): """If value is unavailable, use given default.""" return "context.%s or '%s'" % (value,arg) default_compiled.is_safe = False register_compiled = Library()
Re: GSoc : Templates Compilation
How exactly do you want to solve dynamic inheritance? It seems that some people are still interested in dynamic inheritance, by using {% extends variable %}. (Which is still dirty in my opinion, but anyway.) Block information has to be kept somehow. Maybe one small improvement. Isn't the following > date(context.variable or "Default value"),"Y-m-d") faster than this? > date(default(resolve(context,variable),"Default value"),"Y-m-d") P.S. I like the cleanness of adding an (optional?) compile method to every Node-derived class. But on the other hand, I would like to see Django move to a more end- user-friendly way of defining custom template tags. A way which does not involve any knowledge of the template parser/interpreter/compiler. Of course, that could also be build upon the first. -- You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to django-developers@googlegroups.com. To unsubscribe from this group, send email to django-developers+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
GSoc : Templates Compilation
I'm interested in participating in your mentors program in Google Summer Code. Looking at the template implementation I've seen that I can make some solutions for implementation compiling in bytecode templates. Just adding function «compile» to every Node-derived class and modifying/ adding new functionality to internal functions,classes, such as django.template.Variable, django.template.FilterExpression, and others. E.g. Node-derived classes : class TextNode(Node): def compile(self): return "print \"\"\"%s\"\"\";\n" % self.s class Variable(object): def compile(self): print "resolve(context,%s)" % self.lookups class FilterExpression(object): def compile(self, ignore_failures=False): if isinstance(self.var, Variable): try: obj = self.var.compile() except VariableDoesNotExist: if ignore_failures: obj = None else: if settings.COMPILED_TEMPLATE_STRING_IF_INVALID: global invalid_var_format_string if invalid_var_format_string is None: invalid_var_format_string = '%s' in settings.COMPILED_TEMPLATE_STRING_IF_INVALID if invalid_var_format_string: return settings.COMPILED_TEMPLATE_STRING_IF_INVALID % self.var return settings.COMPILED_TEMPLATE_STRING_IF_INVALID else: obj = settings.COMPILED_TEMPLATE_STRING_IF_INVALID else: obj = self.var for func, args in self.filters: arg_vals = "" i = 0 for lookup, arg in args: if i > 0 : arg_vals = arg_vals + "," if not lookup: arg_vals = arg_vals + "\"%s\"" % mark_safe(arg) else: arg_vals = arg_vals + "%s" % arg.compile(context) if getattr(func, 'needs_autoescape', False): new_obj = "%s(%s,autoescape=context.autoescape,%s)" % (func.__name__,obj,arg_vals) #new_obj = func(obj, autoescape=context.autoescape, *arg_vals) else: new_obj = "%s(%s,%s)" % (func.__name__,obj,arg_vals) #new_obj = func(obj, *arg_vals) if getattr(func, 'is_safe', False) and isinstance(obj, SafeData): obj = "mark_safe(%s)" % new_obj elif isinstance(obj, EscapeData): obj = "mark_for_escaping(%s)" % new_obj else: obj = new_obj return obj Simple example of used modifications : from django.template import Parser, FilterExpression token = 'variable|default:"Default value"|date:"Y-m-d"' p = Parser('') fe = FilterExpression(token, p) fe.compile() will produce : 'date(default(resolve(context,variable),"Default value"),"Y-m-d")' Structure of compiled template will consists of 2 parts : Dependencies part. Section consists of importing modules. Planned that dependencies should be added by using {% load %} tag for developer- written tags. Code part. Section that will consist of internal template functions, such as «resolve» that will get variable name and resolve it using current context, and «render» that will consist of compiled template. E.g. : # default imports from django.template.defaulttags import * from django.template.defaultfilters import * # importing external modules, section created by using {% load %} tag from ... import ... def resolve(context,var_name): """ should be looked like method _resolve_lookup in django.template.Variable """ def render(context): """ compiled template will be here """ -- You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to django-developers@googlegroups.com. To unsubscribe from this group, send email to django-developers+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.