0
# Error Handling
1
2
The `gntp.errors` module provides a comprehensive exception hierarchy for handling all GNTP-related error conditions. These exceptions are raised by all GNTP operations and provide detailed error information with appropriate error codes.
3
4
## Exception Hierarchy
5
6
All GNTP exceptions inherit from a common base class and include error codes that correspond to GNTP protocol error codes.
7
8
```python { .api }
9
class BaseError(Exception):
10
"""
11
Base exception class for all GNTP errors.
12
13
All GNTP exceptions inherit from this class.
14
"""
15
16
class ParseError(BaseError):
17
"""
18
Error parsing GNTP message.
19
20
Raised when GNTP message format is invalid, required headers are missing,
21
or message structure cannot be understood.
22
23
Attributes:
24
- errorcode (int): 500 (Internal Server Error)
25
- errordesc (str): 'Error parsing the message'
26
"""
27
28
class AuthError(BaseError):
29
"""
30
Error with GNTP authentication.
31
32
Raised when password is incorrect, missing when required, or hash
33
validation fails.
34
35
Attributes:
36
- errorcode (int): 400 (Bad Request)
37
- errordesc (str): 'Error with authorization'
38
"""
39
40
class UnsupportedError(BaseError):
41
"""
42
Currently unsupported operation or feature.
43
44
Raised when attempting to use unsupported hash algorithms, protocol
45
features, or operations not implemented in gntp.py.
46
47
Attributes:
48
- errorcode (int): 500 (Internal Server Error)
49
- errordesc (str): 'Currently unsupported by gntp.py'
50
"""
51
52
class NetworkError(BaseError):
53
"""
54
Error connecting to Growl server.
55
56
Raised when socket connection fails, server is unreachable, connection
57
times out, or other network-related issues occur.
58
59
Attributes:
60
- errorcode (int): 500 (Internal Server Error)
61
- errordesc (str): 'Error connecting to growl server'
62
"""
63
```
64
65
## Usage Examples
66
67
### Basic Error Handling
68
69
```python
70
import gntp.notifier
71
import gntp.errors
72
73
try:
74
growl = gntp.notifier.GrowlNotifier(hostname="unreachable-server.com")
75
growl.register()
76
growl.notify("Test", "Title", "Message")
77
78
except gntp.errors.NetworkError as e:
79
print(f"Cannot connect to Growl server: {e}")
80
print(f"Error code: {e.errorcode}")
81
82
except gntp.errors.AuthError as e:
83
print(f"Authentication failed: {e}")
84
print(f"Error code: {e.errorcode}")
85
86
except gntp.errors.ParseError as e:
87
print(f"Invalid response from server: {e}")
88
print(f"Error code: {e.errorcode}")
89
90
except gntp.errors.BaseError as e:
91
print(f"GNTP error: {e}")
92
print(f"Error code: {e.errorcode}")
93
```
94
95
### Specific Error Scenarios
96
97
#### Network Connectivity Issues
98
99
```python
100
import gntp.notifier
101
import gntp.errors
102
103
def send_notification_with_retry(message, max_retries=3):
104
for attempt in range(max_retries):
105
try:
106
growl = gntp.notifier.GrowlNotifier(
107
hostname="growl.company.com",
108
socketTimeout=5 # 5 second timeout
109
)
110
growl.register()
111
return growl.notify("Alert", "Status", message)
112
113
except gntp.errors.NetworkError as e:
114
print(f"Attempt {attempt + 1} failed: {e}")
115
if attempt == max_retries - 1:
116
print("All retry attempts failed")
117
raise
118
time.sleep(2 ** attempt) # Exponential backoff
119
```
120
121
#### Authentication Problems
122
123
```python
124
import gntp.notifier
125
import gntp.errors
126
127
def authenticate_with_fallback(app_name, message):
128
passwords = ["primary-password", "backup-password", None]
129
130
for password in passwords:
131
try:
132
growl = gntp.notifier.GrowlNotifier(
133
applicationName=app_name,
134
password=password
135
)
136
growl.register()
137
return growl.notify("Message", "Title", message)
138
139
except gntp.errors.AuthError:
140
if password is None:
141
print("All authentication methods failed")
142
raise
143
print(f"Password '{password}' failed, trying next...")
144
continue
145
```
146
147
#### Message Parsing Issues
148
149
```python
150
import gntp.core
151
import gntp.errors
152
153
def parse_server_response(raw_data):
154
try:
155
response = gntp.core.parse_gntp(raw_data)
156
return response
157
158
except gntp.errors.ParseError as e:
159
print(f"Cannot parse server response: {e}")
160
print(f"Raw data: {raw_data[:100]}...") # First 100 chars
161
162
# Try to extract any readable information
163
if b'GNTP/' in raw_data:
164
print("Response appears to be GNTP format but invalid")
165
else:
166
print("Response does not appear to be GNTP format")
167
168
raise
169
```
170
171
#### Unsupported Features
172
173
```python
174
import gntp.core
175
import gntp.errors
176
177
def create_secure_message(title, description):
178
try:
179
notice = gntp.core.GNTPNotice(title=title)
180
notice.add_header('Notification-Text', description)
181
182
# Try to use most secure hash algorithm
183
notice.set_password("secure-password", "SHA512")
184
return notice
185
186
except gntp.errors.UnsupportedError as e:
187
print(f"SHA512 not supported: {e}")
188
189
# Fall back to supported algorithm
190
notice.set_password("secure-password", "SHA256")
191
return notice
192
```
193
194
### Comprehensive Error Handling Strategy
195
196
```python
197
import gntp.notifier
198
import gntp.errors
199
import logging
200
201
class NotificationService:
202
def __init__(self, hostname="localhost", password=None):
203
self.hostname = hostname
204
self.password = password
205
self.logger = logging.getLogger(__name__)
206
207
def send_notification(self, title, message, priority=0):
208
"""Send notification with comprehensive error handling."""
209
210
try:
211
growl = gntp.notifier.GrowlNotifier(
212
applicationName="Notification Service",
213
notifications=["Alert", "Info", "Warning"],
214
hostname=self.hostname,
215
password=self.password
216
)
217
218
# Try to register
219
result = growl.register()
220
if result is not True:
221
self.logger.error(f"Registration failed: {result}")
222
return False
223
224
# Send notification
225
result = growl.notify("Alert", title, message, priority=priority)
226
if result is not True:
227
self.logger.error(f"Notification failed: {result}")
228
return False
229
230
self.logger.info("Notification sent successfully")
231
return True
232
233
except gntp.errors.NetworkError as e:
234
self.logger.error(f"Network error connecting to {self.hostname}: {e}")
235
return False
236
237
except gntp.errors.AuthError as e:
238
self.logger.error(f"Authentication failed: {e}")
239
return False
240
241
except gntp.errors.ParseError as e:
242
self.logger.error(f"Server response parsing failed: {e}")
243
return False
244
245
except gntp.errors.UnsupportedError as e:
246
self.logger.error(f"Unsupported operation: {e}")
247
return False
248
249
except gntp.errors.BaseError as e:
250
self.logger.error(f"Unexpected GNTP error: {e}")
251
return False
252
253
except Exception as e:
254
self.logger.error(f"Unexpected system error: {e}")
255
return False
256
257
# Usage
258
service = NotificationService("growl.company.com", "password123")
259
success = service.send_notification("Build Failed", "Unit tests failed", priority=2)
260
```
261
262
### Error Logging and Monitoring
263
264
```python
265
import gntp.notifier
266
import gntp.errors
267
import logging
268
import json
269
from datetime import datetime
270
271
def log_gntp_error(error, context=None):
272
"""Log GNTP errors with structured information."""
273
274
error_info = {
275
"timestamp": datetime.utcnow().isoformat(),
276
"error_type": type(error).__name__,
277
"error_code": getattr(error, 'errorcode', None),
278
"error_description": getattr(error, 'errordesc', None),
279
"error_message": str(error),
280
"context": context or {}
281
}
282
283
logging.error("GNTP Error: %s", json.dumps(error_info))
284
285
# Usage example
286
try:
287
gntp.notifier.mini("Test message", hostname="bad-server")
288
except gntp.errors.NetworkError as e:
289
log_gntp_error(e, {
290
"operation": "send_notification",
291
"hostname": "bad-server",
292
"message": "Test message"
293
})
294
```
295
296
## Error Recovery Patterns
297
298
### Graceful Degradation
299
300
```python
301
import gntp.notifier
302
import gntp.errors
303
import sys
304
305
def notify_with_fallback(message, title="Notification"):
306
"""Try Growl notification, fall back to console if it fails."""
307
308
try:
309
gntp.notifier.mini(message, title=title)
310
return "growl"
311
312
except gntp.errors.BaseError as e:
313
# Growl failed, fall back to console output
314
print(f"NOTIFICATION: {title} - {message}")
315
return "console"
316
```
317
318
### Circuit Breaker Pattern
319
320
```python
321
import gntp.notifier
322
import gntp.errors
323
import time
324
325
class GrowlCircuitBreaker:
326
def __init__(self, failure_threshold=5, timeout=60):
327
self.failure_threshold = failure_threshold
328
self.timeout = timeout
329
self.failure_count = 0
330
self.last_failure_time = None
331
self.state = "CLOSED" # CLOSED, OPEN, HALF_OPEN
332
333
def send_notification(self, message, **kwargs):
334
if self.state == "OPEN":
335
if time.time() - self.last_failure_time > self.timeout:
336
self.state = "HALF_OPEN"
337
else:
338
raise gntp.errors.NetworkError("Circuit breaker is OPEN")
339
340
try:
341
result = gntp.notifier.mini(message, **kwargs)
342
343
# Success - reset circuit breaker
344
self.failure_count = 0
345
self.state = "CLOSED"
346
return result
347
348
except gntp.errors.BaseError as e:
349
self.failure_count += 1
350
self.last_failure_time = time.time()
351
352
if self.failure_count >= self.failure_threshold:
353
self.state = "OPEN"
354
355
raise
356
```
357
358
## Error Codes Reference
359
360
| Exception | Error Code | Description | Common Causes |
361
|-----------|------------|-------------|---------------|
362
| `AuthError` | 400 | Bad Request | Wrong password, missing authentication |
363
| `ParseError` | 500 | Internal Server Error | Invalid message format, missing headers |
364
| `UnsupportedError` | 500 | Internal Server Error | Unsupported hash algorithm, unimplemented feature |
365
| `NetworkError` | 500 | Internal Server Error | Connection refused, timeout, network unreachable |
366
367
These error codes correspond to GNTP protocol error codes and can be used for protocol-level error handling and server implementation.