mirror of
https://github.com/django/django.git
synced 2025-03-31 19:46:42 +00:00
Refs #15053 -- Removed support for non-recursive template loading.
Per deprecation timeline.
This commit is contained in:
parent
56a5760543
commit
5d8da093a9
@ -130,21 +130,11 @@ class Engine(object):
|
|||||||
def find_template(self, name, dirs=None, skip=None):
|
def find_template(self, name, dirs=None, skip=None):
|
||||||
tried = []
|
tried = []
|
||||||
for loader in self.template_loaders:
|
for loader in self.template_loaders:
|
||||||
if loader.supports_recursion:
|
try:
|
||||||
try:
|
template = loader.get_template(name, skip=skip)
|
||||||
template = loader.get_template(
|
return template, template.origin
|
||||||
name, template_dirs=dirs, skip=skip,
|
except TemplateDoesNotExist as e:
|
||||||
)
|
tried.extend(e.tried)
|
||||||
return template, template.origin
|
|
||||||
except TemplateDoesNotExist as e:
|
|
||||||
tried.extend(e.tried)
|
|
||||||
else:
|
|
||||||
# RemovedInDjango20Warning: Use old api for non-recursive
|
|
||||||
# loaders.
|
|
||||||
try:
|
|
||||||
return loader(name, dirs)
|
|
||||||
except TemplateDoesNotExist:
|
|
||||||
pass
|
|
||||||
raise TemplateDoesNotExist(name, tried=tried)
|
raise TemplateDoesNotExist(name, tried=tried)
|
||||||
|
|
||||||
def from_string(self, template_code):
|
def from_string(self, template_code):
|
||||||
|
@ -19,10 +19,6 @@ BLOCK_CONTEXT_KEY = 'block_context'
|
|||||||
logger = logging.getLogger('django.template')
|
logger = logging.getLogger('django.template')
|
||||||
|
|
||||||
|
|
||||||
class ExtendsError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class BlockContext(object):
|
class BlockContext(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# Dictionary of FIFO queues.
|
# Dictionary of FIFO queues.
|
||||||
@ -107,23 +103,6 @@ class ExtendsNode(Node):
|
|||||||
passed as the skip argument. This enables extends to work recursively
|
passed as the skip argument. This enables extends to work recursively
|
||||||
without extending the same template twice.
|
without extending the same template twice.
|
||||||
"""
|
"""
|
||||||
# RemovedInDjango20Warning: If any non-recursive loaders are installed
|
|
||||||
# do a direct template lookup. If the same template name appears twice,
|
|
||||||
# raise an exception to avoid system recursion.
|
|
||||||
for loader in context.template.engine.template_loaders:
|
|
||||||
if not loader.supports_recursion:
|
|
||||||
history = context.render_context.setdefault(
|
|
||||||
self.context_key, [context.template.origin.template_name],
|
|
||||||
)
|
|
||||||
if template_name in history:
|
|
||||||
raise ExtendsError(
|
|
||||||
"Cannot extend templates recursively when using "
|
|
||||||
"non-recursive template loaders",
|
|
||||||
)
|
|
||||||
template = context.template.engine.get_template(template_name)
|
|
||||||
history.append(template_name)
|
|
||||||
return template
|
|
||||||
|
|
||||||
history = context.render_context.setdefault(
|
history = context.render_context.setdefault(
|
||||||
self.context_key, [context.template.origin],
|
self.context_key, [context.template.origin],
|
||||||
)
|
)
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
import warnings
|
from django.template import Template, TemplateDoesNotExist
|
||||||
|
|
||||||
from django.template import Origin, Template, TemplateDoesNotExist
|
|
||||||
from django.utils.deprecation import RemovedInDjango20Warning
|
|
||||||
from django.utils.inspect import func_supports_parameter
|
|
||||||
|
|
||||||
|
|
||||||
class Loader(object):
|
class Loader(object):
|
||||||
@ -10,11 +6,7 @@ class Loader(object):
|
|||||||
def __init__(self, engine):
|
def __init__(self, engine):
|
||||||
self.engine = engine
|
self.engine = engine
|
||||||
|
|
||||||
def __call__(self, template_name, template_dirs=None):
|
def get_template(self, template_name, skip=None):
|
||||||
# RemovedInDjango20Warning: Allow loaders to be called like functions.
|
|
||||||
return self.load_template(template_name, template_dirs)
|
|
||||||
|
|
||||||
def get_template(self, template_name, template_dirs=None, skip=None):
|
|
||||||
"""
|
"""
|
||||||
Calls self.get_template_sources() and returns a Template object for
|
Calls self.get_template_sources() and returns a Template object for
|
||||||
the first template matching template_name. If skip is provided,
|
the first template matching template_name. If skip is provided,
|
||||||
@ -23,13 +15,7 @@ class Loader(object):
|
|||||||
"""
|
"""
|
||||||
tried = []
|
tried = []
|
||||||
|
|
||||||
args = [template_name]
|
for origin in self.get_template_sources(template_name):
|
||||||
# RemovedInDjango20Warning: Add template_dirs for compatibility with
|
|
||||||
# old loaders
|
|
||||||
if func_supports_parameter(self.get_template_sources, 'template_dirs'):
|
|
||||||
args.append(template_dirs)
|
|
||||||
|
|
||||||
for origin in self.get_template_sources(*args):
|
|
||||||
if skip is not None and origin in skip:
|
if skip is not None and origin in skip:
|
||||||
tried.append((origin, 'Skipped'))
|
tried.append((origin, 'Skipped'))
|
||||||
continue
|
continue
|
||||||
@ -46,30 +32,6 @@ class Loader(object):
|
|||||||
|
|
||||||
raise TemplateDoesNotExist(template_name, tried=tried)
|
raise TemplateDoesNotExist(template_name, tried=tried)
|
||||||
|
|
||||||
def load_template(self, template_name, template_dirs=None):
|
|
||||||
warnings.warn(
|
|
||||||
'The load_template() method is deprecated. Use get_template() '
|
|
||||||
'instead.', RemovedInDjango20Warning,
|
|
||||||
)
|
|
||||||
source, display_name = self.load_template_source(
|
|
||||||
template_name, template_dirs,
|
|
||||||
)
|
|
||||||
origin = Origin(
|
|
||||||
name=display_name,
|
|
||||||
template_name=template_name,
|
|
||||||
loader=self,
|
|
||||||
)
|
|
||||||
try:
|
|
||||||
template = Template(source, origin, template_name, self.engine)
|
|
||||||
except TemplateDoesNotExist:
|
|
||||||
# If compiling the template we found raises TemplateDoesNotExist,
|
|
||||||
# back off to returning the source and display name for the
|
|
||||||
# template we were asked to load. This allows for correct
|
|
||||||
# identification of the actual template that does not exist.
|
|
||||||
return source, display_name
|
|
||||||
else:
|
|
||||||
return template, None
|
|
||||||
|
|
||||||
def get_template_sources(self, template_name):
|
def get_template_sources(self, template_name):
|
||||||
"""
|
"""
|
||||||
An iterator that yields possible matching template paths for a
|
An iterator that yields possible matching template paths for a
|
||||||
@ -79,26 +41,9 @@ class Loader(object):
|
|||||||
'subclasses of Loader must provide a get_template_sources() method'
|
'subclasses of Loader must provide a get_template_sources() method'
|
||||||
)
|
)
|
||||||
|
|
||||||
def load_template_source(self, template_name, template_dirs=None):
|
|
||||||
"""
|
|
||||||
RemovedInDjango20Warning: Returns a tuple containing the source and
|
|
||||||
origin for the given template name.
|
|
||||||
"""
|
|
||||||
raise NotImplementedError(
|
|
||||||
'subclasses of Loader must provide a load_template_source() method'
|
|
||||||
)
|
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
"""
|
"""
|
||||||
Resets any state maintained by the loader instance (e.g. cached
|
Resets any state maintained by the loader instance (e.g. cached
|
||||||
templates or cached loader modules).
|
templates or cached loader modules).
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@property
|
|
||||||
def supports_recursion(self):
|
|
||||||
"""
|
|
||||||
RemovedInDjango20Warning: This is an internal property used by the
|
|
||||||
ExtendsNode during the deprecation of non-recursive loaders.
|
|
||||||
"""
|
|
||||||
return hasattr(self, 'get_contents')
|
|
||||||
|
@ -4,13 +4,10 @@ to load templates from them in order, caching the result.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import warnings
|
|
||||||
|
|
||||||
from django.template import Origin, Template, TemplateDoesNotExist
|
from django.template import TemplateDoesNotExist
|
||||||
from django.template.backends.django import copy_exception
|
from django.template.backends.django import copy_exception
|
||||||
from django.utils.deprecation import RemovedInDjango20Warning
|
|
||||||
from django.utils.encoding import force_bytes, force_text
|
from django.utils.encoding import force_bytes, force_text
|
||||||
from django.utils.inspect import func_supports_parameter
|
|
||||||
|
|
||||||
from .base import Loader as BaseLoader
|
from .base import Loader as BaseLoader
|
||||||
|
|
||||||
@ -19,7 +16,6 @@ class Loader(BaseLoader):
|
|||||||
|
|
||||||
def __init__(self, engine, loaders):
|
def __init__(self, engine, loaders):
|
||||||
self.template_cache = {}
|
self.template_cache = {}
|
||||||
self.find_template_cache = {} # RemovedInDjango20Warning
|
|
||||||
self.get_template_cache = {}
|
self.get_template_cache = {}
|
||||||
self.loaders = engine.get_template_loaders(loaders)
|
self.loaders = engine.get_template_loaders(loaders)
|
||||||
super(Loader, self).__init__(engine)
|
super(Loader, self).__init__(engine)
|
||||||
@ -27,7 +23,7 @@ class Loader(BaseLoader):
|
|||||||
def get_contents(self, origin):
|
def get_contents(self, origin):
|
||||||
return origin.loader.get_contents(origin)
|
return origin.loader.get_contents(origin)
|
||||||
|
|
||||||
def get_template(self, template_name, template_dirs=None, skip=None):
|
def get_template(self, template_name, skip=None):
|
||||||
"""
|
"""
|
||||||
Perform the caching that gives this loader its name. Often many of the
|
Perform the caching that gives this loader its name. Often many of the
|
||||||
templates attempted will be missing, so memory use is of concern here.
|
templates attempted will be missing, so memory use is of concern here.
|
||||||
@ -46,7 +42,7 @@ class Loader(BaseLoader):
|
|||||||
memory leak. Thus, unraised copies of the exceptions are cached and
|
memory leak. Thus, unraised copies of the exceptions are cached and
|
||||||
copies of those copies are raised after they're fetched from the cache.
|
copies of those copies are raised after they're fetched from the cache.
|
||||||
"""
|
"""
|
||||||
key = self.cache_key(template_name, template_dirs, skip)
|
key = self.cache_key(template_name, skip)
|
||||||
cached = self.get_template_cache.get(key)
|
cached = self.get_template_cache.get(key)
|
||||||
if cached:
|
if cached:
|
||||||
if isinstance(cached, type) and issubclass(cached, TemplateDoesNotExist):
|
if isinstance(cached, type) and issubclass(cached, TemplateDoesNotExist):
|
||||||
@ -56,9 +52,7 @@ class Loader(BaseLoader):
|
|||||||
return cached
|
return cached
|
||||||
|
|
||||||
try:
|
try:
|
||||||
template = super(Loader, self).get_template(
|
template = super(Loader, self).get_template(template_name, skip)
|
||||||
template_name, template_dirs, skip,
|
|
||||||
)
|
|
||||||
except TemplateDoesNotExist as e:
|
except TemplateDoesNotExist as e:
|
||||||
self.get_template_cache[key] = copy_exception(e) if self.engine.debug else TemplateDoesNotExist
|
self.get_template_cache[key] = copy_exception(e) if self.engine.debug else TemplateDoesNotExist
|
||||||
raise
|
raise
|
||||||
@ -67,17 +61,12 @@ class Loader(BaseLoader):
|
|||||||
|
|
||||||
return template
|
return template
|
||||||
|
|
||||||
def get_template_sources(self, template_name, template_dirs=None):
|
def get_template_sources(self, template_name):
|
||||||
for loader in self.loaders:
|
for loader in self.loaders:
|
||||||
args = [template_name]
|
for origin in loader.get_template_sources(template_name):
|
||||||
# RemovedInDjango20Warning: Add template_dirs for compatibility
|
|
||||||
# with old loaders
|
|
||||||
if func_supports_parameter(loader.get_template_sources, 'template_dirs'):
|
|
||||||
args.append(template_dirs)
|
|
||||||
for origin in loader.get_template_sources(*args):
|
|
||||||
yield origin
|
yield origin
|
||||||
|
|
||||||
def cache_key(self, template_name, template_dirs, skip=None):
|
def cache_key(self, template_name, skip=None):
|
||||||
"""
|
"""
|
||||||
Generate a cache key for the template name, dirs, and skip.
|
Generate a cache key for the template name, dirs, and skip.
|
||||||
|
|
||||||
@ -97,78 +86,12 @@ class Loader(BaseLoader):
|
|||||||
if matching:
|
if matching:
|
||||||
skip_prefix = self.generate_hash(matching)
|
skip_prefix = self.generate_hash(matching)
|
||||||
|
|
||||||
if template_dirs:
|
|
||||||
dirs_prefix = self.generate_hash(template_dirs)
|
|
||||||
|
|
||||||
return '-'.join(filter(bool, [force_text(template_name), skip_prefix, dirs_prefix]))
|
return '-'.join(filter(bool, [force_text(template_name), skip_prefix, dirs_prefix]))
|
||||||
|
|
||||||
def generate_hash(self, values):
|
def generate_hash(self, values):
|
||||||
return hashlib.sha1(force_bytes('|'.join(values))).hexdigest()
|
return hashlib.sha1(force_bytes('|'.join(values))).hexdigest()
|
||||||
|
|
||||||
@property
|
|
||||||
def supports_recursion(self):
|
|
||||||
"""
|
|
||||||
RemovedInDjango20Warning: This is an internal property used by the
|
|
||||||
ExtendsNode during the deprecation of non-recursive loaders.
|
|
||||||
"""
|
|
||||||
return all(hasattr(loader, 'get_contents') for loader in self.loaders)
|
|
||||||
|
|
||||||
def find_template(self, name, dirs=None):
|
|
||||||
"""
|
|
||||||
RemovedInDjango20Warning: An internal method to lookup the template
|
|
||||||
name in all the configured loaders.
|
|
||||||
"""
|
|
||||||
key = self.cache_key(name, dirs)
|
|
||||||
try:
|
|
||||||
result = self.find_template_cache[key]
|
|
||||||
except KeyError:
|
|
||||||
result = None
|
|
||||||
for loader in self.loaders:
|
|
||||||
try:
|
|
||||||
template, display_name = loader(name, dirs)
|
|
||||||
except TemplateDoesNotExist:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
origin = Origin(
|
|
||||||
name=display_name,
|
|
||||||
template_name=name,
|
|
||||||
loader=loader,
|
|
||||||
)
|
|
||||||
result = template, origin
|
|
||||||
break
|
|
||||||
self.find_template_cache[key] = result
|
|
||||||
if result:
|
|
||||||
return result
|
|
||||||
else:
|
|
||||||
self.template_cache[key] = TemplateDoesNotExist
|
|
||||||
raise TemplateDoesNotExist(name)
|
|
||||||
|
|
||||||
def load_template(self, template_name, template_dirs=None):
|
|
||||||
warnings.warn(
|
|
||||||
'The load_template() method is deprecated. Use get_template() '
|
|
||||||
'instead.', RemovedInDjango20Warning,
|
|
||||||
)
|
|
||||||
key = self.cache_key(template_name, template_dirs)
|
|
||||||
template_tuple = self.template_cache.get(key)
|
|
||||||
# A cached previous failure:
|
|
||||||
if template_tuple is TemplateDoesNotExist:
|
|
||||||
raise TemplateDoesNotExist(template_name)
|
|
||||||
elif template_tuple is None:
|
|
||||||
template, origin = self.find_template(template_name, template_dirs)
|
|
||||||
if not hasattr(template, 'render'):
|
|
||||||
try:
|
|
||||||
template = Template(template, origin, template_name, self.engine)
|
|
||||||
except TemplateDoesNotExist:
|
|
||||||
# If compiling the template we found raises TemplateDoesNotExist,
|
|
||||||
# back off to returning the source and display name for the template
|
|
||||||
# we were asked to load. This allows for correct identification (later)
|
|
||||||
# of the actual template that does not exist.
|
|
||||||
self.template_cache[key] = (template, origin)
|
|
||||||
self.template_cache[key] = (template, None)
|
|
||||||
return self.template_cache[key]
|
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
"Empty the template cache."
|
"Empty the template cache."
|
||||||
self.template_cache.clear()
|
self.template_cache.clear()
|
||||||
self.find_template_cache.clear() # RemovedInDjango20Warning
|
|
||||||
self.get_template_cache.clear()
|
self.get_template_cache.clear()
|
||||||
|
@ -54,21 +54,3 @@ class Loader(BaseLoader):
|
|||||||
template_name=template_name,
|
template_name=template_name,
|
||||||
loader=self,
|
loader=self,
|
||||||
)
|
)
|
||||||
|
|
||||||
def load_template_source(self, template_name, template_dirs=None):
|
|
||||||
"""
|
|
||||||
Loads templates from Python eggs via pkg_resource.resource_string.
|
|
||||||
|
|
||||||
For every installed app, it tries to get the resource (app, template_name).
|
|
||||||
"""
|
|
||||||
warnings.warn(
|
|
||||||
'The load_template_sources() method is deprecated. Use '
|
|
||||||
'get_template() or get_contents() instead.',
|
|
||||||
RemovedInDjango20Warning,
|
|
||||||
)
|
|
||||||
for origin in self.get_template_sources(template_name):
|
|
||||||
try:
|
|
||||||
return self.get_contents(origin), origin.name
|
|
||||||
except TemplateDoesNotExist:
|
|
||||||
pass
|
|
||||||
raise TemplateDoesNotExist(template_name)
|
|
||||||
|
@ -4,12 +4,10 @@ Wrapper for loading templates from the filesystem.
|
|||||||
|
|
||||||
import errno
|
import errno
|
||||||
import io
|
import io
|
||||||
import warnings
|
|
||||||
|
|
||||||
from django.core.exceptions import SuspiciousFileOperation
|
from django.core.exceptions import SuspiciousFileOperation
|
||||||
from django.template import Origin, TemplateDoesNotExist
|
from django.template import Origin, TemplateDoesNotExist
|
||||||
from django.utils._os import safe_join
|
from django.utils._os import safe_join
|
||||||
from django.utils.deprecation import RemovedInDjango20Warning
|
|
||||||
|
|
||||||
from .base import Loader as BaseLoader
|
from .base import Loader as BaseLoader
|
||||||
|
|
||||||
@ -32,15 +30,13 @@ class Loader(BaseLoader):
|
|||||||
raise TemplateDoesNotExist(origin)
|
raise TemplateDoesNotExist(origin)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def get_template_sources(self, template_name, template_dirs=None):
|
def get_template_sources(self, template_name):
|
||||||
"""
|
"""
|
||||||
Return an Origin object pointing to an absolute path in each directory
|
Return an Origin object pointing to an absolute path in each directory
|
||||||
in template_dirs. For security reasons, if a path doesn't lie inside
|
in template_dirs. For security reasons, if a path doesn't lie inside
|
||||||
one of the template_dirs it is excluded from the result set.
|
one of the template_dirs it is excluded from the result set.
|
||||||
"""
|
"""
|
||||||
if not template_dirs:
|
for template_dir in self.get_dirs():
|
||||||
template_dirs = self.get_dirs()
|
|
||||||
for template_dir in template_dirs:
|
|
||||||
try:
|
try:
|
||||||
name = safe_join(template_dir, template_name)
|
name = safe_join(template_dir, template_name)
|
||||||
except SuspiciousFileOperation:
|
except SuspiciousFileOperation:
|
||||||
@ -53,16 +49,3 @@ class Loader(BaseLoader):
|
|||||||
template_name=template_name,
|
template_name=template_name,
|
||||||
loader=self,
|
loader=self,
|
||||||
)
|
)
|
||||||
|
|
||||||
def load_template_source(self, template_name, template_dirs=None):
|
|
||||||
warnings.warn(
|
|
||||||
'The load_template_sources() method is deprecated. Use '
|
|
||||||
'get_template() or get_contents() instead.',
|
|
||||||
RemovedInDjango20Warning,
|
|
||||||
)
|
|
||||||
for origin in self.get_template_sources(template_name, template_dirs):
|
|
||||||
try:
|
|
||||||
return self.get_contents(origin), origin.name
|
|
||||||
except TemplateDoesNotExist:
|
|
||||||
pass
|
|
||||||
raise TemplateDoesNotExist(template_name)
|
|
||||||
|
@ -2,10 +2,7 @@
|
|||||||
Wrapper for loading templates from a plain Python dict.
|
Wrapper for loading templates from a plain Python dict.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
from django.template import Origin, TemplateDoesNotExist
|
from django.template import Origin, TemplateDoesNotExist
|
||||||
from django.utils.deprecation import RemovedInDjango20Warning
|
|
||||||
|
|
||||||
from .base import Loader as BaseLoader
|
from .base import Loader as BaseLoader
|
||||||
|
|
||||||
@ -28,14 +25,3 @@ class Loader(BaseLoader):
|
|||||||
template_name=template_name,
|
template_name=template_name,
|
||||||
loader=self,
|
loader=self,
|
||||||
)
|
)
|
||||||
|
|
||||||
def load_template_source(self, template_name, template_dirs=None):
|
|
||||||
warnings.warn(
|
|
||||||
'The load_template_sources() method is deprecated. Use '
|
|
||||||
'get_template() or get_contents() instead.',
|
|
||||||
RemovedInDjango20Warning,
|
|
||||||
)
|
|
||||||
try:
|
|
||||||
return self.templates_dict[template_name], template_name
|
|
||||||
except KeyError:
|
|
||||||
raise TemplateDoesNotExist(template_name)
|
|
||||||
|
@ -1057,37 +1057,6 @@ Loader methods
|
|||||||
:meth:`get_contents` for custom template loaders. ``get_template()``
|
:meth:`get_contents` for custom template loaders. ``get_template()``
|
||||||
will usually not need to be overridden.
|
will usually not need to be overridden.
|
||||||
|
|
||||||
.. method:: load_template_source(template_name, template_dirs=None)
|
|
||||||
|
|
||||||
Returns a tuple of (``template_string``, ``template_origin``), where
|
|
||||||
``template_string`` is a string containing the template contents,
|
|
||||||
and ``template_origin`` is a string identifying the template source.
|
|
||||||
A filesystem-based loader may return the full path to the file as the
|
|
||||||
``template_origin``, for example.
|
|
||||||
|
|
||||||
``template_dirs`` is an optional argument used to control which
|
|
||||||
directories the loader will search.
|
|
||||||
|
|
||||||
This method is called automatically by :meth:`load_template` and should
|
|
||||||
be overridden when writing custom template loaders.
|
|
||||||
|
|
||||||
.. deprecated:: 1.9
|
|
||||||
|
|
||||||
Custom loaders should use :meth:`get_template` and
|
|
||||||
:meth:`get_contents` instead.
|
|
||||||
|
|
||||||
.. method:: load_template(template_name, template_dirs=None)
|
|
||||||
|
|
||||||
Returns a tuple of (``template``, ``template_origin``), where ``template``
|
|
||||||
is a ``Template`` object and ``template_origin`` is a string identifying
|
|
||||||
the template source. A filesystem-based loader may return the full
|
|
||||||
path to the file as the ``template_origin``, for example.
|
|
||||||
|
|
||||||
.. deprecated:: 1.9
|
|
||||||
|
|
||||||
Custom loaders should use :meth:`get_template` and
|
|
||||||
:meth:`get_contents` instead.
|
|
||||||
|
|
||||||
.. admonition:: Building your own
|
.. admonition:: Building your own
|
||||||
|
|
||||||
For examples, `read the source code for Django's built-in loaders`_.
|
For examples, `read the source code for Django's built-in loaders`_.
|
||||||
|
@ -265,3 +265,23 @@ these features.
|
|||||||
* The ``GeoManager`` and ``GeoQuerySet`` classes are removed.
|
* The ``GeoManager`` and ``GeoQuerySet`` classes are removed.
|
||||||
|
|
||||||
* The ``django.contrib.gis.geoip`` module is removed.
|
* The ``django.contrib.gis.geoip`` module is removed.
|
||||||
|
|
||||||
|
* The ``supports_recursion`` check for template loaders is removed from:
|
||||||
|
|
||||||
|
* ``django.template.engine.Engine.find_template()``
|
||||||
|
* ``django.template.loader_tags.ExtendsNode.find_template()``
|
||||||
|
* ``django.template.loaders.base.Loader.supports_recursion()``
|
||||||
|
* ``django.template.loaders.cached.Loader.supports_recursion()``
|
||||||
|
|
||||||
|
* The ``load_template`` and ``load_template_sources`` template loader methods
|
||||||
|
are removed.
|
||||||
|
|
||||||
|
* The ``template_dirs`` argument for template loaders is removed:
|
||||||
|
|
||||||
|
* ``django.template.loaders.base.Loader.get_template()``
|
||||||
|
* ``django.template.loaders.cached.Loader.cache_key()``
|
||||||
|
* ``django.template.loaders.cached.Loader.get_template()``
|
||||||
|
* ``django.template.loaders.cached.Loader.get_template_sources()``
|
||||||
|
* ``django.template.loaders.filesystem.Loader.get_template_sources()``
|
||||||
|
|
||||||
|
* ``django.template.loaders.base.Loader.__call__()`` is removed.
|
||||||
|
@ -248,9 +248,6 @@ class IncludeTests(SimpleTestCase):
|
|||||||
self.assertEqual(e.exception.args[0], 'missing.html')
|
self.assertEqual(e.exception.args[0], 'missing.html')
|
||||||
|
|
||||||
def test_extends_include_missing_cachedloader(self):
|
def test_extends_include_missing_cachedloader(self):
|
||||||
"""
|
|
||||||
Test the cache loader separately since it overrides load_template.
|
|
||||||
"""
|
|
||||||
engine = Engine(debug=True, loaders=[
|
engine = Engine(debug=True, loaders=[
|
||||||
('django.template.loaders.cached.Loader', [
|
('django.template.loaders.cached.Loader', [
|
||||||
'django.template.loaders.app_directories.Loader',
|
'django.template.loaders.app_directories.Loader',
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from django.template import Context, Engine, TemplateDoesNotExist
|
from django.template import Context, Engine, TemplateDoesNotExist
|
||||||
from django.template.loader_tags import ExtendsError
|
from django.test import SimpleTestCase
|
||||||
from django.template.loaders.base import Loader
|
|
||||||
from django.test import SimpleTestCase, ignore_warnings
|
|
||||||
from django.utils.deprecation import RemovedInDjango20Warning
|
|
||||||
|
|
||||||
from .utils import ROOT
|
from .utils import ROOT
|
||||||
|
|
||||||
@ -120,64 +117,3 @@ class ExtendsBehaviorTests(SimpleTestCase):
|
|||||||
template = engine.get_template('base.html')
|
template = engine.get_template('base.html')
|
||||||
output = template.render(Context({}))
|
output = template.render(Context({}))
|
||||||
self.assertEqual(output.strip(), 'loader2 loader1')
|
self.assertEqual(output.strip(), 'loader2 loader1')
|
||||||
|
|
||||||
|
|
||||||
class NonRecursiveLoader(Loader):
|
|
||||||
|
|
||||||
def __init__(self, engine, templates_dict):
|
|
||||||
self.templates_dict = templates_dict
|
|
||||||
super(NonRecursiveLoader, self).__init__(engine)
|
|
||||||
|
|
||||||
def load_template_source(self, template_name, template_dirs=None):
|
|
||||||
try:
|
|
||||||
return self.templates_dict[template_name], template_name
|
|
||||||
except KeyError:
|
|
||||||
raise TemplateDoesNotExist(template_name)
|
|
||||||
|
|
||||||
|
|
||||||
@ignore_warnings(category=RemovedInDjango20Warning)
|
|
||||||
class NonRecursiveLoaderExtendsTests(SimpleTestCase):
|
|
||||||
|
|
||||||
loaders = [
|
|
||||||
('template_tests.test_extends.NonRecursiveLoader', {
|
|
||||||
'base.html': 'base',
|
|
||||||
'index.html': '{% extends "base.html" %}',
|
|
||||||
'recursive.html': '{% extends "recursive.html" %}',
|
|
||||||
'other-recursive.html': '{% extends "recursive.html" %}',
|
|
||||||
'a.html': '{% extends "b.html" %}',
|
|
||||||
'b.html': '{% extends "a.html" %}',
|
|
||||||
}),
|
|
||||||
]
|
|
||||||
|
|
||||||
def test_extend(self):
|
|
||||||
engine = Engine(loaders=self.loaders)
|
|
||||||
output = engine.render_to_string('index.html')
|
|
||||||
self.assertEqual(output, 'base')
|
|
||||||
|
|
||||||
def test_extend_cached(self):
|
|
||||||
engine = Engine(loaders=[
|
|
||||||
('django.template.loaders.cached.Loader', self.loaders),
|
|
||||||
])
|
|
||||||
output = engine.render_to_string('index.html')
|
|
||||||
self.assertEqual(output, 'base')
|
|
||||||
|
|
||||||
cache = engine.template_loaders[0].template_cache
|
|
||||||
self.assertIn('base.html', cache)
|
|
||||||
self.assertIn('index.html', cache)
|
|
||||||
|
|
||||||
# Render a second time from cache
|
|
||||||
output = engine.render_to_string('index.html')
|
|
||||||
self.assertEqual(output, 'base')
|
|
||||||
|
|
||||||
def test_extend_error(self):
|
|
||||||
engine = Engine(loaders=self.loaders)
|
|
||||||
msg = 'Cannot extend templates recursively when using non-recursive template loaders'
|
|
||||||
|
|
||||||
with self.assertRaisesMessage(ExtendsError, msg):
|
|
||||||
engine.render_to_string('recursive.html')
|
|
||||||
|
|
||||||
with self.assertRaisesMessage(ExtendsError, msg):
|
|
||||||
engine.render_to_string('other-recursive.html')
|
|
||||||
|
|
||||||
with self.assertRaisesMessage(ExtendsError, msg):
|
|
||||||
engine.render_to_string('a.html')
|
|
||||||
|
@ -91,62 +91,6 @@ class CachedLoaderTests(SimpleTestCase):
|
|||||||
self.assertIsNone(e.__context__, error_msg)
|
self.assertIsNone(e.__context__, error_msg)
|
||||||
self.assertIsNone(e.__cause__, error_msg)
|
self.assertIsNone(e.__cause__, error_msg)
|
||||||
|
|
||||||
@ignore_warnings(category=RemovedInDjango20Warning)
|
|
||||||
def test_load_template(self):
|
|
||||||
loader = self.engine.template_loaders[0]
|
|
||||||
template, origin = loader.load_template('index.html')
|
|
||||||
self.assertEqual(template.origin.template_name, 'index.html')
|
|
||||||
|
|
||||||
cache = self.engine.template_loaders[0].template_cache
|
|
||||||
self.assertEqual(cache['index.html'][0], template)
|
|
||||||
|
|
||||||
# Run a second time from cache
|
|
||||||
loader = self.engine.template_loaders[0]
|
|
||||||
source, name = loader.load_template('index.html')
|
|
||||||
self.assertEqual(template.origin.template_name, 'index.html')
|
|
||||||
|
|
||||||
@ignore_warnings(category=RemovedInDjango20Warning)
|
|
||||||
def test_load_template_missing(self):
|
|
||||||
"""
|
|
||||||
#19949 -- TemplateDoesNotExist exceptions should be cached.
|
|
||||||
"""
|
|
||||||
loader = self.engine.template_loaders[0]
|
|
||||||
|
|
||||||
self.assertNotIn('missing.html', loader.template_cache)
|
|
||||||
|
|
||||||
with self.assertRaises(TemplateDoesNotExist):
|
|
||||||
loader.load_template("missing.html")
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
loader.template_cache["missing.html"],
|
|
||||||
TemplateDoesNotExist,
|
|
||||||
"Cached loader failed to cache the TemplateDoesNotExist exception",
|
|
||||||
)
|
|
||||||
|
|
||||||
@ignore_warnings(category=RemovedInDjango20Warning)
|
|
||||||
def test_load_nonexistent_cached_template(self):
|
|
||||||
loader = self.engine.template_loaders[0]
|
|
||||||
template_name = 'nonexistent.html'
|
|
||||||
|
|
||||||
# fill the template cache
|
|
||||||
with self.assertRaises(TemplateDoesNotExist):
|
|
||||||
loader.find_template(template_name)
|
|
||||||
|
|
||||||
with self.assertRaisesMessage(TemplateDoesNotExist, template_name):
|
|
||||||
loader.get_template(template_name)
|
|
||||||
|
|
||||||
def test_templatedir_caching(self):
|
|
||||||
"""
|
|
||||||
#13573 -- Template directories should be part of the cache key.
|
|
||||||
"""
|
|
||||||
# Retrieve a template specifying a template directory to check
|
|
||||||
t1, name = self.engine.find_template('test.html', (os.path.join(TEMPLATE_DIR, 'first'),))
|
|
||||||
# Now retrieve the same template name, but from a different directory
|
|
||||||
t2, name = self.engine.find_template('test.html', (os.path.join(TEMPLATE_DIR, 'second'),))
|
|
||||||
|
|
||||||
# The two templates should not have the same content
|
|
||||||
self.assertNotEqual(t1.render(Context({})), t2.render(Context({})))
|
|
||||||
|
|
||||||
def test_template_name_leading_dash_caching(self):
|
def test_template_name_leading_dash_caching(self):
|
||||||
"""
|
"""
|
||||||
#26536 -- A leading dash in a template name shouldn't be stripped
|
#26536 -- A leading dash in a template name shouldn't be stripped
|
||||||
@ -239,20 +183,6 @@ class EggLoaderTests(SimpleTestCase):
|
|||||||
output = template.render(Context({}))
|
output = template.render(Context({}))
|
||||||
self.assertEqual(output, "y")
|
self.assertEqual(output, "y")
|
||||||
|
|
||||||
@ignore_warnings(category=RemovedInDjango20Warning)
|
|
||||||
def test_load_template_source(self):
|
|
||||||
loader = self.engine.template_loaders[0]
|
|
||||||
templates = {
|
|
||||||
os.path.normcase('templates/y.html'): six.StringIO("y"),
|
|
||||||
}
|
|
||||||
|
|
||||||
with self.create_egg('egg', templates):
|
|
||||||
with override_settings(INSTALLED_APPS=['egg']):
|
|
||||||
source, name = loader.load_template_source('y.html')
|
|
||||||
|
|
||||||
self.assertEqual(source.strip(), 'y')
|
|
||||||
self.assertEqual(name, 'egg:egg:templates/y.html')
|
|
||||||
|
|
||||||
def test_non_existing(self):
|
def test_non_existing(self):
|
||||||
"""
|
"""
|
||||||
Template loading fails if the template is not in the egg.
|
Template loading fails if the template is not in the egg.
|
||||||
@ -323,13 +253,6 @@ class FileSystemLoaderTests(SimpleTestCase):
|
|||||||
with self.assertRaises(TemplateDoesNotExist):
|
with self.assertRaises(TemplateDoesNotExist):
|
||||||
engine.get_template('index.html')
|
engine.get_template('index.html')
|
||||||
|
|
||||||
@ignore_warnings(category=RemovedInDjango20Warning)
|
|
||||||
def test_load_template_source(self):
|
|
||||||
loader = self.engine.template_loaders[0]
|
|
||||||
source, name = loader.load_template_source('index.html')
|
|
||||||
self.assertEqual(source.strip(), 'index')
|
|
||||||
self.assertEqual(name, os.path.join(TEMPLATE_DIR, 'index.html'))
|
|
||||||
|
|
||||||
def test_directory_security(self):
|
def test_directory_security(self):
|
||||||
with self.source_checker(['/dir1', '/dir2']) as check_sources:
|
with self.source_checker(['/dir1', '/dir2']) as check_sources:
|
||||||
check_sources('index.html', ['/dir1/index.html', '/dir2/index.html'])
|
check_sources('index.html', ['/dir1/index.html', '/dir2/index.html'])
|
||||||
@ -353,10 +276,10 @@ class FileSystemLoaderTests(SimpleTestCase):
|
|||||||
"""
|
"""
|
||||||
Invalid UTF-8 encoding in bytestrings should raise a useful error
|
Invalid UTF-8 encoding in bytestrings should raise a useful error
|
||||||
"""
|
"""
|
||||||
engine = Engine()
|
engine = self.engine
|
||||||
loader = engine.template_loaders[0]
|
loader = engine.template_loaders[0]
|
||||||
with self.assertRaises(UnicodeDecodeError):
|
with self.assertRaises(UnicodeDecodeError):
|
||||||
list(loader.get_template_sources(b'\xc3\xc3', ['/dir1']))
|
list(loader.get_template_sources(b'\xc3\xc3'))
|
||||||
|
|
||||||
def test_unicode_dir_name(self):
|
def test_unicode_dir_name(self):
|
||||||
with self.source_checker([b'/Stra\xc3\x9fe']) as check_sources:
|
with self.source_checker([b'/Stra\xc3\x9fe']) as check_sources:
|
||||||
@ -410,14 +333,6 @@ class AppDirectoriesLoaderTests(SimpleTestCase):
|
|||||||
self.assertEqual(template.origin.template_name, 'index.html')
|
self.assertEqual(template.origin.template_name, 'index.html')
|
||||||
self.assertEqual(template.origin.loader, self.engine.template_loaders[0])
|
self.assertEqual(template.origin.loader, self.engine.template_loaders[0])
|
||||||
|
|
||||||
@ignore_warnings(category=RemovedInDjango20Warning)
|
|
||||||
@override_settings(INSTALLED_APPS=['template_tests'])
|
|
||||||
def test_load_template_source(self):
|
|
||||||
loader = self.engine.template_loaders[0]
|
|
||||||
source, name = loader.load_template_source('index.html')
|
|
||||||
self.assertEqual(source.strip(), 'index')
|
|
||||||
self.assertEqual(name, os.path.join(TEMPLATE_DIR, 'index.html'))
|
|
||||||
|
|
||||||
@override_settings(INSTALLED_APPS=[])
|
@override_settings(INSTALLED_APPS=[])
|
||||||
def test_not_installed(self):
|
def test_not_installed(self):
|
||||||
with self.assertRaises(TemplateDoesNotExist):
|
with self.assertRaises(TemplateDoesNotExist):
|
||||||
@ -440,10 +355,3 @@ class LocmemLoaderTests(SimpleTestCase):
|
|||||||
self.assertEqual(template.origin.name, 'index.html')
|
self.assertEqual(template.origin.name, 'index.html')
|
||||||
self.assertEqual(template.origin.template_name, 'index.html')
|
self.assertEqual(template.origin.template_name, 'index.html')
|
||||||
self.assertEqual(template.origin.loader, self.engine.template_loaders[0])
|
self.assertEqual(template.origin.loader, self.engine.template_loaders[0])
|
||||||
|
|
||||||
@ignore_warnings(category=RemovedInDjango20Warning)
|
|
||||||
def test_load_template_source(self):
|
|
||||||
loader = self.engine.template_loaders[0]
|
|
||||||
source, name = loader.load_template_source('index.html')
|
|
||||||
self.assertEqual(source.strip(), 'index')
|
|
||||||
self.assertEqual(name, 'index.html')
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user