config2py 0.1.43__tar.gz → 0.1.44__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {config2py-0.1.43 → config2py-0.1.44}/PKG-INFO +1 -1
- {config2py-0.1.43 → config2py-0.1.44}/config2py/sync_store.py +61 -7
- {config2py-0.1.43 → config2py-0.1.44}/config2py.egg-info/PKG-INFO +1 -1
- {config2py-0.1.43 → config2py-0.1.44}/setup.cfg +1 -1
- {config2py-0.1.43 → config2py-0.1.44}/LICENSE +0 -0
- {config2py-0.1.43 → config2py-0.1.44}/README.md +0 -0
- {config2py-0.1.43 → config2py-0.1.44}/config2py/__init__.py +0 -0
- {config2py-0.1.43 → config2py-0.1.44}/config2py/base.py +0 -0
- {config2py-0.1.43 → config2py-0.1.44}/config2py/errors.py +0 -0
- {config2py-0.1.43 → config2py-0.1.44}/config2py/s_configparser.py +0 -0
- {config2py-0.1.43 → config2py-0.1.44}/config2py/scrap/__init__.py +0 -0
- {config2py-0.1.43 → config2py-0.1.44}/config2py/tests/__init__.py +0 -0
- {config2py-0.1.43 → config2py-0.1.44}/config2py/tests/test_sync_store.py +0 -0
- {config2py-0.1.43 → config2py-0.1.44}/config2py/tests/test_tools.py +0 -0
- {config2py-0.1.43 → config2py-0.1.44}/config2py/tests/utils_for_testing.py +0 -0
- {config2py-0.1.43 → config2py-0.1.44}/config2py/tools.py +0 -0
- {config2py-0.1.43 → config2py-0.1.44}/config2py/util.py +0 -0
- {config2py-0.1.43 → config2py-0.1.44}/config2py.egg-info/SOURCES.txt +0 -0
- {config2py-0.1.43 → config2py-0.1.44}/config2py.egg-info/dependency_links.txt +0 -0
- {config2py-0.1.43 → config2py-0.1.44}/config2py.egg-info/not-zip-safe +0 -0
- {config2py-0.1.43 → config2py-0.1.44}/config2py.egg-info/requires.txt +0 -0
- {config2py-0.1.43 → config2py-0.1.44}/config2py.egg-info/top_level.txt +0 -0
- {config2py-0.1.43 → config2py-0.1.44}/setup.py +0 -0
|
@@ -266,21 +266,38 @@ class FileStore(SyncStore):
|
|
|
266
266
|
dumper: Optional custom dumper (auto-detected from extension if not provided)
|
|
267
267
|
mode: File read mode ('r' for text, 'rb' for binary)
|
|
268
268
|
dump_kwargs: Additional kwargs for dumper
|
|
269
|
+
create_file_content: Optional factory callable that returns initial dict content
|
|
270
|
+
for missing files. If None, FileNotFoundError is raised for missing files.
|
|
271
|
+
create_key_path_content: Optional factory callable that returns initial content
|
|
272
|
+
for missing key_path. If None, KeyError is raised for missing key paths.
|
|
269
273
|
|
|
270
274
|
Example:
|
|
271
275
|
>>> import tempfile
|
|
276
|
+
>>> import os
|
|
277
|
+
>>>
|
|
278
|
+
>>> # Basic usage with existing file
|
|
272
279
|
>>> with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
|
|
273
280
|
... _ = f.write('{"section": {"key": "value"}}')
|
|
274
281
|
... temp_file = f.name
|
|
275
282
|
>>>
|
|
276
|
-
>>> # Work with nested section
|
|
277
283
|
>>> section = FileStore(temp_file, key_path='section')
|
|
278
284
|
>>> section['key']
|
|
279
285
|
'value'
|
|
280
286
|
>>> section['new'] = 'data'
|
|
281
|
-
>>>
|
|
282
|
-
>>> import os
|
|
283
287
|
>>> os.unlink(temp_file)
|
|
288
|
+
>>>
|
|
289
|
+
>>> # Auto-create missing file and key_path
|
|
290
|
+
>>> with tempfile.TemporaryDirectory() as tmpdir:
|
|
291
|
+
... new_file = os.path.join(tmpdir, 'config.json')
|
|
292
|
+
... store = FileStore(
|
|
293
|
+
... new_file,
|
|
294
|
+
... key_path='servers',
|
|
295
|
+
... create_file_content=lambda: {},
|
|
296
|
+
... create_key_path_content=lambda: {}
|
|
297
|
+
... )
|
|
298
|
+
... store['myserver'] = {'command': 'python'}
|
|
299
|
+
... 'myserver' in store
|
|
300
|
+
True
|
|
284
301
|
"""
|
|
285
302
|
|
|
286
303
|
def __init__(
|
|
@@ -292,11 +309,15 @@ class FileStore(SyncStore):
|
|
|
292
309
|
dumper: Optional[Callable[[dict], str]] = None,
|
|
293
310
|
mode: str = "r",
|
|
294
311
|
dump_kwargs: Optional[dict] = None,
|
|
312
|
+
create_file_content: Optional[Callable[[], dict]] = None,
|
|
313
|
+
create_key_path_content: Optional[Callable[[], Any]] = None,
|
|
295
314
|
):
|
|
296
315
|
self.filepath = Path(filepath).expanduser()
|
|
297
316
|
self.key_path = _normalize_key_path(key_path)
|
|
298
317
|
self.mode = mode
|
|
299
318
|
self.dump_kwargs = dump_kwargs or {}
|
|
319
|
+
self.create_file_content = create_file_content
|
|
320
|
+
self.create_key_path_content = create_key_path_content
|
|
300
321
|
|
|
301
322
|
# Auto-detect format if not provided
|
|
302
323
|
if loader is None or dumper is None:
|
|
@@ -318,10 +339,43 @@ class FileStore(SyncStore):
|
|
|
318
339
|
|
|
319
340
|
def _load_from_file(self) -> dict:
|
|
320
341
|
"""Read and parse file, returning the section specified by key_path."""
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
342
|
+
# Handle missing file
|
|
343
|
+
if not self.filepath.exists():
|
|
344
|
+
if self.create_file_content is None:
|
|
345
|
+
raise FileNotFoundError(f"File not found: {self.filepath}")
|
|
346
|
+
|
|
347
|
+
# Create file with initial content
|
|
348
|
+
initial_data = self.create_file_content()
|
|
349
|
+
self.filepath.parent.mkdir(parents=True, exist_ok=True)
|
|
350
|
+
content = self._file_dumper(initial_data, **self.dump_kwargs)
|
|
351
|
+
write_mode = "w" if "b" not in self.mode else "wb"
|
|
352
|
+
with open(self.filepath, write_mode) as f:
|
|
353
|
+
f.write(content)
|
|
354
|
+
data = initial_data
|
|
355
|
+
else:
|
|
356
|
+
# Load existing file
|
|
357
|
+
with open(self.filepath, self.mode) as f:
|
|
358
|
+
content = f.read()
|
|
359
|
+
data = self._file_loader(content)
|
|
360
|
+
|
|
361
|
+
# Handle missing key_path
|
|
362
|
+
try:
|
|
363
|
+
return _get_nested(data, self.key_path)
|
|
364
|
+
except (KeyError, TypeError):
|
|
365
|
+
if self.create_key_path_content is None:
|
|
366
|
+
raise KeyError(f"Key path not found: {self.key_path}")
|
|
367
|
+
|
|
368
|
+
# Create key_path with initial content
|
|
369
|
+
initial_content = self.create_key_path_content()
|
|
370
|
+
full_data = _set_nested(data, self.key_path, initial_content)
|
|
371
|
+
|
|
372
|
+
# Write back to file
|
|
373
|
+
content = self._file_dumper(full_data, **self.dump_kwargs)
|
|
374
|
+
write_mode = "w" if "b" not in self.mode else "wb"
|
|
375
|
+
with open(self.filepath, write_mode) as f:
|
|
376
|
+
f.write(content)
|
|
377
|
+
|
|
378
|
+
return initial_content
|
|
325
379
|
|
|
326
380
|
def _dump_to_file(self, section_data: dict) -> None:
|
|
327
381
|
"""Write data to file, updating only the section specified by key_path."""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|