Python library for cross-platform desktop notifications
—
Primary notification classes providing both asynchronous and synchronous interfaces for sending desktop notifications with full platform integration and callback support.
The main asynchronous notification API class that provides non-blocking notification operations with full callback support requiring a running event loop.
class DesktopNotifier:
def __init__(
self,
app_name: str = "Python",
app_icon: Icon | None = DEFAULT_ICON,
notification_limit: int | None = None
) -> None:
"""
Initialize desktop notifier.
Parameters:
- app_name: Name to identify the application in notification center
- app_icon: Default icon for notifications
- notification_limit: Deprecated, no longer has effect
"""
@property
def app_name(self) -> str:
"""The application name"""
@app_name.setter
def app_name(self, value: str) -> None: ...
@property
def app_icon(self) -> Icon | None:
"""The application icon"""
@app_icon.setter
def app_icon(self, value: Icon | None) -> None: ...Methods for requesting and checking notification permissions, automatically handling platform-specific authorization requirements.
async def request_authorisation(self) -> bool:
"""
Request authorization to send notifications.
On platforms like macOS/iOS, shows permission dialog on first call.
Automatically called when sending first notification.
Returns:
bool: Whether authorization was granted
"""
async def has_authorisation(self) -> bool:
"""
Check if authorized to send notifications.
Returns:
bool: Current authorization status
"""Core methods for dispatching notifications with comprehensive parameter support and automatic platform adaptation.
async def send(
self,
title: str,
message: str,
urgency: Urgency = Urgency.Normal,
icon: Icon | None = None,
buttons: Sequence[Button] = (),
reply_field: ReplyField | None = None,
on_dispatched: Callable[[], Any] | None = None,
on_clicked: Callable[[], Any] | None = None,
on_dismissed: Callable[[], Any] | None = None,
attachment: Attachment | None = None,
sound: Sound | None = None,
thread: str | None = None,
timeout: int = -1
) -> str:
"""
Send desktop notification with all options.
Parameters:
- title: Notification title
- message: Notification message body
- urgency: Priority level (Critical, Normal, Low)
- icon: Custom notification icon
- buttons: Interactive buttons (up to platform limit)
- reply_field: Text input field for user responses
- on_dispatched: Callback when notification is sent
- on_clicked: Callback when notification is clicked
- on_dismissed: Callback when notification is dismissed
- attachment: File attachment for preview
- sound: Notification sound
- thread: Grouping identifier for related notifications
- timeout: Display duration in seconds (-1 for system default)
Returns:
str: Unique notification identifier
"""
async def send_notification(self, notification: Notification) -> str:
"""
Send a Notification object.
Parameters:
- notification: Pre-constructed Notification instance
Returns:
str: Unique notification identifier
"""Methods for querying, clearing, and managing active notifications in the system notification center.
async def get_current_notifications(self) -> list[str]:
"""
Get identifiers of all currently displayed notifications for this app.
Returns:
list[str]: List of notification identifiers
"""
async def clear(self, identifier: str) -> None:
"""
Remove specific notification from notification center.
Parameters:
- identifier: Notification identifier from send() or send_notification()
"""
async def clear_all(self) -> None:
"""
Remove all currently displayed notifications for this app.
"""Method for querying platform-specific feature support to enable adaptive behavior across different operating systems.
async def get_capabilities(self) -> frozenset[Capability]:
"""
Query which features are supported by current platform.
Returns:
frozenset[Capability]: Set of supported capability flags
"""Class-level callback handlers that apply to all notifications when individual notification callbacks are not specified.
@property
def on_dispatched(self) -> Callable[[str], Any] | None:
"""
Global callback when notification is sent to notification server.
Handler receives notification identifier as argument.
"""
@on_dispatched.setter
def on_dispatched(self, handler: Callable[[str], Any] | None) -> None: ...
@property
def on_clicked(self) -> Callable[[str], Any] | None:
"""
Global callback when notification is clicked.
Handler receives notification identifier as argument.
"""
@on_clicked.setter
def on_clicked(self, handler: Callable[[str], Any] | None) -> None: ...
@property
def on_dismissed(self) -> Callable[[str], Any] | None:
"""
Global callback when notification is dismissed.
Handler receives notification identifier as argument.
"""
@on_dismissed.setter
def on_dismissed(self, handler: Callable[[str], Any] | None) -> None: ...
@property
def on_button_pressed(self) -> Callable[[str, str], Any] | None:
"""
Global callback when notification button is pressed.
Handler receives notification identifier and button identifier as arguments.
"""
@on_button_pressed.setter
def on_button_pressed(self, handler: Callable[[str, str], Any] | None) -> None: ...
@property
def on_replied(self) -> Callable[[str, str], Any] | None:
"""
Global callback when user replies via reply field.
Handler receives notification identifier and reply text as arguments.
"""
@on_replied.setter
def on_replied(self, handler: Callable[[str, str], Any] | None) -> None: ...Synchronous wrapper providing blocking equivalents of all DesktopNotifier methods for use in non-async contexts.
class DesktopNotifierSync:
def __init__(
self,
app_name: str = "Python",
app_icon: Icon | None = DEFAULT_ICON,
notification_limit: int | None = None
) -> None:
"""
Initialize synchronous desktop notifier.
Warning: Callbacks may not work on macOS/Linux without running event loop.
Parameters: Same as DesktopNotifier
"""
# Properties (same as DesktopNotifier)
@property
def app_name(self) -> str: ...
@app_name.setter
def app_name(self, value: str) -> None: ...
@property
def app_icon(self) -> Icon | None: ...
@app_icon.setter
def app_icon(self, value: Icon | None) -> None: ...
# Methods (blocking versions of DesktopNotifier methods)
def request_authorisation(self) -> bool: ...
def has_authorisation(self) -> bool: ...
def send(self, title: str, message: str, **kwargs) -> str: ...
def send_notification(self, notification: Notification) -> str: ...
def get_current_notifications(self) -> list[str]: ...
def clear(self, identifier: str) -> None: ...
def clear_all(self) -> None: ...
def get_capabilities(self) -> frozenset[Capability]: ...
# Global callback properties (same interface as DesktopNotifier)
@property
def on_dispatched(self) -> Callable[[str], Any] | None: ...
@on_dispatched.setter
def on_dispatched(self, handler: Callable[[str], Any] | None) -> None: ...
# ... (all other callback properties same as DesktopNotifier)import asyncio
from desktop_notifier import DesktopNotifier
async def main():
notifier = DesktopNotifier(app_name="My App")
# Check authorization
if not await notifier.has_authorisation():
authorized = await notifier.request_authorisation()
if not authorized:
print("Notification permission denied")
return
# Send notification
notification_id = await notifier.send(
title="Task Complete",
message="Your background task has finished successfully"
)
print(f"Sent notification: {notification_id}")
asyncio.run(main())from desktop_notifier import DesktopNotifierSync
# Create synchronous notifier
notifier = DesktopNotifierSync(app_name="My App")
# Send notification (blocks until complete)
notification_id = notifier.send(
title="Sync Notification",
message="This was sent synchronously"
)
print(f"Sent notification: {notification_id}")import asyncio
import platform
# Required for macOS callback support
if platform.system() == "Darwin":
from rubicon.objc.eventloop import EventLoopPolicy
asyncio.set_event_loop_policy(EventLoopPolicy())
async def main():
notifier = DesktopNotifier(app_name="Event Loop App")
# Set global callbacks
notifier.on_clicked = lambda nid: print(f"Notification {nid} clicked")
notifier.on_dismissed = lambda nid: print(f"Notification {nid} dismissed")
await notifier.send("Test", "Click or dismiss me!")
# Keep event loop running to handle callbacks
await asyncio.sleep(30)
asyncio.run(main())Install with Tessl CLI
npx tessl i tessl/pypi-desktop-notifier