Skip to content

Commit 4fad211

Browse files
authored
Merge pull request #28 from EuroPython/add_pretalx_script
Add scripts to get speakers info from pretalx
2 parents 35277f8 + 7bd76cb commit 4fad211

File tree

3 files changed

+181
-0
lines changed

3 files changed

+181
-0
lines changed

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,26 @@ The fields for speakers are the following:
5050
* Title: Title of the proposal
5151
* Level: If provided by the schedule. If two levels are displayed, pick the
5252
most general one
53+
54+
## Scripts
55+
56+
> [!NOTE]
57+
> Make sure to install the dependencies in `scripts/requirements.txt`
58+
59+
In case the event you are trying to contribute is using Pretalx, you can get
60+
the speaker list by running the command:
61+
62+
```
63+
python scripts/get_speakers.py --url https://pretalx.com/api/events/pyladiescon-2025
64+
```
65+
To write the output directly into a file, you can use the `--output` option,
66+
and execute the script like this:
67+
68+
```
69+
python scripts/get_speakers.py \
70+
--url https://pretalx.com/api/events/pyladiescon-2024 \
71+
--output data/speakers/PyLadiesCon/2024.json
72+
```
73+
74+
> [!IMPORTANT]
75+
> Make sure that the URL needs to the the one pointing to the API.

scripts/get_speakers.py

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
import json
2+
import sys
3+
import argparse
4+
from typing import Any
5+
from datetime import datetime
6+
7+
import requests
8+
9+
10+
def get_response_data_from_url(url: str) -> dict[str, Any]:
11+
try:
12+
response = requests.get(url, headers={"Authorization": TOKEN})
13+
data = response.json()
14+
except requests.exceptions.RequestException as e:
15+
print(f"Error fetching data: {e}")
16+
sys.exit(1)
17+
18+
return data
19+
20+
21+
def get_pretalx_submission_types(conference_url: str) -> dict[str, str]:
22+
url: str | None = f"{conference_url}/submission-types"
23+
submission_types: dict[str, str] = {}
24+
25+
while url:
26+
data: dict[str, Any] = get_response_data_from_url(url)
27+
28+
for stype in data["results"]:
29+
if stype["id"] not in submission_types:
30+
submission_types[stype["id"]] = stype["name"]
31+
32+
url = data.get("next")
33+
34+
return submission_types
35+
36+
37+
def get_pretalx_submissions(conference_url: str, all_speakers: dict[str, str]) -> dict[str, dict]:
38+
url: str | None = f"{conference_url}/submissions"
39+
confirmed_submissions = {}
40+
41+
submissions_types = get_pretalx_submission_types(conference_url)
42+
43+
while url:
44+
data: dict[str, Any] = get_response_data_from_url(url)
45+
46+
for submission in data["results"]:
47+
48+
if submission["state"] == "confirmed":
49+
50+
submission_code = submission["code"]
51+
submission_speakers = submission["speakers"]
52+
submission_type = submissions_types[submission["submission_type"]]
53+
if isinstance(submission_type, dict):
54+
try:
55+
# Search for 'en' default language
56+
# otherwise, the first one
57+
submission_type = submission_type["en"]
58+
except KeyError:
59+
for k, v in submission_type.items():
60+
submission_type = v
61+
break
62+
63+
for speaker_code in submission_speakers:
64+
65+
speaker_name = all_speakers[speaker_code]
66+
confirmed_submissions[f"{submission_code}-{speaker_code}"] = {
67+
"fullname": speaker_name,
68+
"title": submission["title"],
69+
"type": submission_type,
70+
}
71+
72+
url = data.get("next")
73+
74+
return confirmed_submissions
75+
76+
77+
def get_pretalx_speakers(conference_url: str) -> dict[str, str]:
78+
url: str | None = f"{conference_url}/speakers"
79+
speakers = {}
80+
81+
while url:
82+
data: dict[str, Any] = get_response_data_from_url(url)
83+
84+
for speaker in data["results"]:
85+
code = speaker["code"]
86+
if code not in speakers:
87+
speakers[code] = speaker["name"]
88+
89+
url = data.get("next")
90+
91+
return speakers
92+
93+
94+
def get_event_year(conference_url: str) -> int:
95+
data: dict[str, Any] = get_response_data_from_url(conference_url)
96+
date = data["date_from"]
97+
year: int = 2025
98+
try:
99+
date_from = datetime.strptime(date, "%Y-%m-%d")
100+
except ValueError:
101+
print(f"Error: couldn't parse date '{date}'. Falling back to 2025")
102+
return year
103+
104+
return date_from.year
105+
106+
107+
if __name__ == "__main__":
108+
# This URL can be a custom URL or pretalx.com/ one depending on the event configuration
109+
CONFERENCE_URL = ""
110+
TOKEN = "" # Not necessary, but in case of private events it's required
111+
112+
parser = argparse.ArgumentParser()
113+
parser.add_argument('--url')
114+
parser.add_argument('--output')
115+
args = parser.parse_args()
116+
117+
# Check command-line arguments
118+
if args.url is not None:
119+
if CONFERENCE_URL:
120+
print(f"-- WARNING: Overriding url '{CONFERENCE_URL}' "
121+
f"with command line value '{args.url}'")
122+
print(f"-- Using event url: '{args.url}'")
123+
CONFERENCE_URL = args.url
124+
125+
if args.output is not None:
126+
if not args.output.endswith(".json"):
127+
print(f"ERROR: file '{args.output}' is not a JSON file")
128+
sys.exit(1)
129+
130+
year = get_event_year(CONFERENCE_URL)
131+
speakers = get_pretalx_speakers(CONFERENCE_URL)
132+
submission_data = get_pretalx_submissions(CONFERENCE_URL, speakers)
133+
134+
data: dict[str, Any] = {}
135+
136+
if submission_data:
137+
138+
data["year"] = year
139+
data["speakers"] = []
140+
for _, entry in submission_data.items():
141+
data["speakers"].append(
142+
{
143+
"fullname": entry["fullname"],
144+
"type": entry["type"],
145+
"title": entry["title"],
146+
}
147+
)
148+
149+
if args.output is not None:
150+
with open(args.output, "w") as f:
151+
json.dump(data, f, ensure_ascii=False, indent=4)
152+
print(f"-- Written file: '{args.output}'")
153+
else:
154+
print(json.dumps(data, indent=4))
155+
else:
156+
print("Failed to fetch speakers data")

scripts/requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
requests
2+
types-requests

0 commit comments

Comments
 (0)