|
3 | 3 | from __future__ import annotations |
4 | 4 |
|
5 | 5 | import inspect |
6 | | -import logging |
7 | 6 | import os |
8 | 7 | from collections.abc import Callable, Iterable |
9 | 8 | from importlib import import_module |
| 9 | +from importlib.metadata import entry_points |
10 | 10 | from typing import Any |
11 | 11 |
|
12 | | -try: # pragma: no cover - fall back for older Python versions |
13 | | - from importlib.metadata import entry_points |
14 | | -except ImportError: # pragma: no cover |
15 | | - from importlib_metadata import entry_points # type: ignore |
16 | | - |
17 | 12 | from hls4ml.backends.backend import Backend, register_backend |
18 | 13 | from hls4ml.writer.writers import register_writer |
19 | 14 |
|
|
23 | 18 | _plugins_loaded = False |
24 | 19 |
|
25 | 20 |
|
26 | | -def load_backend_plugins(logger: logging.Logger | None = None) -> None: |
| 21 | +def load_backend_plugins() -> None: |
27 | 22 | """Discover and register backend plugins. |
28 | 23 |
|
29 | 24 | This function loads plugins published via Python entry points under the |
30 | 25 | ``hls4ml.backends`` group as well as modules listed in the |
31 | 26 | ``HLS4ML_BACKEND_PLUGINS`` environment variable. The environment variable |
32 | 27 | accepts a separator compatible with :data:`os.pathsep`. |
33 | | -
|
34 | | - Args: |
35 | | - logger (logging.Logger, optional): Optional logger used for diagnostics. |
36 | | - When omitted, a module-local logger will be used. |
37 | 28 | """ |
38 | | - |
39 | 29 | global _plugins_loaded |
40 | 30 | if _plugins_loaded: |
41 | 31 | return |
42 | 32 |
|
43 | | - logger = logger or logging.getLogger(__name__) |
44 | | - |
45 | | - _load_entry_point_plugins(logger) |
46 | | - _load_env_plugins(logger) |
| 33 | + _load_entry_point_plugins() |
| 34 | + _load_env_plugins() |
47 | 35 |
|
48 | 36 | _plugins_loaded = True |
49 | 37 |
|
50 | 38 |
|
51 | | -def _load_entry_point_plugins(logger: logging.Logger) -> None: |
52 | | - eps = entry_points() |
53 | | - |
54 | | - if hasattr(eps, 'select'): |
55 | | - group_eps = eps.select(group=ENTRY_POINT_GROUP) |
56 | | - else: # pragma: no cover - legacy importlib_metadata API |
57 | | - group_eps = eps.get(ENTRY_POINT_GROUP, []) |
| 39 | +def _load_entry_point_plugins() -> None: |
| 40 | + group_eps = entry_points().select(group=ENTRY_POINT_GROUP) |
58 | 41 |
|
59 | 42 | for ep in group_eps: |
60 | 43 | try: |
61 | 44 | obj = ep.load() |
62 | | - except Exception as exc: # pragma: no cover - defensive |
63 | | - logger.warning( |
64 | | - 'Failed to load backend plugin entry %s: %s', ep.name, exc, exc_info=logger.isEnabledFor(logging.DEBUG) |
65 | | - ) |
| 45 | + except Exception as exc: |
| 46 | + print(f'WARNING: failed to load backend plugin entry "{ep.name}": {exc}') |
66 | 47 | continue |
67 | | - _register_plugin_object(ep.name, obj, logger) |
| 48 | + _register_plugin_object(ep.name, obj) |
68 | 49 |
|
69 | 50 |
|
70 | | -def _load_env_plugins(logger: logging.Logger) -> None: |
| 51 | +def _load_env_plugins() -> None: |
71 | 52 | raw_modules = os.environ.get(ENV_PLUGIN_MODULES, '') |
72 | 53 | if not raw_modules: |
73 | 54 | return |
74 | 55 |
|
75 | 56 | for module_name in filter(None, raw_modules.split(os.pathsep)): |
76 | 57 | try: |
77 | 58 | module = import_module(module_name) |
78 | | - except Exception as exc: # pragma: no cover - defensive |
79 | | - logger.warning( |
80 | | - 'Failed to import backend plugin module %s: %s', |
81 | | - module_name, |
82 | | - exc, |
83 | | - exc_info=logger.isEnabledFor(logging.DEBUG), |
84 | | - ) |
| 59 | + except Exception as exc: |
| 60 | + print(f'WARNING: failed to import backend plugin module "{module_name}": {exc}') |
85 | 61 | continue |
86 | 62 |
|
87 | 63 | register_callable: Any = getattr(module, 'register', module) |
88 | | - _register_plugin_object(module_name, register_callable, logger) |
| 64 | + _register_plugin_object(module_name, register_callable) |
89 | 65 |
|
90 | 66 |
|
91 | | -def _register_plugin_object(name: str, obj: Any, logger: logging.Logger) -> None: |
| 67 | +def _register_plugin_object(name: str, obj: Any) -> None: |
92 | 68 | """Interpret the plugin object and register provided backends.""" |
93 | 69 |
|
94 | 70 | if inspect.isclass(obj) and issubclass(obj, Backend): |
95 | | - _safe_register_backend(name, obj, logger) |
| 71 | + _safe_register_backend(name, obj) |
96 | 72 | return |
97 | 73 |
|
98 | 74 | if isinstance(obj, Iterable) and not isinstance(obj, (str, bytes)): |
99 | 75 | for item in obj: |
100 | | - _register_plugin_object(name, item, logger) |
| 76 | + _register_plugin_object(name, item) |
101 | 77 | return |
102 | 78 |
|
103 | 79 | if callable(obj): |
104 | | - _invoke_registration_callable(name, obj, logger) |
| 80 | + _invoke_registration_callable(name, obj) |
105 | 81 | return |
106 | 82 |
|
107 | | - logger.warning('Plugin entry %s did not provide a usable backend registration (got %r)', name, obj) |
| 83 | + print(f'WARNING: plugin entry "{name}" did not provide a usable backend registration (got {obj!r})') |
108 | 84 |
|
109 | 85 |
|
110 | | -def _invoke_registration_callable(name: str, func: Callable[..., Any], logger: logging.Logger) -> None: |
| 86 | +def _invoke_registration_callable(name: str, func: Callable[..., Any]) -> None: |
111 | 87 | try: |
112 | 88 | func(register_backend=register_backend, register_writer=register_writer) |
| 89 | + return |
113 | 90 | except TypeError: |
114 | 91 | try: |
115 | 92 | func(register_backend, register_writer) |
116 | | - except Exception as exc: # pragma: no cover - defensive |
117 | | - logger.warning('Backend plugin callable %s failed: %s', name, exc, exc_info=logger.isEnabledFor(logging.DEBUG)) |
118 | | - else: |
119 | 93 | return |
120 | | - except Exception as exc: # pragma: no cover - defensive |
121 | | - logger.warning('Backend plugin callable %s failed: %s', name, exc, exc_info=logger.isEnabledFor(logging.DEBUG)) |
122 | | - return |
123 | | - else: |
| 94 | + except Exception as exc: |
| 95 | + print(f'WARNING: backend plugin callable "{name}" failed: {exc}') |
| 96 | + return |
| 97 | + except Exception as exc: |
| 98 | + print(f'WARNING: backend plugin callable "{name}" failed: {exc}') |
124 | 99 | return |
125 | 100 |
|
126 | 101 |
|
127 | | -def _safe_register_backend(name: str, backend_cls: type[Backend], logger: logging.Logger) -> None: |
| 102 | +def _safe_register_backend(name: str, backend_cls: type[Backend]) -> None: |
128 | 103 | try: |
129 | 104 | register_backend(name, backend_cls) |
130 | | - except Exception as exc: # pragma: no cover - defensive |
131 | | - logger.warning( |
132 | | - 'Failed to register backend %s from plugin: %s', name, exc, exc_info=logger.isEnabledFor(logging.DEBUG) |
133 | | - ) |
| 105 | + except Exception as exc: |
| 106 | + print(f'WARNING: failed to register backend "{name}" from plugin: {exc}') |
0 commit comments