python / importlib_resources

Backport of the importlib.resources module
Apache License 2.0
63 stars 47 forks source link

Possible bug introduced with PR250, joinpath with "." causes StopIteration #263

Closed VolkerH closed 1 year ago

VolkerH commented 2 years ago

Consider the following code snippet:

stopiteration_bug.py:

import spacem_maldi.Ontologies
from importlib_resources import files

print(files(spacem_maldi.Ontologies) / ".")

With importlib-resources<=5.7.1 this produces the following output:

/home/hilsenst/GitlabEMBL/spacem-ht/src/spacem-maldi/spacem_maldi/Ontologies

Starting from version 5.8.0, i.e. after PR #250 this throws a StopIteration exception:

~/Untracked$ python stopiteration_bug.py 
Traceback (most recent call last):
  File "stopiteration_bug.py", line 5, in <module>
    print(files(spacem_maldi.Ontologies) / ".")
  File "/home/hilsenst/miniconda3/envs/spacem-maldi-control/lib/python3.8/site-packages/importlib_resources/abc.py", line 130, in __truediv__
    return self.joinpath(child)
  File "/home/hilsenst/miniconda3/envs/spacem-maldi-control/lib/python3.8/site-packages/importlib_resources/readers.py", line 87, in joinpath
    return super().joinpath(*descendants)
  File "/home/hilsenst/miniconda3/envs/spacem-maldi-control/lib/python3.8/site-packages/importlib_resources/abc.py", line 114, in joinpath
    target = next(names)
StopIteration

The spacem_maldi package is a private package, but I don't think that is relevant here. If needed I can try and create a minimal public package.

blackadar commented 2 years ago

+1, there should be a way to get the Pathlib Path without joinpath anyways.

Also, a workaround for now:

print((files(spacem_maldi.Ontologies) / "fakefilename.txt").parent)

VolkerH commented 2 years ago

there should be a way to get the Pathlib Path without joinpath anyways

Yes, I felt that / "." was a crutch to start with but couln't find a better (proper) way.

jaraco commented 1 year ago

Oh, you shouldn't rely on joinpath to get a materialized path. If what you need is a materialized path on the file system, use as_file(traversable). files() returns a Traversable and Traversable.joinpath also returns a Traversable, which may or may not be on the filesystem. Although depending on your usage, you may not need to materialize the traversable at all and you may be able to get the value directly from the Traversable (such as with .open or .read_text()).

Still, you shouldn't get a StopIteration by attempting to join a path.

jaraco commented 1 year ago

I'm unable to replicate the issue:

>>> import importlib_resources as resources
>>> print(resources.files('importlib_resources') / ".")
/Users/jaraco/code/python/importlib_resources/importlib_resources

What's special about spacem_maldi.Ontologies that triggers the issue?

jaraco commented 1 year ago

I thought maybe the issue was that Ontologies was a directory without an __init__, but I'm still unable to trigger the failure:

>>> import pathlib
>>> pathlib.Path('importlib_resources/foo').mkdir()
>>> print(resources.files('importlib_resources.foo') / ".")
/Users/jaraco/code/python/importlib_resources/importlib_resources/foo
jaraco commented 1 year ago

Since the issue isn't reproducible, I'm closing it, but feel free to follow-up with the requested info and we can investigate further.