Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace pkg_resource by importlib_resources #970

gsemet opened this issue Apr 18, 2019 · 4 comments · Fixed by #1082

Replace pkg_resource by importlib_resources #970

gsemet opened this issue Apr 18, 2019 · 4 comments · Fixed by #1082


Copy link

@gsemet gsemet commented Apr 18, 2019


Can you provide a future-proof loader that use importlib_resources instead of pkg_resource, which does not work pretty well in every case (on my pyinstaller package for instance it fails).

For me the use of pkg_resource should be avoided, it is about to be discarded (or maybe one day setuptools will not embed it). Providing a loader compatible with importlib_resources (the backport that brings' 3.7 importlib.resources to Python <3.7) is the easiest and more future-proof solution.


Copy link

@ThiefMaster ThiefMaster commented Apr 18, 2019

Sounds like a good first contribution :)

Copy link

@gsemet gsemet commented Apr 18, 2019

Working on it, but I do not garantee anything.

For information, they have a migration guide.

Copy link

@gsemet gsemet commented Apr 30, 2019

So here is my resource loader I have developped for my simple use case (works fine):

# coding: utf-8

A Jinja template loader using Importlib_resource.

# Third Party Libraries
import importlib_resources
from jinja2.exceptions import TemplateNotFound
from jinja2.loaders import BaseLoader
from jinja2.loaders import split_template_path

class ImportLibResourceLoader(BaseLoader):
    # Adapted from PackageResource, using this migration guide:

    def __init__(self, templates_path, encoding='utf-8'):
        self.templates_path = templates_path
        self.encoding = encoding

    def get_source(self, environment, template):
        pieces = split_template_path(template)
        p = '/'.join((self.templates_path, ) + tuple(pieces))
        if not self._has_resource(p):
            raise TemplateNotFound(template)

        package_name, _, filename = p.rpartition("/")
        source = importlib_resources.read_binary(package_name, filename)

        def uptodate():
            return False

        return source.decode(self.encoding), filename, uptodate

    def list_templates(self):
        path = self.templates_path
        if path[:2] == './':
            path = path[2:]
        elif path == '.':
            path = ''
        offset = len(path)
        results = []

        def _walk(path):
            for filename in importlib_resources.contents(path):
                fullname = path + '/' + filename
                if self._is_dir(path, filename):

        return results

    def _is_dir(self, templates_path: str, wanted_resource: str) -> bool:
        return (wanted_resource in importlib_resources.contents(templates_path) and
                not importlib_resources.is_resource(templates_path,

    def _has_resource(self, resource_path: str) -> bool:
        dir_name, _, filename = resource_path.rpartition("/")
        return filename in importlib_resources.contents(dir_name)

Copy link

@davidism davidism commented Mar 30, 2020

Reverting this in 2.11.2, it broke compatibility with Pytest. However, support will be present when 3.0 is released. See #1168, #1169

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Nov 13, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
None yet
None yet
3 participants