Desktop Notifications¶
nv.Desktop.notify(title, body) raises an operating-system notification — the kind
that appears in the corner of the screen and lands in the notification center.
It exists for one job: telling the user that something finished while they
were in another window.
nv.Desktop.notify("Import done") # title only
nv.Desktop.notify("Import done", "1,000 rows written") # title + body
The runnable demo is at
samples/window/desktop_notifications.py.
Desktop.notify is fire-and-forget¶
- It never blocks. It returns in milliseconds; the notification appears on
its own a moment later. There is nothing to
await. - It never raises. A platform that cannot show the notification logs the failure once and moves on — a notification is a courtesy, and it must not take the app down. There is no return value to check.
- It is safe from any thread. Call it from an event handler or straight from the worker thread that just finished its job — no marshalling to the UI thread is needed. This is the natural last line of a long job wired up as in Background Work.
Delivery is best-effort even when everything works: the OS may still suppress the notification (Do Not Disturb / Focus modes, per-app notification settings), silently. Never make a notification the only way the user learns something — keep the result visible in the app too.
What the notification looks like¶
Run from source (python app.py), the notification carries a borrowed
identity — the OS attributes it to the helper that raised it, not to your app:
- macOS — delivered via
osascript, attributed to Script Editor. The helper process adds a fraction of a second before the banner appears. - Windows — shown as a regular toast through a transient notification-area icon; the icon appears while the toast is up and disappears when it closes. The attribution line shows the notification's own title.
- Linux — delivered via
notify-send, which most desktops show without any attribution line.
A packaged app does better on macOS. Inside a signed .app bundle with a
bundle identifier, notifications go through the native notification center
in-process: your app's own name and icon, instant delivery, and the app gets
its own row in System Settings → Notifications. The first notification asks
the user for permission; if they decline, later calls are silently ignored
(see above — never rely on delivery). None of this needs code changes — the
same nv.Desktop.notify call upgrades itself when a bundle identifier is
present. macOS App Identity shows the
build flags that produce such a bundle.
If nothing appears on Linux¶
Notifications are delivered by notify-send. Most desktop distributions ship
it; on a minimal install, add the libnotify package (libnotify-bin on
Debian/Ubuntu). Without it every nv.Desktop.notify call is a logged no-op —
the app keeps running.