From 8cb0f3fc9868ee44369ec7d3cddf7013b7a62b40 Mon Sep 17 00:00:00 2001 From: Lucas Rangel Cezimbra Date: Thu, 18 Aug 2022 20:53:48 -0300 Subject: [PATCH 1/4] Improve docstrings --- dcache/backends.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/dcache/backends.py b/dcache/backends.py index bb99e49..f097e3b 100644 --- a/dcache/backends.py +++ b/dcache/backends.py @@ -49,19 +49,12 @@ def __setitem__(self, key, value): class InMemory(dict, Base): """ - InMemory backend uses a dict to save the cached values. - - >>> from dcache.backends import InMemory as InMemoryBackend - ... - >>> backend = InMemoryBackend() - >>> backend['key'] = 'value' - >>> backend['key'] - 'value' + Backend that uses a Python dict to cache values. """ def __getitem__(self, *args, **kwargs): """ - Override `dict.__get__` to raise :class:`dcache.exceptions.NotExistError` + Override `dict.__getitem__` to raise :class:`dcache.exceptions.NotExistError` instead of the default KeyError. :raises NotExistError: From eba4f13548500152b4170db21c4edb840578558d Mon Sep 17 00:00:00 2001 From: Lucas Rangel Cezimbra Date: Thu, 18 Aug 2022 21:19:19 -0300 Subject: [PATCH 2/4] Add File backend --- dcache/backends.py | 31 +++++++++++++++++++ tests/backends/test_file.py | 62 +++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 tests/backends/test_file.py diff --git a/dcache/backends.py b/dcache/backends.py index f097e3b..3d0f964 100644 --- a/dcache/backends.py +++ b/dcache/backends.py @@ -1,3 +1,8 @@ +import json +import tempfile +from json.decoder import JSONDecodeError +from pathlib import Path + from dcache.exceptions import NotExistError @@ -66,3 +71,29 @@ def __getitem__(self, *args, **kwargs): return super().__getitem__(*args, **kwargs) except KeyError as e: raise NotExistError from e + + +class File(Base): + def __init__(self, filepath=None): + self.memory = InMemory() + self._filepath = filepath + + @property + def filepath(self): + if not self._filepath: + _, self._filepath = tempfile.mkstemp() + return Path(self._filepath) + + def __getitem__(self, key): + try: + with open(self.filepath, "r") as f: + data = json.load(f) + return data[key] + except (FileNotFoundError, JSONDecodeError, KeyError) as e: + raise NotExistError from e + + def __setitem__(self, key, value): + self.memory[key] = value + + with open(self.filepath, "w") as f: + json.dump(self.memory, f) diff --git a/tests/backends/test_file.py b/tests/backends/test_file.py new file mode 100644 index 0000000..6393154 --- /dev/null +++ b/tests/backends/test_file.py @@ -0,0 +1,62 @@ +import json +import tempfile +from uuid import uuid4 + +import pytest + +from dcache.backends import File +from dcache.exceptions import NotExistError + + +def test_set(): + backend, key, value = File(), str(uuid4()), str(uuid4()) + + backend[key] = value + + with open(backend.filepath) as f: + data = json.load(f) + + assert data == {key: value} + + +def test_get_not_existing_file(): + backend = File(filepath="/not_exist") + + with pytest.raises(NotExistError): + backend[str(uuid4())] + + +def test_get_empty_file(): + backend = File() + + with pytest.raises(NotExistError): + backend[str(uuid4())] + + +def test_get_not_existing_value(): + backend, key, other_key = File(), str(uuid4()), str(uuid4()) + + backend[key] = "" + + with pytest.raises(NotExistError): + backend[other_key] + + +def test_set_and_get(): + backend, key, value = File(), str(uuid4()), str(uuid4()) + + backend[key] = value + + assert backend[key] == value + + +def test_custom_filepath(): + with tempfile.NamedTemporaryFile() as f: + backend = File(filepath=f.name) + key, value = str(uuid4()), str(uuid4()) + + backend[key] = value + + data = json.load(f) + + assert data == {key: value} From bf3b110bf87bf567c2320711cec905e717511732 Mon Sep 17 00:00:00 2001 From: Lucas Rangel Cezimbra Date: Thu, 18 Aug 2022 21:38:27 -0300 Subject: [PATCH 3/4] Add Raw and Json serializers --- dcache/serializers.py | 26 +++++++++++++++++++++++++- tests/serializers/test_json.py | 13 +++++++++++++ tests/serializers/test_raw.py | 18 ++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 tests/serializers/test_json.py create mode 100644 tests/serializers/test_raw.py diff --git a/dcache/serializers.py b/dcache/serializers.py index 4640904..f6d3ce4 100644 --- a/dcache/serializers.py +++ b/dcache/serializers.py @@ -1 +1,25 @@ -# TODO +import json + + +class Base: + def dumps(self, data): + raise NotImplementedError + + def loads(self, data): + raise NotImplementedError + + +class Raw(Base): + def dumps(self, data): + return data + + def loads(self, data): + return data + + +class Json(Base): + def dumps(self, data): + return json.dumps(data) + + def loads(self, data): + return json.loads(data) diff --git a/tests/serializers/test_json.py b/tests/serializers/test_json.py new file mode 100644 index 0000000..5d71d33 --- /dev/null +++ b/tests/serializers/test_json.py @@ -0,0 +1,13 @@ +import json + +from dcache.serializers import Json + + +def test_dumps(): + serializer, data = Json(), {"key": "value"} + assert serializer.dumps(data) == json.dumps(data) + + +def test_loads(): + serializer, serialized_data = Json(), json.dumps({"key": "value"}) + assert serializer.loads(serialized_data) == json.loads(serialized_data) diff --git a/tests/serializers/test_raw.py b/tests/serializers/test_raw.py new file mode 100644 index 0000000..9d675b8 --- /dev/null +++ b/tests/serializers/test_raw.py @@ -0,0 +1,18 @@ +from uuid import uuid4 + +from dcache.serializers import Raw + + +def test_dumps(): + serializer, value = Raw(), uuid4() + assert serializer.dumps(value) == value + + +def test_loads(): + serializer, value = Raw(), uuid4() + assert serializer.loads(value) == value + + +def test_dumps_loads(): + serializer, value = Raw(), uuid4() + assert serializer.dumps(value) == serializer.loads(value) From c06e85fbc0b5f4e81c93d4b21bd9e4089d96a459 Mon Sep 17 00:00:00 2001 From: Lucas Rangel Cezimbra Date: Thu, 18 Aug 2022 21:50:54 -0300 Subject: [PATCH 4/4] WIP --- dcache/backends.py | 9 +++++---- dcache/serializers.py | 18 ++++++++++++++++++ tests/backends/test_file.py | 13 +++++++++++++ 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/dcache/backends.py b/dcache/backends.py index 3d0f964..59b21a8 100644 --- a/dcache/backends.py +++ b/dcache/backends.py @@ -1,8 +1,8 @@ -import json import tempfile from json.decoder import JSONDecodeError from pathlib import Path +from dcache import serializers from dcache.exceptions import NotExistError @@ -74,9 +74,10 @@ def __getitem__(self, *args, **kwargs): class File(Base): - def __init__(self, filepath=None): + def __init__(self, filepath=None, serializer=None): self.memory = InMemory() self._filepath = filepath + self.serializer = serializer or serializers.Json() @property def filepath(self): @@ -87,7 +88,7 @@ def filepath(self): def __getitem__(self, key): try: with open(self.filepath, "r") as f: - data = json.load(f) + data = self.serializer.load(f) return data[key] except (FileNotFoundError, JSONDecodeError, KeyError) as e: raise NotExistError from e @@ -96,4 +97,4 @@ def __setitem__(self, key, value): self.memory[key] = value with open(self.filepath, "w") as f: - json.dump(self.memory, f) + self.serializer.dump(self.memory, f) diff --git a/dcache/serializers.py b/dcache/serializers.py index f6d3ce4..7a1b2b6 100644 --- a/dcache/serializers.py +++ b/dcache/serializers.py @@ -2,24 +2,42 @@ class Base: + def dump(self, data, file): + raise NotImplementedError + def dumps(self, data): raise NotImplementedError + def load(self, file): + raise NotImplementedError + def loads(self, data): raise NotImplementedError class Raw(Base): + def dump(self, data, file): + return file.write(data) + def dumps(self, data): return data + def load(self, file): + return file.read() + def loads(self, data): return data class Json(Base): + def dump(self, data, file): + return json.dump(data, file) + def dumps(self, data): return json.dumps(data) + def load(self, file): + return json.load(file) + def loads(self, data): return json.loads(data) diff --git a/tests/backends/test_file.py b/tests/backends/test_file.py index 6393154..8ab73fa 100644 --- a/tests/backends/test_file.py +++ b/tests/backends/test_file.py @@ -1,4 +1,5 @@ import json +import pickle import tempfile from uuid import uuid4 @@ -60,3 +61,15 @@ def test_custom_filepath(): data = json.load(f) assert data == {key: value} + + +def test_serializer(): + backend = File(serializer=pickle) + key, value = str(uuid4()), str(uuid4()) + + backend[key] = value + + with open(backend.filepath) as f: + data = pickle.load(f) + + assert data == {key: value}