4242from navigate .config .config import get_navigate_path
4343from navigate .view .custom_widgets .popup import PopUp
4444from navigate .tools .file_functions import load_yaml_file , save_yaml_file
45- from navigate .tools .common_functions import combine_funcs , load_module_from_file
45+ from navigate .tools .common_functions import combine_funcs
4646from navigate .tools .decorators import AcquisitionMode
47- from navigate .model .features import feature_related_functions
4847from navigate .controller .sub_controllers .gui import GUIController
4948from navigate .view .popups .plugins_popup import PluginsPopup
50- from navigate .config import set_feature_attributes
49+
50+ from navigate .plugins .plugin_manager import PluginFileManager , PluginPackageManager
5151
5252
5353class PluginsController :
@@ -69,11 +69,6 @@ def __init__(self, view, parent_controller):
6969 #: object: navigate controller.
7070 self .parent_controller = parent_controller
7171
72- #: str: plugins default path.
73- self .plugins_path = os .path .join (
74- Path (__file__ ).resolve ().parent .parent .parent , "plugins"
75- )
76-
7772 #: dict: installed plugins with GUI
7873 self .plugins_dict = {}
7974
@@ -87,115 +82,61 @@ def populate_experiment_setting(self):
8782
8883 def load_plugins (self ):
8984 """Load plugins"""
90- plugins = os . listdir ( self . plugins_path )
91- installed_plugins = dict (
92- [( f , os . path . join ( self . plugins_path , f )) for f in plugins ]
85+ # load through files
86+ plugins_path = os . path . join (
87+ Path ( __file__ ). resolve (). parent . parent . parent , " plugins"
9388 )
94- # load plugins from plugins_config
9589 plugins_config_path = os .path .join (
9690 get_navigate_path (), "config" , "plugins_config.yml"
9791 )
98- plugins_config = load_yaml_file (plugins_config_path )
99- if plugins_config is None :
100- plugins_config = {}
101- save_yaml_file (get_navigate_path (), {}, "plugins_config.yml" )
102- else :
103- for plugin_name , plugin_path in plugins_config .items ():
104- if plugin_path and os .path .exists (plugin_path ):
105- installed_plugins [plugin_name ] = plugin_path
106- for _ , plugin_path in installed_plugins .items ():
107- if not os .path .isdir (plugin_path ):
108- continue
92+ plugin_file_manager = PluginFileManager (plugins_path , plugins_config_path )
93+ self .load_plugins_through_manager (plugin_file_manager )
94+ self .load_plugins_through_manager (PluginPackageManager )
95+
96+ def load_plugins_through_manager (self , plugin_manager ):
97+ """Load plugins through plugin manager
98+
99+ Parameters
100+ ----------
101+ plugin_manager : object
102+ PluginManager object
103+ """
104+ plugins = plugin_manager .get_plugins ()
105+
106+ for plugin_name , plugin_ref in plugins .items ():
109107
110108 # read "plugin_config.yml"
111- plugin_config = load_yaml_file (
112- os .path .join (plugin_path , "plugin_config.yml" )
113- )
109+ plugin_config = plugin_manager .load_config (plugin_ref )
114110 if plugin_config is None :
115111 continue
116- plugin_name = plugin_config .get ("name" , _ )
117- plugin_file_name = "_" .join (plugin_name .lower ().split ())
118- plugin_class_name = "" .join (plugin_name .title ().split ())
119- if "view" in plugin_config :
120- # verify if "frame_name" and "file_name" are given and correct
121- view_file = os .path .join (
122- plugin_path , "view" , f"{ plugin_file_name } _frame.py"
123- )
124- controller_file = os .path .join (
125- plugin_path ,
126- "controller" ,
127- f"{ plugin_file_name } _controller.py" ,
128- )
129- if (
130- os .path .exists (view_file )
131- and os .path .isfile (view_file )
132- and os .path .exists (controller_file )
133- and os .path .isfile (controller_file )
134- ):
135- plugin_frame_module = load_module_from_file (
136- f"{ plugin_class_name } Frame" , view_file
137- )
138- if plugin_frame_module is None :
139- print (
140- f"Make sure that the plugin frame name "
141- f"{ plugin_class_name } is correct! "
142- f"Plugin { plugin_name } needs to be uninstalled from "
143- f"navigate or reinstalled!"
144- )
145- continue
146- plugin_frame = getattr (
147- plugin_frame_module , f"{ plugin_class_name } Frame"
148- )
149- plugin_controller_module = load_module_from_file (
150- f"{ plugin_class_name } Controller" , controller_file
151- )
152- if plugin_controller_module is None :
153- print (
154- f"Make sure that the plugin controller "
155- f"{ plugin_class_name } is correct! "
156- f"Plugin { plugin_name } needs to be uninstalled from "
157- f"navigate or reinstalled!"
158- )
159- continue
160- plugin_controller = getattr (
161- plugin_controller_module , f"{ plugin_class_name } Controller"
162- )
112+ plugin_display_name = plugin_config .get ("name" , plugin_name )
113+
114+ plugin_frame = plugin_manager .load_view (plugin_ref , plugin_display_name )
115+ plugin_controller = plugin_manager .load_controller (
116+ plugin_ref , plugin_display_name
117+ )
163118
164- if plugin_config ["view" ] == "Popup" :
165- # menu
166- self .parent_controller .view .menubar .menu_plugins .add_command (
167- label = plugin_name ,
168- command = self .build_popup_window (
169- plugin_name , plugin_frame , plugin_controller
170- ),
171- )
172- else :
173- self .build_tab_window (
119+ if plugin_frame and plugin_controller :
120+ if plugin_config ["view" ] == "Popup" :
121+ # menu
122+ self .parent_controller .view .menubar .menu_plugins .add_command (
123+ label = plugin_name ,
124+ command = self .build_popup_window (
174125 plugin_name , plugin_frame , plugin_controller
175- )
126+ ),
127+ )
128+ else :
129+ self .build_tab_window (plugin_name , plugin_frame , plugin_controller )
176130 # feature
177- set_feature_attributes ( plugin_path )
131+ plugin_manager . load_features ( plugin_ref )
178132
179133 # acquisition mode
180134 acquisition_modes = plugin_config .get ("acquisition_modes" , [])
181- for acquisition_mode_config in acquisition_modes :
182- acquisition_file = os .path .join (
183- plugin_path , acquisition_mode_config ["file_name" ]
184- )
185- if os .path .exists (acquisition_file ):
186- module = load_module_from_file (
187- acquisition_mode_config ["file_name" ][:- 3 ], acquisition_file
188- )
189- acquisition_mode = [
190- m
191- for m in dir (module )
192- if isinstance (getattr (module , m ), AcquisitionMode )
193- ]
194- if acquisition_mode :
195- self .parent_controller .add_acquisition_mode (
196- acquisition_mode_config ["name" ],
197- getattr (module , acquisition_mode [0 ]),
198- )
135+ plugin_manager .load_acquisition_modes (
136+ plugin_ref ,
137+ acquisition_modes ,
138+ self .register_acquisition_mode ,
139+ )
199140
200141 def build_tab_window (self , plugin_name , frame , controller ):
201142 """Build tab for a plugin
@@ -220,11 +161,12 @@ def build_tab_window(self, plugin_name, frame, controller):
220161 "__plugin" + "_" .join (plugin_name .lower ().split ()) + "_controller"
221162 )
222163 self .plugins_dict [controller_name ] = plugin_controller
223- except Exception :
164+ except Exception as e :
224165 messagebox .showwarning (
225166 title = "Warning" ,
226167 message = (
227168 f"Plugin { plugin_name } has something went wrong."
169+ f"Error: { e } "
228170 f"Please make sure the plugin works correctly or uninstall it!"
229171 ),
230172 )
@@ -295,6 +237,27 @@ def func_with_wrapper(*args, **kwargs):
295237
296238 return func_with_wrapper
297239
240+ def register_acquisition_mode (self , acquisition_mode_name , module ):
241+ """Register acquisition mode
242+
243+ Parameters
244+ ----------
245+ acquisition_mode_name : str
246+ The name of an acquisition mode
247+ module : module
248+ acquisition mode module
249+ """
250+ if not module :
251+ return
252+ acquisition_mode = [
253+ m for m in dir (module ) if isinstance (getattr (module , m ), AcquisitionMode )
254+ ]
255+ if acquisition_mode :
256+ self .parent_controller .add_acquisition_mode (
257+ acquisition_mode_name ,
258+ getattr (module , acquisition_mode [0 ]),
259+ )
260+
298261
299262class UninstallPluginController (GUIController ):
300263 """Uninstall plugin controller"""
0 commit comments