Skip to content

Commit cb8dc30

Browse files
committed
Fix transaction test and add complete_object_dict function
1 parent b435ba5 commit cb8dc30

File tree

3 files changed

+130
-3
lines changed

3 files changed

+130
-3
lines changed

gramps_webapi/api/tasks.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
from gramps.gen.db import DbTxn
3333
from gramps.gen.db.base import DbReadBase
3434
from gramps.gen.errors import HandleError
35-
from gramps.gen.lib.json_utils import object_to_dict
35+
from gramps.gen.lib.json_utils import data_to_object, object_to_dict
3636
from gramps.gen.merge.diff import diff_items
3737

3838
from gramps_webapi.api.search.indexer import SearchIndexer, SemanticSearchIndexer
@@ -57,7 +57,7 @@
5757
abort_with_message,
5858
check_quota_people,
5959
close_db,
60-
from_json_legacy,
60+
complete_gramps_object_dict,
6161
get_config,
6262
get_db_outside_request,
6363
send_email,
@@ -493,7 +493,7 @@ def process_transactions(
493493
abort_with_message(409, "Object has changed")
494494
new_data = item["new"]
495495
if new_data:
496-
new_obj = from_json_legacy(json.dumps(new_data))
496+
new_obj = data_to_object(complete_gramps_object_dict(new_data))
497497
if trans_type == "delete":
498498
handle_delete(trans, class_name, handle)
499499
if (

gramps_webapi/api/util.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
from gramps.gen.db.exceptions import DbUpgradeRequiredError
6767
from gramps.gen.dbstate import DbState
6868
from gramps.gen.errors import HandleError
69+
from gramps.gen.lib.json_utils import object_to_dict
6970
from gramps.gen.proxy import PrivateProxyDb
7071
from gramps.gen.proxy.private import sanitize_media
7172
from gramps.gen.proxy.proxybase import ProxyDbBase
@@ -803,3 +804,25 @@ def from_json_legacy(data):
803804
not require the dictionary to contain all properties.
804805
"""
805806
return json.loads(data, object_hook=__object_hook)
807+
808+
809+
def complete_gramps_object_dict(data: dict[str, Any]):
810+
"""Restore a JSON dictionary to its full form, adding placeholders
811+
for missing attributes."""
812+
for key, value in data.items():
813+
if isinstance(value, list):
814+
for i in range(len(value)):
815+
if isinstance(value[i], dict):
816+
value[i] = complete_gramps_object_dict(value[i])
817+
elif isinstance(value, dict):
818+
data[key] = complete_gramps_object_dict(value)
819+
_class = data.get("_class")
820+
if _class is None:
821+
return data
822+
cls = gramps.gen.lib.__dict__[_class]
823+
empty_obj = cls()
824+
empty_obj_dict = object_to_dict(empty_obj)
825+
for key, value in empty_obj_dict.items():
826+
if key not in data:
827+
data[key] = value
828+
return data

tests/test_util.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import pytest
2+
from gramps.gen.lib.json_utils import data_to_object
3+
4+
from gramps_webapi.api import util
5+
from gramps_webapi.const import PRIMARY_GRAMPS_OBJECTS
6+
7+
8+
def _test_complete_gramps_object_dict(obj_dict):
9+
util.complete_gramps_object_dict(obj_dict)
10+
# this will raise an exception if the object dict is not valid
11+
data_to_object(obj_dict)
12+
13+
14+
def test_complete_gramps_object_dict_empty():
15+
"""Test with empty dictionaries for each primary object"""
16+
for class_name in PRIMARY_GRAMPS_OBJECTS:
17+
if class_name == "Family":
18+
continue
19+
obj_dict = {"_class": class_name}
20+
try:
21+
_test_complete_gramps_object_dict(obj_dict)
22+
except:
23+
pytest.fail(f"Failed to complete {class_name} object dict")
24+
raise
25+
26+
27+
def test_complete_gramps_object_dict_nested():
28+
"""Test with nested objects that need completion."""
29+
# Test a Person with incomplete Name object
30+
person_dict = {
31+
"_class": "Person",
32+
"gender": 0,
33+
"primary_name": {"_class": "Name", "first_name": "John"},
34+
}
35+
_test_complete_gramps_object_dict(person_dict)
36+
37+
# Test an Event with incomplete Place reference
38+
event_dict = {"_class": "Event", "place": {"_class": "PlaceRef", "ref": "abcd1234"}}
39+
_test_complete_gramps_object_dict(event_dict)
40+
41+
42+
def test_complete_gramps_object_dict_lists():
43+
"""Test with objects containing lists of other objects."""
44+
# Test Person with attribute list
45+
person_dict = {
46+
"_class": "Person",
47+
"attribute_list": [
48+
{"_class": "Attribute", "type": "Birth", "value": "Hospital"}
49+
],
50+
}
51+
_test_complete_gramps_object_dict(person_dict)
52+
53+
54+
def test_complete_gramps_object_dict_secondary_objects():
55+
"""Test with various secondary objects that aren't in PRIMARY_GRAMPS_OBJECTS."""
56+
secondary_objects = [
57+
"Date",
58+
"Address",
59+
"Location",
60+
"Attribute",
61+
"Surname",
62+
"Name",
63+
"PlaceRef",
64+
"MediaRef",
65+
"EventRef",
66+
"Url",
67+
]
68+
69+
for class_name in secondary_objects:
70+
obj_dict = {"_class": class_name}
71+
try:
72+
_test_complete_gramps_object_dict(obj_dict)
73+
except:
74+
pytest.fail(f"Failed to complete {class_name} object dict")
75+
raise
76+
77+
78+
def test_complete_gramps_object_dict_with_data():
79+
"""Test with dictionaries containing partial data."""
80+
obj_dict = {
81+
"_class": "Person",
82+
"gender": 1, # Female
83+
"primary_name": {
84+
"_class": "Name",
85+
"first_name": "Jane",
86+
"surname_list": [{"_class": "Surname", "surname": "Doe"}],
87+
},
88+
}
89+
_test_complete_gramps_object_dict(obj_dict)
90+
91+
# The dictionary should now be complete and can be converted to a Person object
92+
assert obj_dict["_class"] == "Person"
93+
assert obj_dict["gender"] == 1
94+
assert "attribute_list" in obj_dict
95+
assert "address_list" in obj_dict
96+
assert "event_ref_list" in obj_dict
97+
98+
99+
def test_complete_gramps_object_dict_non_gramps_dict():
100+
"""Test with dictionaries that are not Gramps objects."""
101+
# Dictionary without _class should be returned unchanged
102+
obj_dict = {"name": "Test", "value": 123}
103+
result = util.complete_gramps_object_dict(obj_dict.copy())
104+
assert result == obj_dict

0 commit comments

Comments
 (0)