Source code for elasticai.creator.plugin.plugin_spec
from dataclasses import dataclass
from inspect import signature as _signature
[docs]
@dataclass
class PluginSpec:
"""The specification of a plugin.
Typically built by reading a dictionary from a toml file and
building the spec using <<build_plugin_spec, `build_plugin_spec()`>>.
The dataclass is only used to provide convenient access to the fields,
support type checking and improve code readability.
You can achieve your goals just as well with the `PluginDict` dictionary.
That is defined as an alias for `dict[str, str | tuple[str, ...]]`.
"""
name: str
target_platform: str
target_runtime: str
version: str
api_version: str
package: str
type PluginMap = dict[str, str | list[str] | PluginMap]
[docs]
def build_plugin_spec[SpecT: PluginSpec](d: PluginMap, spec_type: type[SpecT]) -> SpecT:
"""inspect spec_type and build an instance of it from the dictionary `d`.
Missing field raise an error while extra fields will be ignored.
"""
args = d
s = _signature(spec_type)
expected_params = set(s.parameters.keys())
actual_params = set(args.keys())
if expected_params != actual_params:
if not actual_params.issuperset(expected_params):
raise MissingFieldError(
expected_params.difference(actual_params),
spec_type,
)
bound = {k: args[k] for k in s.parameters.keys()}
return spec_type(**bound) # type: ignore
[docs]
class MissingFieldError[PluginSpecT: PluginSpec](Exception):
def __init__(self, field_names: set[str], plugin_type: type[PluginSpecT]):
super().__init__(
f"missing required fields {field_names} for plugin spec '{plugin_type.__qualname__}'\n\tAre you sure you are loading the correct plugin?\n\tIs the meta.toml file correct?"
)