#7799: django.template refactoring
-----------------------------+----------------------------------------------
Reporter: emulbreh | Owner: nobody
Status: new | Milestone:
Component: Template system | Version: SVN
Keywords: | Stage: Unreviewed
Has_patch: 0 |
-----------------------------+----------------------------------------------
== Why should `django.template` be refactored? ==
Filter and Variable parsing is inconsistent. Many ad hoc parsers in
defaulttags are fragile.
Whitespace handling is ungraceful.
The patch provided splits `__init__.py` into separate modules and
introduces a `TokenStream`
class that allows parsing of literals, vars (called lookups) and filter
expressions. No docs yet,
have a look at the source (it all happens in ~150 loc).
Additionally some features crept in, listed below.
The patch only touches `django.template` and `django.templatetags`.
Tests are separate so you can run them with the old code.
== Modules in `django.template` ==
* `context` (no dependencies)[[BR]]
Mostly untouched. There's a `Context` level template cache included,
accessible via `Context.get_template()` and
Context.select_template().
This is used in `IncludeNode`, `ExtendsNode`, and `inclusion_tag`.
Slightly backwards incompatible if you rely on parse time
sideeffects
(ie `{% load %}`) in included templates.
A loader kwarg is added to Context to force use of a specific
templateloader (something with a get_template() method).
{{{
#!python
class PrefixLoader:
def __init__(self, prefix_list):
self.prefix_list = prefix_list
def get_template(name):
from django.template.loader import select_template
return select_template(['%s/%s' % (prefix, name) for prefix in
self.prefix_list])
tpl.render(Context({}, loader=PrefixLoader(['a', 'b', 'c'])))
}}}
* `expressions` (no dependencies)[[BR]]
Contains `Lookup`, `Literal`, and `FilterExpression`. All are
subclasses of a marker
class `Expression`. These replace `Variable` and the old
`FilterExpression` class.
A `Variable` equivalent is provided in `compat.Variable`.
* `nodes` (depends on expressions)[[BR]]
Contains `Node`, `NodeList`, `TextNode`, and `ExpressionNode`. The
latter
is the old `VariableNode` renamed. A `VariableNode` alias is
provided in `compat`.
* `compiler` (depends on context, expressions, nodes)[[BR]]
Contains `Parser`, `Lexer`, `Token`, `TemplateSyntaxError`,
`Origin`, `StringOrgin`, and `compile_string()`. Those are mostly
untouched.
Additionally there are `TokenStream`, and `TokenSyntaxError`. Those
provide
a safe way to parse `Tokens` containing expressions.
* `library` (depends on compiler, nodes, context)[[BR]]
Contains `InvalidTemplateLibrary`, `Library`, `get_library()`, and
`add_to_builtins()`.
Mostly untouched.
* `loader`[[BR]]
Untouched. Moved `TemplateDoesNotExist` here.
* `utils`[[BR]]
`ConditionalNode`, base class for `IfNode`, `IfEqualNode`.
`EmptyNode`.
Helper functions:
`parse_conditional_nodelists(parser, name)`, `parse_as(bits)`
`parse_context_map(bits)`, `render_with_context_map(renderable,
context_map, context)`.
`parse_args_and_kwargs(bits)`, `resolve_args_and_kwargs(args,
kwargs)`
* `compat`[[BR]]
Provides backwards compatibility for `Variable`, `VariableNode`,
`TokenParser`,
and `resolve_variable()`
* `defaulttags`, `loader_tags`[[BR]]
Refactored to use `TokenStream` where appropriate.
Extended with-tag syntax to allow
{{{
{% with foo as x, bar as y, ... %}
}}}
Extended include-tag syntax to allow
{{{
{% include "template" with foo as x, bar as y %}
}}}
== Tickets ==
* #1105 - takes_context and takes_nodelist for simple_tag[[BR]]
fixed, based on julien's patch. tests not included to keep the
tplrf-tests.diff
functional for current trunk.
* #2949 - templating engine too tightly tied to TEMPLATE_DIRS in the
settings
fixed through `Context(loader=...)`.
* #3544 - recursive includes[[BR]]
fixed. test included.
* #4278 - get_template should accept a dirs argument[[BR]]
fixed through `Context(loader=...)`.
* #4746 - allow whitespace before and after filter separator[[BR]]
fixed. tests are there (filter-syntax03, filter-syntax04) but expect
TemplateSyntaxError.
* #5270 - empty string literals[[BR]]
fixed. tests included.
* #5756 - accept filters (almost) everywhere[[BR]]
fixed. a few tests included.
* #5862 - dup of #5756[[BR]]
fixed.
* #5971 - token parser bug[[BR]]
`TokenParser` will be deprecated.
* #6271 - filter arguments with spaces[[BR]]
fixed. test included. (seems to be fixed in trunk already)
* #6296 - expressions for ifequal[[BR]]
fixed. tests included (dup of #5756 ?)
* #6510 - `get_nodes_by_type()` problem
probably fixed.
* #6535 - negative numeric literals[[BR]]
fixed. tests included.
* #6834 - support for templates to be loaded from dynamically-selected
directories[[BR]]
fixed through `Context(loader=...)`
* #7295 - quotes, escaping and translation of string literals handled
inconsistently in templates[[BR]]
fixed.
* #7438 keyword support for simple_tag and inclusion_tag[[BR]]
not fixed yet. but `utils.parse_args_and_kwargs()` would make this
easy.
it's there for `{% url %}` anyway.
== Performance ==
Comparing `runtests.py templates` measures, it appears the refactored
version is faster.
But I'm not sure why and don't really trust these numbers. Are failing
tests expensive?
== Todo ==
`{% if not %}` is currently valid. The refactored implementation is greedy
and reports a syntax error.
Could be fixed, not sure it's worth it. Broken tests are: if-tag-not02,
if-tag-not03. DDN.
Numeric literals ending with "." are now considered a syntax error.
Broken test: ifequal-numeric07. DDN.
`{% url %}` currently accepts an arbitrary unquoted unicode string for the
view name.
The refactored implementation only accepts bare python identifiers or
quoted string literals.
Broken test: url05. DDN.
`TemplateSyntaxError` messages need some work. Eventually shortcut methods
on `TokenStream`.
Find better names for `TokenSyntaxError` and `TokenStream`.
Provide a decorator that handles the boilerplate
`bits=parser.token_stream(token)`
and `bits.assert_consumed()` calls.
Docs and more tests.
#1199 - multiple filter arguments[[BR]]
I'd like to implement this. But the proposed syntax `foo|bar:x,y,z` will
not work
for `{% url %}` and the new `{% with %}`.
Proposals:
* New syntax: `foo|bar(x,y,z)`, keeping `foo|bar:x` for bc.
* Tupel primitives: `foo|bar:(x,y,z)`, would allow `{% for x in (a,b,c)
%}`
* Lisp style: `foo|bar:(x|cons:y)`, this would basically allows bracketed
expressions as arguments to filters.
Arguably the ugliest.
#7261 - `__html__()` support[[BR]]
This could be useful. But would be easy to abuse.
--
Ticket URL: <http://code.djangoproject.com/ticket/7799>
Django Code <http://code.djangoproject.com/>
The web framework for perfectionists with deadlines
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/django-updates?hl=en
-~----------~----~----~----~------~----~------~--~---