Skip to content

Commit 363f01f

Browse files
authored
refactor: use importlib instead of pkg_resources (#1669)
* refactor: use importlib instead of pkg_resources * fix: remove try/except import check for importlib * fix: workaround to support python 3.9 and older * tests: add basic entry_point_plugins tests I needed to further adjust the files lookup to ignore distributions that were not found. * docs: add info to CHANGES
1 parent db0973e commit 363f01f

File tree

4 files changed

+70
-37
lines changed

4 files changed

+70
-37
lines changed

CHANGES.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ fixes:
2828
- fix: add extra_plugin_dir support to FullStackTest (#1726)
2929
- fix: add missing py 3.13 in tox (#1731)
3030
- fix: add filter to tar extract (#1730)
31+
- refactor: use importlib to find plugins in entry_points (#1669)
3132

3233

3334
v6.2.0 (2024-01-01)

errbot/repo_manager.py

Lines changed: 22 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import tarfile
77
from collections import namedtuple
88
from datetime import datetime, timedelta
9+
from importlib.metadata import distribution
910
from os import path
1011
from pathlib import Path
1112
from typing import Dict, Generator, List, Optional, Sequence, Tuple
@@ -91,40 +92,30 @@ def check_dependencies(req_path: Path) -> Tuple[Optional[str], Sequence[str]]:
9192
Or None, [] if everything is OK.
9293
"""
9394
log.debug("check dependencies of %s", req_path)
94-
# noinspection PyBroadException
95-
try:
96-
from pkg_resources import get_distribution
97-
98-
missing_pkg = []
99-
100-
if not req_path.is_file():
101-
log.debug("%s has no requirements.txt file", req_path)
102-
return None, missing_pkg
103-
104-
with req_path.open() as f:
105-
for line in f:
106-
stripped = line.strip()
107-
# skip empty lines.
108-
if not stripped:
109-
continue
110-
111-
# noinspection PyBroadException
112-
try:
113-
get_distribution(stripped)
114-
except Exception:
115-
missing_pkg.append(stripped)
116-
if missing_pkg:
117-
return (
118-
f"You need these dependencies for {req_path}: " + ",".join(missing_pkg),
119-
missing_pkg,
120-
)
95+
missing_pkg = []
96+
97+
if not req_path.is_file():
98+
log.debug("%s has no requirements.txt file", req_path)
12199
return None, missing_pkg
122-
except Exception:
123-
log.exception("Problem checking for dependencies.")
100+
101+
with req_path.open() as f:
102+
for line in f:
103+
stripped = line.strip()
104+
# skip empty lines.
105+
if not stripped:
106+
continue
107+
108+
# noinspection PyBroadException
109+
try:
110+
distribution(stripped)
111+
except Exception:
112+
missing_pkg.append(stripped)
113+
if missing_pkg:
124114
return (
125-
"You need to have setuptools installed for the dependency check of the plugins",
126-
[],
115+
f"You need these dependencies for {req_path}: " + ",".join(missing_pkg),
116+
missing_pkg,
127117
)
118+
return None, missing_pkg
128119

129120

130121
class BotRepoManager(StoreMixin):

errbot/utils.py

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
import collections
22
import fnmatch
3+
import importlib.metadata
34
import inspect
45
import logging
56
import os
7+
import pathlib
68
import re
79
import sys
810
import time
911
from functools import wraps
1012
from platform import system
1113
from typing import List, Tuple, Union
1214

13-
import pkg_resources
1415
from dulwich import porcelain
1516

1617
log = logging.getLogger(__name__)
@@ -199,9 +200,31 @@ def collect_roots(base_paths: List, file_sig: str = "*.plug") -> List:
199200

200201
def entry_point_plugins(group):
201202
paths = []
202-
for entry_point in pkg_resources.iter_entry_points(group):
203-
ep = next(pkg_resources.iter_entry_points(group, entry_point.name))
204-
paths.append(f"{ep.dist.module_path}/{entry_point.module_name}")
203+
204+
eps = importlib.metadata.entry_points()
205+
try:
206+
entry_points = eps.select(group=group)
207+
except AttributeError:
208+
# workaround to support python 3.9 and older
209+
entry_points = eps.get(group, ())
210+
211+
for entry_point in entry_points:
212+
module_name = entry_point.module
213+
file_name = module_name.replace(".", "/") + ".py"
214+
try:
215+
files = entry_point.dist.files
216+
except AttributeError:
217+
# workaround to support python 3.9 and older
218+
try:
219+
files = importlib.metadata.distribution(entry_point.name).files
220+
except importlib.metadata.PackageNotFoundError:
221+
# entrypoint is not a distribution, so let's skip looking for files
222+
continue
223+
224+
for f in files:
225+
if file_name == str(f):
226+
parent = str(pathlib.Path(f).resolve().parent)
227+
paths.append(f"{parent}/{module_name}")
205228
return paths
206229

207230

tests/utils_test.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# coding=utf-8
22
import logging
33
import sys
4-
54
from datetime import timedelta
65

76
import pytest
@@ -11,7 +10,12 @@
1110
from errbot.bootstrap import CORE_STORAGE, bot_config_defaults
1211
from errbot.storage import StoreMixin
1312
from errbot.storage.base import StoragePluginBase
14-
from errbot.utils import version2tuple, format_timedelta, split_string_after
13+
from errbot.utils import (
14+
entry_point_plugins,
15+
format_timedelta,
16+
split_string_after,
17+
version2tuple,
18+
)
1519

1620
log = logging.getLogger(__name__)
1721

@@ -103,3 +107,17 @@ def test_split_string_after_returns_two_chunks_when_chunksize_equals_half_length
103107
splitter = split_string_after(str_, int(len(str_) / 2))
104108
split = [chunk for chunk in splitter]
105109
assert ["foobar2000", "foobar2000"] == split
110+
111+
112+
def test_entry_point_plugins_no_groups():
113+
result = entry_point_plugins("does_not_exist")
114+
assert [] == result
115+
116+
117+
def test_entry_point_plugins_valid_groups():
118+
results = entry_point_plugins("console_scripts")
119+
match = False
120+
for result in results:
121+
if result.endswith("errbot/errbot.cli"):
122+
match = True
123+
assert match

0 commit comments

Comments
 (0)