Skip to content

bpo-33254: do not return an empty list when asking for the contents of a namespace package#6467

Merged
brettcannon merged 10 commits into
python:masterfrom
brettcannon:resource-empty-list-yield
Apr 30, 2018
Merged

bpo-33254: do not return an empty list when asking for the contents of a namespace package#6467
brettcannon merged 10 commits into
python:masterfrom
brettcannon:resource-empty-list-yield

Conversation

@brettcannon

@brettcannon brettcannon commented Apr 13, 2018

Copy link
Copy Markdown
Member

While the iteration will still be empty and you would only notice the accidental inclusion of the empty list if you introspected on StopIteration's value attribute, it wasn't necessary.

https://bugs.python.org/issue33254

@brettcannon brettcannon requested a review from warsaw April 13, 2018 22:15

@warsaw warsaw left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks and I'll backport this to importlib_resources

@serhiy-storchaka serhiy-storchaka left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why yield from? Wouldn't returning the iterator itself be simpler?

And the docstring doesn't match the behavior. It mentions the list of entries.

@warsaw

warsaw commented Apr 19, 2018

Copy link
Copy Markdown
Member

@serhiy-storchaka Good catch on the docstring. @brettcannon that does need to be updated.

As for the yield from do you mean the one that yields from os.listdir()? That has to yield from since os.listdir() returns a concrete list object.

@serhiy-storchaka

Copy link
Copy Markdown
Member

It can return an iterator. And str() is not needed since listdir() supports the path protocol.

return iter(os.listdir(package_directory))

@brettcannon

Copy link
Copy Markdown
Member Author

We can also change the type to Iterable if we wanted.

@brettcannon

Copy link
Copy Markdown
Member Author

@warsaw @serhiy-storchaka made everything return an iterable. PTAL.

@serhiy-storchaka

Copy link
Copy Markdown
Member

Changing the type to Iterable can break a user code that just calls next() on the result. Don't know whether this is important.

@serhiy-storchaka

Copy link
Copy Markdown
Member

Ah since the class is added in 3.7 I don't expect this change will break a lot of user code. 😉

@serhiy-storchaka serhiy-storchaka left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yet few suggestions. Mostly minor, but the note about _normalize_path() may be important.

Comment thread Lib/importlib/abc.py
"""Return an iterator of strings over the contents of the package."""
return iter([])
"""Return an iterable of strings over the contents of the package."""
return []

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe return a tuple? Creating and iterating a tuple is a tiny bit faster, and the empty tuple consumes less memory.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+0 - I leave it up to @brettcannon

Comment thread Lib/importlib/resources.py Outdated
# exception, but that's extra work, so just inline the check.
if package.__spec__.origin is None or not package.__spec__.has_location:
elif package.__spec__.origin is None or not package.__spec__.has_location:
return []

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same as above. A tuple can be returned here.

Comment thread Lib/importlib/resources.py Outdated
yield from os.listdir(str(package_directory))
else:
package_directory = Path(package.__spec__.origin).parent
return os.listdir(str(package_directory))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

str() is not needed here. os.listdir() supports the path protocol.

str() can be removed also in _normalize_path(). Actually calling str() in _normalize_path() can mask an error when wrong type is passed.

self.assertEqual(len(contents), 0)
def test_namespaces_cannot_have_resources(self):
contents = resources.contents('test.test_importlib.data03.namespace')
self.assertEqual(len(set(contents)), 0)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.assertEqual(list(contents), []) or self.assertFalse(list(contents)) could provide more informative error report (including the content list itself) if failed.

Why set() is used in other tests? Only because the order is not specified? assertCountEqual() in addition could check that items are not repeated (set() hides duplications).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. I don't feel a burning need to change all the tests though. One thing that would be helpful is to keep in mind that I am cross-porting changes here into importlib_resources. That's not a reason not to use whatever Python 3.7 constructs make sense, just to be mindful that I have to somehow make it work in 2.7, and 3.4-3.6 :)

@warsaw

warsaw commented Apr 22, 2018

Copy link
Copy Markdown
Member

FWIW, I'm also not concerned about minor API breakages in importlib_resources. There's a reason why its version number is < 1.0 :)

@brettcannon brettcannon self-assigned this Apr 23, 2018
@brettcannon

Copy link
Copy Markdown
Member Author

OK, I think I addressed all of the comments from @serhiy-storchaka . PTAL.

@brettcannon brettcannon merged commit 3ab9365 into python:master Apr 30, 2018
@miss-islington

Copy link
Copy Markdown
Contributor

Thanks @brettcannon for the PR 🌮🎉.. I'm working now to backport this PR to: 3.7.
🐍🍒⛏🤖

@brettcannon brettcannon deleted the resource-empty-list-yield branch April 30, 2018 18:31
miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Apr 30, 2018
…f a namespace package (pythonGH-6467)

(cherry picked from commit 3ab9365)

Co-authored-by: Brett Cannon <brettcannon@users.noreply.github.com>
@bedevere-bot

Copy link
Copy Markdown

GH-6664 is a backport of this pull request to the 3.7 branch.

miss-islington added a commit that referenced this pull request Apr 30, 2018
…f a namespace package (GH-6467)

(cherry picked from commit 3ab9365)

Co-authored-by: Brett Cannon <brettcannon@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants