Skip to content

Commit 7b92d84

Browse files
committed
cleanup
1 parent f409344 commit 7b92d84

File tree

3 files changed

+48
-307
lines changed

3 files changed

+48
-307
lines changed

nodescraper/cli/cli.py

Lines changed: 1 addition & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import os
3131
import platform
3232
import sys
33-
from importlib import import_module
3433
from typing import Optional
3534

3635
import nodescraper
@@ -56,85 +55,6 @@
5655
from nodescraper.pluginregistry import PluginRegistry
5756

5857

59-
def discover_external_plugins():
60-
"""Discover ext_nodescraper_plugins from all installed packages.
61-
62-
Returns:
63-
list: List of discovered plugin packages
64-
"""
65-
extra_pkgs = []
66-
seen_paths = set() # Track paths to avoid duplicates
67-
68-
try:
69-
import ext_nodescraper_plugins as ext_pkg
70-
71-
extra_pkgs.append(ext_pkg)
72-
if hasattr(ext_pkg, "__file__") and ext_pkg.__file__:
73-
seen_paths.add(ext_pkg.__file__)
74-
except ImportError:
75-
pass
76-
77-
# Discover ext_nodescraper_plugins from installed packages
78-
try:
79-
from importlib.metadata import distributions
80-
81-
for dist in distributions():
82-
pkg_name = dist.metadata.get("Name", "")
83-
if not pkg_name:
84-
continue
85-
86-
name_variants = [
87-
pkg_name.replace("-", "_"),
88-
pkg_name.replace("_", "-"),
89-
]
90-
91-
try:
92-
top_level = dist.read_text("top_level.txt")
93-
if top_level:
94-
name_variants.extend(top_level.strip().split("\n"))
95-
except Exception:
96-
pass
97-
98-
for variant in name_variants:
99-
if not variant:
100-
continue
101-
102-
try:
103-
module_path = f"{variant}.ext_nodescraper_plugins"
104-
ext_pkg = import_module(module_path)
105-
106-
# Check if we already have this package (by file path)
107-
pkg_path = getattr(ext_pkg, "__file__", None)
108-
if pkg_path and pkg_path in seen_paths:
109-
continue
110-
111-
# Add the package
112-
extra_pkgs.append(ext_pkg)
113-
if pkg_path:
114-
seen_paths.add(pkg_path)
115-
116-
break
117-
118-
except (ImportError, AttributeError, ModuleNotFoundError):
119-
continue
120-
121-
except Exception:
122-
pass
123-
124-
return extra_pkgs
125-
126-
127-
# Fix sys.path[0] if it's the venv/bin directory to avoid breaking editable install discovery
128-
_original_syspath0 = sys.path[0]
129-
if _original_syspath0.endswith("/bin") or _original_syspath0.endswith("\\Scripts"):
130-
sys.path[0] = ""
131-
132-
extra_pkgs = discover_external_plugins()
133-
134-
# Restore original sys.path[0]
135-
sys.path[0] = _original_syspath0
136-
137-
13858
def build_parser(
13959
plugin_reg: PluginRegistry,
14060
config_reg: ConfigRegistry,
@@ -449,7 +369,7 @@ def main(arg_input: Optional[list[str]] = None):
449369
if arg_input is None:
450370
arg_input = sys.argv[1:]
451371

452-
plugin_reg = PluginRegistry(plugin_pkg=extra_pkgs)
372+
plugin_reg = PluginRegistry()
453373

454374
config_reg = ConfigRegistry()
455375
parser, plugin_subparser_map = build_parser(plugin_reg, config_reg)

nodescraper/pluginregistry.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#
2525
###############################################################################
2626
import importlib
27+
import importlib.metadata
2728
import inspect
2829
import pkgutil
2930
import types
@@ -45,12 +46,14 @@ def __init__(
4546
self,
4647
plugin_pkg: Optional[list[types.ModuleType]] = None,
4748
load_internal_plugins: bool = True,
49+
load_entry_point_plugins: bool = True,
4850
) -> None:
4951
"""Initialize the PluginRegistry with optional plugin packages.
5052
5153
Args:
5254
plugin_pkg (Optional[list[types.ModuleType]], optional): The module to search for plugins in. Defaults to None.
5355
load_internal_plugins (bool, optional): Whether internal plugin should be loaded. Defaults to True.
56+
load_entry_point_plugins (bool, optional): Whether to load plugins from entry points. Defaults to True.
5457
"""
5558
if load_internal_plugins:
5659
self.plugin_pkg = [internal_plugins, internal_connections, internal_collators]
@@ -70,6 +73,10 @@ def __init__(
7073
PluginResultCollator, self.plugin_pkg
7174
)
7275

76+
if load_entry_point_plugins:
77+
entry_point_plugins = self.load_plugins_from_entry_points()
78+
self.plugins.update(entry_point_plugins)
79+
7380
@staticmethod
7481
def load_plugins(
7582
base_class: type,
@@ -104,3 +111,42 @@ def _recurse_pkg(pkg: types.ModuleType, base_class: type) -> None:
104111
for pkg in search_modules:
105112
_recurse_pkg(pkg, base_class)
106113
return registry
114+
115+
@staticmethod
116+
def load_plugins_from_entry_points() -> dict[str, type]:
117+
"""Load plugins registered via entry points.
118+
119+
Returns:
120+
dict[str, type]: A dictionary mapping plugin names to their classes.
121+
"""
122+
plugins = {}
123+
124+
try:
125+
# Python 3.10+ supports group parameter
126+
try:
127+
plugin_entry_points = importlib.metadata.entry_points(group="nodescraper.plugins") # type: ignore[call-arg]
128+
except TypeError:
129+
# Python 3.9 - entry_points() returns dict-like object
130+
all_entry_points = importlib.metadata.entry_points()
131+
plugin_entry_points = all_entry_points.get("nodescraper.plugins", []) # type: ignore[attr-defined]
132+
133+
for entry_point in plugin_entry_points:
134+
try:
135+
plugin_class = entry_point.load()
136+
137+
if (
138+
inspect.isclass(plugin_class)
139+
and issubclass(plugin_class, PluginInterface)
140+
and not inspect.isabstract(plugin_class)
141+
):
142+
if hasattr(plugin_class, "is_valid") and not plugin_class.is_valid():
143+
continue
144+
145+
plugins[plugin_class.__name__] = plugin_class
146+
except Exception:
147+
pass
148+
149+
except Exception:
150+
pass
151+
152+
return plugins

0 commit comments

Comments
 (0)