diff --git a/ipyparallel/cluster/app.py b/ipyparallel/cluster/app.py index 08665d91..3e547235 100755 --- a/ipyparallel/cluster/app.py +++ b/ipyparallel/cluster/app.py @@ -11,7 +11,11 @@ import sys from functools import partial -import entrypoints +try: + from importlib.metadata import entry_points +except ImportError: + from importlib_metadata import entry_points + import zmq from IPython.core.profiledir import ProfileDir from traitlets import Bool, CaselessStrEnum, Dict, Integer, List, default @@ -339,13 +343,14 @@ def _classes_default(self): launcher_classes = [] for kind in ('controller', 'engine'): group_name = f'ipyparallel.{kind}_launchers' - group = entrypoints.get_group_named(group_name) - for key, value in group.items(): + group = entry_points(group=group_name) + for entrypoint in group: + key = entrypoint.name try: - cls = value.load() + cls = entrypoint.load() except Exception as e: self.log.error( - f"Failed to load entrypoint {group_name}: {key} = {value}\n{e}" + f"Failed to load entrypoint {group_name}: {key} = {entrypoint.value}\n{e}" ) else: launcher_classes.append(cls) diff --git a/ipyparallel/cluster/launcher.py b/ipyparallel/cluster/launcher.py index a3999f5f..8bf06302 100644 --- a/ipyparallel/cluster/launcher.py +++ b/ipyparallel/cluster/launcher.py @@ -23,7 +23,11 @@ from tempfile import TemporaryDirectory from textwrap import indent -import entrypoints +try: + from importlib.metadata import entry_points +except ImportError: + from importlib_metadata import entry_points + import psutil from IPython.utils.path import ensure_dir_exists, get_home_dir from IPython.utils.text import EvalFormatter @@ -2533,16 +2537,16 @@ def find_launcher_class(name, kind): group_name = 'ipyparallel.controller_launchers' else: raise ValueError(f"kind must be 'engine' or 'controller', not {kind!r}") - group = entrypoints.get_group_named(group_name) + group = entry_points(group=group_name) # make it case-insensitive - registry = {key.lower(): value for key, value in group.items()} + registry = {entrypoint.name.lower(): entrypoint for entrypoint in group} return registry[name.lower()].load() @lru_cache def abbreviate_launcher_class(cls): """Abbreviate a launcher class back to its entrypoint name""" - cls_key = f"{cls.__module__}.{cls.__name__}" + cls_key = f"{cls.__module__}:{cls.__name__}" # allow entrypoint_name attribute in case the definition module # is not the same as the 'import' module if getattr(cls, 'entrypoint_name', None): @@ -2550,8 +2554,8 @@ def abbreviate_launcher_class(cls): for kind in ('controller', 'engine'): group_name = f'ipyparallel.{kind}_launchers' - group = entrypoints.get_group_named(group_name) - for key, value in group.items(): - if f"{value.module_name}.{value.object_name}" == cls_key: - return key.lower() + group = entry_points(group=group_name) + for entrypoint in group: + if entrypoint.value == cls_key: + return entrypoint.name.lower() return cls_key diff --git a/ipyparallel/tests/test_launcher.py b/ipyparallel/tests/test_launcher.py index f0ec2d6b..6cc4b24c 100644 --- a/ipyparallel/tests/test_launcher.py +++ b/ipyparallel/tests/test_launcher.py @@ -10,7 +10,11 @@ import time from subprocess import Popen -import entrypoints +try: + from importlib.metadata import entry_points +except ImportError: + from importlib_metadata import entry_points + import pytest from traitlets.config import Config @@ -156,9 +160,10 @@ def _wait_one(timeout): @pytest.mark.parametrize("kind", ("controller", "engine")) def test_entrypoints(kind): group_name = f"ipyparallel.{kind}_launchers" - group = entrypoints.get_group_named(group_name) + group = entry_points(group=group_name) assert len(group) > 2 - for key, entrypoint in group.items(): + for entrypoint in group: + key = entrypoint.name # verify entrypoints are valid cls = entrypoint.load() diff --git a/ipyparallel/traitlets.py b/ipyparallel/traitlets.py index 69fa64e0..e9f1ca97 100644 --- a/ipyparallel/traitlets.py +++ b/ipyparallel/traitlets.py @@ -1,6 +1,10 @@ """Custom ipyparallel trait types""" -import entrypoints +try: + from importlib.metadata import entry_points +except ImportError: + from importlib_metadata import entry_points + from traitlets import List, TraitError, Type @@ -24,9 +28,7 @@ def help(self): chunks = [self._original_help] chunks.append("Currently installed: ") for key, entry_point in self.load_entry_points().items(): - chunks.append( - f" - {key}: {entry_point.module_name}.{entry_point.object_name}" - ) + chunks.append(f" - {key}: {entry_point.value}") return '\n'.join(chunks) @help.setter @@ -35,10 +37,10 @@ def help(self, value): def load_entry_points(self): """Load my entry point group""" - # load the group - group = entrypoints.get_group_named(self.entry_point_group) - # make it case-insensitive - return {key.lower(): value for key, value in group.items()} + return { + entry_point.name.lower(): entry_point + for entry_point in entry_points(group=self.entry_point_group) + } def validate(self, obj, value): if isinstance(value, str): diff --git a/pyproject.toml b/pyproject.toml index 40cbe764..402f2f70 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ classifiers = [ urls = {Homepage = "https://ipython.org"} requires-python = ">=3.8" dependencies = [ - "entrypoints", + "importlib_metadata>=3.6; python_version < '3.10'", "decorator", "pyzmq>=18", "traitlets>=4.3",