Cross-platform desktop notifier in Python

I am looking for Growl-like, Windows balloon-tip-like notifications library in Python. Imagine writing code like:

>>> import desktopnotifier as dn
>>> dn.notify('Title', 'Long description goes here')

.. and that would notify with corresponding tooltips on Mac, Windows and Linux. Does such a library exist? If not, how would I go about writing one myself?

  • Does Mac come with a default notifier? Is Growl something that I should install separately?
  • On Windows, I assume this may require pywin32?
  • On Linux, assuming GNOME, is there a GNOME API (using gnome-python) that does this?
  • Can I make notifications 'sticky' (i.e., don't fade out ever) on all platforms?

Update: My preference is to not depend on gigantic GUI frameworks like PyQT4 and wxPython for a simple task such as this.

Answers


Here's a desktop notifier I wrote a few years ago using wxPython - it behaves identically across Windows and Linux and should also run on OSX. It contains a threaded event loop that can be used to animate a notification window containing an icon and message that can be clicked on. It probably needs a couple of tweaks to customize it for your own purpose but the ground work is done.


At Pycon 2010 there was a presentation on cross-platform Python development. There was a html page about it as well, containing some advice for cross-platform notification. However, I don't find it online anymore, but I saved a local copy, and this is the part on notifications:

There are occasions in which your application wants to notify the user about something: software updates are available, a new instant message have been received, the 300 page print job has finally finished, etc.

  • To keep notifications easy to port cross-platform, don't make them interactive. For example Ubuntu does not support notifications that require user interaction.
  • These are the most important libraries:

    o Linux: pynotify.

    o Mac OS X: Growl, which is not standard, is usually installed.

    o Windows: a good wxPython solution is ToasterBox of Andrea Gavana, which mimics the look of Firefox or Thunderbird notifications.

  • For Phatch we developed a library that unifies these three systems in one API: phatch/lib/notify.py.

The linked python file is very interesting, and I think you should be able to use the linked python file almost as is. The code is also very clear, so you'll quickly see what it does.

The basic approach is it detects what notification systems are available, almost regardless of the platform, and tries to use them in a certain order but falls back to more simple systems if necessary. This way, if the user has e.g. Growl installed it'll use it, regardless of the platform.

You could adapt it to provide support for other notification systems than the three mentioned above.


  • How to go about writing it

    Check how keyring handles the cross-platform issues (it's a python library which plugs into various autodetected keychain backends for storage)

  • Growl isn't bundled with OSX you have to install it separately, OSX doesn't come with any built-in notification system.

  • For unixes, you might want to hook into DBus as already mentioned (as a fallback, note that dbus might also be available in OSX), but both KDE and Gnome have Growl-like libraries. Respectively, KNotification for KDE and libnotify for Gnome.

  • For windows, check out Snarl, fall back to notification bubbles if not available (using something along the lines of ToasterBox)

Do not ever even think of making notifications sticky. It's stupid, it's insensitive and it's freaking annoying. Also, due to people like you it's been made not available in most notification systems.

Finally, even if there is no Python lib for any of these, you can probably use ctypes to access them.


try PyQt4, if you don't care about the size.

here is the class for this job: http://doc.trolltech.com/4.5/qsystemtrayicon.html


Sounds like you need Growl for Windows


Here is something simple that works for me. The Toast stays up for 2 secs and disappears. Yes, OP didn't want 'gigantic' PyQt4, but this may be useful to others.

import sys, time
from PyQt4 import QtCore, QtGui
import uiToast

window = None   # global

# Usage: Toast('Message')
class Toast(QtGui.QMainWindow):
    def __init__(self, msg):
        global window               # some space outside the local stack
        window = self               # save pointer till killed to avoid GC
        QtGui.QWidget.__init__(self)
        self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
        self.ui = uiToast.Ui_MainWindow()
        self.ui.setupUi(self)

        self.ui.display.setText(msg)

        self.toastThread = ToastThread()    # start thread to remove display
        self.connect(self.toastThread, QtCore.SIGNAL("finished()"), self.toastDone)
        self.toastThread.start()
        self.show()

    def toastDone(self):
        global window
        window = None               # kill pointer to window object to close it and GC

class ToastThread(QtCore.QThread):
    def __init__(self):
        QtCore.QThread.__init__(self)

    def run(self):
        time.sleep(2.0)             # wait and die

The trimmed down file 'uiToast.py' created by pyuic4 is:

from PyQt4 import QtCore, QtGui
class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.resize(547, 96)
        palette = QtGui.QPalette()
        brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Base, brush)
        brush = QtGui.QBrush(QtGui.QColor(255, 170, 0))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Window, brush)
        MainWindow.setPalette(palette)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.display = QtGui.QTextBrowser(self.centralwidget)
        self.display.setGeometry(QtCore.QRect(0, 0, 551, 101))
        palette = QtGui.QPalette()
        brush = QtGui.QBrush(QtGui.QColor(255, 170, 0))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Base, brush)
        self.display.setPalette(palette)
        font = QtGui.QFont()
        font.setPointSize(12)
        self.display.setFont(font)
        MainWindow.setCentralWidget(self.centralwidget)

For good cross-platform support, I would look at PyQt. It will add some heft to your library, but they've done a good job working out most of the kinks.


On win you can use snarl.

Using it with python: www.k23productions.com/e107_plugins/forum/forum_viewtopic.php?2972


Need Your Help

updating node.js in windows 7 64 bit

javascript node.js npm windows-7-x64

How to update node.js in Windows 7 64-bit OS?

Writing rules generated by Apriori

r data-mining apriori arules

I'm working with some large transactions data. I've been using read.transactions and apriori (parts of the arules package) to mine for frequent item pairings.