def get_plugin_by_name(self, name, type_name=None, timeout=10): """ Find a collected plugin named `name`, optionally by also specifying the type of plugin. Parameters ---------- name : str name of the plugin to get type_name : str type of the plugin to get (optional) Returns ------- object the matching plugin object (may be a class or instance), or None if not found """ return_plugin = self._get_plugin_by_name(name, type_name) if return_plugin: return return_plugin # If still actively collecting plugins if self.state != State.READY: # find the matching entrypoint entrypoint, type_name = self._get_entrypoint_by_name( name, type_name) if not entrypoint: raise NameError( f'The plugin named {name} of type {type_name} could not be discovered. ' f'Check your installation integrity.') # Load it immediately; it will move to top of instantiate queue as well msg.logMessage(f"Immediately loading {entrypoint.name}.", level=msg.INFO) self._load_plugin(type_name, entrypoint) # Add another instantiate event to the Qt event queue, so that it triggers in the next event loop threads.invoke_as_event(self._instantiate_plugin) # wait for it to load with load_timer() as elapsed: while not return_plugin: return_plugin = self._get_plugin_by_name(name, type_name) if threads.is_main_thread(): QApplication.processEvents() # else: time.sleep(0.01) if elapsed() > timeout: raise TimeoutError( f"Plugin named {name} waited too long to instantiate and timed out" ) return return_plugin
def _instantiate_plugin(self): if not self._instantiate_queue.empty(): type_name, entrypoint, plugin_class = self._instantiate_queue.get() # if this plugin was already instantiated earlier, skip it; mark done if self.type_mapping[type_name].get(entrypoint.name, None) is None: # inject the entrypoint name into the class plugin_class._name = entrypoint.name success = False # ... and instantiate it (as long as its supposed to be singleton) try: if getattr(plugin_class, "is_singleton", False): msg.logMessage(f"Instantiating {entrypoint.name} plugin object.", level=msg.INFO) with load_timer() as elapsed: self.type_mapping[type_name][entrypoint.name] = plugin_class() msg.logMessage( f"{int(elapsed() * 1000)} ms elapsed while instantiating {entrypoint.name}", level=msg.INFO ) else: self.type_mapping[type_name][entrypoint.name] = plugin_class success = True except (Exception, SystemError) as ex: msg.logMessage( f"Unable to instantiate {entrypoint.name} plugin from module: {entrypoint.module_name}", msg.ERROR ) msg.logError(ex) msg.notifyMessage(repr(ex), title=f'An error occurred while starting the "{entrypoint.name}" plugin.') if success: msg.logMessage(f"Successfully collected {entrypoint.name} plugin.", level=msg.INFO) msg.showProgress(self._progress_count(), maxval=self._entrypoint_count()) self._notify(Filters.UPDATE) # mark it as completed self._instantiate_queue.task_done() # If this was the last plugin if self._load_queue.empty() and self._instantiate_queue.empty() and self.state in [State.INSTANTIATING, State.READY]: self.state = State.READY msg.logMessage("Plugin collection completed!") msg.hideProgress() self._notify(Filters.COMPLETE) if not self.state == State.READY: # if we haven't reached the last task, but there's nothing queued threads.invoke_as_event(self._instantiate_plugin) # return to the event loop, but come back soon
def _load_plugins(self): # For every entrypoint in the load queue while not self._load_queue.empty(): load_task = self._load_queue.get() # load it self._load_plugin(load_task) if not self.instantiating: # If this is the first load # Start an event chain to pull from the queue threads.invoke_as_event(self._instantiate_plugin) self.instantiating = True # mark it as completed self._load_queue.task_done() yield
def setParameters(self, operation: OperationPlugin): if operation: # Create a new Parameter from the emitted operation, # Then wire up its connections for use in a parameter tree. parameter = operation.as_parameter() group = GroupParameter(name='Selected Operation', children=parameter) operation.wireup_parameter(group) # Add the Parameter to the parameter tree group.blockSignals(True) for child in group.children(): child.blockSignals(True) self.operationeditor.setParameters(group, showTop=False) threads.invoke_as_event(self._unblock_group, group) else: self.operationeditor.clear()
def _load_plugins(self): started_instantiating = False # For every entrypoint in the load queue while not self._load_queue.empty(): type_name, entrypoint = self._load_queue.get() # load it self._load_plugin(type_name, entrypoint) if not started_instantiating: # If this is the first load # Start an event chain to pull from the queue threads.invoke_as_event(self._instantiate_plugin) started_instantiating = True # mark it as completed self._load_queue.task_done() # Finished loading, progress if self.state == State.LOADING: self.state = State.INSTANTIATING
def get_plugin_by_name(self, name, type_name=None, timeout=10): """ Find a collected plugin named `name`, optionally by also specifying the type of plugin. Parameters ---------- name : str name of the plugin to get type_name : str type of the plugin to get (optional) Returns ------- object the matching plugin object (may be a class or instance), or None if not found """ return_plugin = self._get_plugin_by_name(name, type_name) if return_plugin: return return_plugin # Find the matching plugin from the queue match_task = next(filter(lambda task: task.name==name and task.type_name == type_name, self._tasks), None) # If the matched task is already failed if match_task and match_task.status in [Status.FailedLoad, Status.FailedInstantiate]: raise NameError(f"The plugin named {name} of type {type_name} has already failed to load.") # Otherwise, prioritize it elif match_task: # If its queued to load, load it immediately in the main thread if match_task.status is Status.LoadingQueue: self._load_plugin(match_task) # If its queued to instantiate, instantiate it immediately if match_task.status is Status.InstantiateQueue: self._instantiate_plugin(match_task) # If the instantiate event chain isn't running, run it now if not self.instantiating: threads.invoke_as_event(self._instantiate_plugin) self.instantiating = True # Or, if there was no match else: raise NameError( f"The plugin named {name} of type {type_name} could not be discovered. " f"Check your installation integrity." ) # wait for it to load with load_timer() as elapsed: while match_task.status not in [Status.Success, Status.FailedInstantiate, Status.FailedLoad]: if threads.is_main_thread(): from qtpy.QtWidgets import QApplication # Required as late import to avoid loading Qt things too soon QApplication.processEvents() else: time.sleep(0.01) if elapsed() > timeout: raise TimeoutError(f"Plugin named {name} waited too long to instantiate and timed out") if match_task.status in [Status.FailedInstantiate, Status.FailedLoad]: raise NameError(f"The plugin named {name} of type {type_name} failed to load while we were waiting for it.") elif match_task.status == Status.Success: return_plugin = self._get_plugin_by_name(name, type_name) return return_plugin
def _instantiate_plugin(self, instantiate_task_request: PluginTask=None): """ Instantiate a single plugin by request or from the queue. This is typically invoked by an event, and will re-post an event to the event queue to repeat until the task queue is emptied. """ instantiate_task = None if instantiate_task_request or not self._instantiate_queue.empty(): if instantiate_task_request: instantiate_task = instantiate_task_request else: instantiate_task = self._instantiate_queue.get() entrypoint = instantiate_task.entry_point type_name = instantiate_task.type_name plugin_class = instantiate_task.plugin_class # if this plugin was already instantiated earlier, skip it; mark done; also skips if the group isn't active if self.type_mapping.get(type_name, {entrypoint.name: True}).get(entrypoint.name, None) is None: instantiate_task.status = Status.Instantiating # inject the entrypoint name into the class plugin_class._name = entrypoint.name # ... and instantiate it (as long as its supposed to be singleton) plugin_object = plugin_class try: if getattr(plugin_class, "is_singleton", False): msg.logMessage(f"Instantiating {entrypoint.name} plugin object.", level=msg.INFO) with load_timer() as elapsed: self.type_mapping[type_name][entrypoint.name] = plugin_object = plugin_class() msg.logMessage( f"{int(elapsed() * 1000)} ms elapsed while instantiating {entrypoint.name}", level=msg.INFO ) else: self.type_mapping[type_name][entrypoint.name] = plugin_class except (Exception, SystemError) as ex: msg.logMessage( f"Unable to instantiate {entrypoint.name} plugin from module: {entrypoint.module_name}", msg.ERROR ) msg.logError(ex) msg.notifyMessage(repr(ex), title=f'An error occurred while starting the "{entrypoint.name}" plugin.') instantiate_task.status = Status.FailedInstantiate else: # inject useful info into plugin plugin_object._entrypoint_name = entrypoint.name plugin_object._plugin_type = type_name msg.logMessage(f"Successfully collected {entrypoint.name} plugin.", level=msg.INFO) self._notify(Filters.UPDATE) msg.showProgress(self._progress_count(), maxval=self._task_count()) # mark it as completed if instantiate_task_request is None: self._instantiate_queue.task_done() instantiate_task.status = Status.Success # If this was the last plugin if self._load_queue.empty() and self._instantiate_queue.empty(): msg.logMessage("Plugin collection completed!") msg.hideProgress() self._notify(Filters.COMPLETE) self.instantiating = False self._tasks.clear() elif instantiate_task_request is None: # if we haven't reached the last task, but there's nothing queued threads.invoke_as_event(self._instantiate_plugin) # return to the event loop, but come back soon