Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
v4.7.0
======

* #330: In ``packages_distributions``, now infer top-level
names from ``.files()`` when a ``top-level.txt``
(Setuptools-specific metadata) is not present.

v4.6.4
======

Expand Down
14 changes: 13 additions & 1 deletion importlib_metadata/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1013,6 +1013,18 @@ def packages_distributions() -> Mapping[str, List[str]]:
"""
pkg_to_dist = collections.defaultdict(list)
for dist in distributions():
for pkg in (dist.read_text('top_level.txt') or '').split():
for pkg in _top_level_declared(dist) or _top_level_inferred(dist):
pkg_to_dist[pkg].append(dist.metadata['Name'])
return dict(pkg_to_dist)


def _top_level_declared(dist):
return (dist.read_text('top_level.txt') or '').split()


def _top_level_inferred(dist):
return {
f.parts[0] if len(f.parts) > 1 else f.with_suffix('').name
for f in dist.files
Copy link

@harupy harupy Aug 26, 2021

Choose a reason for hiding this comment

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

Hi @jaraco, does this line throw when dist.files returns None? In our repo, we observed an issue that seems related to this line:

https://github.com/mlflow/mlflow/runs/3428616955#step:5:7078

  File "/miniconda/lib/python3.9/site-packages/importlib_metadata/__init__.py", line 1016, in packages_distributions
    for pkg in _top_level_declared(dist) or _top_level_inferred(dist):
  File "/miniconda/lib/python3.9/site-packages/importlib_metadata/__init__.py", line 1026, in _top_level_inferred
    return {
TypeError: 'NoneType' object is not iterable

if f.suffix == ".py"
}
2 changes: 2 additions & 0 deletions prepare/example2/example2/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def main():
return "example"
10 changes: 10 additions & 0 deletions prepare/example2/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[build-system]
build-backend = 'trampolim'
requires = ['trampolim']

[project]
name = 'example2'
version = '1.0.0'

[project.scripts]
example = 'example2:main'
Binary file added tests/data/example2-1.0.0-py3-none-any.whl
Binary file not shown.
2 changes: 1 addition & 1 deletion tests/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ class ZipFixtures:
def _fixture_on_path(self, filename):
pkg_file = resources.files(self.root).joinpath(filename)
file = self.resources.enter_context(resources.as_file(pkg_file))
assert file.name.startswith('example-'), file.name
assert file.name.startswith('example'), file.name
sys.path.insert(0, str(file))
self.resources.callback(sys.path.pop, 0)

Expand Down
15 changes: 15 additions & 0 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
distributions,
entry_points,
metadata,
packages_distributions,
version,
)

Expand Down Expand Up @@ -282,3 +283,17 @@ def test_unicode_dir_on_sys_path(self):
prefix=self.site_dir,
)
list(distributions())


class PackagesDistributionsTest(fixtures.ZipFixtures, unittest.TestCase):
def test_packages_distributions_example(self):
self._fixture_on_path('example-21.12-py3-none-any.whl')
assert packages_distributions()['example'] == ['example']

def test_packages_distributions_example2(self):
"""
Test packages_distributions on a wheel built
by trampolim.
"""
self._fixture_on_path('example2-1.0.0-py3-none-any.whl')
assert packages_distributions()['example2'] == ['example2']