Coverage for agentlib/utils/plugin_import.py: 54%
26 statements
« prev ^ index » next coverage.py v7.4.4, created at 2025-04-07 16:27 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2025-04-07 16:27 +0000
1"""
2Module containing all function to import new plugins
3"""
5import importlib
6from pydantic import BaseModel
9class ModuleImport(BaseModel):
10 """
11 Data-Class to import a given python file
12 from ``import_path`` and load the given
13 ``class_name``
14 """
16 import_path: str
17 class_name: str
19 def import_class(self):
20 """Import the Module with class_name from the import path"""
21 module = importlib.import_module(self.import_path)
22 return getattr(module, self.class_name)
25class SaveUpdateDict(dict):
26 """
27 Custom object to safely update the dictionary.
28 Duplicate entries will raise an error.
29 """
31 def update(self, new_dict, **kwargs) -> None:
32 """Check if all modules have distinct identifier strings
34 Args:
35 new_dict:
36 **kwargs:
37 """
38 duplicates = set(self.keys()).intersection(new_dict.keys())
39 if duplicates:
40 raise KeyError(
41 "One or multiple MODULE_TYPES contain "
42 "the same string identifier (type). "
43 f"The type has to be unique! {', '.join(duplicates)}"
44 )
45 super().update(new_dict)
48def load_plugin(name: str, loaded_classes: SaveUpdateDict, plugin_types_name: str):
49 """
50 Loads the plugin based on the given name.
52 Args:
53 name str:
54 Name of the plugin
55 loaded_classes SaveUpdateDict:
56 SaveUpdateDict instance with already
57 loaded classes (modules or models)
58 plugin_types_name str:
59 Name of the dictionary in the plugin.
60 Typical values are "MODULE_TYPES" or "MODEL_TYPES".
61 """
62 for key in loaded_classes:
63 if key.startswith(f"{name}."):
64 return # Already loaded
65 try:
66 plugin = importlib.import_module(name)
67 except ImportError as err:
68 raise ImportError(f"Plugin '{name}' is not installed.") from err
69 try:
70 plugin_dict = getattr(plugin, plugin_types_name)
71 except AttributeError:
72 raise ImportError(
73 f"Plugin '{name}' has no dictionary called "
74 f"'{plugin_types_name}' to import plugin types."
75 )
76 if not isinstance(plugin_dict, dict):
77 raise TypeError(
78 f"Loaded object '{plugin_types_name}' is not a dictionary "
79 f"but a {type(plugin_dict)}"
80 )
81 for key, value in plugin_dict.items():
82 loaded_classes.update({f"{name}.{key}": value})