Skip to content

Commit

Permalink
v0.3.38
Browse files Browse the repository at this point in the history
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
  • Loading branch information
ms7m authored Dec 5, 2022
2 parents 5ee3eed + 481cec7 commit ebfb585
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 141 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ You may need to add ``python3 -m`` to the beginning.
- [Leterax](https://github.com/Leterax)
- [jnoortheen](https://github.com/jnoortheen)
- [dynobo](https://github.com/dynobo)
- [Xou](https://github.com/GiorgosXou)

---

Expand Down
2 changes: 1 addition & 1 deletion notifypy/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .notify import Notify
from .os_notifiers._base import BaseNotifier

__version__ = "0.3.31"
__version__ = "0.3.38"
2 changes: 1 addition & 1 deletion notifypy/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Custom and Clear Exceptions for NotifyPy


class BaseNotifyPyException(BaseException):
class BaseNotifyPyException(Exception):
"""Base Exception to be Inheritied"""


Expand Down
62 changes: 40 additions & 22 deletions notifypy/notify.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def __init__(
default_notification_title="Default Title",
default_notification_message="Default Message",
default_notification_application_name="Python Application (notify.py)",
default_notification_urgency='normal',
default_notification_icon=None,
default_notification_audio=None,
enable_logging=False,
Expand Down Expand Up @@ -74,6 +75,7 @@ def __init__(
self._notification_title = default_notification_title
self._notification_message = default_notification_message
self._notification_application_name = default_notification_application_name
self._notification_urgency = default_notification_urgency

# These defaults require verification
if default_notification_icon:
Expand Down Expand Up @@ -103,25 +105,7 @@ def _selected_notification_system(
else:
selected_platform = platform.system()

if selected_platform == "Linux":

if linux_use_legacy_notifier:
from .os_notifiers.linux import LinuxNotifierLibNotify

return LinuxNotifierLibNotify
else:

from .os_notifiers.linux import USE_LEGACY

if USE_LEGACY == False:
from .os_notifiers.linux import LinuxNotifier

return LinuxNotifier
else:
from .os_notifiers.linux import LinuxNotifierLibNotify

return LinuxNotifierLibNotify
elif selected_platform == "Darwin":
if selected_platform == "Darwin":
from .os_notifiers.macos import MacOSNotifier

return MacOSNotifier
Expand All @@ -140,9 +124,25 @@ def _selected_notification_system(
f"This version of Windows ({platform.release()}) is not supported."
)
else:
raise UnsupportedPlatform(
"Platform couldn't be detected, please manually specifiy platform."
)
if selected_platform != "Linux":
logger.warning(f'{selected_platform} might not be supported!')

if linux_use_legacy_notifier:
from .os_notifiers.linux import LinuxNotifierLibNotify

return LinuxNotifierLibNotify
else:

from .os_notifiers.linux import NOTIFY

if NOTIFY:
from .os_notifiers.linux import LinuxNotifierLibNotify

return LinuxNotifierLibNotify
else:
from .os_notifiers.linux import LinuxNotifier

return LinuxNotifier

@staticmethod
def _verify_audio_path(new_audio_path):
Expand Down Expand Up @@ -250,6 +250,20 @@ def application_name(self):
def application_name(self, new_application_name):
self._notification_application_name = new_application_name

@property
def urgency(self):
"""The urgency of the notification (low, normal, critical)
Works only with libnotify (Linux), as of now
Returns:
str: The urgency of the notification.
"""
return self._notification_urgency

@urgency.setter
def urgency(self, new_urgency):
self._notification_urgency = new_urgency

def send(self, block=True):
"""Main send function. This will take all attributes sent and forward to
send_notification.
Expand Down Expand Up @@ -288,6 +302,7 @@ def start_notification_thread(self, event):
supplied_title=self._notification_title,
supplied_message=self._notification_message,
supplied_application_name=self._notification_application_name,
supplied_urgency=self._notification_urgency,
supplied_icon_path=self._notification_icon,
supplied_audio_path=self._notification_audio,
)
Expand All @@ -301,6 +316,7 @@ def send_notification(
supplied_title,
supplied_message,
supplied_application_name,
supplied_urgency,
supplied_icon_path,
supplied_audio_path,
):
Expand All @@ -310,6 +326,7 @@ def send_notification(
supplied_title str: Title for notification
supplied_message str: Message for notification
supplied_application_name str: Application name for notification (if platform needs it)
supplied_urgency str: low, normal, critical | Notification urgency
supplied_icon_path str: Direct path to custom icon
supplied_audio_path str: Direct path to custom audio
Expand All @@ -324,6 +341,7 @@ def send_notification(
notification_title=str(supplied_title),
notification_subtitle=str(supplied_message),
application_name=str(supplied_application_name),
notification_urgency=str(supplied_urgency),
notification_icon=str(supplied_icon_path),
notification_audio=str(supplied_audio_path)
if supplied_audio_path
Expand Down
148 changes: 33 additions & 115 deletions notifypy/os_notifiers/linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,81 +2,43 @@
import subprocess
import shlex

from ..exceptions import BinaryNotFound, NotificationFailure, LinuxDbusException
from ..exceptions import BinaryNotFound
from ._base import BaseNotifier

try:
from jeepney import DBusAddress, new_method_call
from jeepney.io.blocking import open_dbus_connection
import os

# check if dbus is available
_dbus_address = os.getenv("DBUS_SESSION_BUS_ADDRESS")
if _dbus_address:
logger.info("Jeepney and Dbus is available. Using DBUS for notifications..")
USE_LEGACY = False
else:
logger.error(
"Jeepney is available but DBUS is not. Using legacy notification instead."
)
USE_LEGACY = True
except ImportError:
logger.error("DBUS suppport not installed. Using libnotify for notifications!")
USE_LEGACY = True
from shutil import which

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

class LinuxNotifierLibNotify(BaseNotifier):
def __init__(self, **kwargs):
"""Main Linux Notification Class
if NOTIFY:
logger.info("libnotify found, using it for notifications")
else: # check if dbus is available
import os
_dbus_address = os.getenv("DBUS_SESSION_BUS_ADDRESS")
if _dbus_address:
logger.info("Jeepney and Dbus is available. Using DBUS for notifications..")
else:
raise ImportError

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

"""
if APLAY == None:
logger.debug("aplay binary not installed.. audio will not work!")

call_find_notify_send = self._find_installed_notify_send()

if not call_find_notify_send:
logger.error("Unable to find notify-send.")
raise BinaryNotFound("notify-send")
if call_find_notify_send:
self._notify_send_binary = call_find_notify_send
except ImportError:
logger.error("libnotify nor DBUS installed.")

call_find_aplay = self._find_installed_aplay()
if not call_find_aplay:
# no Aplay is available.
self._aplay_binary = False
else:
self._aplay_binary = call_find_aplay

@staticmethod
def _find_installed_aplay():
"""Function to find the path for notify-send"""
try:
run_which_for_aplay = subprocess.check_output(["which", "aplay"])
return run_which_for_aplay.decode("utf-8")
except subprocess.CalledProcessError:
logger.exception("Unable to find aplay.")
return False
except Exception:
logger.exception("Unhandled exception for finding aplay.")
return False
class LinuxNotifierLibNotify(BaseNotifier):
def __init__(self, **kwargs):
"""Main Linux Notification Class
@staticmethod
def _find_installed_notify_send():
"""Function to find the path for notify-send"""
try:
run_which_for_notify_send = subprocess.check_output(
["which", "notify-send"]
)
return run_which_for_notify_send.decode("utf-8")
except subprocess.CalledProcessError:
logger.exception("Unable to find notify-send.")
return False
except Exception:
logger.exception("Unhandled exception for finding notify-send.")
return False
This uses libnotify's tool of notfiy-send.
"""
pass

def send_notification(
self,
Expand All @@ -87,14 +49,13 @@ def send_notification(
**kwargs,
):
try:

notification_title = " " if notification_title == "" else notification_title
notification_subtitle = (
" " if notification_subtitle == "" else notification_subtitle
)

generated_command = [
self._notify_send_binary.strip(),
NOTIFY,
notification_title,
notification_subtitle,
]
Expand All @@ -107,14 +68,17 @@ def send_notification(
f"--app-name={shlex.quote(kwargs.get('application_name'))}"
)

if kwargs.get('notification_urgency'):
generated_command.extend(["-u", kwargs.get('notification_urgency')])

logger.debug(f"Generated command: {generated_command}")
if notification_audio:

if self._aplay_binary == False:
if APLAY == None:
raise BinaryNotFound("aplay (Alsa)")

subprocess.Popen(
[self._aplay_binary.strip(), notification_audio],
[APLAY, notification_audio],
stdout=subprocess.DEVNULL,
stderr=subprocess.STDOUT,
)
Expand Down Expand Up @@ -143,31 +107,6 @@ def __init__(self, **kwargs):
interface="org.freedesktop.Notifications",
)

call_find_aplay = self._find_installed_aplay()
if not call_find_aplay:
# no Aplay is available.
self._aplay_binary = False
logger.debug("aplay binary not installed.. audio will not work!")
else:
self._aplay_binary = call_find_aplay

if kwargs.get("linux_fallback_libnotify"):
self._fallback_to_libnotify = True
else:
self._fallback_to_libnotify = False

@staticmethod
def _find_installed_aplay():
"""Function to find the path for notify-send"""
try:
run_which_for_aplay = subprocess.check_output(["which", "aplay"])
return run_which_for_aplay.decode("utf-8")
except subprocess.CalledProcessError:
logger.exception("Unable to find aplay.")
return False
except Exception:
logger.exception("Unhandled exception for finding aplay.")
return False

def send_notification(
self,
Expand All @@ -182,35 +121,23 @@ def send_notification(
logger.debug("linux: opened dbus connection")
except Exception:
logger.exception("issue with opening DBUS connection!")
if self._fallback_to_libnotify == True:
logger.debug("falling back to libnotify!")
return LinuxNotifierLibNotify().send_notification(
notification_title,
notification_subtitle,
notification_icon,
notification_audio,
**kwargs,
)
else:
logger.exception(
"there was an exception trying to open the dbus connection. fallback was not enabled, therefore this will return False."
)
return False
return False

try:
notification_title = " " if notification_title == "" else notification_title
notification_subtitle = (
" " if notification_subtitle == "" else notification_subtitle
)

if notification_audio:
# TODO: https://specifications.freedesktop.org/notification-spec/latest/ar01s09.html
# use sound param instead of relying on alsa?

if self._aplay_binary == False:
if APLAY == None:
raise BinaryNotFound("aplay (Alsa)")

subprocess.Popen(
[self._aplay_binary.strip(), notification_audio],
[APLAY, notification_audio],
stdout=subprocess.DEVNULL,
stderr=subprocess.STDOUT,
)
Expand Down Expand Up @@ -238,13 +165,4 @@ def send_notification(

except Exception:
logger.exception("issue with sending through dbus!")
if self._fallback_to_libnotify == True:
logger.debug("falling back to libnotify!")
return LinuxNotifierLibNotify().send_notification(
notification_title,
notification_subtitle,
notification_icon,
notification_audio,
**kwargs,
)
return False
1 change: 1 addition & 0 deletions notifypy/os_notifiers/windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ def send_notification(
notification_icon,
application_name,
notification_audio,
**kwargs,
):
generated_file = self._generate_notification_xml(
notification_title=notification_title,
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "notify_py"
version = "0.3.31"
version = "0.3.38"
description = "Cross-platform desktop notification library for Python"
authors = ["Mustafa Mohamed <mustafa@ms7m.me>"]
repository = "https://github.com/ms7m/notify-py"
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

setup(
name="notify_py",
version="0.3.31",
version="0.3.38",
author="Mustafa Mohamed",
author_email="ms7mohamed@gmail.com",
description="Cross-platform desktop notification library for Python",
Expand Down

0 comments on commit ebfb585

Please sign in to comment.