Exemple #1
0
    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
Exemple #2
0
    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
Exemple #3
0
    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
Exemple #4
0
    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()
Exemple #5
0
    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
Exemple #6
0
    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
Exemple #7
0
    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