Cross-platform desktop notifier in Python
Asked Answered
N

8

46

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.

Natator answered 10/2, 2010 at 22:2 Comment(1)
Note that on OSX, there is a default notifier now and Growl has become commercial (and thus mostly non-standard). See here. Or here for a Python implementation.Slattern
R
19

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.

Rackety answered 11/2, 2010 at 12:21 Comment(2)
What license is this released under? Edit: Nevermind...it's a type of BSD license...thank you for releasing the code as such. It's a pain to find libraries or things I want to LEARN from that wouldn't risk any future releases of my code. But I have no problem giving credit where credit is due ;)Mabellemable
looks like this link is dead now! is it on GitHub by any chance ? thanks in advanceNoncontributory
S
17

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.

Siegler answered 16/8, 2011 at 9:37 Comment(3)
I don't know why this answer doesn't have more upvotes. It worked great right out of the box, and is super easy to understand.Mystique
Tried notify.py. It needs to be updated with import other.pyWx.toasterboximport wx.lib.agw.toasterbox as TB, I believe. But it still doesn't do anything: send('title','message')PyNoAppError: The wx.App object must be created first!Giacopo
Essentially I have window-less apps and I want to say balloon('something') instead of print('something'). Why do we have to go through all the trouble of creating and destroying windows and stuff just to pop up dialogs or balloons? https://mcmap.net/q/355820/-what-39-s-the-simplest-cross-platform-way-to-pop-up-graphical-dialogs-in-python/125507Giacopo
S
7
  • 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.

Stinko answered 11/2, 2010 at 7:37 Comment(2)
this is exactly how i would approach this if there isn’t a module for it. upvoted for mind reading. now only someone needs to code it… PS: i’d personally use Qt’s bubbles as fallback everywhere though. They are ugly, but every GUI app i write uses qt, so it’s at least always available.Puebla
"OSX doesn't come with any built-in notification system" not true for the latest OSX versions.Swanee
U
3

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

Uranian answered 12/2, 2010 at 4:28 Comment(0)
G
2

Sounds like you need Growl for Windows

Gyromagnetic answered 13/7, 2010 at 18:44 Comment(0)
S
1

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)
Sac answered 9/2, 2014 at 14:38 Comment(0)
S
0

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.

Soup answered 11/2, 2010 at 4:24 Comment(1)
PyQT is too much for my simple requirement. Besides, deploying apps with PyQT is a pain: arstechnica.com/open-source/guides/2009/03/…Natator
E
0

On win you can use snarl.

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

Exteriorize answered 11/2, 2010 at 6:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.