Esempio n. 1
0
class MainWindow(QtWidgets.QMainWindow):
    serialRxQu = Queue()  # serial FIFO RX Queue
    serialWo = SerialWorker(serialRxQu)  # serial Worker Thread

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Momentarily choose to load the ui from file for flexibility during
        # development, eventually it could be converted in a .py if stable.
        uic.loadUi("test_serial.ui", self)
        self.refreshButton.clicked.connect(self.handle_refresh_button)
        self.connectButton.clicked.connect(self.handle_connect_button)
        self.disconnectButton.clicked.connect(self.handle_disconnect_button)

        axes = self.canvas.figure.add_subplot(1, 1, 1)
        line2, = axes.plot([], [])

        # Temporarily create the figure here and pass it to the view thread.
        # fig = plt.figure()
        # ax = fig.add_subplot(111)
        # ax.autoscale()
        # line1,  = ax.plot([], [])
        # fig.show()

        # Visualization Worker Thread, started as soon as
        # the thread pool is started. Pass the figure to plot on.
        # self.viewWo = ViewWorker(self.serialRxQu, fig, line1) # debug with an external figure.
        self.viewWo = ViewWorker(self.serialRxQu, self.canvas.figure, line2)

        self.threadpool = QThreadPool()
        self.threadpool.start(self.viewWo)

    def handle_refresh_button(self):
        """Get list of serial ports available."""
        ls = self.serialWo.get_port_list()
        if ls:
            print(ls)
            self.serialPortsComboBox.clear()
            self.serialPortsComboBox.addItems(ls)
        else:
            print('No serial ports available.')
            self.serialPortsComboBox.clear()

    def handle_connect_button(self):
        """Connect button opens the selected serial port and
           creates the serial worker thread. If the thread was
           already created previously and paused, it revives it."""
        print(self.serialPortsComboBox.currentText())
        self.serialWo.open_port(self.serialPortsComboBox.currentText())
        if self.serialWo.no_serial_worker:
            self.serialWo.revive_it()
            self.threadpool.start(self.serialWo)
            self.serialWo.thread_is_started()
        if self.serialWo.is_paused:
            self.serialWo.revive_it()

    def handle_disconnect_button(self):
        """Disconnect button closes the serial port."""
        self.serialWo.close_port()
Esempio n. 2
0
class WorkHandler(object):
    """
    Class to handle threading of "work" (concretely this is just the evaluation of a function of the
     form func(*args, **kwargs).

     The process ID identifies (uniquely) each instance of a Worker; but the caller also defines
     an ID which is then used to identify the Worker through the API.
    """
    class WorkListener(metaclass=ABCMeta):
        """
        This abstract base class defines methods which must be overriden and which
        handle responses to certain worker actions such as raised errors, or completion.
        """
        def __init__(self):
            pass

        @abstractmethod
        def on_processing_finished(self, result):
            pass

        @abstractmethod
        def on_processing_error(self, error):
            pass

    def __init__(self):
        self.thread_pool = None
        self._listener = {}
        self._worker = {}
        self.thread_pool = QThreadPool()

    def _add_listener(self, listener, process_id, id):
        if not isinstance(listener, self.WorkListener):
            raise ValueError("The listener is not of type "
                             "WorkListener but rather {}".format(
                                 type(listener)))
        self._listener.update({process_id: {'id': id, 'listener': listener}})

    @Slot()
    def on_finished(self, process_id):
        if process_id not in self._worker:
            return
        result = self._worker.pop(process_id)['worker'].result
        self._listener.pop(process_id)['listener'].on_processing_finished(
            result)

    @Slot()
    def on_error(self, process_id, error):
        if process_id not in self._worker:
            return
        self._listener[process_id]['listener'].on_processing_error(error)

    def process(self, caller, func, id, *args, **kwargs):
        """
        Process a function call with arbitrary arguments on a new thread.

        :param caller: ??
        :param func: The function to be evaluated.
        :param id: An identifying integer for the task.
        :param args: args for func.
        :param kwargs: keyword args for func.
        """
        self.remove_already_processing(id)
        process_id = uuid.uuid4()
        # Add the caller
        self._add_listener(caller, process_id, id)

        finished_callback = functools.partial(self.on_finished, process_id)
        error_callback = functools.partial(self.on_error, process_id)

        worker = Worker(func, *args, **kwargs)
        worker.signals.finished.connect(finished_callback)
        worker.signals.error.connect(error_callback)

        self._worker.update({process_id: {'id': id, 'worker': worker}})

        self.thread_pool.start(self._worker[process_id]['worker'])

    def remove_already_processing(self, id):
        """
        Remove workers with ID
        :param id:
        """
        for key, process in list(self._listener.items()):
            if process['id'] == id:
                self._listener.pop(key)
                self._worker.pop(key)

    def wait_for_done(self):
        self.thread_pool.waitForDone()

    def __eq__(self, other):
        return self.__dict__ == other.__dict__

    def __ne__(self, other):
        return self.__dict__ != other.__dict__
Esempio n. 3
0
class WorkHandler(object):
    """
    Class to handle threading of "work" (concretely this is just the evaluation of a function of the
     form func(*args, **kwargs).

     The process ID identifies (uniquely) each instance of a Worker; but the caller also defines
     an ID which is then used to identify the Worker through the API.
    """

    class WorkListener(with_metaclass(ABCMeta, object)):
        """
        This abstract base class defines methods which must be overriden and which
        handle responses to certain worker actions such as raised errors, or completion.
        """

        def __init__(self):
            pass

        @abstractmethod
        def on_processing_finished(self, result):
            pass

        @abstractmethod
        def on_processing_error(self, error):
            pass

    def __init__(self):
        self.thread_pool = None
        self._listener = {}
        self._worker = {}
        self.thread_pool = QThreadPool()

    def _add_listener(self, listener, process_id, id):
        if not isinstance(listener, WorkHandler.WorkListener):
            raise ValueError("The listener is not of type "
                             "WorkListener but rather {}".format(type(listener)))
        self._listener.update({process_id: {'id': id, 'listener': listener}})

    @Slot()
    def on_finished(self, process_id):
        if process_id not in self._worker:
            return
        result = self._worker.pop(process_id)['worker'].result
        self._listener.pop(process_id)['listener'].on_processing_finished(result)

    @Slot()
    def on_error(self, process_id, error):
        if process_id not in self._worker:
            return
        self._listener[process_id]['listener'].on_processing_error(error)

    def process(self, caller, func, id, *args, **kwargs):
        """
        Process a function call with arbitrary arguments on a new thread.

        :param caller: ??
        :param func: The function to be evaluated.
        :param id: An identifying integer for the task.
        :param args: args for func.
        :param kwargs: keyword args for func.
        """
        self.remove_already_processing(id)
        process_id = uuid.uuid4()
        # Add the caller
        self._add_listener(caller, process_id, id)

        finished_callback = functools.partial(self.on_finished, process_id)
        error_callback = functools.partial(self.on_error, process_id)

        worker = Worker(func, *args, **kwargs)
        worker.signals.finished.connect(finished_callback)
        worker.signals.error.connect(error_callback)

        self._worker.update({process_id: {'id': id, 'worker': worker}})

        self.thread_pool.start(self._worker[process_id]['worker'])

    def remove_already_processing(self, id):
        """
        Remove workers with ID
        :param id:
        """
        for key, process in list(self._listener.items()):
            if process['id'] == id:
                self._listener.pop(key)
                self._worker.pop(key)

    def wait_for_done(self):
        self.thread_pool.waitForDone()

    def __eq__(self, other):
        return self.__dict__ == other.__dict__

    def __ne__(self, other):
        return self.__dict__ != other.__dict__