From 2de06b7dc218348fd31a44e99f2e915c68decfd0 Mon Sep 17 00:00:00 2001 From: AlexDo1 Date: Mon, 22 Jan 2024 17:09:30 +0100 Subject: [PATCH 1/3] Add to_json method for exporting Entry metadata to JSON --- metacatalog/models/entry.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/metacatalog/models/entry.py b/metacatalog/models/entry.py index 48245ec5..463bd0d9 100644 --- a/metacatalog/models/entry.py +++ b/metacatalog/models/entry.py @@ -18,6 +18,7 @@ from uuid import uuid4 import warnings from collections import defaultdict +from decimal import Decimal from sqlalchemy import Column, ForeignKey, event from sqlalchemy import Integer, String, Boolean, DateTime @@ -399,10 +400,41 @@ def from_dict(cls, session: Session, data: dict) -> 'Entry': return entry + @classmethod def is_valid(cls, entry: 'Entry') -> bool: return isinstance(entry, Entry) and entry.id is not None + + def to_json(self, path: str) -> None: + """ + Exports the Entry metadata (from the to_dict method) to a serializable + JSON. + + .. versionadded:: 0.9.1 + + Parameters + ---------- + path : str + Path to the file to write the JSON to. + + """ + # custom encoder for datetime and Decimal data types + class DictToSerializableJsonEncoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, Decimal): + return str(obj) + if isinstance(obj, dt): + return obj.isoformat() + return super().default(obj) + + # get the dict + entry_dict = self.to_dict() + + # write + with open(path, 'w') as f: + json.dump(entry_dict, f, indent=4, cls=DictToSerializableJsonEncoder) + @property def checksum(self) -> str: """ From 376df0674c2b13731c5022426c9312234a2926c8 Mon Sep 17 00:00:00 2001 From: AlexDo1 Date: Mon, 22 Jan 2024 17:30:01 +0100 Subject: [PATCH 2/3] Add check_to_json function to test Entry.to_json() --- metacatalog/test/test_todict_fromdict.py | 30 ++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/metacatalog/test/test_todict_fromdict.py b/metacatalog/test/test_todict_fromdict.py index 35a9a18b..642ae3b0 100644 --- a/metacatalog/test/test_todict_fromdict.py +++ b/metacatalog/test/test_todict_fromdict.py @@ -3,6 +3,7 @@ from metacatalog import api from metacatalog.models import Entry from ._util import connect +import json def check_to_dict_persons(session): @@ -46,6 +47,35 @@ def check_from_dict(session): return True +def check_to_json(session, tmp_path): + """ + Check Entry.to_json(). + This also checks if the output is a valid json by trying to load + it with json.load(). + + """ + # test for all entries in test database + for entry in api.find_entries(session): + # create a temporary file + tmp_file = tmp_path / "entry.json" + + # write JSON to the temporary file + entry.to_json(path=str(tmp_file)) + + # load the JSON from the file, if the JSON is not valid, the test fails with a JSONDecodeError + + with open(tmp_file, 'r') as f: + loaded_dict = json.load(f) + + assert loaded_dict['title'] == entry.title + assert isinstance(loaded_dict[id], int) + assert isinstance(loaded_dict['author'], dict) + assert isinstance(loaded_dict['authors'], list) + assert isinstance(loaded_dict['embargo'], bool) + + return True + + @pytest.mark.depends(on=['add_find'], name='dict_methods') def test_fromdict_todict(): """ From 32360d8517dddde93c4934c09c8da58951fed266 Mon Sep 17 00:00:00 2001 From: AlexDo1 Date: Mon, 22 Jan 2024 17:40:36 +0100 Subject: [PATCH 3/3] Fix typo and add test_to_json method --- metacatalog/test/test_todict_fromdict.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/metacatalog/test/test_todict_fromdict.py b/metacatalog/test/test_todict_fromdict.py index 642ae3b0..0cc65fdd 100644 --- a/metacatalog/test/test_todict_fromdict.py +++ b/metacatalog/test/test_todict_fromdict.py @@ -55,7 +55,7 @@ def check_to_json(session, tmp_path): """ # test for all entries in test database - for entry in api.find_entries(session): + for entry in api.find_entry(session): # create a temporary file tmp_file = tmp_path / "entry.json" @@ -68,7 +68,7 @@ def check_to_json(session, tmp_path): loaded_dict = json.load(f) assert loaded_dict['title'] == entry.title - assert isinstance(loaded_dict[id], int) + assert isinstance(loaded_dict['id'], int) assert isinstance(loaded_dict['author'], dict) assert isinstance(loaded_dict['authors'], list) assert isinstance(loaded_dict['embargo'], bool) @@ -77,7 +77,7 @@ def check_to_json(session, tmp_path): @pytest.mark.depends(on=['add_find'], name='dict_methods') -def test_fromdict_todict(): +def test_fromdict_todict(tmp_path): """ Currently tests Entry.to_dict() and Entry.from_dict() """ @@ -105,3 +105,4 @@ def test_fromdict_todict(): # run single tests assert check_to_dict_persons(session) assert check_from_dict(session) + assert check_to_json(session, tmp_path=tmp_path) \ No newline at end of file