notify2-0.3/0000775000175000017500000000000011754251751013570 5ustar thomasthomas00000000000000notify2-0.3/setup.py0000664000175000017500000000132111754251647015303 0ustar thomasthomas00000000000000from distutils.core import setup import notify2 long_description = notify2.__doc__ setup(name='notify2', version='0.3', description='Python interface to DBus notifications', long_description=long_description, author='Thomas Kluyver', author_email='takowl@gmail.com', url='https://bitbucket.org/takluyver/pynotify2', py_modules=['notify2'], classifiers = [ 'License :: OSI Approved :: BSD License', 'Programming Language :: Python', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 3', 'Topic :: Desktop Environment', 'Topic :: Software Development :: Libraries :: Python Modules', ] ) notify2-0.3/examples/0000775000175000017500000000000011754251751015406 5ustar thomasthomas00000000000000notify2-0.3/examples/multi-actions.py0000775000175000017500000000270711753275434020564 0ustar thomasthomas00000000000000#!/usr/bin/env python from gi.repository import Gtk import notify2 import sys # Ubuntu's notify-osd doesn't officially support actions. However, it does have # a dialog fallback which we can use for this demonstration. In real use, please # respect the capabilities the notification server reports! OVERRIDE_NO_ACTIONS = True def help_cb(n, action): assert action == "help" print("You clicked Help") n.close() def ignore_cb(n, action): assert action == "ignore" print("You clicked Ignore") n.close() def empty_cb(n, action): assert action == "empty" print("You clicked Empty Trash") n.close() def closed_cb(n): print("Notification closed") Gtk.main_quit() if __name__ == '__main__': if not notify2.init("Multi Action Test", mainloop='glib'): sys.exit(1) server_capabilities = notify2.get_server_caps() n = notify2.Notification("Low disk space", "You can free up some disk space by " + "emptying the trash can.") n.set_urgency(notify2.URGENCY_CRITICAL) n.set_category("device") if ('actions' in server_capabilities) or OVERRIDE_NO_ACTIONS: n.add_action("help", "Help", help_cb) n.add_action("ignore", "Ignore", ignore_cb) n.add_action("empty", "Empty Trash", empty_cb) n.connect('closed', closed_cb) if not n.show(): print("Failed to send notification") sys.exit(1) Gtk.main() notify2-0.3/examples/qt-app.py0000775000175000017500000000347211753307072017170 0ustar thomasthomas00000000000000#!/usr/bin/env python """Callbacks from notify2 work with PyQt applications as well. """ from PyQt4.QtCore import QCoreApplication import notify2 import sys # Ubuntu's notify-osd doesn't officially support actions. However, it does have # a dialog fallback which we can use for this demonstration. In real use, please # respect the capabilities the notification server reports! OVERRIDE_NO_ACTIONS = True class MyApp(QCoreApplication): def __init__(self, argv): super(MyApp, self).__init__(argv) # This needs to be before any other use of notify2, but after the Qt # application has been instantiated. notify2.init("Multi Action Test", mainloop='qt') server_capabilities = notify2.get_server_caps() n = notify2.Notification("Low disk space", "You can free up some disk space by " + "emptying the trash can.") n.set_urgency(notify2.URGENCY_CRITICAL) n.set_category("device") if ('actions' in server_capabilities) or OVERRIDE_NO_ACTIONS: n.add_action("help", "Help", self.help_cb) n.add_action("ignore", "Ignore", self.ignore_cb) n.add_action("empty", "Empty Trash", self.empty_cb) n.connect('closed', self.closed_cb) n.show() def help_cb(self, n, action): assert action == "help" print("You clicked Help") n.close() def ignore_cb(self, n, action): assert action == "ignore" print("You clicked Ignore") n.close() def empty_cb(self, n, action): assert action == "empty" print("You clicked Empty Trash") n.close() def closed_cb(self, n): print("Notification closed") self.quit() if __name__ == "__main__": MyApp(sys.argv).exec_() notify2-0.3/examples/applet-critical.png0000664000175000017500000000257311753275434021203 0ustar thomasthomas00000000000000PNG  IHDRĴl; pHYs  d_tIME 6^'bKGDIDAT8eU]UU]{spQWs4M 1A%-Q^DzK!{W@S2TAKp39w{f:a;ko}k#{~W>B枛P{rK (< nsdocQؿg <\|:XҌrU*B3l[mc>;},| s,1ʕ[rMD=EdTc{H{?<i"wwt܍EX/'N`m2T1u^^QjTMcO_-oS]˔i tq5kVžS8FP 0\|7<2j8P. @\CP*!@ TSqe˓ܽ[fl6oF~:&'9zSc7nel& V BJl"pZνrQݤ#H#ßI6(BDi2(׭{`,+&"n95CPP$)- d׮H1D b۶3$˶&d \L. IƎ,cf -8[6_x)d""`H!iv°0-VK4<9s*GL"v]ksI{BeW k~MMpL+F4V:7%c\{߳drҵ ׅjvp(C7/yc-daς HTzm7Y(mZg[&#mڔLEPۨ)gi|VǸnLdw8>sΈxBآSN@o %$&߀Z׃|Om˟i2=J=q,ḨK3Y]2Ư_,p~gw¸mPr1 &FZ)0Kהi.=J jxA e֣fg?J*NE=Kd:quu&lg'=> )yzft|ژ{Fxe81Ȳt9MUQ SK̯JGf6 YAwIb۝cm 1VSy8󴒅(4pu4 n.hints[key] = value Only exists for compatibility with pynotify. """ self.hints[key] = value set_hint_string = set_hint_int32 = set_hint_double = set_hint def set_hint_byte(self, key, value): """Set a hint with a dbus byte value. The input value can be an integer or a bytes string of length 1. """ self.hints[key] = dbus.Byte(value) def set_urgency(self, level): """Set the urgency level to one of URGENCY_LOW, URGENCY_NORMAL or URGENCY_CRITICAL. """ if level not in urgency_levels: raise ValueError("Unknown urgency level specified", level) self.set_hint_byte("urgency", level) def set_category(self, category): """Set the 'category' hint for this notification. """ self.hints['category'] = category def set_timeout(self, timeout): """Set the display duration in milliseconds, or one of the special values EXPIRES_DEFAULT or EXPIRES_NEVER. Only exists for compatibility with pynotify; you can simply set:: n.timeout = 5000 """ if not isinstance(timeout, int): raise TypeError("timeout value was not int", timeout) self.timeout = timeout def get_timeout(self): """Return the timeout value for this notification. Only exists for compatibility with pynotify; you can inspect the timeout attribute directly. """ return self.timeout def add_action(self, action, label, callback, user_data=None): """Add an action to the notification (if the server supports it). action : str A brief key. label : str The text displayed on the action button callback : callable A function taking at 2-3 parameters: the Notification object, the action key and (if specified) the user_data. user_data : An extra argument to pass to the callback. """ self.actions[action] = (label, callback, user_data) def _make_actions_array(self): """Make the actions array to send over DBus. """ arr = [] for action, (label, callback, user_data) in self.actions.items(): arr.append(action) arr.append(label) return arr def _action_callback(self, action): """Called when the user selects an action on the notification, to dispatch it to the relevant user-specified callback. """ try: label, callback, user_data = self.actions[action] except KeyError: return if user_data is None: callback(self, action) else: callback(self, action, user_data) def connect(self, event, callback): """Set the callback for the notification closing; the only valid value for event is 'closed'. The API is compatible with pynotify. """ if event != 'closed': raise ValueError("'closed' is the only valid value for event", event) self._closed_callback = callback def set_data(self, key, value): """n.set_data(key, value) <--> n.data[key] = value Only exists for compatibility with pynotify. """ self.data[key] = value def get_data(self, key): """n.get_data(key) <--> n.data[key] Only exists for compatibility with pynotify. """ return self.data[key] def set_icon_from_pixbuf(self, icon): """Set a custom icon from a GdkPixbuf. """ struct = ( icon.get_width(), icon.get_height(), icon.get_rowstride(), icon.get_has_alpha(), icon.get_bits_per_sample(), icon.get_n_channels(), dbus.ByteArray(icon.get_pixels()) ) self.hints['icon_data'] = struct def set_location(self, x, y): """Set the notification location as (x, y), if the server supports it. """ if (not isinstance(x, int)) or (not isinstance(y, int)): raise TypeError("x and y must both be ints", (x,y)) self.hints['x'] = x self.hints['y'] = y notify2-0.3/PKG-INFO0000664000175000017500000000462511754251751014674 0ustar thomasthomas00000000000000Metadata-Version: 1.1 Name: notify2 Version: 0.3 Summary: Python interface to DBus notifications Home-page: https://bitbucket.org/takluyver/pynotify2 Author: Thomas Kluyver Author-email: takowl@gmail.com License: UNKNOWN Description: This is a pure-python replacement for notify-python, using python-dbus to communicate with the notifications server directly. It's compatible with Python 2 and 3, and its callbacks can work with Gtk 3 or Qt 4 applications. To use it, first call ``notify2.init('app name')``, then create and show notifications:: n = notify2.Notification("Summary", "Some body text", "notification-message-im" # Icon name ) n.show() To see more of what's possible, refer to docstrings of methods and objects. Based on the notifications spec at: http://developer.gnome.org/notification-spec/ Porting applications from pynotify ---------------------------------- There are a few differences from pynotify you should be aware of: - If you need callbacks from notifications, notify2 must know about your event loop. The simplest way is to pass 'glib' or 'qt' as the ``mainloop`` parameter to ``init``. - The methods ``attach_to_widget`` and ``attach_to_status_icon`` are not implemented. You can calculate the location you want the notification to appear and call ``Notification``. - ``set_property`` and ``get_property`` are not implemented. The summary, body and icon are accessible as attributes of a ``Notification`` instance. - Various methods that pynotify Notification instances got from gobject do not exist, or only implement part of the functionality. Several pynotify functions, especially getters and setters, are only supported for compatibility. You are encouraged to use more direct, Pythonic alternatives. Platform: UNKNOWN Classifier: License :: OSI Approved :: BSD License Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Desktop Environment Classifier: Topic :: Software Development :: Libraries :: Python Modules notify2-0.3/test_notify2.py0000664000175000017500000000756311754251426016605 0ustar thomasthomas00000000000000"""Tests for notify2.py. We can't actually check that notifications are displayed, so this is mostly just smoke tests to check errors aren't raised. Running this may display several notifications. """ import unittest import notify2 from gi.repository import GdkPixbuf class ModuleTests(unittest.TestCase): """Test module level functions. """ def setUp(self): notify2.init("notify2 test suite") def test_init_uninit(self): assert notify2.is_initted() self.assertEqual(notify2.get_app_name(), "notify2 test suite") notify2.uninit() assert not notify2.is_initted() def test_get_server_info(self): r = notify2.get_server_info() assert isinstance(r, dict), type(r) def test_get_server_caps(self): r = notify2.get_server_caps() assert isinstance(r, list), type(r) class NotificationTests(unittest.TestCase): """Test notifications. """ def setUp(self): notify2.init("notify2 test suite") def test_basic(self): n = notify2.Notification("Title", "Body text") n.show() n.close() def test_icon(self): n = notify2.Notification("MLK", "I have a dream", "notification-message-im") n.show() n.close() def test_icon_only(self): if 'x-canonical-private-icon-only' in notify2.get_server_caps(): n = notify2.Notification ("", # for a11y-reasons put something meaningfull here "", # for a11y-reasons put something meaningfull here "notification-device-eject") n.set_hint_string ("x-canonical-private-icon-only", "true"); n.show () def test_urgency(self): nl = notify2.Notification("Low", "Who cares?") nl.set_urgency(notify2.URGENCY_LOW) nl.show() nl.close() nn = notify2.Notification("Normal", "Some information") nn.set_urgency(notify2.URGENCY_NORMAL) nn.show() nn.close() nu = notify2.Notification("Urgent", "Vital information!") nu.set_urgency(notify2.URGENCY_CRITICAL) nu.show() nu.close() def test_update(self): n = notify2.Notification("First message", "Some text", "notification-message-im") n.show() # The icon should stay the same with this n.update("Second message", "Some more text") n.show() # But this should replace the icon n.update("Third message", "Yet more text, new icon.", "notification-message-email") n.show() n.close() def test_category(self): n = notify2.Notification("Plain") n.set_category('im.received') n.show() n.close() def test_timeout(self): n = notify2.Notification("Plain") self.assertEqual(n.get_timeout(), notify2.EXPIRES_DEFAULT) n.set_timeout(notify2.EXPIRES_NEVER) self.assertEqual(n.get_timeout(), notify2.EXPIRES_NEVER) n.set_timeout(5000) self.assertEqual(n.get_timeout(), 5000) n.show() n.close() def test_data(self): n = notify2.Notification("Plain") n.data['a'] = 1 n.set_data('b', 2) # pynotify API n.show() self.assertEqual(n.get_data('a'), 1) # pynotify API self.assertEqual(n.data['b'], 2) n.close() def test_icon_from_pixbuf(self): pb = GdkPixbuf.Pixbuf.new_from_file("examples/applet-critical.png") n = notify2.Notification("Icon", "Testing icon from pixbuf") n.set_icon_from_pixbuf(pb) n.show() n.close() def test_set_location(self): n = notify2.Notification("Location", "Test setting location") n.set_location(320, 240) n.show() n.close() if __name__ == "__main__": unittest.main()