0
# Error Handling
1
2
Comprehensive exception hierarchy for parsing errors, validation failures, and runtime issues with detailed error reporting. TOML Kit provides specific exceptions for different error conditions to enable precise error handling.
3
4
## Capabilities
5
6
### Base Exception Classes
7
8
Foundation exception classes that other TOML Kit exceptions inherit from.
9
10
```python { .api }
11
class TOMLKitError(Exception):
12
"""Base exception class for all TOML Kit errors."""
13
14
class ParseError(ValueError, TOMLKitError):
15
"""
16
Base class for TOML parsing errors with position information.
17
18
Attributes:
19
- line: Line number where error occurred
20
- col: Column number where error occurred
21
"""
22
23
def __init__(self, line: int, col: int, message: str | None = None) -> None: ...
24
25
@property
26
def line(self) -> int:
27
"""Get the line number of the error."""
28
29
@property
30
def col(self) -> int:
31
"""Get the column number of the error."""
32
```
33
34
### Parsing Error Classes
35
36
Specific exceptions for different TOML syntax and parsing errors.
37
38
```python { .api }
39
class MixedArrayTypesError(ParseError):
40
"""Array contains elements of different types (invalid in TOML)."""
41
42
class InvalidNumberError(ParseError):
43
"""Numeric value has invalid format."""
44
45
class InvalidDateTimeError(ParseError):
46
"""DateTime value has invalid RFC3339 format."""
47
48
class InvalidDateError(ParseError):
49
"""Date value has invalid format (YYYY-MM-DD)."""
50
51
class InvalidTimeError(ParseError):
52
"""Time value has invalid format."""
53
54
class InvalidNumberOrDateError(ParseError):
55
"""Value cannot be parsed as number or date."""
56
57
class InvalidUnicodeValueError(ParseError):
58
"""Unicode escape sequence is invalid."""
59
60
class UnexpectedCharError(ParseError):
61
"""Unexpected character encountered during parsing."""
62
63
def __init__(self, line: int, col: int, char: str) -> None: ...
64
65
class EmptyKeyError(ParseError):
66
"""Key is empty or missing."""
67
68
class EmptyTableNameError(ParseError):
69
"""Table name is empty."""
70
71
class InvalidCharInStringError(ParseError):
72
"""String contains invalid character."""
73
74
def __init__(self, line: int, col: int, char: str) -> None: ...
75
76
class UnexpectedEofError(ParseError):
77
"""File ended unexpectedly during parsing."""
78
79
class InternalParserError(ParseError):
80
"""Internal parser error indicating a bug."""
81
82
class InvalidControlChar(ParseError):
83
"""String contains invalid control character."""
84
85
def __init__(self, line: int, col: int, char: int, type: str) -> None: ...
86
```
87
88
### Runtime Error Classes
89
90
Exceptions that occur during TOML document manipulation and conversion.
91
92
```python { .api }
93
class NonExistentKey(KeyError, TOMLKitError):
94
"""Attempted to access a key that doesn't exist."""
95
96
def __init__(self, key) -> None: ...
97
98
class KeyAlreadyPresent(TOMLKitError):
99
"""Attempted to add a key that already exists."""
100
101
def __init__(self, key) -> None: ...
102
103
class InvalidStringError(ValueError, TOMLKitError):
104
"""String value contains invalid character sequences."""
105
106
def __init__(self, value: str, invalid_sequences: Collection[str], delimiter: str) -> None: ...
107
108
class ConvertError(TypeError, ValueError, TOMLKitError):
109
"""Failed to convert Python value to TOML item."""
110
```
111
112
## Usage Examples
113
114
### Basic Error Handling
115
116
```python
117
import tomlkit
118
from tomlkit.exceptions import ParseError, TOMLKitError
119
120
def safe_parse(content: str):
121
"""Parse TOML with error handling."""
122
try:
123
return tomlkit.parse(content)
124
except ParseError as e:
125
print(f"Parse error at line {e.line}, column {e.col}: {e}")
126
return None
127
except TOMLKitError as e:
128
print(f"TOML Kit error: {e}")
129
return None
130
131
# Valid TOML
132
valid_toml = 'title = "My App"'
133
doc = safe_parse(valid_toml)
134
135
# Invalid TOML - syntax error
136
invalid_toml = 'title = "unclosed string'
137
doc = safe_parse(invalid_toml) # Prints error message
138
```
139
140
### Specific Parse Error Handling
141
142
```python
143
import tomlkit
144
from tomlkit.exceptions import (
145
InvalidNumberError, InvalidDateError, MixedArrayTypesError,
146
UnexpectedCharError, EmptyKeyError
147
)
148
149
def parse_with_specific_handling(content: str):
150
"""Handle specific parsing errors differently."""
151
try:
152
return tomlkit.parse(content)
153
except InvalidNumberError as e:
154
print(f"Invalid number format at line {e.line}: {e}")
155
# Could attempt to fix or provide suggestions
156
except InvalidDateError as e:
157
print(f"Invalid date format at line {e.line}: {e}")
158
# Could suggest correct date format
159
except MixedArrayTypesError as e:
160
print(f"Array has mixed types at line {e.line}: {e}")
161
# Could explain TOML array type rules
162
except UnexpectedCharError as e:
163
print(f"Unexpected character at line {e.line}, col {e.col}: {e}")
164
# Could highlight the problematic character
165
except EmptyKeyError as e:
166
print(f"Empty key at line {e.line}: {e}")
167
# Could suggest key naming rules
168
169
# Test different error types
170
test_cases = [
171
'number = 123.45.67', # InvalidNumberError
172
'date = 2023-13-01', # InvalidDateError
173
'mixed = [1, "text", true]', # MixedArrayTypesError
174
'key = value @', # UnexpectedCharError
175
' = "value"', # EmptyKeyError
176
]
177
178
for i, case in enumerate(test_cases):
179
print(f"\nTest case {i+1}:")
180
parse_with_specific_handling(case)
181
```
182
183
### Runtime Error Handling
184
185
```python
186
import tomlkit
187
from tomlkit.exceptions import NonExistentKey, KeyAlreadyPresent, ConvertError
188
189
def safe_document_operations():
190
"""Demonstrate runtime error handling."""
191
doc = tomlkit.document()
192
193
# Key access errors
194
try:
195
value = doc["nonexistent"]
196
except NonExistentKey as e:
197
print(f"Key error: {e}")
198
199
# Key collision errors
200
doc["title"] = "My App"
201
try:
202
# Attempting to add existing key in certain contexts
203
doc.add("title", "Another Title")
204
except KeyAlreadyPresent as e:
205
print(f"Key already exists: {e}")
206
207
# Conversion errors
208
class CustomObject:
209
pass
210
211
try:
212
doc["custom"] = CustomObject() # Cannot convert to TOML
213
except ConvertError as e:
214
print(f"Conversion error: {e}")
215
216
safe_document_operations()
217
```
218
219
### Error Recovery Strategies
220
221
```python
222
import tomlkit
223
from tomlkit.exceptions import ParseError, InvalidNumberError, InvalidDateError
224
import re
225
226
def parse_with_recovery(content: str):
227
"""Attempt to parse with error recovery strategies."""
228
try:
229
return tomlkit.parse(content)
230
except InvalidNumberError as e:
231
print(f"Attempting to fix number format error at line {e.line}")
232
# Simple recovery: remove extra decimal points
233
lines = content.split('\n')
234
line_content = lines[e.line - 1]
235
236
# Fix common number format issues
237
fixed_line = re.sub(r'(\d+\.\d+)\.\d+', r'\1', line_content)
238
lines[e.line - 1] = fixed_line
239
240
try:
241
return tomlkit.parse('\n'.join(lines))
242
except ParseError:
243
print("Recovery failed")
244
return None
245
246
except InvalidDateError as e:
247
print(f"Attempting to fix date format error at line {e.line}")
248
# Could implement date format corrections
249
return None
250
251
except ParseError as e:
252
print(f"Unrecoverable parse error: {e}")
253
return None
254
255
# Test recovery
256
problematic_toml = '''title = "Test"
257
version = 1.2.3.4
258
date = 2023-01-01'''
259
260
doc = parse_with_recovery(problematic_toml)
261
```
262
263
### Validation with Error Reporting
264
265
```python
266
import tomlkit
267
from tomlkit.exceptions import TOMLKitError
268
from typing import List, Tuple
269
270
def validate_config(content: str) -> Tuple[bool, List[str]]:
271
"""Validate TOML configuration and return errors."""
272
errors = []
273
274
try:
275
doc = tomlkit.parse(content)
276
except ParseError as e:
277
errors.append(f"Syntax error at line {e.line}, col {e.col}: {str(e)}")
278
return False, errors
279
280
# Custom validation rules
281
try:
282
# Check required fields
283
if "title" not in doc:
284
errors.append("Missing required field: title")
285
286
if "version" not in doc:
287
errors.append("Missing required field: version")
288
289
# Validate types
290
if "port" in doc and not isinstance(doc["port"], int):
291
errors.append("Port must be an integer")
292
293
# Validate ranges
294
if "port" in doc and not (1 <= doc["port"] <= 65535):
295
errors.append("Port must be between 1 and 65535")
296
297
except (KeyError, TypeError, ValueError) as e:
298
errors.append(f"Validation error: {e}")
299
300
return len(errors) == 0, errors
301
302
# Test validation
303
configs = [
304
'title = "Valid App"\nversion = "1.0"\nport = 8080',
305
'title = "Invalid App"\nport = "not a number"',
306
'version = "1.0"\nport = 70000', # Missing title, invalid port
307
]
308
309
for i, config in enumerate(configs):
310
valid, errors = validate_config(config)
311
print(f"\nConfig {i+1}: {'Valid' if valid else 'Invalid'}")
312
for error in errors:
313
print(f" - {error}")
314
```
315
316
### Error Logging and Debugging
317
318
```python
319
import tomlkit
320
from tomlkit.exceptions import ParseError, TOMLKitError
321
import logging
322
323
# Set up logging
324
logging.basicConfig(level=logging.INFO)
325
logger = logging.getLogger(__name__)
326
327
def parse_with_logging(content: str, source: str = ""):
328
"""Parse TOML with comprehensive error logging."""
329
try:
330
doc = tomlkit.parse(content)
331
logger.info(f"Successfully parsed TOML from {source}")
332
return doc
333
334
except ParseError as e:
335
# Log detailed parse error information
336
lines = content.split('\n')
337
error_line = lines[e.line - 1] if e.line <= len(lines) else ""
338
339
logger.error(f"Parse error in {source}:")
340
logger.error(f" Line {e.line}, Column {e.col}: {str(e)}")
341
logger.error(f" Content: {error_line}")
342
logger.error(f" Position: {' ' * (e.col - 1)}^")
343
344
# Additional context
345
start_line = max(0, e.line - 3)
346
end_line = min(len(lines), e.line + 2)
347
348
logger.error("Context:")
349
for i in range(start_line, end_line):
350
marker = ">>>" if i == e.line - 1 else " "
351
logger.error(f" {marker} {i+1:3d}: {lines[i]}")
352
353
except TOMLKitError as e:
354
logger.error(f"TOML Kit error in {source}: {str(e)}")
355
356
except Exception as e:
357
logger.error(f"Unexpected error parsing {source}: {str(e)}")
358
359
return None
360
361
# Test with logging
362
test_content = '''title = "Test App"
363
version = 1.0.0
364
invalid_syntax = @#$%
365
host = "localhost"'''
366
367
doc = parse_with_logging(test_content, "test-config.toml")
368
```
369
370
### Exception Hierarchies for Different Handling
371
372
```python
373
import tomlkit
374
from tomlkit.exceptions import *
375
376
def categorized_error_handling(content: str):
377
"""Handle errors by category."""
378
try:
379
return tomlkit.parse(content)
380
381
except (InvalidNumberError, InvalidDateError, InvalidTimeError,
382
InvalidDateTimeError, InvalidNumberOrDateError) as e:
383
# Data format errors - might be recoverable
384
print(f"Data format error: {e}")
385
print("Consider checking date/time/number formats")
386
return None
387
388
except (EmptyKeyError, EmptyTableNameError, InvalidCharInStringError) as e:
389
# Structural errors - usually need manual fix
390
print(f"Structure error: {e}")
391
print("Check TOML syntax and key naming")
392
return None
393
394
except (UnexpectedCharError, UnexpectedEofError) as e:
395
# Syntax errors - need content review
396
print(f"Syntax error: {e}")
397
print("Review TOML syntax")
398
return None
399
400
except ParseError as e:
401
# General parse errors
402
print(f"Parse error: {e}")
403
return None
404
405
except (NonExistentKey, KeyAlreadyPresent) as e:
406
# Runtime errors - programming issues
407
print(f"Runtime error: {e}")
408
return None
409
410
except TOMLKitError as e:
411
# Any other TOML Kit error
412
print(f"TOML Kit error: {e}")
413
return None
414
415
# Test different error categories
416
test_cases = [
417
'date = 2023-99-99', # Data format error
418
' = "empty key"', # Structure error
419
'key = "value" @', # Syntax error
420
]
421
422
for case in test_cases:
423
categorized_error_handling(case)
424
```