From e2357fad71cee5ae93cb66ca27deb9dd67ccefa5 Mon Sep 17 00:00:00 2001 From: David Lord Date: Mon, 30 Mar 2020 10:11:22 -0700 Subject: [PATCH] Revert "PackageLoader doesn't depend on setuptools" This reverts commit 4b6077a8c0a0f56bb8dbac37f8f9027130b4091c. --- src/jinja2/loaders.py | 131 +++++++++++++++--------------------------- tests/res/package.zip | Bin 1036 -> 0 bytes tests/test_loader.py | 50 ---------------- 3 files changed, 47 insertions(+), 134 deletions(-) delete mode 100644 tests/res/package.zip 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 diff --git a/tests/res/package.zip b/tests/res/package.zip deleted file mode 100644 index d4c9ce9cea96284a040c61f78e373062436bc4ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc-jL100001 literal 1036 zc-jl_W@h1H00G0S0DlG~z|J7UP!eB|n4GO28p6rIe6MPG>|-D9*0WO>2NzyKx! z;09Qs86b!-pd>Z7ASbaTwHRX52cR(@@EHYi%hb9^P8J{=gr%?<1;izK86~+naOd5_ zG}Fm3h${f6A4Rd5o0gxikIzU{iX z?7?O%Qn(U!HfH1_JNpSX^C3xrIHOS$0