Cleaned up the django.template namespace.

Since this package is going to hold both the implementation of the Django
Template Language and the infrastructure for Multiple Template Engines,
it should be untied from the DTL as much as possible within our
backwards-compatibility policy.

Only public APIs (i.e. APIs mentioned in the documentation) were left.
This commit is contained in:
Aymeric Augustin 2014-11-10 21:40:26 +01:00
parent bfa21ddf76
commit 7eefdbf7ab
11 changed files with 99 additions and 100 deletions

View File

@ -3,7 +3,6 @@ import inspect
import os
import re
from django import template
from django.apps import apps
from django.conf import settings
from django.contrib import admin
@ -13,6 +12,8 @@ from django.core.exceptions import ViewDoesNotExist
from django.http import Http404
from django.core import urlresolvers
from django.contrib.admindocs import utils
from django.template.base import (builtins, get_library,
get_templatetags_modules, InvalidTemplateLibrary, libraries)
from django.template.engine import Engine
from django.utils.decorators import method_decorator
from django.utils._os import upath
@ -61,8 +62,8 @@ class TemplateTagIndexView(BaseAdminDocsView):
load_all_installed_template_libraries()
tags = []
app_libs = list(six.iteritems(template.libraries))
builtin_libs = [(None, lib) for lib in template.builtins]
app_libs = list(six.iteritems(libraries))
builtin_libs = [(None, lib) for lib in builtins]
for module_name, library in builtin_libs + app_libs:
for tag_name, tag_func in library.tags.items():
title, body, metadata = utils.parse_docstring(tag_func.__doc__)
@ -72,7 +73,7 @@ class TemplateTagIndexView(BaseAdminDocsView):
body = utils.parse_rst(body, 'tag', _('tag:') + tag_name)
for key in metadata:
metadata[key] = utils.parse_rst(metadata[key], 'tag', _('tag:') + tag_name)
if library in template.builtins:
if library in builtins:
tag_library = ''
else:
tag_library = module_name.split('.')[-1]
@ -94,8 +95,8 @@ class TemplateFilterIndexView(BaseAdminDocsView):
load_all_installed_template_libraries()
filters = []
app_libs = list(six.iteritems(template.libraries))
builtin_libs = [(None, lib) for lib in template.builtins]
app_libs = list(six.iteritems(libraries))
builtin_libs = [(None, lib) for lib in builtins]
for module_name, library in builtin_libs + app_libs:
for filter_name, filter_func in library.filters.items():
title, body, metadata = utils.parse_docstring(filter_func.__doc__)
@ -105,7 +106,7 @@ class TemplateFilterIndexView(BaseAdminDocsView):
body = utils.parse_rst(body, 'filter', _('filter:') + filter_name)
for key in metadata:
metadata[key] = utils.parse_rst(metadata[key], 'filter', _('filter:') + filter_name)
if library in template.builtins:
if library in builtins:
tag_library = ''
else:
tag_library = module_name.split('.')[-1]
@ -313,7 +314,7 @@ class TemplateDetailView(BaseAdminDocsView):
def load_all_installed_template_libraries():
# Load/register all template tag libraries from installed apps.
for module_name in template.get_templatetags_modules():
for module_name in get_templatetags_modules():
mod = import_module(module_name)
if not hasattr(mod, '__file__'):
# e.g. packages installed as eggs
@ -330,8 +331,8 @@ def load_all_installed_template_libraries():
else:
for library_name in libraries:
try:
template.get_library(library_name)
except template.InvalidTemplateLibrary:
get_library(library_name)
except InvalidTemplateLibrary:
pass

View File

@ -1,80 +1,17 @@
"""
This is the Django template system.
How it works:
The Lexer.tokenize() function converts a template string (i.e., a string containing
markup with custom template tags) to tokens, which can be either plain text
(TOKEN_TEXT), variables (TOKEN_VAR) or block statements (TOKEN_BLOCK).
The Parser() class takes a list of tokens in its constructor, and its parse()
method returns a compiled template -- which is, under the hood, a list of
Node objects.
Each Node is responsible for creating some sort of output -- e.g. simple text
(TextNode), variable values in a given context (VariableNode), results of basic
logic (IfNode), results of looping (ForNode), or anything else. The core Node
types are TextNode, VariableNode, IfNode and ForNode, but plugin modules can
define their own custom node types.
Each Node has a render() method, which takes a Context and returns a string of
the rendered node. For example, the render() method of a Variable Node returns
the variable's value as a string. The render() method of a ForNode returns the
rendered output of whatever was inside the loop, recursively.
The Template class is a convenient wrapper that takes care of template
compilation and rendering.
Usage:
The only thing you should ever use directly in this file is the Template class.
Create a compiled template object with a template_string, then call render()
with a context. In the compilation stage, the TemplateSyntaxError exception
will be raised if the template doesn't have proper syntax.
Sample code:
>>> from django import template
>>> s = u'<html>{% if test %}<h1>{{ varvalue }}</h1>{% endif %}</html>'
>>> t = template.Template(s)
(t is now a compiled template, and its render() method can be called multiple
times with multiple contexts)
>>> c = template.Context({'test':True, 'varvalue': 'Hello'})
>>> t.render(c)
u'<html><h1>Hello</h1></html>'
>>> c = template.Context({'test':False, 'varvalue': 'Hello'})
>>> t.render(c)
u'<html></html>'
"""
# Template lexing symbols
from django.template.base import (ALLOWED_VARIABLE_CHARS, BLOCK_TAG_END, # NOQA
BLOCK_TAG_START, COMMENT_TAG_END, COMMENT_TAG_START,
FILTER_ARGUMENT_SEPARATOR, FILTER_SEPARATOR, SINGLE_BRACE_END,
SINGLE_BRACE_START, TOKEN_BLOCK, TOKEN_COMMENT, TOKEN_TEXT, TOKEN_VAR,
TRANSLATOR_COMMENT_MARK, UNKNOWN_SOURCE, VARIABLE_ATTRIBUTE_SEPARATOR,
VARIABLE_TAG_END, VARIABLE_TAG_START, filter_re, tag_re)
# Exceptions
from django.template.base import (ContextPopException, InvalidTemplateLibrary, # NOQA
TemplateDoesNotExist, TemplateEncodingError, TemplateSyntaxError,
VariableDoesNotExist)
# Public exceptions
from .base import (TemplateDoesNotExist, TemplateSyntaxError, # NOQA
VariableDoesNotExist)
from .context import ContextPopException # NOQA
# Template parts
from django.template.base import (Context, FilterExpression, Lexer, Node, # NOQA
NodeList, Parser, RequestContext, Origin, StringOrigin, Template,
TextNode, Token, TokenParser, Variable, VariableNode, constant_string,
filter_raw_string)
from .base import (Context, Node, NodeList, RequestContext, # NOQA
StringOrigin, Template, Variable)
# Compiling templates
from django.template.base import (resolve_variable, # NOQA
unescape_string_literal, generic_tag_compiler)
# Deprecated in Django 1.8, will be removed in Django 2.0.
from .base import resolve_variable # NOQA
# Library management
from django.template.base import (Library, add_to_builtins, builtins, # NOQA
get_library, get_templatetags_modules, get_text_list, import_library,
libraries)
from .base import Library # NOQA
__all__ = ('Template', 'Context', 'RequestContext')

View File

@ -1,3 +1,54 @@
"""
This is the Django template system.
How it works:
The Lexer.tokenize() function converts a template string (i.e., a string containing
markup with custom template tags) to tokens, which can be either plain text
(TOKEN_TEXT), variables (TOKEN_VAR) or block statements (TOKEN_BLOCK).
The Parser() class takes a list of tokens in its constructor, and its parse()
method returns a compiled template -- which is, under the hood, a list of
Node objects.
Each Node is responsible for creating some sort of output -- e.g. simple text
(TextNode), variable values in a given context (VariableNode), results of basic
logic (IfNode), results of looping (ForNode), or anything else. The core Node
types are TextNode, VariableNode, IfNode and ForNode, but plugin modules can
define their own custom node types.
Each Node has a render() method, which takes a Context and returns a string of
the rendered node. For example, the render() method of a Variable Node returns
the variable's value as a string. The render() method of a ForNode returns the
rendered output of whatever was inside the loop, recursively.
The Template class is a convenient wrapper that takes care of template
compilation and rendering.
Usage:
The only thing you should ever use directly in this file is the Template class.
Create a compiled template object with a template_string, then call render()
with a context. In the compilation stage, the TemplateSyntaxError exception
will be raised if the template doesn't have proper syntax.
Sample code:
>>> from django import template
>>> s = u'<html>{% if test %}<h1>{{ varvalue }}</h1>{% endif %}</html>'
>>> t = template.Template(s)
(t is now a compiled template, and its render() method can be called multiple
times with multiple contexts)
>>> c = template.Context({'test':True, 'varvalue': 'Hello'})
>>> t.render(c)
u'<html><h1>Hello</h1></html>'
>>> c = template.Context({'test':False, 'varvalue': 'Hello'})
>>> t.render(c)
u'<html></html>'
"""
from __future__ import unicode_literals
import re

View File

@ -3,9 +3,8 @@ import re
import sys
from django.conf import settings
from django.template import (Node, Variable, TemplateSyntaxError,
TokenParser, Library, TOKEN_TEXT, TOKEN_VAR)
from django.template.base import render_value_in_context
from django.template import Library, Node, TemplateSyntaxError, Variable
from django.template.base import render_value_in_context, TokenParser, TOKEN_TEXT, TOKEN_VAR
from django.template.defaulttags import token_kwargs
from django.utils import six
from django.utils import translation

View File

@ -544,8 +544,8 @@ def templatize(src, origin=None):
does so by translating the Django translation tags into standard gettext
function invocations.
"""
from django.template import (Lexer, TOKEN_TEXT, TOKEN_VAR, TOKEN_BLOCK,
TOKEN_COMMENT, TRANSLATOR_COMMENT_MARK)
from django.template.base import (Lexer, TOKEN_TEXT, TOKEN_VAR,
TOKEN_BLOCK, TOKEN_COMMENT, TRANSLATOR_COMMENT_MARK)
src = force_text(src, settings.FILE_CHARSET)
out = StringIO('')
message_context = None

View File

@ -832,6 +832,14 @@ Django previously closed database connections between each test within a
``TestCase`` within a transaction. If some of your tests relied on the old
behavior, you should have them inherit from ``TransactionTestCase`` instead.
Cleanup of the ``django.template`` namespace
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you've been relying on private APIs exposed in the ``django.template``
module, you may have to import them from ``django.template.base`` instead.
Also ``django.template.base.compile_string()`` was removed.
Miscellaneous
~~~~~~~~~~~~~
@ -906,8 +914,6 @@ Miscellaneous
delete a key if ``set()`` fails. This is necessary to ensure the ``cache_db``
session store always fetches the most current session data.
* Private API ``django.template.compile_string`` was removed.
* Private APIs ``override_template_loaders`` and ``override_with_test_loader``
in ``django.test.utils`` were removed. Override ``TEMPLATE_LOADERS`` with
``override_settings`` instead.

View File

@ -1,6 +1,7 @@
from unittest import TestCase
from django.template import Context, Template, VariableNode
from django.template import Context, Template
from django.template.base import VariableNode
from django.test import override_settings

View File

@ -5,8 +5,8 @@ from __future__ import unicode_literals
from unittest import TestCase
from django.template import (TokenParser, FilterExpression, Parser, Variable,
Template, TemplateSyntaxError, Library)
from django.template import Library, Template, TemplateSyntaxError
from django.template.base import FilterExpression, Parser, TokenParser, Variable
from django.test import override_settings
from django.utils import six

View File

@ -3,7 +3,8 @@ from __future__ import unicode_literals
from unittest import TestCase
from django.template import Template, TemplateEncodingError, Context
from django.template import Template, Context
from django.template.base import TemplateEncodingError
from django.utils.safestring import SafeData
from django.utils import six

View File

@ -8,7 +8,8 @@ import unittest
from django import template
from django.contrib.auth.models import Group
from django.core import urlresolvers
from django.template import loader, Context, RequestContext, Template, TemplateSyntaxError
from django.template import (base as template_base, loader,
Context, RequestContext, Template, TemplateSyntaxError)
from django.template.engine import Engine
from django.template.loaders import app_directories, filesystem
from django.test import RequestFactory, SimpleTestCase
@ -245,7 +246,7 @@ class TemplateRegressionTests(SimpleTestCase):
def test_token_smart_split(self):
# Regression test for #7027
token = template.Token(template.TOKEN_BLOCK, 'sometag _("Page not found") value|yesno:_("yes,no")')
token = template_base.Token(template_base.TOKEN_BLOCK, 'sometag _("Page not found") value|yesno:_("yes,no")')
split = token.split_contents()
self.assertEqual(split, ["sometag", '_("Page not found")', 'value|yesno:_("yes,no")'])

View File

@ -6,7 +6,7 @@ import functools
from django import template
from django.template import Library
from django.template.base import Context
from django.template.base import Context, libraries
from django.template.engine import Engine
from django.template.loader import get_template
from django.test.utils import override_settings
@ -100,9 +100,11 @@ def upper(value):
def register_test_tags(func):
@functools.wraps(func)
def inner(self):
template.libraries['testtags'] = register
func(self)
del template.libraries['testtags']
libraries['testtags'] = register
try:
func(self)
finally:
del libraries['testtags']
return inner