or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-api.mdenums-constants.mdindex.mdnotification-components.mdresources.md

notification-components.mddocs/

0

# Notification Components

1

2

Data classes and types for constructing rich, interactive notifications with buttons, reply fields, media attachments, and custom styling options.

3

4

## Capabilities

5

6

### Notification

7

8

The main data class representing a complete desktop notification with all possible configuration options and interaction handlers.

9

10

```python { .api }

11

@dataclass(frozen=True)

12

class Notification:

13

title: str

14

"""Notification title"""

15

16

message: str

17

"""Notification message body"""

18

19

urgency: Urgency = field(default=Urgency.Normal, repr=False)

20

"""

21

Notification urgency level affecting appearance and behavior.

22

Determines stickiness, visual styling, and ability to break through

23

do-not-disturb settings.

24

"""

25

26

icon: Icon | None = field(default=None, repr=False)

27

"""Custom icon for this notification (overrides app default)"""

28

29

buttons: tuple[Button, ...] = field(default_factory=tuple, repr=False)

30

"""Interactive buttons for user actions (platform limits apply)"""

31

32

buttons_dict: immutabledict[str, Button] = field(

33

default_factory=immutabledict, init=False, repr=False, compare=False

34

)

35

"""Buttons indexed by identifier for lookup (computed automatically)"""

36

37

reply_field: ReplyField | None = field(default=None, repr=False)

38

"""Text input field for user responses"""

39

40

on_dispatched: Callable[[], Any] | None = field(default=None, repr=False)

41

"""Callback when notification is sent to notification server"""

42

43

on_clicked: Callable[[], Any] | None = field(default=None, repr=False)

44

"""Callback when notification body is clicked"""

45

46

on_dismissed: Callable[[], Any] | None = field(default=None, repr=False)

47

"""Callback when notification is dismissed"""

48

49

attachment: Attachment | None = field(default=None, repr=False)

50

"""File attachment displayed as preview (platform-dependent file types)"""

51

52

sound: Sound | None = field(default=None, repr=False)

53

"""Custom sound to play when notification appears"""

54

55

thread: str | None = field(default=None, repr=False)

56

"""

57

Thread identifier for grouping related notifications.

58

Useful for chat apps, email threads, or any sequence of related notifications.

59

"""

60

61

timeout: int = field(default=-1, repr=False)

62

"""

63

Display duration in seconds.

64

-1 uses system default, 0 makes sticky, positive values set timeout.

65

"""

66

67

identifier: str = field(default_factory=uuid_str)

68

"""

69

Unique notification identifier.

70

Generated automatically if not provided, used for callbacks and clearing.

71

"""

72

```

73

74

### Button

75

76

Interactive button component for notifications enabling custom user actions with callback support.

77

78

```python { .api }

79

@dataclass(frozen=True)

80

class Button:

81

title: str

82

"""

83

Localized button text displayed to user.

84

Should be concise and action-oriented (e.g., "Reply", "Mark as Read").

85

"""

86

87

on_pressed: Callable[[], Any] | None = None

88

"""

89

Callback function invoked when button is pressed.

90

Receives no arguments, use closures to capture context.

91

"""

92

93

identifier: str = dataclasses.field(default_factory=uuid_str)

94

"""

95

Unique button identifier for callback routing.

96

Generated automatically if not provided.

97

"""

98

```

99

100

### ReplyField

101

102

Text input field component enabling direct text responses from notifications without opening the main application.

103

104

```python { .api }

105

@dataclass(frozen=True)

106

class ReplyField:

107

title: str = "Reply"

108

"""

109

Title for the reply field itself.

110

On macOS, this becomes the title of the button that reveals the field.

111

"""

112

113

button_title: str = "Send"

114

"""

115

Title of the button that submits the reply text.

116

Should be localized for the target user's language.

117

"""

118

119

on_replied: Callable[[str], Any] | None = None

120

"""

121

Callback function invoked when user submits reply.

122

Receives the reply text as a string argument.

123

"""

124

```

125

126

### Exception Classes

127

128

Exception types for notification authorization and delivery failures.

129

130

```python { .api }

131

class AuthorisationError(Exception):

132

"""

133

Raised when application lacks permission to send notifications.

134

135

Typically occurs on first run before user grants permission,

136

or if user later revokes notification permissions in system settings.

137

"""

138

```

139

140

## Usage Examples

141

142

### Basic Notification Construction

143

144

```python

145

from desktop_notifier import Notification, Urgency, DEFAULT_SOUND

146

147

# Simple notification

148

notification = Notification(

149

title="System Alert",

150

message="Your backup has completed successfully",

151

urgency=Urgency.Normal

152

)

153

154

# Rich notification with all options

155

rich_notification = Notification(

156

title="New Message",

157

message="John Doe: Hey, are you available for a quick call?",

158

urgency=Urgency.Critical,

159

sound=DEFAULT_SOUND,

160

thread="chat_john_doe",

161

timeout=30,

162

on_clicked=lambda: print("User clicked the notification"),

163

on_dismissed=lambda: print("User dismissed the notification")

164

)

165

```

166

167

### Interactive Notifications with Buttons

168

169

```python

170

from desktop_notifier import Notification, Button, Urgency

171

172

def handle_approve():

173

print("User approved the request")

174

# Add approval logic here

175

176

def handle_deny():

177

print("User denied the request")

178

# Add denial logic here

179

180

# Create notification with action buttons

181

notification = Notification(

182

title="Permission Request",

183

message="App wants to access your camera. Allow access?",

184

urgency=Urgency.Critical,

185

buttons=(

186

Button(title="Allow", on_pressed=handle_approve),

187

Button(title="Deny", on_pressed=handle_deny),

188

),

189

timeout=60 # Give user time to respond

190

)

191

```

192

193

### Reply Field for Text Input

194

195

```python

196

from desktop_notifier import Notification, ReplyField, Button

197

198

def handle_reply(reply_text: str):

199

print(f"User replied: {reply_text}")

200

# Process the reply (send to chat, save to database, etc.)

201

202

def handle_mark_read():

203

print("Message marked as read")

204

205

# Notification with reply capability (like messaging apps)

206

message_notification = Notification(

207

title="Sarah Connor",

208

message="The meeting has been moved to 3 PM. Can you make it?",

209

buttons=(

210

Button(title="Mark as Read", on_pressed=handle_mark_read),

211

),

212

reply_field=ReplyField(

213

title="Reply",

214

button_title="Send",

215

on_replied=handle_reply

216

),

217

thread="chat_sarah_connor"

218

)

219

```

220

221

### Notification with Media Attachment

222

223

```python

224

from desktop_notifier import Notification, Attachment

225

from pathlib import Path

226

227

# Notification with image preview

228

image_notification = Notification(

229

title="Photo Shared",

230

message="New photo from your camera roll",

231

attachment=Attachment(path=Path("/path/to/photo.jpg")),

232

on_clicked=lambda: print("User wants to view the photo")

233

)

234

235

# Notification with document attachment

236

document_notification = Notification(

237

title="Document Ready",

238

message="Your report has been generated",

239

attachment=Attachment(uri="file:///path/to/report.pdf")

240

)

241

```

242

243

### Threaded Notifications

244

245

```python

246

from desktop_notifier import DesktopNotifier, Notification

247

import asyncio

248

249

async def send_conversation_notifications():

250

notifier = DesktopNotifier(app_name="Chat App")

251

252

# All notifications with same thread ID will be grouped together

253

thread_id = "conversation_team_alpha"

254

255

await notifier.send_notification(Notification(

256

title="Team Alpha",

257

message="Alice: Has everyone reviewed the proposal?",

258

thread=thread_id

259

))

260

261

await asyncio.sleep(2)

262

263

await notifier.send_notification(Notification(

264

title="Team Alpha",

265

message="Bob: I'm still going through it, need 10 more minutes",

266

thread=thread_id

267

))

268

269

await asyncio.sleep(2)

270

271

await notifier.send_notification(Notification(

272

title="Team Alpha",

273

message="Carol: Looks good to me, just one minor suggestion",

274

thread=thread_id

275

))

276

277

asyncio.run(send_conversation_notifications())

278

```

279

280

### Custom Notification Callbacks

281

282

```python

283

from desktop_notifier import DesktopNotifier, Notification

284

import asyncio

285

286

class NotificationHandler:

287

def __init__(self, app_name: str):

288

self.notifier = DesktopNotifier(app_name=app_name)

289

self.active_notifications = {}

290

291

async def send_with_tracking(self, title: str, message: str):

292

notification = Notification(

293

title=title,

294

message=message,

295

on_dispatched=self.on_notification_sent,

296

on_clicked=self.on_notification_clicked,

297

on_dismissed=self.on_notification_dismissed

298

)

299

300

notification_id = await self.notifier.send_notification(notification)

301

self.active_notifications[notification_id] = {

302

'title': title,

303

'sent_at': asyncio.get_event_loop().time()

304

}

305

return notification_id

306

307

def on_notification_sent(self):

308

print("Notification successfully displayed to user")

309

310

def on_notification_clicked(self):

311

print("User interacted with notification")

312

313

def on_notification_dismissed(self):

314

print("User dismissed notification")

315

316

# Usage

317

async def main():

318

handler = NotificationHandler("Tracking App")

319

await handler.send_with_tracking(

320

"Task Complete",

321

"Your data processing job has finished"

322

)

323

324

asyncio.run(main())

325

```