first comit
This commit is contained in:
Executable
BIN
Binary file not shown.
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
+13
@@ -0,0 +1,13 @@
|
||||
"""
|
||||
Wrapper for loading templates from "templates" directories in INSTALLED_APPS
|
||||
packages.
|
||||
"""
|
||||
|
||||
from django.template.utils import get_app_template_dirs
|
||||
|
||||
from .filesystem import Loader as FilesystemLoader
|
||||
|
||||
|
||||
class Loader(FilesystemLoader):
|
||||
def get_dirs(self):
|
||||
return get_app_template_dirs("templates")
|
||||
@@ -0,0 +1,51 @@
|
||||
from django.template import Template, TemplateDoesNotExist
|
||||
|
||||
|
||||
class Loader:
|
||||
def __init__(self, engine):
|
||||
self.engine = engine
|
||||
|
||||
def get_template(self, template_name, skip=None):
|
||||
"""
|
||||
Call self.get_template_sources() and return a Template object for
|
||||
the first template matching template_name. If skip is provided, ignore
|
||||
template origins in skip. This is used to avoid recursion during
|
||||
template extending.
|
||||
"""
|
||||
tried = []
|
||||
|
||||
for origin in self.get_template_sources(template_name):
|
||||
if skip is not None and origin in skip:
|
||||
tried.append((origin, "Skipped to avoid recursion"))
|
||||
continue
|
||||
|
||||
try:
|
||||
contents = self.get_contents(origin)
|
||||
except TemplateDoesNotExist:
|
||||
tried.append((origin, "Source does not exist"))
|
||||
continue
|
||||
else:
|
||||
return Template(
|
||||
contents,
|
||||
origin,
|
||||
origin.template_name,
|
||||
self.engine,
|
||||
)
|
||||
|
||||
raise TemplateDoesNotExist(template_name, tried=tried)
|
||||
|
||||
def get_template_sources(self, template_name):
|
||||
"""
|
||||
An iterator that yields possible matching template paths for a
|
||||
template name.
|
||||
"""
|
||||
raise NotImplementedError(
|
||||
"subclasses of Loader must provide a get_template_sources() method"
|
||||
)
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Reset any state maintained by the loader instance (e.g. cached
|
||||
templates or cached loader modules).
|
||||
"""
|
||||
pass
|
||||
@@ -0,0 +1,100 @@
|
||||
"""
|
||||
Wrapper class that takes a list of template loaders as an argument and attempts
|
||||
to load templates from them in order, caching the result.
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
|
||||
from django.template import TemplateDoesNotExist
|
||||
from django.template.backends.django import copy_exception
|
||||
|
||||
from .base import Loader as BaseLoader
|
||||
|
||||
|
||||
class Loader(BaseLoader):
|
||||
def __init__(self, engine, loaders):
|
||||
self.get_template_cache = {}
|
||||
self.loaders = engine.get_template_loaders(loaders)
|
||||
super().__init__(engine)
|
||||
|
||||
def get_dirs(self):
|
||||
for loader in self.loaders:
|
||||
if hasattr(loader, "get_dirs"):
|
||||
yield from loader.get_dirs()
|
||||
|
||||
def get_contents(self, origin):
|
||||
return origin.loader.get_contents(origin)
|
||||
|
||||
def get_template(self, template_name, skip=None):
|
||||
"""
|
||||
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.
|
||||
To keep it in check, caching behavior is a little complicated when a
|
||||
template is not found. See ticket #26306 for more details.
|
||||
|
||||
With template debugging disabled, cache the TemplateDoesNotExist class
|
||||
for every missing template and raise a new instance of it after
|
||||
fetching it from the cache.
|
||||
|
||||
With template debugging enabled, a unique TemplateDoesNotExist object
|
||||
is cached for each missing template to preserve debug data. When
|
||||
raising an exception, Python sets __traceback__, __context__, and
|
||||
__cause__ attributes on it. Those attributes can contain references to
|
||||
all sorts of objects up the call chain and caching them creates a
|
||||
memory leak. Thus, unraised copies of the exceptions are cached and
|
||||
copies of those copies are raised after they're fetched from the cache.
|
||||
"""
|
||||
key = self.cache_key(template_name, skip)
|
||||
cached = self.get_template_cache.get(key)
|
||||
if cached:
|
||||
if isinstance(cached, type) and issubclass(cached, TemplateDoesNotExist):
|
||||
raise cached(template_name)
|
||||
elif isinstance(cached, TemplateDoesNotExist):
|
||||
raise copy_exception(cached)
|
||||
return cached
|
||||
|
||||
try:
|
||||
template = super().get_template(template_name, skip)
|
||||
except TemplateDoesNotExist as e:
|
||||
self.get_template_cache[key] = (
|
||||
copy_exception(e) if self.engine.debug else TemplateDoesNotExist
|
||||
)
|
||||
raise
|
||||
else:
|
||||
self.get_template_cache[key] = template
|
||||
|
||||
return template
|
||||
|
||||
def get_template_sources(self, template_name):
|
||||
for loader in self.loaders:
|
||||
yield from loader.get_template_sources(template_name)
|
||||
|
||||
def cache_key(self, template_name, skip=None):
|
||||
"""
|
||||
Generate a cache key for the template name and skip.
|
||||
|
||||
If skip is provided, only origins that match template_name are included
|
||||
in the cache key. This ensures each template is only parsed and cached
|
||||
once if contained in different extend chains like:
|
||||
|
||||
x -> a -> a
|
||||
y -> a -> a
|
||||
z -> a -> a
|
||||
"""
|
||||
skip_prefix = ""
|
||||
|
||||
if skip:
|
||||
matching = [
|
||||
origin.name for origin in skip if origin.template_name == template_name
|
||||
]
|
||||
if matching:
|
||||
skip_prefix = self.generate_hash(matching)
|
||||
|
||||
return "-".join(s for s in (str(template_name), skip_prefix) if s)
|
||||
|
||||
def generate_hash(self, values):
|
||||
return hashlib.sha1("|".join(values).encode()).hexdigest()
|
||||
|
||||
def reset(self):
|
||||
"Empty the template cache."
|
||||
self.get_template_cache.clear()
|
||||
@@ -0,0 +1,45 @@
|
||||
"""
|
||||
Wrapper for loading templates from the filesystem.
|
||||
"""
|
||||
|
||||
from django.core.exceptions import SuspiciousFileOperation
|
||||
from django.template import Origin, TemplateDoesNotExist
|
||||
from django.utils._os import safe_join
|
||||
|
||||
from .base import Loader as BaseLoader
|
||||
|
||||
|
||||
class Loader(BaseLoader):
|
||||
def __init__(self, engine, dirs=None):
|
||||
super().__init__(engine)
|
||||
self.dirs = dirs
|
||||
|
||||
def get_dirs(self):
|
||||
return self.dirs if self.dirs is not None else self.engine.dirs
|
||||
|
||||
def get_contents(self, origin):
|
||||
try:
|
||||
with open(origin.name, encoding=self.engine.file_charset) as fp:
|
||||
return fp.read()
|
||||
except FileNotFoundError:
|
||||
raise TemplateDoesNotExist(origin)
|
||||
|
||||
def get_template_sources(self, template_name):
|
||||
"""
|
||||
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
|
||||
one of the template_dirs it is excluded from the result set.
|
||||
"""
|
||||
for template_dir in self.get_dirs():
|
||||
try:
|
||||
name = safe_join(template_dir, template_name)
|
||||
except SuspiciousFileOperation:
|
||||
# The joined path was located outside of this template_dir
|
||||
# (it might be inside another one, so this isn't fatal).
|
||||
continue
|
||||
|
||||
yield Origin(
|
||||
name=name,
|
||||
template_name=template_name,
|
||||
loader=self,
|
||||
)
|
||||
@@ -0,0 +1,26 @@
|
||||
"""
|
||||
Wrapper for loading templates from a plain Python dict.
|
||||
"""
|
||||
|
||||
from django.template import Origin, TemplateDoesNotExist
|
||||
|
||||
from .base import Loader as BaseLoader
|
||||
|
||||
|
||||
class Loader(BaseLoader):
|
||||
def __init__(self, engine, templates_dict):
|
||||
self.templates_dict = templates_dict
|
||||
super().__init__(engine)
|
||||
|
||||
def get_contents(self, origin):
|
||||
try:
|
||||
return self.templates_dict[origin.name]
|
||||
except KeyError:
|
||||
raise TemplateDoesNotExist(origin)
|
||||
|
||||
def get_template_sources(self, template_name):
|
||||
yield Origin(
|
||||
name=template_name,
|
||||
template_name=template_name,
|
||||
loader=self,
|
||||
)
|
||||
Reference in New Issue
Block a user