diff options
author | shadchin <shadchin@yandex-team.ru> | 2022-02-10 16:44:39 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:44:39 +0300 |
commit | e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (patch) | |
tree | 64175d5cadab313b3e7039ebaa06c5bc3295e274 /contrib/python/Jinja2/py3/jinja2/loaders.py | |
parent | 2598ef1d0aee359b4b6d5fdd1758916d5907d04f (diff) | |
download | ydb-e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0.tar.gz |
Restoring authorship annotation for <shadchin@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/python/Jinja2/py3/jinja2/loaders.py')
-rw-r--r-- | contrib/python/Jinja2/py3/jinja2/loaders.py | 682 |
1 files changed, 341 insertions, 341 deletions
diff --git a/contrib/python/Jinja2/py3/jinja2/loaders.py b/contrib/python/Jinja2/py3/jinja2/loaders.py index f7e2cadc3e..cc58eca221 100644 --- a/contrib/python/Jinja2/py3/jinja2/loaders.py +++ b/contrib/python/Jinja2/py3/jinja2/loaders.py @@ -1,47 +1,47 @@ -"""API and implementations for loading templates from different data -sources. +"""API and implementations for loading templates from different data +sources. """ -import importlib.util +import importlib.util import os import sys -import pkgutil -import typing as t +import pkgutil +import typing as t import weakref -import zipimport -from collections import abc -from hashlib import sha1 -from importlib import import_module +import zipimport +from collections import abc +from hashlib import sha1 +from importlib import import_module from types import ModuleType -from .exceptions import TemplateNotFound -from .utils import internalcode -from .utils import open_if_exists - -if t.TYPE_CHECKING: - from .environment import Environment - from .environment import Template - -import __res as arcadia_res - - -def split_template_path(template: str) -> t.List[str]: +from .exceptions import TemplateNotFound +from .utils import internalcode +from .utils import open_if_exists + +if t.TYPE_CHECKING: + from .environment import Environment + from .environment import Template + +import __res as arcadia_res + + +def split_template_path(template: str) -> t.List[str]: """Split a path into segments and perform a sanity check. If it detects '..' in the path it will raise a `TemplateNotFound` error. """ pieces = [] - for piece in template.split("/"): - if ( - os.path.sep in piece - or (os.path.altsep and os.path.altsep in piece) - or piece == os.path.pardir - ): + for piece in template.split("/"): + if ( + os.path.sep in piece + or (os.path.altsep and os.path.altsep in piece) + or piece == os.path.pardir + ): raise TemplateNotFound(template) - elif piece and piece != ".": + elif piece and piece != ".": pieces.append(piece) return pieces -class BaseLoader: +class BaseLoader: """Baseclass for all loaders. Subclass this and override `get_source` to implement a custom loading mechanism. The environment provides a `get_template` method that calls the loader's `load` method to get the @@ -63,8 +63,8 @@ class BaseLoader: if not exists(path): raise TemplateNotFound(template) mtime = getmtime(path) - with open(path) as f: - source = f.read() + with open(path) as f: + source = f.read() return source, path, lambda: mtime == getmtime(path) """ @@ -74,18 +74,18 @@ class BaseLoader: #: .. versionadded:: 2.4 has_source_access = True - def get_source( - self, environment: "Environment", template: str - ) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]: + def get_source( + self, environment: "Environment", template: str + ) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]: """Get the template source, filename and reload helper for a template. It's passed the environment and template name and has to return a tuple in the form ``(source, filename, uptodate)`` or raise a `TemplateNotFound` error if it can't locate the template. The source part of the returned tuple must be the source of the - template as a string. The filename should be the name of the - file on the filesystem if it was loaded from there, otherwise - ``None``. The filename is used by Python for the tracebacks + template as a string. The filename should be the name of the + file on the filesystem if it was loaded from there, otherwise + ``None``. The filename is used by Python for the tracebacks if no loader extension is used. The last item in the tuple is the `uptodate` function. If auto @@ -95,24 +95,24 @@ class BaseLoader: the template will be reloaded. """ if not self.has_source_access: - raise RuntimeError( - f"{type(self).__name__} cannot provide access to the source" - ) + raise RuntimeError( + f"{type(self).__name__} cannot provide access to the source" + ) raise TemplateNotFound(template) - def list_templates(self) -> t.List[str]: + def list_templates(self) -> t.List[str]: """Iterates over all templates. If the loader does not support that it should raise a :exc:`TypeError` which is the default behavior. """ - raise TypeError("this loader cannot iterate over all templates") + raise TypeError("this loader cannot iterate over all templates") @internalcode - def load( - self, - environment: "Environment", - name: str, - globals: t.Optional[t.MutableMapping[str, t.Any]] = None, - ) -> "Template": + def load( + self, + environment: "Environment", + name: str, + globals: t.Optional[t.MutableMapping[str, t.Any]] = None, + ) -> "Template": """Loads a template. This method looks up the template in the cache or loads one by calling :meth:`get_source`. Subclasses should not override this method as loaders working on collections of other @@ -146,57 +146,57 @@ class BaseLoader: bucket.code = code bcc.set_bucket(bucket) - return environment.template_class.from_code( - environment, code, globals, uptodate - ) + return environment.template_class.from_code( + environment, code, globals, uptodate + ) class FileSystemLoader(BaseLoader): - """Load templates from a directory in the file system. + """Load templates from a directory in the file system. + + The path can be relative or absolute. Relative paths are relative to + the current working directory. + + .. code-block:: python - The path can be relative or absolute. Relative paths are relative to - the current working directory. + loader = FileSystemLoader("templates") - .. code-block:: python + A list of paths can be given. The directories will be searched in + order, stopping at the first matching template. - loader = FileSystemLoader("templates") + .. code-block:: python - A list of paths can be given. The directories will be searched in - order, stopping at the first matching template. + loader = FileSystemLoader(["/override/templates", "/default/templates"]) - .. code-block:: python + :param searchpath: A path, or list of paths, to the directory that + contains the templates. + :param encoding: Use this encoding to read the text from template + files. + :param followlinks: Follow symbolic links in the path. - loader = FileSystemLoader(["/override/templates", "/default/templates"]) - - :param searchpath: A path, or list of paths, to the directory that - contains the templates. - :param encoding: Use this encoding to read the text from template - files. - :param followlinks: Follow symbolic links in the path. - - .. versionchanged:: 2.8 - Added the ``followlinks`` parameter. + .. versionchanged:: 2.8 + Added the ``followlinks`` parameter. """ - def __init__( - self, - searchpath: t.Union[str, os.PathLike, t.Sequence[t.Union[str, os.PathLike]]], - encoding: str = "utf-8", - followlinks: bool = False, - ) -> None: - if not isinstance(searchpath, abc.Iterable) or isinstance(searchpath, str): + def __init__( + self, + searchpath: t.Union[str, os.PathLike, t.Sequence[t.Union[str, os.PathLike]]], + encoding: str = "utf-8", + followlinks: bool = False, + ) -> None: + if not isinstance(searchpath, abc.Iterable) or isinstance(searchpath, str): searchpath = [searchpath] - - self.searchpath = [os.fspath(p) for p in searchpath] + + self.searchpath = [os.fspath(p) for p in searchpath] self.encoding = encoding self.followlinks = followlinks - def get_source( - self, environment: "Environment", template: str - ) -> t.Tuple[str, str, t.Callable[[], bool]]: + def get_source( + self, environment: "Environment", template: str + ) -> t.Tuple[str, str, t.Callable[[], bool]]: pieces = split_template_path(template) for searchpath in self.searchpath: - filename = os.path.join(searchpath, *pieces) + filename = os.path.join(searchpath, *pieces) f = open_if_exists(filename) if f is None: continue @@ -205,29 +205,29 @@ class FileSystemLoader(BaseLoader): finally: f.close() - mtime = os.path.getmtime(filename) + mtime = os.path.getmtime(filename) - def uptodate() -> bool: + def uptodate() -> bool: try: - return os.path.getmtime(filename) == mtime + return os.path.getmtime(filename) == mtime except OSError: return False - + return contents, filename, uptodate raise TemplateNotFound(template) - def list_templates(self) -> t.List[str]: + def list_templates(self) -> t.List[str]: found = set() for searchpath in self.searchpath: walk_dir = os.walk(searchpath, followlinks=self.followlinks) - for dirpath, _, filenames in walk_dir: + for dirpath, _, filenames in walk_dir: for filename in filenames: - template = ( - os.path.join(dirpath, filename)[len(searchpath) :] - .strip(os.path.sep) - .replace(os.path.sep, "/") - ) - if template[:2] == "./": + template = ( + os.path.join(dirpath, filename)[len(searchpath) :] + .strip(os.path.sep) + .replace(os.path.sep, "/") + ) + if template[:2] == "./": template = template[2:] if template not in found: found.add(template) @@ -235,74 +235,74 @@ class FileSystemLoader(BaseLoader): class PackageLoader(BaseLoader): - """Load templates from a directory in a Python package. - - :param package_name: Import name of the package that contains the - template directory. - :param package_path: Directory within the imported package that - contains the templates. - :param encoding: Encoding of template files. - - The following example looks up templates in the ``pages`` directory - within the ``project.ui`` package. - - .. code-block:: python - - loader = PackageLoader("project.ui", "pages") - - Only packages installed as directories (standard pip behavior) or - zip/egg files (less common) are supported. The Python API for - introspecting data in packages is too limited to support other - installation methods the way this loader requires. - - There is limited support for :pep:`420` namespace packages. The - template directory is assumed to only be in one namespace - contributor. Zip files contributing to a namespace are not - supported. - - .. versionchanged:: 3.0 - No longer uses ``setuptools`` as a dependency. - - .. versionchanged:: 3.0 - Limited PEP 420 namespace package support. + """Load templates from a directory in a Python package. + + :param package_name: Import name of the package that contains the + template directory. + :param package_path: Directory within the imported package that + contains the templates. + :param encoding: Encoding of template files. + + The following example looks up templates in the ``pages`` directory + within the ``project.ui`` package. + + .. code-block:: python + + loader = PackageLoader("project.ui", "pages") + + Only packages installed as directories (standard pip behavior) or + zip/egg files (less common) are supported. The Python API for + introspecting data in packages is too limited to support other + installation methods the way this loader requires. + + There is limited support for :pep:`420` namespace packages. The + template directory is assumed to only be in one namespace + contributor. Zip files contributing to a namespace are not + supported. + + .. versionchanged:: 3.0 + No longer uses ``setuptools`` as a dependency. + + .. versionchanged:: 3.0 + Limited PEP 420 namespace package support. """ - def __init__( - self, - package_name: str, - package_path: "str" = "templates", - encoding: str = "utf-8", - ) -> None: - package_path = os.path.normpath(package_path).rstrip(os.path.sep) - - # normpath preserves ".", which isn't valid in zip paths. - if package_path == os.path.curdir: - package_path = "" - elif package_path[:2] == os.path.curdir + os.path.sep: - package_path = package_path[2:] - - self.package_path = package_path - self.package_name = package_name + def __init__( + self, + package_name: str, + package_path: "str" = "templates", + encoding: str = "utf-8", + ) -> None: + package_path = os.path.normpath(package_path).rstrip(os.path.sep) + + # normpath preserves ".", which isn't valid in zip paths. + if package_path == os.path.curdir: + package_path = "" + elif package_path[:2] == os.path.curdir + os.path.sep: + package_path = package_path[2:] + + self.package_path = package_path + self.package_name = package_name self.encoding = encoding - # Make sure the package exists. This also makes namespace - # packages work, otherwise get_loader returns None. - package = import_module(package_name) - spec = importlib.util.find_spec(package_name) - assert spec is not None, "An import spec was not found for the package." - loader = spec.loader - assert loader is not None, "A loader was not found for the package." - self._loader = loader - self._archive = None - self._package = package - template_root = None - - if isinstance(loader, zipimport.zipimporter): - self._archive = loader.archive - pkgdir = next(iter(spec.submodule_search_locations)) # type: ignore - template_root = os.path.join(pkgdir, package_path) - elif hasattr(loader, "arcadia_source_finder"): - template_root = os.path.dirname(package.__file__) + # Make sure the package exists. This also makes namespace + # packages work, otherwise get_loader returns None. + package = import_module(package_name) + spec = importlib.util.find_spec(package_name) + assert spec is not None, "An import spec was not found for the package." + loader = spec.loader + assert loader is not None, "A loader was not found for the package." + self._loader = loader + self._archive = None + self._package = package + template_root = None + + if isinstance(loader, zipimport.zipimporter): + self._archive = loader.archive + pkgdir = next(iter(spec.submodule_search_locations)) # type: ignore + template_root = os.path.join(pkgdir, package_path) + elif hasattr(loader, "arcadia_source_finder"): + template_root = os.path.dirname(package.__file__) else: roots: t.List[str] = [] @@ -315,131 +315,131 @@ class PackageLoader(BaseLoader): roots.append(os.path.dirname(spec.origin)) for root in roots: - root = os.path.join(root, package_path) - - if os.path.isdir(root): - template_root = root - break - - if template_root is None: - raise ValueError( - f"The {package_name!r} package was not installed in a" - " way that PackageLoader understands." - ) - - self._template_root = template_root - - def get_source( - self, environment: "Environment", template: str - ) -> t.Tuple[str, str, t.Optional[t.Callable[[], bool]]]: - p = os.path.join(self._template_root, *split_template_path(template)) - up_to_date: t.Optional[t.Callable[[], bool]] - - if self._archive is None and hasattr(self, "_package"): - try: - source = pkgutil.get_data(self.package_name, os.path.join(self.package_path, *split_template_path(template))) - except OSError: - raise TemplateNotFound(template) - - def up_to_date() -> bool: - return True - - elif self._archive is None: - # Package is a directory. - if not os.path.isfile(p): - raise TemplateNotFound(template) - - with open(p, "rb") as f: - source = f.read() - - mtime = os.path.getmtime(p) - - def up_to_date() -> bool: - return os.path.isfile(p) and os.path.getmtime(p) == mtime - - else: - # Package is a zip file. - try: - source = self._loader.get_data(p) # type: ignore - except OSError as e: - raise TemplateNotFound(template) from e - - # Could use the zip's mtime for all template mtimes, but - # would need to safely reload the module if it's out of - # date, so just report it as always current. - up_to_date = None - - return source.decode(self.encoding), p, up_to_date - - def list_templates(self) -> t.List[str]: - results: t.List[str] = [] - - if self._archive is None and hasattr(self, "_package"): - prefix = os.path.join(self._template_root, self.package_path).encode() + b"/" - for name in arcadia_res.resfs_files(prefix): - results.append(name.removeprefix(prefix).decode()) - - elif self._archive is None: - # Package is a directory. - offset = len(self._template_root) - - for dirpath, _, filenames in os.walk(self._template_root): - dirpath = dirpath[offset:].lstrip(os.path.sep) - results.extend( - os.path.join(dirpath, name).replace(os.path.sep, "/") - for name in filenames - ) - else: - if not hasattr(self._loader, "_files"): - raise TypeError( - "This zip import does not have the required" - " metadata to list templates." - ) - - # Package is a zip file. - prefix = ( - self._template_root[len(self._archive) :].lstrip(os.path.sep) - + os.path.sep - ) - offset = len(prefix) - - for name in self._loader._files.keys(): # type: ignore - # Find names under the templates directory that aren't directories. - if name.startswith(prefix) and name[-1] != os.path.sep: - results.append(name[offset:].replace(os.path.sep, "/")) - + root = os.path.join(root, package_path) + + if os.path.isdir(root): + template_root = root + break + + if template_root is None: + raise ValueError( + f"The {package_name!r} package was not installed in a" + " way that PackageLoader understands." + ) + + self._template_root = template_root + + def get_source( + self, environment: "Environment", template: str + ) -> t.Tuple[str, str, t.Optional[t.Callable[[], bool]]]: + p = os.path.join(self._template_root, *split_template_path(template)) + up_to_date: t.Optional[t.Callable[[], bool]] + + if self._archive is None and hasattr(self, "_package"): + try: + source = pkgutil.get_data(self.package_name, os.path.join(self.package_path, *split_template_path(template))) + except OSError: + raise TemplateNotFound(template) + + def up_to_date() -> bool: + return True + + elif self._archive is None: + # Package is a directory. + if not os.path.isfile(p): + raise TemplateNotFound(template) + + with open(p, "rb") as f: + source = f.read() + + mtime = os.path.getmtime(p) + + def up_to_date() -> bool: + return os.path.isfile(p) and os.path.getmtime(p) == mtime + + else: + # Package is a zip file. + try: + source = self._loader.get_data(p) # type: ignore + except OSError as e: + raise TemplateNotFound(template) from e + + # Could use the zip's mtime for all template mtimes, but + # would need to safely reload the module if it's out of + # date, so just report it as always current. + up_to_date = None + + return source.decode(self.encoding), p, up_to_date + + def list_templates(self) -> t.List[str]: + results: t.List[str] = [] + + if self._archive is None and hasattr(self, "_package"): + prefix = os.path.join(self._template_root, self.package_path).encode() + b"/" + for name in arcadia_res.resfs_files(prefix): + results.append(name.removeprefix(prefix).decode()) + + elif self._archive is None: + # Package is a directory. + offset = len(self._template_root) + + for dirpath, _, filenames in os.walk(self._template_root): + dirpath = dirpath[offset:].lstrip(os.path.sep) + results.extend( + os.path.join(dirpath, name).replace(os.path.sep, "/") + for name in filenames + ) + else: + if not hasattr(self._loader, "_files"): + raise TypeError( + "This zip import does not have the required" + " metadata to list templates." + ) + + # Package is a zip file. + prefix = ( + self._template_root[len(self._archive) :].lstrip(os.path.sep) + + os.path.sep + ) + offset = len(prefix) + + for name in self._loader._files.keys(): # type: ignore + # Find names under the templates directory that aren't directories. + if name.startswith(prefix) and name[-1] != os.path.sep: + results.append(name[offset:].replace(os.path.sep, "/")) + results.sort() return results class DictLoader(BaseLoader): - """Loads a template from a Python dict mapping template names to - template source. This loader is useful for unittesting: + """Loads a template from a Python dict mapping template names to + template source. This loader is useful for unittesting: >>> loader = DictLoader({'index.html': 'source here'}) Because auto reloading is rarely useful this is disabled per default. """ - def __init__(self, mapping: t.Mapping[str, str]) -> None: + def __init__(self, mapping: t.Mapping[str, str]) -> None: self.mapping = mapping - def get_source( - self, environment: "Environment", template: str - ) -> t.Tuple[str, None, t.Callable[[], bool]]: + def get_source( + self, environment: "Environment", template: str + ) -> t.Tuple[str, None, t.Callable[[], bool]]: if template in self.mapping: source = self.mapping[template] return source, None, lambda: source == self.mapping.get(template) raise TemplateNotFound(template) - def list_templates(self) -> t.List[str]: + def list_templates(self) -> t.List[str]: return sorted(self.mapping) class FunctionLoader(BaseLoader): """A loader that is passed a function which does the loading. The function receives the name of the template and has to return either - a string with the template source, a tuple in the form ``(source, + a string with the template source, a tuple in the form ``(source, filename, uptodatefunc)`` or `None` if the template does not exist. >>> def load_template(name): @@ -454,30 +454,30 @@ class FunctionLoader(BaseLoader): return value. """ - def __init__( - self, - load_func: t.Callable[ - [str], - t.Optional[ - t.Union[ - str, t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]] - ] - ], - ], - ) -> None: + def __init__( + self, + load_func: t.Callable[ + [str], + t.Optional[ + t.Union[ + str, t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]] + ] + ], + ], + ) -> None: self.load_func = load_func - def get_source( - self, environment: "Environment", template: str - ) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]: + def get_source( + self, environment: "Environment", template: str + ) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]: rv = self.load_func(template) - + if rv is None: raise TemplateNotFound(template) - - if isinstance(rv, str): + + if isinstance(rv, str): return rv, None, None - + return rv @@ -496,49 +496,49 @@ class PrefixLoader(BaseLoader): by loading ``'app2/index.html'`` the file from the second. """ - def __init__( - self, mapping: t.Mapping[str, BaseLoader], delimiter: str = "/" - ) -> None: + def __init__( + self, mapping: t.Mapping[str, BaseLoader], delimiter: str = "/" + ) -> None: self.mapping = mapping self.delimiter = delimiter - def get_loader(self, template: str) -> t.Tuple[BaseLoader, str]: + def get_loader(self, template: str) -> t.Tuple[BaseLoader, str]: try: prefix, name = template.split(self.delimiter, 1) loader = self.mapping[prefix] - except (ValueError, KeyError) as e: - raise TemplateNotFound(template) from e + except (ValueError, KeyError) as e: + raise TemplateNotFound(template) from e return loader, name - def get_source( - self, environment: "Environment", template: str - ) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]: + def get_source( + self, environment: "Environment", template: str + ) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]: loader, name = self.get_loader(template) try: return loader.get_source(environment, name) - except TemplateNotFound as e: + except TemplateNotFound as e: # re-raise the exception with the correct filename here. # (the one that includes the prefix) - raise TemplateNotFound(template) from e + raise TemplateNotFound(template) from e @internalcode - def load( - self, - environment: "Environment", - name: str, - globals: t.Optional[t.MutableMapping[str, t.Any]] = None, - ) -> "Template": + def load( + self, + environment: "Environment", + name: str, + globals: t.Optional[t.MutableMapping[str, t.Any]] = None, + ) -> "Template": loader, local_name = self.get_loader(name) try: return loader.load(environment, local_name, globals) - except TemplateNotFound as e: + except TemplateNotFound as e: # re-raise the exception with the correct filename here. # (the one that includes the prefix) - raise TemplateNotFound(name) from e + raise TemplateNotFound(name) from e - def list_templates(self) -> t.List[str]: + def list_templates(self) -> t.List[str]: result = [] - for prefix, loader in self.mapping.items(): + for prefix, loader in self.mapping.items(): for template in loader.list_templates(): result.append(prefix + self.delimiter + template) return result @@ -558,12 +558,12 @@ class ChoiceLoader(BaseLoader): from a different location. """ - def __init__(self, loaders: t.Sequence[BaseLoader]) -> None: + def __init__(self, loaders: t.Sequence[BaseLoader]) -> None: self.loaders = loaders - def get_source( - self, environment: "Environment", template: str - ) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]: + def get_source( + self, environment: "Environment", template: str + ) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]: for loader in self.loaders: try: return loader.get_source(environment, template) @@ -572,12 +572,12 @@ class ChoiceLoader(BaseLoader): raise TemplateNotFound(template) @internalcode - def load( - self, - environment: "Environment", - name: str, - globals: t.Optional[t.MutableMapping[str, t.Any]] = None, - ) -> "Template": + def load( + self, + environment: "Environment", + name: str, + globals: t.Optional[t.MutableMapping[str, t.Any]] = None, + ) -> "Template": for loader in self.loaders: try: return loader.load(environment, name, globals) @@ -585,7 +585,7 @@ class ChoiceLoader(BaseLoader): pass raise TemplateNotFound(name) - def list_templates(self) -> t.List[str]: + def list_templates(self) -> t.List[str]: found = set() for loader in self.loaders: found.update(loader.list_templates()) @@ -611,24 +611,24 @@ class ModuleLoader(BaseLoader): has_source_access = False - def __init__( - self, path: t.Union[str, os.PathLike, t.Sequence[t.Union[str, os.PathLike]]] - ) -> None: - package_name = f"_jinja2_module_templates_{id(self):x}" + def __init__( + self, path: t.Union[str, os.PathLike, t.Sequence[t.Union[str, os.PathLike]]] + ) -> None: + package_name = f"_jinja2_module_templates_{id(self):x}" # create a fake module that looks for the templates in the # path given. mod = _TemplateModule(package_name) - - if not isinstance(path, abc.Iterable) or isinstance(path, str): + + if not isinstance(path, abc.Iterable) or isinstance(path, str): path = [path] - mod.__path__ = [os.fspath(p) for p in path] # type: ignore + mod.__path__ = [os.fspath(p) for p in path] # type: ignore + + sys.modules[package_name] = weakref.proxy( + mod, lambda x: sys.modules.pop(package_name, None) + ) - sys.modules[package_name] = weakref.proxy( - mod, lambda x: sys.modules.pop(package_name, None) - ) - # the only strong reference, the sys.modules entry is weak # so that the garbage collector can remove it once the # loader that created it goes out of business. @@ -636,40 +636,40 @@ class ModuleLoader(BaseLoader): self.package_name = package_name @staticmethod - def get_template_key(name: str) -> str: - return "tmpl_" + sha1(name.encode("utf-8")).hexdigest() + def get_template_key(name: str) -> str: + return "tmpl_" + sha1(name.encode("utf-8")).hexdigest() @staticmethod - def get_module_filename(name: str) -> str: - return ModuleLoader.get_template_key(name) + ".py" + def get_module_filename(name: str) -> str: + return ModuleLoader.get_template_key(name) + ".py" @internalcode - def load( - self, - environment: "Environment", - name: str, - globals: t.Optional[t.MutableMapping[str, t.Any]] = None, - ) -> "Template": + def load( + self, + environment: "Environment", + name: str, + globals: t.Optional[t.MutableMapping[str, t.Any]] = None, + ) -> "Template": key = self.get_template_key(name) - module = f"{self.package_name}.{key}" + module = f"{self.package_name}.{key}" mod = getattr(self.module, module, None) - + if mod is None: try: - mod = __import__(module, None, None, ["root"]) - except ImportError as e: - raise TemplateNotFound(name) from e + mod = __import__(module, None, None, ["root"]) + except ImportError as e: + raise TemplateNotFound(name) from e # remove the entry from sys.modules, we only want the attribute # on the module object we have stored on the loader. sys.modules.pop(module, None) - if globals is None: - globals = {} - + if globals is None: + globals = {} + return environment.template_class.from_module_dict( - environment, mod.__dict__, globals - ) + environment, mod.__dict__, globals + ) class ResourceLoader(BaseLoader): @@ -683,4 +683,4 @@ class ResourceLoader(BaseLoader): try: return self.module_loader.get_data(os.path.join(self.prefix, template)).decode('utf-8'), None, None except IOError: - raise TemplateNotFound(template) + raise TemplateNotFound(template) |