Initial commit
This commit is contained in:
1
Bot/jsonwrapper/__init__.py
Normal file
1
Bot/jsonwrapper/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .autosavedict import * # noqa
|
||||
BIN
Bot/jsonwrapper/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
Bot/jsonwrapper/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
Bot/jsonwrapper/__pycache__/__init__.cpython-39.pyc
Normal file
BIN
Bot/jsonwrapper/__pycache__/__init__.cpython-39.pyc
Normal file
Binary file not shown.
BIN
Bot/jsonwrapper/__pycache__/autosavedict.cpython-311.pyc
Normal file
BIN
Bot/jsonwrapper/__pycache__/autosavedict.cpython-311.pyc
Normal file
Binary file not shown.
BIN
Bot/jsonwrapper/__pycache__/autosavedict.cpython-39.pyc
Normal file
BIN
Bot/jsonwrapper/__pycache__/autosavedict.cpython-39.pyc
Normal file
Binary file not shown.
120
Bot/jsonwrapper/autosavedict.py
Normal file
120
Bot/jsonwrapper/autosavedict.py
Normal file
@@ -0,0 +1,120 @@
|
||||
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)
|
||||
146
Bot/jsonwrapper/tests.py
Normal file
146
Bot/jsonwrapper/tests.py
Normal file
@@ -0,0 +1,146 @@
|
||||
import os
|
||||
import json
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from .autosavedict import AutoSaveDict
|
||||
|
||||
|
||||
BASE_DIR = f'{os.sep}'.join(__file__.split(os.sep)[:-1])
|
||||
|
||||
|
||||
class TestAutoSaveDict(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.path = Path(BASE_DIR) / 'test.json'
|
||||
self.default = {'a': 1, 'b': 2}
|
||||
asd = AutoSaveDict(self.path, **self.default)
|
||||
asd.init()
|
||||
return super().setUp()
|
||||
|
||||
def tearDown(self) -> None:
|
||||
os.remove(self.path)
|
||||
return super().tearDown()
|
||||
|
||||
def test_init(self) -> None:
|
||||
asd = AutoSaveDict(self.path, **self.default)
|
||||
asd.init()
|
||||
self.assertTrue(os.path.exists(self.path))
|
||||
self.assertEqual(asd, self.default)
|
||||
self.assertEqual(asd._pairs, self.default)
|
||||
self.assertEqual(asd._read(), self.default)
|
||||
|
||||
def test_restore(self) -> None:
|
||||
asd = AutoSaveDict(self.path, **self.default)
|
||||
asd['c'] = 3
|
||||
self.assertIn('c', asd)
|
||||
asd.restore()
|
||||
self.assertEqual(asd, self.default)
|
||||
self.assertEqual(asd._read(), self.default)
|
||||
self.assertEqual(asd._pairs, self.default)
|
||||
|
||||
def test_pop(self) -> None:
|
||||
asd = AutoSaveDict(self.path, **self.default)
|
||||
asd.init()
|
||||
|
||||
key = tuple(self.default.keys())[0]
|
||||
asd.pop(key)
|
||||
|
||||
self.assertNotIn(key, asd._read())
|
||||
self.assertNotIn(key, asd._pairs)
|
||||
self.assertNotIn(key, asd)
|
||||
|
||||
def test_popitem(self) -> None:
|
||||
asd = AutoSaveDict(self.path, **self.default)
|
||||
asd.init()
|
||||
key = tuple(asd.keys())[-1]
|
||||
val = asd[key]
|
||||
result = asd.popitem()
|
||||
self.assertEqual(result, (key, val))
|
||||
self.assertNotIn(key, asd)
|
||||
self.assertNotIn(key, asd._read())
|
||||
self.assertNotIn(key, asd._pairs)
|
||||
|
||||
def test_update(self) -> None:
|
||||
asd = AutoSaveDict(self.path, **self.default)
|
||||
asd.init()
|
||||
new = {'b': 3}
|
||||
asd.update(new)
|
||||
self.assertEqual(asd['b'], new['b'])
|
||||
self.assertEqual(asd._read()['b'], new['b'])
|
||||
self.assertEqual(asd._pairs['b'], new['b'])
|
||||
|
||||
def test_copy(self) -> None:
|
||||
copy_path = 'test_copy.json'
|
||||
asd = AutoSaveDict(self.path, **self.default)
|
||||
asd_copy = asd.copy(copy_path) # type: ignore
|
||||
asd.init()
|
||||
asd_copy.init()
|
||||
|
||||
self.assertEqual(asd_copy, asd)
|
||||
self.assertEqual(asd_copy, asd._read())
|
||||
self.assertEqual(asd_copy, asd._pairs)
|
||||
os.remove(copy_path)
|
||||
|
||||
def test_fromfile(self) -> None:
|
||||
file = 'test_fromfile.json'
|
||||
config = {'b': 3, 'c': 4}
|
||||
|
||||
with open(file, mode='w') as f:
|
||||
json.dump(config, f)
|
||||
os.remove(self.path)
|
||||
asd = AutoSaveDict.fromfile(file, self.path) # type: ignore
|
||||
asd.init()
|
||||
|
||||
self.assertEqual(config, asd)
|
||||
self.assertEqual(config, asd._pairs)
|
||||
self.assertEqual(config, asd._read())
|
||||
self.assertIsInstance(asd, AutoSaveDict)
|
||||
os.remove(file)
|
||||
|
||||
def test_frommapping(self) -> None:
|
||||
path = 'test_frommapping.json'
|
||||
mapping = (
|
||||
('a', 1),
|
||||
('b', 2),
|
||||
('c', 3),
|
||||
)
|
||||
expected = dict(mapping)
|
||||
|
||||
asd = AutoSaveDict.frommapping(mapping, path) # type: ignore
|
||||
asd.init()
|
||||
|
||||
self.assertEqual(expected, asd)
|
||||
self.assertEqual(expected, asd._read())
|
||||
self.assertEqual(expected, asd._pairs)
|
||||
os.remove(path)
|
||||
|
||||
def test_fromkeys(self) -> None:
|
||||
path = 'test_fromkeys.json'
|
||||
keys = 'test'
|
||||
expected = dict.fromkeys(keys)
|
||||
|
||||
asd = AutoSaveDict.fromkeys(keys, file_path=path) # type: ignore
|
||||
asd.init()
|
||||
self.assertEqual(asd, expected)
|
||||
self.assertEqual(asd._read(), expected)
|
||||
self.assertEqual(asd._pairs, expected)
|
||||
os.remove(path)
|
||||
|
||||
def test_setitem(self) -> None:
|
||||
expected = {**self.default, "z": 3}
|
||||
asd = AutoSaveDict(self.path, **self.default)
|
||||
asd['z'] = 3
|
||||
self.assertEqual(asd, expected)
|
||||
self.assertEqual(asd._read(), expected)
|
||||
self.assertEqual(asd._pairs, expected)
|
||||
|
||||
def test_delitem(self) -> None:
|
||||
config = self.default.copy()
|
||||
key = tuple(config.keys())[0]
|
||||
asd = AutoSaveDict(self.path, **config)
|
||||
asd.init()
|
||||
|
||||
del config[key]
|
||||
del asd[key]
|
||||
self.assertEqual(asd, config)
|
||||
self.assertEqual(asd._read(), config)
|
||||
self.assertEqual(asd._pairs, config)
|
||||
Reference in New Issue
Block a user