0
# File Operations
1
2
High-level interface for reading and writing TOML files with automatic encoding handling and line ending preservation. The TOMLFile class provides a convenient wrapper for file-based TOML operations.
3
4
## Capabilities
5
6
### TOMLFile Class
7
8
A file wrapper that handles TOML document I/O with proper encoding and line ending detection.
9
10
```python { .api }
11
class TOMLFile:
12
"""
13
Represents a TOML file with automatic encoding and line ending handling.
14
"""
15
16
def __init__(self, path: StrPath) -> None:
17
"""
18
Initialize TOMLFile with file path.
19
20
Parameters:
21
- path: File system path (string or PathLike object)
22
"""
23
24
def read(self) -> TOMLDocument:
25
"""
26
Read the file content as a TOMLDocument.
27
28
Returns:
29
TOMLDocument with preserved formatting
30
31
Raises:
32
FileNotFoundError: If file does not exist
33
ParseError: If TOML content is invalid
34
UnicodeDecodeError: If file encoding is invalid
35
"""
36
37
def write(self, data: TOMLDocument) -> None:
38
"""
39
Write TOMLDocument to the file.
40
41
Parameters:
42
- data: TOMLDocument to write
43
44
Raises:
45
PermissionError: If file cannot be written
46
"""
47
```
48
49
## Usage Examples
50
51
### Basic File Operations
52
53
```python
54
import tomlkit
55
from tomlkit.toml_file import TOMLFile
56
57
# Create TOMLFile instance
58
config_file = TOMLFile("config.toml")
59
60
# Read existing file
61
try:
62
config = config_file.read()
63
print(f"Title: {config['title']}")
64
print(f"Version: {config['version']}")
65
except FileNotFoundError:
66
print("Config file not found, creating new one")
67
config = tomlkit.document()
68
69
# Modify configuration
70
config["title"] = "Updated Application"
71
config["version"] = "2.0.0"
72
config["last_modified"] = tomlkit.datetime("2023-06-15T10:30:00Z")
73
74
# Write back to file
75
config_file.write(config)
76
```
77
78
### Line Ending Preservation
79
80
```python
81
import tomlkit
82
from tomlkit.toml_file import TOMLFile
83
84
# TOMLFile automatically detects and preserves line endings
85
config_file = TOMLFile("config.toml")
86
87
# Read file (line endings detected automatically)
88
config = config_file.read()
89
90
# Modify content
91
config["new_setting"] = "value"
92
93
# Write preserves original line endings
94
# - Windows files keep \r\n
95
# - Unix files keep \n
96
# - Mixed files are handled appropriately
97
config_file.write(config)
98
```
99
100
### Configuration Management
101
102
```python
103
import tomlkit
104
from tomlkit.toml_file import TOMLFile
105
from pathlib import Path
106
107
def load_config(config_path: str = "app.toml") -> tomlkit.TOMLDocument:
108
"""Load configuration with defaults."""
109
config_file = TOMLFile(config_path)
110
111
try:
112
return config_file.read()
113
except FileNotFoundError:
114
# Create default configuration
115
config = tomlkit.document()
116
config["app"] = {
117
"name": "MyApp",
118
"version": "1.0.0",
119
"debug": False
120
}
121
config["server"] = {
122
"host": "localhost",
123
"port": 8080,
124
"workers": 1
125
}
126
config["database"] = {
127
"url": "sqlite:///app.db",
128
"echo": False
129
}
130
131
# Save default config
132
config_file.write(config)
133
return config
134
135
def update_config(updates: dict, config_path: str = "app.toml"):
136
"""Update configuration file with new values."""
137
config_file = TOMLFile(config_path)
138
config = config_file.read()
139
140
# Apply updates while preserving structure
141
for key, value in updates.items():
142
if "." in key:
143
# Handle nested keys like "server.port"
144
parts = key.split(".")
145
current = config
146
for part in parts[:-1]:
147
if part not in current:
148
current[part] = tomlkit.table()
149
current = current[part]
150
current[parts[-1]] = value
151
else:
152
config[key] = value
153
154
config_file.write(config)
155
156
# Usage
157
config = load_config()
158
update_config({
159
"server.port": 9000,
160
"app.debug": True,
161
"new_feature.enabled": True
162
})
163
```
164
165
### Backup and Rotation
166
167
```python
168
import tomlkit
169
from tomlkit.toml_file import TOMLFile
170
from pathlib import Path
171
import shutil
172
from datetime import datetime
173
174
class TOMLFileManager:
175
"""Enhanced TOML file operations with backup support."""
176
177
def __init__(self, path: str):
178
self.file = TOMLFile(path)
179
self.path = Path(path)
180
181
def read_with_backup(self) -> tomlkit.TOMLDocument:
182
"""Read file, creating backup first."""
183
if self.path.exists():
184
backup_path = self.path.with_suffix('.toml.bak')
185
shutil.copy2(self.path, backup_path)
186
187
return self.file.read()
188
189
def safe_write(self, data: tomlkit.TOMLDocument):
190
"""Write with temporary file for atomicity."""
191
temp_path = self.path.with_suffix('.toml.tmp')
192
temp_file = TOMLFile(temp_path)
193
194
try:
195
# Write to temporary file first
196
temp_file.write(data)
197
198
# Atomic rename
199
temp_path.replace(self.path)
200
except Exception:
201
# Clean up temp file on error
202
if temp_path.exists():
203
temp_path.unlink()
204
raise
205
206
def rotate_backups(self, keep: int = 5):
207
"""Keep only the most recent backup files."""
208
backup_pattern = f"{self.path.stem}.toml.bak*"
209
backups = sorted(
210
self.path.parent.glob(backup_pattern),
211
key=lambda p: p.stat().st_mtime,
212
reverse=True
213
)
214
215
# Remove old backups
216
for backup in backups[keep:]:
217
backup.unlink()
218
219
# Usage
220
config_mgr = TOMLFileManager("important-config.toml")
221
222
# Safe operations
223
config = config_mgr.read_with_backup()
224
config["last_backup"] = tomlkit.datetime(datetime.now().isoformat())
225
config_mgr.safe_write(config)
226
config_mgr.rotate_backups(keep=3)
227
```
228
229
### Multi-file Configuration
230
231
```python
232
import tomlkit
233
from tomlkit.toml_file import TOMLFile
234
from pathlib import Path
235
from typing import Dict, Any
236
237
class ConfigSet:
238
"""Manage multiple related TOML configuration files."""
239
240
def __init__(self, config_dir: str):
241
self.config_dir = Path(config_dir)
242
self.config_dir.mkdir(exist_ok=True)
243
244
def load_all(self) -> Dict[str, tomlkit.TOMLDocument]:
245
"""Load all TOML files in the configuration directory."""
246
configs = {}
247
for toml_file in self.config_dir.glob("*.toml"):
248
name = toml_file.stem
249
file_obj = TOMLFile(toml_file)
250
try:
251
configs[name] = file_obj.read()
252
except Exception as e:
253
print(f"Error loading {name}: {e}")
254
return configs
255
256
def save_config(self, name: str, config: tomlkit.TOMLDocument):
257
"""Save a configuration file."""
258
file_path = self.config_dir / f"{name}.toml"
259
config_file = TOMLFile(file_path)
260
config_file.write(config)
261
262
def merge_configs(self) -> tomlkit.TOMLDocument:
263
"""Merge all configuration files into one document."""
264
merged = tomlkit.document()
265
configs = self.load_all()
266
267
for name, config in configs.items():
268
merged[name] = config
269
270
return merged
271
272
# Usage
273
config_set = ConfigSet("./configs/")
274
275
# Create individual config files
276
app_config = tomlkit.document()
277
app_config["name"] = "MyApp"
278
app_config["version"] = "1.0.0"
279
280
db_config = tomlkit.document()
281
db_config["host"] = "localhost"
282
db_config["port"] = 5432
283
284
config_set.save_config("app", app_config)
285
config_set.save_config("database", db_config)
286
287
# Load and work with all configs
288
all_configs = config_set.load_all()
289
merged_config = config_set.merge_configs()
290
```
291
292
### Error Handling
293
294
```python
295
import tomlkit
296
from tomlkit.toml_file import TOMLFile
297
from tomlkit.exceptions import ParseError
298
import logging
299
300
def robust_config_read(file_path: str) -> tomlkit.TOMLDocument:
301
"""Read TOML config with comprehensive error handling."""
302
config_file = TOMLFile(file_path)
303
304
try:
305
return config_file.read()
306
except FileNotFoundError:
307
logging.warning(f"Config file {file_path} not found, using defaults")
308
return create_default_config()
309
except ParseError as e:
310
logging.error(f"Invalid TOML syntax in {file_path}: {e}")
311
# Could prompt user or try to recover
312
raise
313
except PermissionError:
314
logging.error(f"Permission denied reading {file_path}")
315
raise
316
except UnicodeDecodeError as e:
317
logging.error(f"Encoding error in {file_path}: {e}")
318
# Could try different encodings
319
raise
320
321
def create_default_config() -> tomlkit.TOMLDocument:
322
"""Create a default configuration."""
323
config = tomlkit.document()
324
config["app"] = {"name": "DefaultApp", "version": "1.0.0"}
325
return config
326
327
# Usage with error handling
328
try:
329
config = robust_config_read("my-config.toml")
330
print("Configuration loaded successfully")
331
except Exception as e:
332
print(f"Failed to load configuration: {e}")
333
config = create_default_config()
334
```