napari.qt.threading.WorkerBase

class napari.qt.threading.WorkerBase(func: typing.Optional[typing.Callable[[superqt.utils._qthreading._P], superqt.utils._qthreading._R]] = None, SignalsClass: typing.Type[superqt.utils._qthreading.WorkerBaseSignals] = <class 'superqt.utils._qthreading.WorkerBaseSignals'>)[source]

Bases: PyQt5.QtCore.QRunnable, Generic[superqt.utils._qthreading._R]

Base class for creating a Worker that can run in another thread.

Parameters

SignalsClass (type, optional) – A QObject subclass that contains signals, by default WorkerBaseSignals

signals

signal emitter object. To allow identify which worker thread emitted signal.

Type

WorkerBaseSignals

Methods

autoDelete(self)

await_workers([msecs])

Ask all workers to quit, and wait up to msec for quit.

create(Callable[[], None])

quit()

Send a request to abort the worker.

run()

Start the worker.

setAutoDelete(self, bool)

start()

Start this worker in a thread and add it to the global threadpool.

work()

Main method to execute the worker.

Attributes

abort_requested

Whether the worker has been requested to stop.

is_running

Whether the worker has been started

Details

property abort_requested: bool

Whether the worker has been requested to stop.

autoDelete(self) bool
classmethod await_workers(msecs: Optional[int] = None) None[source]

Ask all workers to quit, and wait up to msec for quit.

Attempts to clean up all running workers by calling worker.quit() method. Any workers in the WorkerBase._worker_set set will have this method.

By default, this function will block indefinitely, until worker threads finish. If a timeout is provided, a RuntimeError will be raised if the workers do not gracefully exit in the time requests, but the threads will NOT be killed. It is (currently) left to the user to use their OS to force-quit rogue threads.

Important

If the user does not put any yields in their function, and the function is super long, it will just hang… For instance, there’s no graceful way to kill this thread in python:

@thread_worker
def ZZZzzz():
    time.sleep(10000000)

This is why it’s always advisable to use a generator that periodically yields for long-running computations in another thread.

See this stack-overflow post for a good discussion on the difficulty of killing a rogue python thread:

Parameters

msecs (int, optional) – Waits up to msecs milliseconds for all threads to exit and removes all threads from the thread pool. If msecs is None (the default), the timeout is ignored (waits for the last thread to exit).

Raises

RuntimeError – If a timeout is provided and workers do not quit successfully within the time allotted.

create(Callable[[], None]) QRunnable
property is_running: bool

Whether the worker has been started

quit() None[source]

Send a request to abort the worker.

Note

It is entirely up to subclasses to honor this method by checking self.abort_requested periodically in their worker.work method, and exiting if True.

run() None[source]

Start the worker.

The end-user should never need to call this function. But it cannot be made private or renamed, since it is called by Qt.

The order of method calls when starting a worker is:

calls QThreadPool.globalInstance().start(worker)
|               triggered by the QThreadPool.start() method
|               |             called by worker.run
|               |             |
V               V             V
worker.start -> worker.run -> worker.work

This is the function that actually gets called when calling QThreadPool.start(worker)(). It simply wraps the work() method, and emits a few signals. Subclasses should NOT override this method (except with good reason), and instead should implement work().

setAutoDelete(self, bool)
start() None[source]

Start this worker in a thread and add it to the global threadpool.

The order of method calls when starting a worker is:

calls QThreadPool.globalInstance().start(worker)
|               triggered by the QThreadPool.start() method
|               |             called by worker.run
|               |             |
V               V             V
worker.start -> worker.run -> worker.work
work() Union[Exception, superqt.utils._qthreading._R][source]

Main method to execute the worker.

The end-user should never need to call this function. But subclasses must implement this method (See GeneratorFunction.work() for an example implementation). Minimally, it should check self.abort_requested periodically and exit if True.

Examples

class MyWorker(WorkerBase):

    def work(self):
        i = 0
        while True:
            if self.abort_requested:
                self.aborted.emit()
                break
            i += 1
            if i > max_iters:
                break
            time.sleep(0.5)