Skip to content

Commit 531cbf2

Browse files
committed
Refactor Speakers dataclass and client to use similar hook setup
1 parent 70f3d62 commit 531cbf2

File tree

5 files changed

+39
-31
lines changed

5 files changed

+39
-31
lines changed

notubiz/api/_hooks_registry.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
from notubiz.api.dataclasses import Event, event_hook
22
from notubiz.api.dataclasses import Meeting, meeting_hook
33
from notubiz.api.dataclasses import AgendaItem, agenda_item_hook
4-
#from notubiz.api.dataclasses import Speakers, speakers_nook
4+
from notubiz.api.dataclasses import Speakers, Speaker, speakers_hook, speaker_hook
55

66
Hooks = {
77
Event: event_hook,
88
Meeting: meeting_hook,
9-
AgendaItem: agenda_item_hook
9+
AgendaItem: agenda_item_hook,
10+
Speakers: speakers_hook,
11+
Speaker: speaker_hook
1012
}

notubiz/api/clients/speakers_client.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from notubiz.api_client import ApiClient
22
from notubiz.api.dataclasses import Speakers
3+
from notubiz.api._converter import get_converter
34

45
class SpeakersClient:
56
api_client : ApiClient
@@ -9,4 +10,4 @@ def __init__(self, api_client : ApiClient):
910

1011
def get(self) -> Speakers:
1112
json_object = self.api_client.get("speakers")
12-
return Speakers.from_json(json_object)
13+
return get_converter().structure(json_object, Speakers)

notubiz/api/dataclasses/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
from notubiz.api.dataclasses.assembly import Assembly
44
from notubiz.api.dataclasses.document import Document
55
from notubiz.api.dataclasses.agenda_item import AgendaItem, agenda_item_hook
6-
from notubiz.api.dataclasses.speakers import Speaker, Speakers # TODO: refactor with speaker_hook
6+
from notubiz.api.dataclasses.speakers import Speakers, Speaker, speakers_hook, speaker_hook

notubiz/api/dataclasses/speakers.py

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
1-
from attrs import define
2-
import cattrs
3-
from cattrs import transform_error
4-
from cattrs.gen import make_dict_unstructure_fn, make_dict_structure_fn, override
1+
from attrs import define, field
2+
from cattr import Converter
3+
from datetime import datetime
4+
5+
from notubiz.api._helpers import parse_date
56

67
@define
78
class SpeakerAttributes:
89
id: int
910
person_id: int
1011
active: int
11-
last_modified: str
12+
last_modified: datetime
1213

1314
@define
1415
class Speaker:
16+
# Auto-filled
1517
photo: str
1618
party: str
1719
email: str
@@ -21,11 +23,25 @@ class Speaker:
2123
sex: str
2224
function: str
2325
url: str
24-
attributes: SpeakerAttributes
26+
27+
# Manually filled
28+
attributes: SpeakerAttributes = field(init=False)
2529

2630
def full_name(self):
2731
return self.firstname + " " + self.lastname
2832

33+
def speaker_hook(data: dict[str, any], cls: type) -> Speaker:
34+
# Auto-fill fields
35+
converter = Converter()
36+
converter.register_structure_hook(datetime, lambda date_string, _: parse_date(date_string))
37+
38+
speaker = converter.structure(data, cls)
39+
40+
# Manually add some fields
41+
speaker.attributes = converter.structure(data.get("@attributes", {}), SpeakerAttributes)
42+
43+
return speaker
44+
2945
@define
3046
class Speakers:
3147
speakers: list[Speaker]
@@ -45,24 +61,12 @@ def find_by_person_id(self, person_id : int):
4561

4662
return None
4763

48-
@staticmethod
49-
def from_json(json_object : any) -> 'Speakers':
50-
c = cattrs.Converter()
51-
52-
unst_hook = make_dict_unstructure_fn(Speakers, c, speakers=override(rename="speaker"))
53-
st_hook = make_dict_structure_fn(Speakers, c, speakers=override(rename="speaker"))
54-
c.register_unstructure_hook(Speakers, unst_hook)
55-
c.register_structure_hook(Speakers, st_hook)
64+
def speakers_hook(data: dict[str, any], cls: type) -> Speakers:
65+
speakers_json_arary = data["speakers"]["speaker"]
5666

57-
unst_hook = make_dict_unstructure_fn(Speaker, c, attributes=override(rename="@attributes"))
58-
st_hook = make_dict_structure_fn(Speaker, c, attributes=override(rename="@attributes"))
59-
c.register_unstructure_hook(Speaker, unst_hook)
60-
c.register_structure_hook(Speaker, st_hook)
67+
c = Converter()
68+
c.register_structure_hook(Speaker, speaker_hook)
6169

62-
try:
63-
speakers = c.structure(json_object["speakers"], Speakers)
64-
except Exception as exc:
65-
print("\n".join(transform_error(exc)))
66-
quit()
70+
speakers = [c.structure(speaker_json, Speaker) for speaker_json in speakers_json_arary]
6771

68-
return speakers
72+
return Speakers(speakers)

test/test_speakers.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,18 @@
33

44
import pytest
55
from test.helpers import read_json
6+
from notubiz.api._converter import get_converter
67

78
@pytest.fixture(scope="session")
89
def input_json():
910
return read_json("./test/data/speakers.json")
1011

1112
@pytest.fixture(scope="session")
12-
def input_speakers():
13-
return Speakers.from_json(read_json("./test/data/speakers.json"))
13+
def input_speakers(input_json):
14+
return get_converter().structure(input_json, Speakers)
1415

1516
def test_deserialization(input_json):
16-
speakers = Speakers.from_json(input_json).speakers
17+
speakers = get_converter().structure(input_json, Speakers).speakers
1718

1819
# Let's not test the entire attrs/cattrs package.
1920
# The serialization did not throw an exception if we reach these lines

0 commit comments

Comments
 (0)