Skip to content

Commit 219bfd0

Browse files
committed
fix(refactor): spliting and generic notifications
1 parent 1d30278 commit 219bfd0

File tree

8 files changed

+143
-132
lines changed

8 files changed

+143
-132
lines changed

src/moodle_painkillers/__init__.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@
77
import bs4
88
import requests as rq
99

10-
from .desktop_notifications import send_notification
10+
from .notifications import send_notification
1111
from .moodle_authenticate import MoodleAuthenticatedSession
1212

1313
log = logging.getLogger(__name__)
1414

1515

16+
NOTIFICATION_TITLE = "Moodle Presence Registration"
17+
18+
1619
try:
1720
from rich.logging import RichHandler
1821
from rich.traceback import install as install_rich_traceback
@@ -166,7 +169,7 @@ def wrapper(*args, **kwargs):
166169
return func(*args, **kwargs)
167170
except Exception as e:
168171
log.error(f"An error occurred: {str(e)}")
169-
_ = send_notification(str(e))
172+
send_notification(str(e), title=NOTIFICATION_TITLE)
170173
raise e
171174

172175
return wrapper

src/moodle_painkillers/desktop_notifications.py

Lines changed: 0 additions & 124 deletions
This file was deleted.
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import platform
2+
from logging import getLogger
3+
4+
from .discord import send_notification as send_discord_notification
5+
6+
log = getLogger(__name__)
7+
8+
9+
match (platform.system()):
10+
case "Windows":
11+
from .windows import send_notification as _send_notification
12+
13+
send_sys_notification = _send_notification
14+
case "Darwin": # macOS
15+
from .macos import send_notification as _send_notification
16+
17+
send_sys_notification = _send_notification
18+
case "Linux":
19+
from .linux import send_notification as _send_notification
20+
21+
send_sys_notification = _send_notification
22+
case _ as system:
23+
log.warning(f"Desktop notifications not supported on {system}")
24+
25+
def send_sys_notification(message: str, title: str) -> None:
26+
_ = message, title
27+
raise ImportError(
28+
f"Desktop notifications not supported on {system}"
29+
)
30+
31+
32+
def send_notification(
33+
message: str, *, title: str, discord_webhook: str | None = None
34+
) -> None:
35+
"""
36+
Send a desktop notification with the given message across different operating systems.
37+
38+
Dependencies:
39+
- Windows: win10toast package (pip install win10toast)
40+
- macOS: AppleScript or pync package (pip install pync)
41+
- Linux: notify-send command
42+
43+
Args:
44+
message (str): The message to display in the notification
45+
46+
Returns:
47+
bool: True if notification was sent successfully, False otherwise
48+
"""
49+
assert isinstance(message, str), "Message must be a string"
50+
assert (
51+
isinstance(discord_webhook, str) or discord_webhook is None
52+
), "Discord webhook must be a string or None"
53+
system = platform.system()
54+
55+
log.info(f"Sending notification: {message}")
56+
57+
if discord_webhook:
58+
send_discord_notification(message, discord_webhook=discord_webhook)
59+
60+
log.debug(f"Sending notification on {system} platform")
61+
62+
try:
63+
send_sys_notification(message, title)
64+
except ImportError as e:
65+
log.exception(f"Failed to setup notification: {e}")
66+
raise
67+
except Exception as e:
68+
log.exception(f"Failed to send notification: {e}")
69+
raise
Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import json
22
import logging
3-
import os
43

54
import requests as rq
65

76
# Set up logger for this module
87
log = logging.getLogger(__name__)
98

109

11-
def send_discord_notification(message: str, *, discord_webhook: str) -> None:
10+
def send_notification(message: str, *, discord_webhook: str) -> None:
1211
data = {
1312
"content": f"{message}",
1413
}
@@ -18,8 +17,6 @@ def send_discord_notification(message: str, *, discord_webhook: str) -> None:
1817
data=json.dumps(data),
1918
headers={"Content-Type": "application/json"},
2019
)
21-
log.info(
22-
f"Notification Discord envoyée: {res.status_code}, {res.text}"
23-
)
20+
log.info(f"Notification Discord envoyée: {res.status_code}, {res.text}")
2421
except Exception as e:
2522
log.error(f"Erreur d'envoi de notification Discord: {str(e)}")
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import subprocess
2+
import shutil
3+
from logging import getLogger
4+
5+
log = getLogger(__name__)
6+
7+
8+
def send_notification(message: str, title: str) -> None:
9+
"""Send a notification on Linux systems"""
10+
assert isinstance(message, str), "Message must be a string"
11+
assert isinstance(title, str), "Title must be a string"
12+
13+
try:
14+
log.debug("Attempting to send Linux notification")
15+
cmd = ["notify-send", title, message]
16+
_ = subprocess.run(cmd, check=True)
17+
log.info("Linux notification sent successfully")
18+
except subprocess.SubprocessError as e:
19+
log.fatal(f"Could not send notification on Linux: {e}")
20+
raise
21+
except FileNotFoundError as e:
22+
log.fatal(f"Could not send notification on Linux: {e}")
23+
raise ImportError("notify-send command not found. Please install libnotify package")
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import shutil
2+
from logging import getLogger
3+
4+
import pync # pyright: ignore[reportMissingImports]
5+
6+
log = getLogger(__name__)
7+
8+
9+
if not shutil.which("terminal-notifier"):
10+
raise ImportError("terminal-notifier not found. Install using brew!")
11+
log.debug("pync module loaded successfully for macOS notifications")
12+
13+
14+
def send_notification(message: str, title: str) -> None:
15+
"""Send a notification on macOS systems"""
16+
assert isinstance(message, str), "Message must be a string"
17+
assert isinstance(title, str), "Title must be a string"
18+
19+
if not pync:
20+
raise ImportError("pync package is required for macOS notifications")
21+
22+
log.debug("Attempting to send macOS notification via pync")
23+
pync.notify(message, title=title)
24+
log.info("macOS notification sent successfully via pync")
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from logging import getLogger
2+
3+
import win10toast # pyright: ignore[reportMissingImports]
4+
5+
log = getLogger(__name__)
6+
7+
8+
def send_notification(message: str, title: str) -> None:
9+
"""Send a notification on Windows systems"""
10+
assert isinstance(message, str), "Message must be a string"
11+
assert isinstance(title, str), "Title must be a string"
12+
13+
if not win10toast:
14+
raise ImportError("win10toast package is required for Windows notifications")
15+
16+
log.debug("Attempting to send Windows notification")
17+
toaster = win10toast.ToastNotifier()
18+
toaster.show_toast(title, message, duration=5)
19+
log.info("Windows notification sent successfully")

tests/test___init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ def failing_func():
244244
assert excinfo.value == test_exception
245245

246246
# Verify send_notification was called with the exception message
247-
mock_send_notification.assert_called_once_with("test error")
247+
mock_send_notification.assert_called_once_with('test error', title='Moodle Presence Registration')
248248

249249
@patch("moodle_painkillers.send_notification")
250250
def test_with_arguments(self, mock_send_notification):

0 commit comments

Comments
 (0)