Change json and toml file API
This commit is contained in:
parent
862a9c1683
commit
c7f7697f66
2 changed files with 64 additions and 30 deletions
|
|
@ -1,12 +1,28 @@
|
||||||
from typing import Self
|
|
||||||
import json
|
import json
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Any
|
from typing import Any, Self
|
||||||
|
|
||||||
from .file import TAG, File
|
from .file import TAG, File
|
||||||
from .text import TextFile
|
from .text import TextFile
|
||||||
|
|
||||||
|
|
||||||
|
def _merge_values(a: Any, b: Any) -> Any:
|
||||||
|
if not isinstance(a, dict) or not isinstance(b, dict):
|
||||||
|
return b
|
||||||
|
|
||||||
|
result = {}
|
||||||
|
for k, v_a in a.items():
|
||||||
|
result[k] = v_a
|
||||||
|
for k, v_b in b.items():
|
||||||
|
v_a = a.get(k)
|
||||||
|
if v_a is None:
|
||||||
|
result[k] = v_b
|
||||||
|
else:
|
||||||
|
result[k] = _merge_values(v_a, v_b)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class JsonFileProxy:
|
class JsonFileProxy:
|
||||||
file: "JsonFile"
|
file: "JsonFile"
|
||||||
|
|
@ -15,18 +31,14 @@ class JsonFileProxy:
|
||||||
def at(self, *path: str) -> Self:
|
def at(self, *path: str) -> Self:
|
||||||
return JsonFileProxy(self.file, self.path + path)
|
return JsonFileProxy(self.file, self.path + path)
|
||||||
|
|
||||||
def set(self, value: Any) -> None:
|
def set(self, path: str | tuple[str, ...], value: Any) -> None:
|
||||||
if not self.path:
|
if isinstance(path, str):
|
||||||
self.file.set(value)
|
path = (path,)
|
||||||
|
|
||||||
data = self.file.data
|
self.file.set(self.path + path, value)
|
||||||
*parts, last = self.path
|
|
||||||
for part in parts:
|
|
||||||
data = data.setdefault(part, {})
|
|
||||||
data[last] = value
|
|
||||||
|
|
||||||
def tag_here(self, tag: str = TAG) -> None:
|
def tag(self, path: str | tuple[str, ...] = "_tag") -> None:
|
||||||
self.set(tag)
|
self.set(path, TAG)
|
||||||
|
|
||||||
|
|
||||||
class JsonFile(File):
|
class JsonFile(File):
|
||||||
|
|
@ -36,13 +48,32 @@ class JsonFile(File):
|
||||||
def at(self, *path: str) -> JsonFileProxy:
|
def at(self, *path: str) -> JsonFileProxy:
|
||||||
return JsonFileProxy(self, path)
|
return JsonFileProxy(self, path)
|
||||||
|
|
||||||
def set(self, value: Any) -> None:
|
def get(self, path: str | tuple[str, ...]) -> Any:
|
||||||
self.data = value
|
data = self.data
|
||||||
|
for part in path:
|
||||||
|
data = data[part]
|
||||||
|
return data
|
||||||
|
|
||||||
def tag(self, tag: str = TAG, key: str | list[str] = "_tag") -> None:
|
def set(self, path: str | tuple[str, ...], value: Any) -> None:
|
||||||
if isinstance(key, str):
|
if isinstance(path, str):
|
||||||
self.at(key).tag_here(tag=tag)
|
path = (path,)
|
||||||
self.at(*key).tag_here(tag=tag)
|
|
||||||
|
if not path:
|
||||||
|
self.data = value
|
||||||
|
return
|
||||||
|
|
||||||
|
*parts, last = path
|
||||||
|
|
||||||
|
data = self.data
|
||||||
|
for part in parts:
|
||||||
|
data = data.setdefault(part, {})
|
||||||
|
data[last] = value
|
||||||
|
|
||||||
|
def merge(self, path: str | tuple[str, ...], value: Any) -> None:
|
||||||
|
self.set(path, _merge_values(self.get(path), value))
|
||||||
|
|
||||||
|
def tag(self, path: str | tuple[str, ...] = "_tag") -> None:
|
||||||
|
self.set(path, TAG)
|
||||||
|
|
||||||
def to_text(self) -> TextFile:
|
def to_text(self) -> TextFile:
|
||||||
return TextFile(json.dumps(self.data))
|
return TextFile(json.dumps(self.data))
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ from typing import Any, Self
|
||||||
import toml
|
import toml
|
||||||
|
|
||||||
from .file import File
|
from .file import File
|
||||||
|
from .json import JsonFile
|
||||||
from .text import TextFile
|
from .text import TextFile
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -15,31 +16,33 @@ class TomlFileProxy:
|
||||||
def at(self, *path: str) -> Self:
|
def at(self, *path: str) -> Self:
|
||||||
return TomlFileProxy(self.file, self.path + path)
|
return TomlFileProxy(self.file, self.path + path)
|
||||||
|
|
||||||
def set(self, value: Any) -> None:
|
def set(self, path: str | tuple[str, ...], value: Any) -> None:
|
||||||
if not self.path:
|
if isinstance(path, str):
|
||||||
self.file.set(value)
|
path = (path,)
|
||||||
|
|
||||||
data = self.file.data
|
self.file.set(self.path + path, value)
|
||||||
*parts, last = self.path
|
|
||||||
for part in parts:
|
|
||||||
data = data.setdefault(part, {})
|
|
||||||
data[last] = value
|
|
||||||
|
|
||||||
|
|
||||||
class TomlFile(File):
|
class TomlFile(File):
|
||||||
def __init__(self, data: Any = {}) -> None:
|
def __init__(self, data: Any = {}) -> None:
|
||||||
self.data = data
|
self.json = JsonFile(data)
|
||||||
|
|
||||||
def at(self, *path: str) -> TomlFileProxy:
|
def at(self, *path: str) -> TomlFileProxy:
|
||||||
return TomlFileProxy(self, path)
|
return TomlFileProxy(self, path)
|
||||||
|
|
||||||
def set(self, value: Any) -> None:
|
def get(self, path: str | tuple[str, ...]) -> Any:
|
||||||
self.data = value
|
return self.json.get(path)
|
||||||
|
|
||||||
|
def set(self, path: str | tuple[str, ...], value: Any) -> None:
|
||||||
|
self.json.set(path, value)
|
||||||
|
|
||||||
|
def merge(self, path: str | tuple[str, ...], value: Any) -> None:
|
||||||
|
self.json.merge(path, value)
|
||||||
|
|
||||||
def to_text(self) -> TextFile:
|
def to_text(self) -> TextFile:
|
||||||
file = TextFile()
|
file = TextFile()
|
||||||
file.tag(comment="#")
|
file.tag(comment="#")
|
||||||
file.append(toml.dumps(self.data), newline=False)
|
file.append(toml.dumps(self.json.data), newline=False)
|
||||||
return file
|
return file
|
||||||
|
|
||||||
def to_bytes(self) -> bytes:
|
def to_bytes(self) -> bytes:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue