Skip to content

Commit ebfb585

Browse files
authored
v0.3.38
Thanks to @GiorgosXou: - Added: notification urgency (low, normal, critical) for notify-send - Fixed: notify-send, now is being used as the first choice if installed - Fixed: OSs like BSD now default under the linux-behavioural category - Fixed: issue under windows with extra kwargs that resulted in error - Removed: linux_fallback_libnotify, no more need for it - Replaced: functions with the in-built shutil.which function
2 parents 5ee3eed + 481cec7 commit ebfb585

File tree

8 files changed

+79
-141
lines changed

8 files changed

+79
-141
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ You may need to add ``python3 -m`` to the beginning.
147147
- [Leterax](https://github.com/Leterax)
148148
- [jnoortheen](https://github.com/jnoortheen)
149149
- [dynobo](https://github.com/dynobo)
150+
- [Xou](https://github.com/GiorgosXou)
150151

151152
---
152153

notifypy/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
from .notify import Notify
22
from .os_notifiers._base import BaseNotifier
33

4-
__version__ = "0.3.31"
4+
__version__ = "0.3.38"

notifypy/exceptions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Custom and Clear Exceptions for NotifyPy
22

33

4-
class BaseNotifyPyException(BaseException):
4+
class BaseNotifyPyException(Exception):
55
"""Base Exception to be Inheritied"""
66

77

notifypy/notify.py

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ def __init__(
2323
default_notification_title="Default Title",
2424
default_notification_message="Default Message",
2525
default_notification_application_name="Python Application (notify.py)",
26+
default_notification_urgency='normal',
2627
default_notification_icon=None,
2728
default_notification_audio=None,
2829
enable_logging=False,
@@ -74,6 +75,7 @@ def __init__(
7475
self._notification_title = default_notification_title
7576
self._notification_message = default_notification_message
7677
self._notification_application_name = default_notification_application_name
78+
self._notification_urgency = default_notification_urgency
7779

7880
# These defaults require verification
7981
if default_notification_icon:
@@ -103,25 +105,7 @@ def _selected_notification_system(
103105
else:
104106
selected_platform = platform.system()
105107

106-
if selected_platform == "Linux":
107-
108-
if linux_use_legacy_notifier:
109-
from .os_notifiers.linux import LinuxNotifierLibNotify
110-
111-
return LinuxNotifierLibNotify
112-
else:
113-
114-
from .os_notifiers.linux import USE_LEGACY
115-
116-
if USE_LEGACY == False:
117-
from .os_notifiers.linux import LinuxNotifier
118-
119-
return LinuxNotifier
120-
else:
121-
from .os_notifiers.linux import LinuxNotifierLibNotify
122-
123-
return LinuxNotifierLibNotify
124-
elif selected_platform == "Darwin":
108+
if selected_platform == "Darwin":
125109
from .os_notifiers.macos import MacOSNotifier
126110

127111
return MacOSNotifier
@@ -140,9 +124,25 @@ def _selected_notification_system(
140124
f"This version of Windows ({platform.release()}) is not supported."
141125
)
142126
else:
143-
raise UnsupportedPlatform(
144-
"Platform couldn't be detected, please manually specifiy platform."
145-
)
127+
if selected_platform != "Linux":
128+
logger.warning(f'{selected_platform} might not be supported!')
129+
130+
if linux_use_legacy_notifier:
131+
from .os_notifiers.linux import LinuxNotifierLibNotify
132+
133+
return LinuxNotifierLibNotify
134+
else:
135+
136+
from .os_notifiers.linux import NOTIFY
137+
138+
if NOTIFY:
139+
from .os_notifiers.linux import LinuxNotifierLibNotify
140+
141+
return LinuxNotifierLibNotify
142+
else:
143+
from .os_notifiers.linux import LinuxNotifier
144+
145+
return LinuxNotifier
146146

147147
@staticmethod
148148
def _verify_audio_path(new_audio_path):
@@ -250,6 +250,20 @@ def application_name(self):
250250
def application_name(self, new_application_name):
251251
self._notification_application_name = new_application_name
252252

253+
@property
254+
def urgency(self):
255+
"""The urgency of the notification (low, normal, critical)
256+
Works only with libnotify (Linux), as of now
257+
258+
Returns:
259+
str: The urgency of the notification.
260+
"""
261+
return self._notification_urgency
262+
263+
@urgency.setter
264+
def urgency(self, new_urgency):
265+
self._notification_urgency = new_urgency
266+
253267
def send(self, block=True):
254268
"""Main send function. This will take all attributes sent and forward to
255269
send_notification.
@@ -288,6 +302,7 @@ def start_notification_thread(self, event):
288302
supplied_title=self._notification_title,
289303
supplied_message=self._notification_message,
290304
supplied_application_name=self._notification_application_name,
305+
supplied_urgency=self._notification_urgency,
291306
supplied_icon_path=self._notification_icon,
292307
supplied_audio_path=self._notification_audio,
293308
)
@@ -301,6 +316,7 @@ def send_notification(
301316
supplied_title,
302317
supplied_message,
303318
supplied_application_name,
319+
supplied_urgency,
304320
supplied_icon_path,
305321
supplied_audio_path,
306322
):
@@ -310,6 +326,7 @@ def send_notification(
310326
supplied_title str: Title for notification
311327
supplied_message str: Message for notification
312328
supplied_application_name str: Application name for notification (if platform needs it)
329+
supplied_urgency str: low, normal, critical | Notification urgency
313330
supplied_icon_path str: Direct path to custom icon
314331
supplied_audio_path str: Direct path to custom audio
315332
@@ -324,6 +341,7 @@ def send_notification(
324341
notification_title=str(supplied_title),
325342
notification_subtitle=str(supplied_message),
326343
application_name=str(supplied_application_name),
344+
notification_urgency=str(supplied_urgency),
327345
notification_icon=str(supplied_icon_path),
328346
notification_audio=str(supplied_audio_path)
329347
if supplied_audio_path

notifypy/os_notifiers/linux.py

Lines changed: 33 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -2,81 +2,43 @@
22
import subprocess
33
import shlex
44

5-
from ..exceptions import BinaryNotFound, NotificationFailure, LinuxDbusException
5+
from ..exceptions import BinaryNotFound
66
from ._base import BaseNotifier
77

88
try:
99
from jeepney import DBusAddress, new_method_call
1010
from jeepney.io.blocking import open_dbus_connection
11-
import os
12-
13-
# check if dbus is available
14-
_dbus_address = os.getenv("DBUS_SESSION_BUS_ADDRESS")
15-
if _dbus_address:
16-
logger.info("Jeepney and Dbus is available. Using DBUS for notifications..")
17-
USE_LEGACY = False
18-
else:
19-
logger.error(
20-
"Jeepney is available but DBUS is not. Using legacy notification instead."
21-
)
22-
USE_LEGACY = True
23-
except ImportError:
24-
logger.error("DBUS suppport not installed. Using libnotify for notifications!")
25-
USE_LEGACY = True
11+
from shutil import which
2612

13+
NOTIFY = which('notify-send') # alternatively: from ctypes.util import find_library
2714

28-
class LinuxNotifierLibNotify(BaseNotifier):
29-
def __init__(self, **kwargs):
30-
"""Main Linux Notification Class
15+
if NOTIFY:
16+
logger.info("libnotify found, using it for notifications")
17+
else: # check if dbus is available
18+
import os
19+
_dbus_address = os.getenv("DBUS_SESSION_BUS_ADDRESS")
20+
if _dbus_address:
21+
logger.info("Jeepney and Dbus is available. Using DBUS for notifications..")
22+
else:
23+
raise ImportError
3124

32-
This uses libnotify's tool of notfiy-send.
33-
I'll add support for (and probably use as first choice) sending
34-
through dbus.
25+
APLAY = which('aplay')
3526

36-
"""
27+
if APLAY == None:
28+
logger.debug("aplay binary not installed.. audio will not work!")
3729

38-
call_find_notify_send = self._find_installed_notify_send()
3930

40-
if not call_find_notify_send:
41-
logger.error("Unable to find notify-send.")
42-
raise BinaryNotFound("notify-send")
43-
if call_find_notify_send:
44-
self._notify_send_binary = call_find_notify_send
31+
except ImportError:
32+
logger.error("libnotify nor DBUS installed.")
4533

46-
call_find_aplay = self._find_installed_aplay()
47-
if not call_find_aplay:
48-
# no Aplay is available.
49-
self._aplay_binary = False
50-
else:
51-
self._aplay_binary = call_find_aplay
5234

53-
@staticmethod
54-
def _find_installed_aplay():
55-
"""Function to find the path for notify-send"""
56-
try:
57-
run_which_for_aplay = subprocess.check_output(["which", "aplay"])
58-
return run_which_for_aplay.decode("utf-8")
59-
except subprocess.CalledProcessError:
60-
logger.exception("Unable to find aplay.")
61-
return False
62-
except Exception:
63-
logger.exception("Unhandled exception for finding aplay.")
64-
return False
35+
class LinuxNotifierLibNotify(BaseNotifier):
36+
def __init__(self, **kwargs):
37+
"""Main Linux Notification Class
6538
66-
@staticmethod
67-
def _find_installed_notify_send():
68-
"""Function to find the path for notify-send"""
69-
try:
70-
run_which_for_notify_send = subprocess.check_output(
71-
["which", "notify-send"]
72-
)
73-
return run_which_for_notify_send.decode("utf-8")
74-
except subprocess.CalledProcessError:
75-
logger.exception("Unable to find notify-send.")
76-
return False
77-
except Exception:
78-
logger.exception("Unhandled exception for finding notify-send.")
79-
return False
39+
This uses libnotify's tool of notfiy-send.
40+
"""
41+
pass
8042

8143
def send_notification(
8244
self,
@@ -87,14 +49,13 @@ def send_notification(
8749
**kwargs,
8850
):
8951
try:
90-
9152
notification_title = " " if notification_title == "" else notification_title
9253
notification_subtitle = (
9354
" " if notification_subtitle == "" else notification_subtitle
9455
)
9556

9657
generated_command = [
97-
self._notify_send_binary.strip(),
58+
NOTIFY,
9859
notification_title,
9960
notification_subtitle,
10061
]
@@ -107,14 +68,17 @@ def send_notification(
10768
f"--app-name={shlex.quote(kwargs.get('application_name'))}"
10869
)
10970

71+
if kwargs.get('notification_urgency'):
72+
generated_command.extend(["-u", kwargs.get('notification_urgency')])
73+
11074
logger.debug(f"Generated command: {generated_command}")
11175
if notification_audio:
11276

113-
if self._aplay_binary == False:
77+
if APLAY == None:
11478
raise BinaryNotFound("aplay (Alsa)")
11579

11680
subprocess.Popen(
117-
[self._aplay_binary.strip(), notification_audio],
81+
[APLAY, notification_audio],
11882
stdout=subprocess.DEVNULL,
11983
stderr=subprocess.STDOUT,
12084
)
@@ -143,31 +107,6 @@ def __init__(self, **kwargs):
143107
interface="org.freedesktop.Notifications",
144108
)
145109

146-
call_find_aplay = self._find_installed_aplay()
147-
if not call_find_aplay:
148-
# no Aplay is available.
149-
self._aplay_binary = False
150-
logger.debug("aplay binary not installed.. audio will not work!")
151-
else:
152-
self._aplay_binary = call_find_aplay
153-
154-
if kwargs.get("linux_fallback_libnotify"):
155-
self._fallback_to_libnotify = True
156-
else:
157-
self._fallback_to_libnotify = False
158-
159-
@staticmethod
160-
def _find_installed_aplay():
161-
"""Function to find the path for notify-send"""
162-
try:
163-
run_which_for_aplay = subprocess.check_output(["which", "aplay"])
164-
return run_which_for_aplay.decode("utf-8")
165-
except subprocess.CalledProcessError:
166-
logger.exception("Unable to find aplay.")
167-
return False
168-
except Exception:
169-
logger.exception("Unhandled exception for finding aplay.")
170-
return False
171110

172111
def send_notification(
173112
self,
@@ -182,35 +121,23 @@ def send_notification(
182121
logger.debug("linux: opened dbus connection")
183122
except Exception:
184123
logger.exception("issue with opening DBUS connection!")
185-
if self._fallback_to_libnotify == True:
186-
logger.debug("falling back to libnotify!")
187-
return LinuxNotifierLibNotify().send_notification(
188-
notification_title,
189-
notification_subtitle,
190-
notification_icon,
191-
notification_audio,
192-
**kwargs,
193-
)
194-
else:
195-
logger.exception(
196-
"there was an exception trying to open the dbus connection. fallback was not enabled, therefore this will return False."
197-
)
198-
return False
124+
return False
199125

200126
try:
201127
notification_title = " " if notification_title == "" else notification_title
202128
notification_subtitle = (
203129
" " if notification_subtitle == "" else notification_subtitle
204130
)
131+
205132
if notification_audio:
206133
# TODO: https://specifications.freedesktop.org/notification-spec/latest/ar01s09.html
207134
# use sound param instead of relying on alsa?
208135

209-
if self._aplay_binary == False:
136+
if APLAY == None:
210137
raise BinaryNotFound("aplay (Alsa)")
211138

212139
subprocess.Popen(
213-
[self._aplay_binary.strip(), notification_audio],
140+
[APLAY, notification_audio],
214141
stdout=subprocess.DEVNULL,
215142
stderr=subprocess.STDOUT,
216143
)
@@ -238,13 +165,4 @@ def send_notification(
238165

239166
except Exception:
240167
logger.exception("issue with sending through dbus!")
241-
if self._fallback_to_libnotify == True:
242-
logger.debug("falling back to libnotify!")
243-
return LinuxNotifierLibNotify().send_notification(
244-
notification_title,
245-
notification_subtitle,
246-
notification_icon,
247-
notification_audio,
248-
**kwargs,
249-
)
250168
return False

notifypy/os_notifiers/windows.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ def send_notification(
9292
notification_icon,
9393
application_name,
9494
notification_audio,
95+
**kwargs,
9596
):
9697
generated_file = self._generate_notification_xml(
9798
notification_title=notification_title,

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "notify_py"
3-
version = "0.3.31"
3+
version = "0.3.38"
44
description = "Cross-platform desktop notification library for Python"
55
authors = ["Mustafa Mohamed <mustafa@ms7m.me>"]
66
repository = "https://github.com/ms7m/notify-py"

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
setup(
1414
name="notify_py",
15-
version="0.3.31",
15+
version="0.3.38",
1616
author="Mustafa Mohamed",
1717
author_email="ms7mohamed@gmail.com",
1818
description="Cross-platform desktop notification library for Python",

0 commit comments

Comments
 (0)