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

importlib.resources.files(__package__) api does not work #977

Closed
pax0r opened this issue Sep 27, 2023 · 4 comments
Closed

importlib.resources.files(__package__) api does not work #977

pax0r opened this issue Sep 27, 2023 · 4 comments
Labels
Milestone

Comments

@pax0r
Copy link

pax0r commented Sep 27, 2023

Describe your issue

For some reason I can't get the importlib.resources.files(__package__) to work. In my case this is used by external library jsonschema but I was able to reproduce this in my own code as well. By documentation this should return some Traversable with files in given module. jsonschema library is using it to load some .json files inside the package directory.

In Chaquopy each call to importlib.resources.files(__package__) returns importlib._adapters.DegenerateFiles.Path which means it cannot read files from package dir.

According to this comment: #745 (comment) it should work

Chaquopy version

id 'com.chaquo.python' version '14.0.2' apply false

Devices or emulators where the issue happens

Tested on emulator only, but I think it does not matter

Relevant parts of your code

from importlib import resources

print('==================', resources.files(__package__))

Should shown a Traversable with files from package, istead it shows importlib._adapters.DegenerateFiles.Path

I have tried both with package mentioned in extractPackages and not.

@mhsmith
Copy link
Member

mhsmith commented Sep 28, 2023

It looks like implementing the new importlib.resources API automatically gives you support for the old one, but not vice versa:

Python 3.10.6 (main, Sep 17 2022, 20:08:30) [Clang 11.0.5 (https://android.googlesource.com/toolchain/llvm-project 87f1315df on linux
The current application context is available in the variable 'context'.
>>> import chaquopy
>>> from importlib import resources
>>> resources.files("chaquopy")
<importlib._adapters.DegenerateFiles.Path object at 0x7667af327eb0>
>>> root = _
>>> list(root.iterdir())
[]
>>> list(resources.contents("chaquopy"))
['__init__.py', 'test', 'utils']

Thanks for the report. We'll fix this in the next version of Chaquopy.

@mhsmith mhsmith added the bug label Sep 28, 2023
@mhsmith
Copy link
Member

mhsmith commented Sep 28, 2023

Since the new importlib.resources API was introduced in Python 3.9, you can probably avoid any related issues in third-party packages by downgrading your app to Python 3.8.

@mhsmith mhsmith added this to the 15.0 milestone Sep 28, 2023
@pax0r
Copy link
Author

pax0r commented Sep 28, 2023

I've managed to patch 3rd party lib by myself but I can't wait for fix in Chaquopy ;)

I've seen that in Python < 3.9 it uses https://pypi.org/project/importlib-resources/ for this task but I haven't tested it on Android.

@mhsmith
Copy link
Member

mhsmith commented Nov 22, 2023

To make it easy to remove the old API, we should reimplement it in terms of the new one, just as importlib itself now does in Python 3.12 (see implementation of importlib.resources.abc.TraversableResources).

There's a probable error here:

Loaders that wish to support resource reading are expected to provide a method called get_resource_reader(fullname) which returns an object implementing this ABC’s interface. If the module specified by fullname is not a package, this method should return None. An object compatible with this ABC should only be returned when the specified module is a package.

But as of Python 3.12, importlib.resources.files can accept a module as well as a package, so it's depending on the get_resource_reader method of the standard importer to always return a reader whether it's passed a module or a package. In the common case, it returns an importlib.resources.readers.FileReader, which determines the directory simply by stripping off the last component of the module's path, whether it's __init__.py or anything else. Leave a comment on our implementation explaining this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants