From 466cd3c8e6036cbd16584629fa0e54d6c0d6b027 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 24 Feb 2021 11:42:19 -0500 Subject: [PATCH] Add 'packages_distributions'. Fixes #131. --- CHANGES.rst | 6 ++++++ docs/using.rst | 11 +++++++++++ importlib_metadata/__init__.py | 20 ++++++++++++++++++-- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index f8df681d..a4e468c0 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,9 @@ +v3.7.0 +====== + +* #131: Added ``packages_distributions`` to conveniently + resolve a top-level package or module to its distribution(s). + v3.6.0 ====== diff --git a/docs/using.rst b/docs/using.rst index 97941452..18aa2fda 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -182,6 +182,17 @@ function:: ["pytest (>=3.0.0) ; extra == 'test'", "pytest-cov ; extra == 'test'"] +Package distributions +--------------------- + +A convience method to resolve the distribution or +distributions (in the case of a namespace package) for top-level +Python packages or modules:: + + >>> packages_distributions() + {'importlib_metadata': ['importlib-metadata'], 'yaml': ['PyYAML'], 'jaraco': ['jaraco.classes', 'jaraco.functools'], ...} + + Distributions ============= diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index b0b1ae0e..5c19c237 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -12,7 +12,7 @@ import functools import itertools import posixpath -import collections +import collections.abc from ._compat import ( NullFinder, @@ -28,7 +28,7 @@ from importlib import import_module from importlib.abc import MetaPathFinder from itertools import starmap -from typing import Any, List, Optional, TypeVar, Union +from typing import Any, List, Mapping, Optional, TypeVar, Union __all__ = [ @@ -796,3 +796,19 @@ def requires(distribution_name): packaging.requirement.Requirement. """ return distribution(distribution_name).requires + + +def packages_distributions() -> Mapping[str, List[str]]: + """ + Return a mapping of top-level packages to their + distributions. + + >>> pkgs = packages_distributions() + >>> all(isinstance(dist, collections.abc.Sequence) for dist in pkgs.values()) + True + """ + pkg_to_dist = collections.defaultdict(list) + for dist in distributions(): + for pkg in (dist.read_text('top_level.txt') or '').split(): + pkg_to_dist[pkg].append(dist.metadata['Name']) + return dict(pkg_to_dist)