Skip to content

reader resolution algorithm seems inconsistent between stdlib and importlib_resources #295

Closed
@mmerickel

Description

@mmerickel

Hello friends,

I'm looking at how to reimplement resource overrides in Pyramid. It's a unique feature that in the past involved patching a custom package.__loader__ which could intercept and do its own file lookups for various requests. This worked with all pkg_resources apis, like pkg_resources.resource_filename, etc to return a different path than the one physically on disk when a path is overridden.

To implement this, I've been going through the PEPs and trying to understand the protocol that importlib.resources uses to support overriding how resources are loaded from a package. I've narrowed this down to spec.loader.get_resource_reader() being able to be defined. My plan will be to define a ProxyLoader which defines its own get_resource_reader but proxies the rest of the loader functionality back to the original loader. So, I'm looking at how to define a custom abc.TraversableResources class that does what I need, and then hook package.__spec__.loader to return it from get_resource_reader().

From what I can tell, the logic here is inconsistent between importlib_resources and the stdlib impl in CPython. I'm looking here:

https://github.com/python/cpython/blob/5ddb2740404ad62e74ecb0ea97ed98651821ed3f/Lib/importlib/resources/_adapters.py#L28-L29

compared to

return (
# local ZipReader if a zip module
_zip_reader(self.spec)
or
# local NamespaceReader if a namespace module
_namespace_reader(self.spec)
or
# local FileReader
_file_reader(self.spec)
or
# native reader if it supplies 'files'
_native_reader(self.spec)
or
# fallback - adapt the spec ResourceReader to TraversableReader
_adapters.CompatibilityFiles(self.spec)
)

In both cases, TraversableResourceLoader is attempting to determine which reader to return. In the stdlib, preference is given to the native spec.loader.get_resource_reader() if the reader returned has a files() method. However, importlib_resources inverts the lookup such that zip/namespace/file take priority over the "native" reader. So for example, if self.path exists, then whatever I set as spec.loader.get_resource_reader() will never be invoked and hence I can't override the lookups.

Currently, to get this to work with importlib_resources, it appears that I would need the spec.path to be a non-existent path, which would trigger the logic to fallback to the native reader that I patch, but this is by far not ideal.

The TLDR is that I would propose importlib_resources moves the _native_reader(self.spec) invocation to the TOP of the list, which would be more in line with the stdlib.

I would really appreciate any guidance here. Maybe I'm completely off base and missing something critical in the importlib machinery, and happy to talk more about this use-case in Pyramid that has been supported for many years via a PEP320 loader used by pkg_resources. Thank you!

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions