Keyboardinterrupt button in voilà

So here is what I did (not perfect but it serves its purpose). For the curious, the context is here

from multiprocessing import Process
import ipywdgets as widgets

class MyWidget(widgets.VBox):
    def __init__(self):
        ...
        self.run_btn = widgets.Button(description="run")
        self.run_btn.button_style = "info"
        self.run_btn.on_click(self.run)

        self.interupt_button = widgets.Button(description="stop")
        self.interupt_button.on_click(self.stop)
        self.current_process = Process(target=lambda: print("Not set"))
        ...

    def run(self, btn):

        if self.current_process.is_alive():
            return

        self.current_process.close()
        with self.output:
            if not self.kwargs:
                self.run_btn.button_style = "danger"
                self.run_btn.description = "errored"
                return
            self.run_btn.description = "running ..."
            self.run_btn.button_style = "warning"
            self.current_process = Process(target=a_long_job, name="main")
            self.current_process.start()
            self.output.clear_output()
            return 0

    def stop(self, btn):
        if not self.current_process.is_alive():
            return

        self.run_btn.description = "stopping"
        self.current_process.terminate()
        self.current_process.join()
        self.current_process.close()
        self.run_btn.description = "stopped"
        self.run_btn.button_style = "danger"

I tried +/- the same code with a Thread instead of a Process but could not get signal.pthread_kill to behave like I wanted to.

There is a strange behavior with notebook restart (the kernel crashes when I try to restart the notebook after I stopped the process). I assume it is because there are hanging threads somewhere, but could not find a solution to that.

Thanks again for the help!

1 Like