feat: add plugin auto-discovery via importlib
This commit is contained in:
parent
7e769872a7
commit
f34c805b84
85
src/proxy_pool/plugins/discovery.py
Normal file
85
src/proxy_pool/plugins/discovery.py
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import importlib
|
||||||
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from proxy_pool.config import Settings
|
||||||
|
from proxy_pool.plugins.protocols import Notifier, ProxyChecker, SourceParser
|
||||||
|
from proxy_pool.plugins.registry import PluginRegistry
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def discover_plugins(
|
||||||
|
package: str,
|
||||||
|
registry: PluginRegistry,
|
||||||
|
settings: Settings,
|
||||||
|
) -> None:
|
||||||
|
try:
|
||||||
|
mod = importlib.import_module(package)
|
||||||
|
except ImportError:
|
||||||
|
logger.warning("Plugin package '%s' not found, skipping", package)
|
||||||
|
return
|
||||||
|
|
||||||
|
if hasattr(mod, "__path__"):
|
||||||
|
logger.warning(
|
||||||
|
"Plugin package '%s' has no __path__ attribute, skipping", package
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
package_path = Path(mod.__path__[0])
|
||||||
|
|
||||||
|
for path in sorted(package_path.rglob("*.py")):
|
||||||
|
if path.name.startswith("_"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
relative = path.relative_to(package_path)
|
||||||
|
module_parts = relative.with_suffix("").parts
|
||||||
|
module_name = f"{package}.{'.'.join(module_parts)}"
|
||||||
|
|
||||||
|
try:
|
||||||
|
plugin_module = importlib.import_module(module_name)
|
||||||
|
except Exception:
|
||||||
|
logger.exception("Failed to import plugin module '%s'", module_name)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not hasattr(plugin_module, "create_plugin"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
plugin = plugin_module.create_plugin(settings)
|
||||||
|
except Exception:
|
||||||
|
logger.exception(
|
||||||
|
"Failed to create plugin from '%s'",
|
||||||
|
module_name,
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if plugin is None:
|
||||||
|
logger.debug(
|
||||||
|
"Plugin '%s' returned None (disabled by config)",
|
||||||
|
module_name,
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
|
_register_plugin(registry, plugin, module_name)
|
||||||
|
|
||||||
|
|
||||||
|
def _register_plugin(
|
||||||
|
registry: PluginRegistry,
|
||||||
|
plugin: object,
|
||||||
|
module_name: str,
|
||||||
|
) -> None:
|
||||||
|
if isinstance(plugin, SourceParser):
|
||||||
|
registry.register_parser(plugin)
|
||||||
|
elif isinstance(plugin, ProxyChecker):
|
||||||
|
registry.register_checker(plugin)
|
||||||
|
elif isinstance(plugin, Notifier):
|
||||||
|
registry.register_notifier(plugin)
|
||||||
|
else:
|
||||||
|
logger.warning(
|
||||||
|
"Plugin from '%s' has unknown type: %s",
|
||||||
|
module_name,
|
||||||
|
type(plugin).__name__,
|
||||||
|
)
|
||||||
Loading…
x
Reference in New Issue
Block a user