def test_unique_distributions(self): """ Two distributions varying only by non-normalized name on the file system should resolve as the same. """ fixtures.build_files(self.make_pkg('abc'), self.site_dir) before = list(_unique(distributions())) alt_site_dir = self.fixtures.enter_context(fixtures.tempdir()) self.fixtures.enter_context(self.add_sys_path(alt_site_dir)) fixtures.build_files(self.make_pkg('ABC'), alt_site_dir) after = list(_unique(distributions())) assert len(after) == len(before)
def test_unicode_dir_on_sys_path(self): """ Ensure a Unicode subdirectory of a directory on sys.path does not crash. """ fixtures.build_files({'☃': {}}, prefix=self.site_dir) list(distributions())
def get_installed_packages() -> Collection: pkgs = sorted(metadata.distributions(), key=lambda x: x.metadata['Name'].upper()) installed_python_packages = [ f"{x.metadata['Name']} {x.metadata['Version']}" for x in pkgs ] return installed_python_packages
def load_setuptools_entrypoints( self, group: str, name: Optional[str] = None ) -> int: """Load modules from querying the specified setuptools ``group``. :param str group: Entry point group to load plugins. :param str name: If given, loads only plugins with the given ``name``. :rtype: int :return: The number of plugins loaded by this call. """ count = 0 for dist in list(importlib_metadata.distributions()): for ep in dist.entry_points: if ( ep.group != group or (name is not None and ep.name != name) # already registered or self.get_plugin(ep.name) or self.is_blocked(ep.name) ): continue plugin = ep.load() self.register(plugin, name=ep.name) self._plugin_distinfo.append((plugin, DistFacade(dist))) count += 1 return count
def entry_points_for( group: str, ) -> Generator[importlib_metadata.EntryPoint, None, None]: """Yield all entry_points matching "group", from any distribution. Distribution here refers more specifically to the information in the dist-info folder that usually accompanies an installed package. If a package in the environment does *not* have a ``dist-info/entry_points.txt`` file, then in will not be discovered by this function. Note: a single package may provide multiple entrypoints for a given group. Parameters ---------- group : str The name of the entry point to search. Yields ------- Generator[importlib_metadata.EntryPoint, None, None] [description] Example ------- >>> list(entry_points_for('napari.plugin')) [EntryPoint(name='napari-reg', value='napari_reg', group='napari.plugin'), EntryPoint(name='myplug', value='another.module', group='napari.plugin')] """ for dist in importlib_metadata.distributions(): for ep in dist.entry_points: if ep.group == group: yield ep
def _get_installed_packages(): try: return set(d.metadata["Name"] for d in importlib_metadata.distributions()) except: logger.debug("Failed to get installed packages") return set()
def tox_runenvreport(venv, action): """Prevent using pip to display installed packages, use importlib.metadata instead, but fallback to default without our flags.""" if not _plugin_active(venv.envconfig.config.option): return None return ("{}=={}".format(d.metadata.get("name"), d.version) for d in sorted(importlib_metadata.distributions(), key=lambda d: d.metadata.get("name")))
def test_unicode_dir_on_sys_path(self): # Ensure a Unicode subdirectory of a directory on sys.path # does not crash. fixtures.build_files( {self.unicode_filename(): {}}, prefix=self.site_dir, ) list(distributions())
def get_distribution_of_module(module_name): """Return the name of the distribution providing the given module""" base_module = module_name.split('.', 1)[0] for distribution in importlib_metadata.distributions(): if distribution.files is None: continue for path in distribution.files: if Path(path).parts[0] == base_module: return distribution.metadata['Name']
def test_importlib_metadata(self): self.assertCountEqual(["chaquopy-libcxx", "murmurhash", "Pygments"], [d.metadata["Name"] for d in metadata.distributions()]) dist = metadata.distribution("murmurhash") self.assertEqual("0.28.0", dist.version) self.assertIsNone(dist.files) self.assertEqual("Matthew Honnibal", dist.metadata["Author"]) self.assertEqual(["chaquopy-libcxx (>=7000)"], dist.requires)
def packages_distributions(): """ Return a mapping of top-level packages to their distributions. Note: copied from https://github.com/python/importlib_metadata/pull/287 """ pkg_to_dist = collections.defaultdict(list) for dist in metadata.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)
def find_entry_points(group, name=None): """Find all entry points with in `group`, optionally filtered by `name` Yields: (EntryPoint, Distribution): entry point and distribution it belongs to """ yield from ((ep, dist) for dist in ilm.distributions() for ep in dist.entry_points if ep.group == group and (name is None or ep.name == name))
def packages_distributions() -> t.Dict[str, t.List[str]]: """Return a mapping of top-level packages to their distributions. We're inlining this helper from the importlib_metadata "backport" here, since it's not available in the builtin importlib.metadata. """ pkg_to_dist = defaultdict(list) for dist in importlib_metadata.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)
def inspect_venv( root_package_name: str, root_package_extras: Set[str], venv_bin_path: Path, venv_python_path: Path, ) -> VenvMetadata: app_paths_of_dependencies: Dict[str, List[Path]] = {} apps_of_dependencies: List[str] = [] root_req = Requirement(root_package_name) root_req.extras = root_package_extras (venv_sys_path, venv_env, venv_python_version) = fetch_info_in_venv( venv_python_path ) venv_inspect_info = VenvInspectInformation( bin_path=venv_bin_path, env=venv_env, distributions=list(metadata.distributions(path=venv_sys_path)), ) root_dist = get_dist(root_req.name, venv_inspect_info.distributions) if root_dist is None: raise PipxError( "Pipx Internal Error: cannot find package {root_req.name!r} metadata." ) app_paths_of_dependencies = _dfs_package_apps( root_dist, root_req, venv_inspect_info, app_paths_of_dependencies ) apps = get_apps(root_dist, venv_bin_path) app_paths = [venv_bin_path / app for app in apps] if WINDOWS: app_paths = _windows_extra_app_paths(app_paths) for dep in app_paths_of_dependencies: apps_of_dependencies += [ dep_path.name for dep_path in app_paths_of_dependencies[dep] ] if WINDOWS: app_paths_of_dependencies[dep] = _windows_extra_app_paths( app_paths_of_dependencies[dep] ) venv_metadata = VenvMetadata( apps=apps, app_paths=app_paths, apps_of_dependencies=apps_of_dependencies, app_paths_of_dependencies=app_paths_of_dependencies, package_version=root_dist.version, python_version=venv_python_version, ) return venv_metadata
def find_entry_points(name, group): """Find all `name` entry points with in `group` Returns: Iterator[(EntryPoint, Distribution)]: entry point and distribution it belongs to """ yield from ((ep, dist) for dist in ilm.distributions() for ep in dist.entry_points if ep.group == group and ep.name == name)
def v030_v040(model: NapariSettings): """Migrate from v0.3.0 to v0.4.0. Prior to v0.4.0, npe2 plugins were automatically added to disabled plugins. This migration removes any npe2 plugins discovered in the environment (at migration time) from the "disabled plugins" set. """ for dist in distributions(): for ep in dist.entry_points: if ep.group == "napari.manifest": model.plugins.disabled_plugins.discard(dist.metadata['Name'])
def get_project_distribution() -> Optional[Distribution]: ditr: Distribution for distr in importlib_metadata.distributions(): relative_path: Path try: relative_path = Path(__file__).relative_to(distr.locate_file("")) except ValueError: pass else: if relative_path in distr.files: return distr return None
def _test_metadata_distributions_after_deprecated_submodule(): # verify deprecated_submodule does not break importlib_metadata.distributions() # See https://github.com/quantumlib/Cirq/issues/4729 deprecated_submodule( new_module_name='cirq.neutral_atoms', old_parent='cirq', old_child='swiss_atoms', deadline="v0.14", create_attribute=True, ) m = pytest.importorskip("importlib_metadata") distlist = list(m.distributions()) assert all(isinstance(d.name, str) for d in distlist)
def test_package_discovery(self): dists = list(distributions()) assert all( isinstance(dist, Distribution) for dist in dists ) assert any( dist.metadata['Name'] == 'egginfo-pkg' for dist in dists ) assert any( dist.metadata['Name'] == 'distinfo-pkg' for dist in dists )
def version_header(self) -> str: """ comment header indicating filename and NEMSpy version """ installed_distributions = importlib_metadata.distributions() for distribution in installed_distributions: if (distribution.metadata['Name'] is not None and distribution.metadata['Name'].lower() == 'nemspy'): version = distribution.version break else: version = 'unknown' return f'# `{self.name}` generated with NEMSpy {version}'
def test_importlib_metadata(self): dists = list(metadata.distributions()) self.assertCountEqual(["chaquopy-libcxx", "murmurhash", "Pygments"], [d.metadata["Name"] for d in dists]) for dist in dists: dist_info = str(dist._path) self.assertPredicate(str.startswith, dist_info, asset_path(REQS_COMMON_ZIP)) self.assertPredicate(str.endswith, dist_info, ".dist-info") # .dist-info directories shouldn't be extracted. self.assertNotPredicate(exists, dist_info) dist = metadata.distribution("murmurhash") self.assertEqual("0.28.0", dist.version) self.assertEqual(dist.version, dist.metadata["Version"]) self.assertIsNone(dist.files) self.assertEqual("Matthew Honnibal", dist.metadata["Author"]) self.assertEqual(["chaquopy-libcxx (>=7000)"], dist.requires)
def get_all_entry_points(): """ Get all entry points related to ``ros2cli`` and any of its extensions. :returns: mapping of entry point names to ``EntryPoint`` instances :rtype: dict """ extension_points = get_entry_points(EXTENSION_POINT_GROUP_NAME) entry_points = defaultdict(dict) for dist in importlib_metadata.distributions(): for ep in dist.entry_points: # skip groups which are not registered as extension points if ep.group not in extension_points: continue entry_points[ep.group][ep.name] = (dist, ep) return entry_points
def main(): seen = set() found = False for d in sorted(metadata.distributions(), key=lambda d: d.metadata['Name']): dname = d.metadata['Name'] if dname in seen: continue classifiers = d.metadata.get_all('Classifier') or () classifiers = [c for c in classifiers if c.startswith('License')] delta = set(classifiers).difference(accept_classifiers) if (delta or not classifiers) and dname not in whitelist_packages: found = True print(f"{dname}: {d.metadata['License']} {classifiers}") seen.add(dname) if found: sys.exit(1)
def get_python_packages_versions(): try: if sys.version_info >= (3, 8): from importlib.metadata import distributions else: from importlib_metadata import distributions except ImportError: # For some reason it is unavailable return [] return sorted( ( distribution.metadata["Name"], (distribution.metadata["Version"] or "Unknown"), ) for distribution in distributions() # Filter out distributions wtih None for name or value. This can be the # case for packages without a METADATA or PKG-INFO file in their relevant # distribution directory. According to comments in importlib.metadata # internals this is possible for certain old packages, but I could only # recreate it by deliberately deleting said files. if distribution.metadata["Name"])
def entry_points_for( group: str, ) -> Generator[ Tuple[importlib_metadata.Distribution, importlib_metadata.EntryPoint], None, None, ]: """Yield all entry_points matching "group", from any distribution. Distribution here refers more specifically to the information in the dist-info folder that usually accompanies an installed package. If a package in the environment does *not* have a ``dist-info/entry_points.txt`` file, then it will not be discovered by this function. Note: a single package may provide multiple entrypoints for a given group. Parameters ---------- group : str The name of the entry point to search. Yields ------- tuples (Distribution, EntryPoint) objects for each matching EntryPoint that matches the provided ``group`` string. Example ------- >>> list(entry_points_for('napari.plugin')) [(<importlib.metadata.PathDistribution at 0x124f0fe80>, EntryPoint(name='napari-reg',value='napari_reg',group='napari.plugin')), (<importlib.metadata.PathDistribution at 0x1041485b0>, EntryPoint(name='myplug',value='another.module',group='napari.plugin'))] """ for dist in importlib_metadata.distributions(): for ep in dist.entry_points: if ep.group == group: yield dist, ep
def list_extensions() -> List[ExtensionInfo]: """ List all installed Chaos Toolkit extensions in the current environment. Notice, for now we can only list extensions that start with `chaostoolkit-` in their package name. This is not as powerful and solid as we want it to be. The trick is that we can't rely on any metadata inside extensions to tell us they exist and what functionnality they provide either. Python has the concept of trove classifiers on packages but we can't extend them yet so they are of no use to us. In a future version, we will provide a mechanism from packages to support a better detection. """ infos = [] distros = importlib_metadata.distributions() seen = [] for dist in distros: info = dist.metadata name = info["Name"] if name == "chaostoolkit-lib": continue if name in seen: continue seen.append(name) if name.startswith("chaostoolkit-"): ext = ExtensionInfo( name=name, version=info["Version"], summary=info["Summary"], license=info["License"], author=info["Author"], url=info["Home-page"], ) infos.append(ext) return infos
def load_setuptools_entrypoints(self, group, name=None): """ Load modules from querying the specified setuptools ``group``. :param str group: entry point group to load plugins :param str name: if given, loads only plugins with the given ``name``. :rtype: int :return: return the number of loaded plugins by this call. """ count = 0 # this code can affect if sys.version_info >= (3, 8): from importlib import metadata as importlib_metadata else: from dbnd._vendor import importlib_metadata importlib_metadata.install(importlib_metadata.MetadataPathFinder) for dist in importlib_metadata.distributions(): for ep in dist.entry_points: if (ep.group != group or (name is not None and ep.name != name) # already registered or self.get_plugin(ep.name) or self.is_blocked(ep.name)): continue plugin = ep.load() self.register(plugin, name=ep.name) self._plugin_distinfo.append((plugin, DistFacade(dist))) count += 1 if not sys.version_info >= (3, 8): # remove our metadata installer from metapath sys.meta_path = [ m for m in sys.meta_path if not isinstance(m, importlib_metadata.MetadataPathFinder) ] return count
def test_one_distribution(self): dists = list(distributions(path=sys.path[:1])) assert len(dists) == 1
def test_invalid_usage(self): with self.assertRaises(ValueError): list(distributions(context='something', name='else'))
"""These are the basic Webviz configuration plugins, distributed through the utility itself. """ from typing import Optional try: # Python 3.8+ from importlib.metadata import distributions # type: ignore except ModuleNotFoundError: # Python < 3.8 from importlib_metadata import distributions # type: ignore from ._utils import load_webviz_plugins_with_metadata, PluginDistInfo metadata = load_webviz_plugins_with_metadata(distributions(), globals())