Source code for polymerist.genutils.fileutils.jsonio.update

'''Tools for statically or dynamically updating JSON files'''

__author__ = 'Timotej Bernat'
__email__ = 'timotej.bernat@colorado.edu'

import json
from pathlib import Path

from .serialize import JSONSerializable
from ..pathutils import allow_string_paths


[docs] @allow_string_paths def append_to_json(json_path : Path, **kwargs) -> None: '''Add an entry to an existing JSON file''' with json_path.open('r') as json_file: jdat = json.load(json_file) jdat.update(**kwargs) with json_path.open('w') as json_file: jdat = json.dump(jdat, json_file, indent=4)
# DEVNOTE: consider replacing with synched_collections JSON utils? # https://github.com/glotzerlab/synced_collections/blob/main/synced_collections/backends/collection_json.py
[docs] class JSONDict(dict): # TODO : add allow_str_path decorators '''Dict subclass which also updates an underlying JSON file - effectively and on-disc dict !NOTE! - JSON doesn't support non-string keys, so all keys given will be stringified - plan accordingly!''' def __init__(self, json_path : Path, *args, **kwargs): if isinstance(json_path, str): json_path = Path(json_path) # make input arg a bit more flexible to str input from user end if json_path.suffix != '.json': raise ValueError(f'The path "{json_path}" does not point to a .json file') self.json_path : Path = json_path if self.json_path.exists(): try: kwargs.update(self._read_file(json_path)) except json.JSONDecodeError: # catches Paths which point to incorrectly formatted JSONs - TODO: revise terrible except-pass structure pass else: self.json_path.touch() super().__init__(*args, **kwargs) self._update_file() # ensure file contains current contents post-init @staticmethod def _read_file(json_path : Path) -> dict: with json_path.open('r') as file: return json.load(file) def _update_file(self, indent : int=4): '''Save current dict contents to JSON file''' with self.json_path.open('w') as file: json.dump(self, file, indent=indent) def __setitem__(self, __key: str, __value: JSONSerializable) -> None: super().__setitem__(__key, __value) self._update_file() def __delitem__(self, __key: str) -> None: super().__delitem__(__key) self._update_file()