diff options
author | David Lord <davidism@gmail.com> | 2020-03-30 10:11:22 -0700 |
---|---|---|
committer | David Lord <davidism@gmail.com> | 2020-03-30 10:11:22 -0700 |
commit | e2357fad71cee5ae93cb66ca27deb9dd67ccefa5 (patch) | |
tree | 1e6bd2b2dc121117340c8056645e4d619985607b /src | |
parent | cf53e2254dd316327a4d54f6f11801714c5af3a7 (diff) | |
download | jinja-e2357fad71cee5ae93cb66ca27deb9dd67ccefa5.tar.gz |
Revert "PackageLoader doesn't depend on setuptools"
This reverts commit 4b6077a8c0a0f56bb8dbac37f8f9027130b4091c.
Diffstat (limited to 'src')
-rw-r--r-- | src/jinja2/loaders.py | 131 |
1 files changed, 47 insertions, 84 deletions
diff --git a/src/jinja2/loaders.py b/src/jinja2/loaders.py index d057ad5f..457c4b59 100644 --- a/src/jinja2/loaders.py +++ b/src/jinja2/loaders.py @@ -3,7 +3,6 @@ sources. """ import os -import pkgutil import sys import weakref from hashlib import sha1 @@ -216,111 +215,75 @@ class FileSystemLoader(BaseLoader): class PackageLoader(BaseLoader): - """Load templates from a directory in a Python package. + """Load templates from python eggs or packages. It is constructed with + the name of the python package and the path to the templates in that + 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. + loader = PackageLoader('mypackage', 'views') - The following example looks up templates in the ``pages`` directory - within the ``project.ui`` package. + If the package path is not given, ``'templates'`` is assumed. - .. 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. - - .. versionchanged:: 2.11.0 - No longer uses ``setuptools`` as a dependency. + Per default the template encoding is ``'utf-8'`` which can be changed + by setting the `encoding` parameter to something else. Due to the nature + of eggs it's only possible to reload templates if the package was loaded + from the file system and not a zip file. """ def __init__(self, package_name, package_path="templates", encoding="utf-8"): - if package_path == os.path.curdir: - package_path = "" - elif package_path[:2] == os.path.curdir + os.path.sep: - package_path = package_path[2:] - - package_path = os.path.normpath(package_path) + from pkg_resources import DefaultProvider + from pkg_resources import get_provider + from pkg_resources import ResourceManager - self.package_name = package_name - self.package_path = package_path + provider = get_provider(package_name) self.encoding = encoding - - self._loader = pkgutil.get_loader(package_name) - # Zip loader's archive attribute points at the zip. - self._archive = getattr(self._loader, "archive", None) - self._template_root = os.path.join( - os.path.dirname(self._loader.get_filename(package_name)), package_path - ).rstrip(os.path.sep) + self.manager = ResourceManager() + self.filesystem_bound = isinstance(provider, DefaultProvider) + self.provider = provider + self.package_path = package_path def get_source(self, environment, template): - p = os.path.join(self._template_root, *split_template_path(template)) + pieces = split_template_path(template) + p = "/".join((self.package_path,) + tuple(pieces)) - if self._archive is None: - # Package is a directory. - if not os.path.isfile(p): - raise TemplateNotFound(template) + if not self.provider.has_resource(p): + raise TemplateNotFound(template) - with open(p, "rb") as f: - source = f.read() + filename = uptodate = None - mtime = os.path.getmtime(p) + if self.filesystem_bound: + filename = self.provider.get_resource_filename(self.manager, p) + mtime = path.getmtime(filename) - def up_to_date(): - return os.path.isfile(p) and os.path.getmtime(p) == mtime + def uptodate(): + try: + return path.getmtime(filename) == mtime + except OSError: + return False - else: - # Package is a zip file. - try: - source = self._loader.get_data(p) - except OSError: - raise TemplateNotFound(template) + source = self.provider.get_resource_string(self.manager, p) + return source.decode(self.encoding), filename, uptodate - # 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 + def list_templates(self): + path = self.package_path - return source.decode(self.encoding), p, up_to_date + if path[:2] == "./": + path = path[2:] + elif path == ".": + path = "" - def list_templates(self): + offset = len(path) results = [] - if 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) + def _walk(path): + for filename in self.provider.resource_listdir(path): + fullname = path + "/" + filename - for name in self._loader._files.keys(): - # 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, "/")) + if self.provider.resource_isdir(fullname): + _walk(fullname) + else: + results.append(fullname[offset:].lstrip("/")) + _walk(path) results.sort() return results |