121 lines
3.4 KiB
Python
121 lines
3.4 KiB
Python
|
|
from __future__ import annotations
|
||
|
|
import os
|
||
|
|
import json
|
||
|
|
from typing import (
|
||
|
|
Any,
|
||
|
|
Dict,
|
||
|
|
Tuple,
|
||
|
|
Mapping,
|
||
|
|
Optional,
|
||
|
|
Iterable,
|
||
|
|
MutableMapping,
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
__all__ = (
|
||
|
|
'AutoSaveDict',
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
class AutoSaveDict(dict[Any, Any]):
|
||
|
|
def __init__(self,
|
||
|
|
file_path: Optional[os.PathLike[Any]] = None,
|
||
|
|
**pairs: Any):
|
||
|
|
self.file_path = file_path
|
||
|
|
self.__default = pairs
|
||
|
|
|
||
|
|
if self.file_path is None:
|
||
|
|
self._pairs = pairs
|
||
|
|
elif not os.path.exists(self.file_path):
|
||
|
|
self._pairs = pairs
|
||
|
|
else:
|
||
|
|
self._pairs = self._read()
|
||
|
|
super(AutoSaveDict, self).__init__(**self._pairs)
|
||
|
|
|
||
|
|
def __setitem__(self, __key: Any, __value: Any) -> None:
|
||
|
|
data = self._read()
|
||
|
|
data[__key] = __value
|
||
|
|
self._write(data)
|
||
|
|
super().__setitem__(__key, __value)
|
||
|
|
|
||
|
|
def __delitem__(self, __key: Any) -> None:
|
||
|
|
data = self._read()
|
||
|
|
del data[__key]
|
||
|
|
self._write(data)
|
||
|
|
return super().__delitem__(__key)
|
||
|
|
|
||
|
|
def __or__(self, __value: Mapping[Any, Any]) -> AutoSaveDict:
|
||
|
|
data = self._pairs | __value
|
||
|
|
return AutoSaveDict(None, **data)
|
||
|
|
|
||
|
|
def _write(self, content: Dict[Any, Any]) -> None:
|
||
|
|
with open(self.file_path, mode='w') as f: # type: ignore
|
||
|
|
json.dump(content, f, indent=4)
|
||
|
|
self._pairs = content
|
||
|
|
|
||
|
|
def _read(self) -> Dict[Any, Any]:
|
||
|
|
with open(self.file_path, mode='r') as f: # type: ignore
|
||
|
|
data: Dict[Any, Any] = json.load(f)
|
||
|
|
return data
|
||
|
|
|
||
|
|
@classmethod
|
||
|
|
def fromkeys(cls, __iterable: Iterable[Any], __value: Any = None,
|
||
|
|
file_path: Optional[os.PathLike[Any]] = None) -> AutoSaveDict:
|
||
|
|
data = {}
|
||
|
|
for key in __iterable:
|
||
|
|
data[key] = __value
|
||
|
|
return cls(file_path, **data)
|
||
|
|
|
||
|
|
@classmethod
|
||
|
|
def frommapping(cls, __mapping: Mapping[Any, Any],
|
||
|
|
file_path: Optional[os.PathLike[Any]] = None)\
|
||
|
|
-> AutoSaveDict:
|
||
|
|
data = dict(__mapping)
|
||
|
|
return cls(file_path, **data)
|
||
|
|
|
||
|
|
@classmethod
|
||
|
|
def fromfile(cls, src: os.PathLike[Any],
|
||
|
|
dst: Optional[os.PathLike[Any]] = None) -> AutoSaveDict:
|
||
|
|
with open(src, mode='r') as f:
|
||
|
|
data = json.load(f)
|
||
|
|
return AutoSaveDict(dst, **data)
|
||
|
|
|
||
|
|
def init(self) -> None:
|
||
|
|
if not os.path.exists(self.file_path): # type: ignore
|
||
|
|
self._write(self._pairs)
|
||
|
|
else:
|
||
|
|
self._pairs = self._read()
|
||
|
|
|
||
|
|
def restore(self) -> None:
|
||
|
|
self.clear()
|
||
|
|
self.update(self.__default)
|
||
|
|
self.init()
|
||
|
|
|
||
|
|
def copy(self,
|
||
|
|
file_path: Optional[os.PathLike[Any]] = None) -> AutoSaveDict:
|
||
|
|
data = {}
|
||
|
|
for key, val in self.items():
|
||
|
|
data[key] = val
|
||
|
|
return AutoSaveDict(file_path, **data)
|
||
|
|
|
||
|
|
def pop(self, __key: Any) -> Any: # type: ignore
|
||
|
|
data = self._read()
|
||
|
|
data.pop(__key)
|
||
|
|
self._write(data)
|
||
|
|
return super().pop(__key)
|
||
|
|
|
||
|
|
def popitem(self) -> Tuple[Any, Any]:
|
||
|
|
key = tuple(self._read().keys())[-1]
|
||
|
|
value = self.pop(key)
|
||
|
|
super().popitem()
|
||
|
|
return (key, value)
|
||
|
|
|
||
|
|
def clear(self) -> None:
|
||
|
|
self._write({})
|
||
|
|
super().clear()
|
||
|
|
|
||
|
|
def update(self, __m: Mapping[Any, Any]) -> MutableMapping: # type: ignore
|
||
|
|
for k, v in __m.items():
|
||
|
|
self[k] = v
|
||
|
|
super().update(__m)
|