1

I wrote a simple Python script to send a desktop notification upon a certain DBus signal (namely, a daemon muting a PulseAudio sink). It works, but terminating the script with Ctrl-C resulted in the following traceback:

Traceback (most recent call last):
  File "./notify.py", line 32, in <module>
    loop.run()
  File "/usr/lib/python3.7/site-packages/gi/overrides/GLib.py", line 495, in run
    super(MainLoop, self).run()
  File "/usr/lib/python3.7/contextlib.py", line 119, in __exit__
    next(self.gen)
  File "/usr/lib/python3.7/site-packages/gi/_ossighelper.py", line 251, in register_sigint_fallback
    signal.default_int_handler(signal.SIGINT, None)
KeyboardInterrupt

I tried registering a clean-up function with atexitto call GLib.MainLoop().quit(), but that didn't seem to work. I am aware that I could just catch the exception with a try: ... except: ... block, but is there a better way to handle this?

Script code follows:

import atexit

import gi
gi.require_version('Notify', '0.7')
from gi.repository import Notify
from pydbus import SessionBus

def handle_muted(interface, changed_props, invalidated_props):
    if changed_props["Muted"]:
        n = Notify.Notification.new("muted")
        n.set_urgency(Notify.Urgency(0))
        n.show()

@atexit.register
def cleanup():
    Notify.uninit()
    props.onPropertiesChanged = None
    loop.quit()

bus = SessionBus()
proxy = bus.get("org.mypadaemon")
props = proxy["org.freedesktop.DBus.Properties"]

if __name__ == '__main__':
    from gi.repository import GLib

    Notify.init("My PA Daemon")
    props.onPropertiesChanged = handle_muted

    loop = GLib.MainLoop()
    loop.run()
A.P.
  • 179
  • 1
  • 8
  • In what way exactly does `GLib.MainLoop.quit()` not work? – charlie Jun 20 '19 at 11:36
  • @LEEE It didn't get rid of the traceback dump. I think the loop might be intercepting the `Ctrl-C` key, rather than the script (which would trigger the `atexit` call). – A.P. Jun 20 '19 at 11:57
  • Try handling `SIGINT` using `GLib.unix_signal_add()` to handle the signal within the GLib main loop: https://www.programcreek.com/python/example/82885/gi.repository.GLib.unix_signal_add (And if that works for you, write it up as a proper answer; I can’t be bothered right now.) – Philip Withnall Jun 20 '19 at 12:18
  • 1
    `@atexit.register` doesn't get rid of the traceback dump. I'd recommend having a look at [this question](https://stackoverflow.com/questions/4205317/capture-keyboardinterrupt-in-python-without-try-except). – charlie Jun 20 '19 at 12:30

1 Answers1

1

Defining a custom signal handler worked:

import signal

def sigint_handler(sig, frame):
    if sig == signal.SIGINT:
        loop.quit()
    else:
        raise ValueError("Undefined handler for '{}'".format(sig))

and in the if __name__ == '__main__' block:

signal.signal(signal.SIGINT, sigint_handler)
A.P.
  • 179
  • 1
  • 8