From e44e4f342a8599dd77659a8bb82925f9afcca2fe Mon Sep 17 00:00:00 2001 From: Sijis Aviles Date: Sun, 29 Oct 2023 01:02:39 -0500 Subject: [PATCH 1/5] refactor: use importlib instead of pkg_resources --- errbot/repo_manager.py | 4 ++-- errbot/utils.py | 15 +++++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/errbot/repo_manager.py b/errbot/repo_manager.py index 32e085303..1bed91416 100644 --- a/errbot/repo_manager.py +++ b/errbot/repo_manager.py @@ -93,7 +93,7 @@ def check_dependencies(req_path: Path) -> Tuple[Optional[str], Sequence[str]]: log.debug("check dependencies of %s", req_path) # noinspection PyBroadException try: - from pkg_resources import get_distribution + from importlib.metadata import distribution missing_pkg = [] @@ -110,7 +110,7 @@ def check_dependencies(req_path: Path) -> Tuple[Optional[str], Sequence[str]]: # noinspection PyBroadException try: - get_distribution(stripped) + distribution(stripped) except Exception: missing_pkg.append(stripped) if missing_pkg: diff --git a/errbot/utils.py b/errbot/utils.py index 68d7d70de..7e54b92d7 100644 --- a/errbot/utils.py +++ b/errbot/utils.py @@ -1,8 +1,10 @@ import collections import fnmatch +import importlib.metadata import inspect import logging import os +import pathlib import re import sys import time @@ -10,7 +12,6 @@ from platform import system from typing import List, Tuple, Union -import pkg_resources from dulwich import porcelain log = logging.getLogger(__name__) @@ -199,9 +200,15 @@ def collect_roots(base_paths: List, file_sig: str = "*.plug") -> List: def entry_point_plugins(group): paths = [] - for entry_point in pkg_resources.iter_entry_points(group): - ep = next(pkg_resources.iter_entry_points(group, entry_point.name)) - paths.append(f"{ep.dist.module_path}/{entry_point.module_name}") + + eps = importlib.metadata.entry_points() + for entry_point in eps.select(group=group): + module_name = entry_point.module + file_name = module_name.replace(".", "/") + ".py" + for f in entry_point.dist.files: + if file_name == str(f): + parent = str(pathlib.Path(f).resolve().parent) + paths.append(f"{parent}/{module_name}") return paths From 8ee18d262af435c9ed6160a5a121e9f85300f48f Mon Sep 17 00:00:00 2001 From: Sijis Aviles Date: Sun, 27 Oct 2024 22:29:48 -0500 Subject: [PATCH 2/5] fix: remove try/except import check for importlib --- errbot/repo_manager.py | 53 ++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/errbot/repo_manager.py b/errbot/repo_manager.py index 1bed91416..0546398e5 100644 --- a/errbot/repo_manager.py +++ b/errbot/repo_manager.py @@ -6,6 +6,7 @@ import tarfile from collections import namedtuple from datetime import datetime, timedelta +from importlib.metadata import distribution from os import path from pathlib import Path from typing import Dict, Generator, List, Optional, Sequence, Tuple @@ -91,40 +92,30 @@ def check_dependencies(req_path: Path) -> Tuple[Optional[str], Sequence[str]]: Or None, [] if everything is OK. """ log.debug("check dependencies of %s", req_path) - # noinspection PyBroadException - try: - from importlib.metadata import distribution - - missing_pkg = [] - - if not req_path.is_file(): - log.debug("%s has no requirements.txt file", req_path) - return None, missing_pkg - - with req_path.open() as f: - for line in f: - stripped = line.strip() - # skip empty lines. - if not stripped: - continue - - # noinspection PyBroadException - try: - distribution(stripped) - except Exception: - missing_pkg.append(stripped) - if missing_pkg: - return ( - f"You need these dependencies for {req_path}: " + ",".join(missing_pkg), - missing_pkg, - ) + missing_pkg = [] + + if not req_path.is_file(): + log.debug("%s has no requirements.txt file", req_path) return None, missing_pkg - except Exception: - log.exception("Problem checking for dependencies.") + + with req_path.open() as f: + for line in f: + stripped = line.strip() + # skip empty lines. + if not stripped: + continue + + # noinspection PyBroadException + try: + distribution(stripped) + except Exception: + missing_pkg.append(stripped) + if missing_pkg: return ( - "You need to have setuptools installed for the dependency check of the plugins", - [], + f"You need these dependencies for {req_path}: " + ",".join(missing_pkg), + missing_pkg, ) + return None, missing_pkg class BotRepoManager(StoreMixin): From 1e3f6f038e1e996cf6d7ad43218ba8f8ba39d6a0 Mon Sep 17 00:00:00 2001 From: Sijis Aviles Date: Sun, 27 Oct 2024 22:32:57 -0500 Subject: [PATCH 3/5] fix: workaround to support python 3.9 and older --- errbot/utils.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/errbot/utils.py b/errbot/utils.py index 7e54b92d7..2c1dff03e 100644 --- a/errbot/utils.py +++ b/errbot/utils.py @@ -202,7 +202,13 @@ def entry_point_plugins(group): paths = [] eps = importlib.metadata.entry_points() - for entry_point in eps.select(group=group): + try: + entry_points = eps.select(group=group) + except AttributeError: + # workaround to support python 3.9 and older + entry_points = eps.get(group, ()) + + for entry_point in entry_points: module_name = entry_point.module file_name = module_name.replace(".", "/") + ".py" for f in entry_point.dist.files: From 2fdcb8fb7137c45d33718f465eecacb773f81c8f Mon Sep 17 00:00:00 2001 From: Sijis Aviles Date: Mon, 28 Oct 2024 00:45:39 -0500 Subject: [PATCH 4/5] tests: add basic entry_point_plugins tests I needed to further adjust the files lookup to ignore distributions that were not found. --- errbot/utils.py | 12 +++++++++++- tests/utils_test.py | 22 ++++++++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/errbot/utils.py b/errbot/utils.py index 2c1dff03e..658e80137 100644 --- a/errbot/utils.py +++ b/errbot/utils.py @@ -211,7 +211,17 @@ def entry_point_plugins(group): for entry_point in entry_points: module_name = entry_point.module file_name = module_name.replace(".", "/") + ".py" - for f in entry_point.dist.files: + try: + files = entry_point.dist.files + except AttributeError: + # workaround to support python 3.9 and older + try: + files = importlib.metadata.distribution(entry_point.name).files + except importlib.metadata.PackageNotFoundError: + # entrypoint is not a distribution, so let's skip looking for files + continue + + for f in files: if file_name == str(f): parent = str(pathlib.Path(f).resolve().parent) paths.append(f"{parent}/{module_name}") diff --git a/tests/utils_test.py b/tests/utils_test.py index fb15c71e9..92ec25bc2 100644 --- a/tests/utils_test.py +++ b/tests/utils_test.py @@ -1,7 +1,6 @@ # coding=utf-8 import logging import sys - from datetime import timedelta import pytest @@ -11,7 +10,12 @@ from errbot.bootstrap import CORE_STORAGE, bot_config_defaults from errbot.storage import StoreMixin from errbot.storage.base import StoragePluginBase -from errbot.utils import version2tuple, format_timedelta, split_string_after +from errbot.utils import ( + entry_point_plugins, + format_timedelta, + split_string_after, + version2tuple, +) log = logging.getLogger(__name__) @@ -103,3 +107,17 @@ def test_split_string_after_returns_two_chunks_when_chunksize_equals_half_length splitter = split_string_after(str_, int(len(str_) / 2)) split = [chunk for chunk in splitter] assert ["foobar2000", "foobar2000"] == split + + +def test_entry_point_plugins_no_groups(): + result = entry_point_plugins("does_not_exist") + assert [] == result + + +def test_entry_point_plugins_valid_groups(): + results = entry_point_plugins("console_scripts") + match = False + for result in results: + if result.endswith("errbot/errbot.cli"): + match = True + assert match From 4230370bd27758fb0ecad5acce4353f0aa8dbef3 Mon Sep 17 00:00:00 2001 From: Sijis Aviles Date: Mon, 28 Oct 2024 00:54:36 -0500 Subject: [PATCH 5/5] docs: add info to CHANGES --- CHANGES.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.rst b/CHANGES.rst index 06f122429..f0cafd81c 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -28,6 +28,7 @@ fixes: - fix: add extra_plugin_dir support to FullStackTest (#1726) - fix: add missing py 3.13 in tox (#1731) - fix: add filter to tar extract (#1730) +- refactor: use importlib to find plugins in entry_points (#1669) v6.2.0 (2024-01-01)