8000 Migrate to new Pretalx API (#133) · EuroPython/programapi@5d8bf31 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5d8bf31

Browse files
authored
Migrate to new Pretalx API (#133)
* Remove outdated query '?questions=all' * Use '?expand=...' to request nested resources * Deserialization: speaker.avatar -> speaker.avatar_url * Deserialization: Localization 'en' -> 'name.en' * Deserialization: Schedule slots * Deserialization: Don't expect embedded submission.speakers * Deserialization: Handle non-expanded submission.resources Workaround for pretalx/pretalx#2040 * Chore: Fix typing * Include submission resources in session export
1 parent 7731354 commit 5d8bf31

File tree

6 files changed

+61
-36
lines changed

6 files changed

+61
-36
lines changed

data/examples/pretalx/speakers.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"submissions": [
77
"A8CD3F"
88
],
9-
"avatar": "https://pretalx.com/media/avatars/picture.jpg",
9+
"avatar_url": "https://pretalx.com/media/avatars/picture.jpg",
1010
"answers": [
1111
{
1212
"id": 272244,

data/examples/pretalx/submissions.json

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,16 @@
22
{
33
"code": "A8CD3F",
44
"speakers": [
5-
{
6-
"code": "F3DC8A",
7-
"name": "A Speaker",
8-
"biography": "This is a biography of F3D speaker",
9-
"avatar": "https://pretalx.com/media/avatars/picture.jpg",
10-
"email": "f3dc8a@example.com"
11-
},
12-
{
13-
"code": "ZXCVBN",
14-
"name": "ZXC Speaker",
15-
"biography": "This is a biography of ZXC speaker",
16-
"avatar": "https://pretalx.com/media/avatars/picture.jpg",
17-
"email": "zxcvbn@example.com"
18-
}
5+
"F3DC8A",
6+
"ZXCVBN"
197
],
208
"title": "This is a test talk from a test speaker about a test topic.",
219
"submission_type": "Talk (long session)",
2210
"submission_type_id": 3961,
2311
"track": {
24-
"en": "Software Engineering & Architecture"
12+
"name": {
13+
"en": "Software Engineering & Architecture"
14+
}
2515
},
2616
"track_id": 4493,
2717
"state": "confirmed",
@@ -125,19 +115,15 @@
125115
{
126116
"code": "B8CD4F",
127117
"speakers": [
128-
{
129-
"code": "G3DC8A",
130-
"name": "Another Speaker",
131-
"biography": "This is a biography of F3D speaker",
132-
"avatar": "https://pretalx.com/media/avatars/picture.jpg",
133-
"email": "g3dc8a@example.com"
134-
}
118+
"G3DC8A"
135119
],
136120
"title": "A talk with shorter title",
137121
"submission_type": "Talk",
138122
"submission_type_id": 3961,
139123
"track": {
140-
"en": "PyData: LLMs"
124+
"name": {
125+
"en": "PyData: LLMs"
126+
}
141127
},
142128
"track_id": 4493,
143129
"state": "confirmed",

src/download.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,16 @@
2525
}
2626

2727
base_url = f"https://pretalx.com/api/events/{Config.event}/"
28-
schedule_url = base_url + "schedules/latest/"
28+
schedule_url = (
29+
base_url
30+
+ "schedules/latest?expand="
31+
+ "slots,slots.submission,slots.submission.submission_type,slots.submission.track,slots.room"
32+
)
2933

3034
# Build resource list dynamically based on exclusions
3135
resources = [
32-
"submissions?questions=all&state=confirmed",
33-
"speakers?questions=all",
36+
"submissions?state=confirmed&expand=answers.question,submission_type,track,slots.room,resources",
37+
"speakers?expand=answers.question",
3438
]
3539

3640
if "youtube" not in exclude:

src/models/pretalx.py

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class PretalxSlot(BaseModel):
3333
@classmethod
3434
def handle_localized(cls, v) -> str | None:
3535
if isinstance(v, dict):
36-
return v.get("en")
36+
return v["name"].get("en")
3737
return v
3838

3939

@@ -45,7 +45,7 @@ class PretalxSpeaker(BaseModel):
4545
code: str
4646
name: str
4747
biography: str | None = None
48-
avatar: str
48+
avatar_url: str
4949
submissions: list[str]
5050
answers: list[PretalxAnswer]
5151

@@ -77,7 +77,7 @@ class PretalxSubmission(BaseModel):
7777
@classmethod
7878
def handle_localized(cls, v) -> str | None:
7979
if isinstance(v, dict):
80-
return v.get("en")
80+
return v["name"].get("en")
8181
return v
8282

8383
@field_validator("duration", mode="before")
@@ -95,11 +95,18 @@ def handle_resources(cls, v) -> list[dict[str, str]] | None:
9595
@model_validator(mode="before")
9696
@classmethod
9797
def process_values(cls, values) -> dict:
98-
values["speakers"] = sorted([s["code"] for s in values["speakers"]])
98+
# Transform resource information
99+
if raw_resources := values.get("resources"):
100+
resources = [
101+
{"description": res["description"], "resource": res["resource"]}
102+
for res in raw_resources
103+
]
104+
values["resources"] = resources
99105

100106
# Set slot information
101-
if values.get("slot"):
102-
slot = PretalxSlot.model_validate(values["slot"])
107+
if values.get("slots"):
108+
slot = PretalxSlot.model_validate(values["slots"][0])
109+
values["slot"] = slot
103110
values["room"] = slot.room
104111
values["start"] = slot.start
105112
values["end"] = slot.end
@@ -146,3 +153,31 @@ class PretalxSchedule(BaseModel):
146153

147154
slots: list[PretalxSubmission]
148155
breaks: list[PretalxScheduleBreak]
156+
157+
@model_validator(mode="before")
158+
@classmethod
159+
def process_values(cls, values) -> dict:
160+
submission_slots = []
161+
break_slots = []
162+
for slot_dict in values["slots"]:
163+
# extract nested slot fields into slot
164+
slot_object = PretalxSlot.model_validate(slot_dict)
165+
slot_dict["slot"] = slot_object
166+
slot_dict["room"] = slot_object.room
167+
slot_dict["start"] = slot_object.start
168+
slot_dict["end"] = slot_object.end
169+
170+
if slot_dict.get("submission") is None:
171+
break_slots.append(slot_dict)
172+
else:
173+
# merge submission fields into slot
174+
slot_dict.update(slot_dict.get("submission", {}))
175+
176+
# remove resource IDs (not expandable with API, not required for schedule)
177+
slot_dict.pop("resources", None)
178+
179+
submission_slots.append(slot_dict)
180+
181+
values["slots"] = submission_slots
182+
values["breaks"] = break_slots
183+
return values

src/utils/parse.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,12 @@ def publishable_speakers(
3434
js = json.load(fd)
3535
all_speakers = [PretalxSpeaker.model_validate(s) for s in js]
3636

37-
speakers_with_publishable_sessions: list[PretalxSubmission] = []
37+
speakers_with_publishable_sessions: list[PretalxSpeaker] = []
3838
for speaker in all_speakers:
3939
if publishable_sessions := Utils.publishable_sessions_of_speaker(
4040
speaker, publishable_sessions_keys
4141
):
42-
speaker.submissions = publishable_sessions
42+
speaker.submissions = sorted(publishable_sessions)
4343
speakers_with_publishable_sessions.append(speaker)
4444

4545
publishable_speakers_by_code = {

src/utils/transform.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def pretalx_speakers_to_europython_speakers(
8383
code=speaker.code,
8484
name=speaker.name,
8585
biography=speaker.biography,
86-
avatar=speaker.avatar,
86+
avatar=speaker.avatar_url,
8787
slug=speaker_code_to_slug[speaker.code],
8888
answers=speaker.answers,
8989
submissions=speaker.submissions,

0 commit comments

Comments
 (0)
0