Coverage for src/cycloplanning/__init__.py: 90%
51 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-22 02:03 +0200
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-22 02:03 +0200
1from dataclasses import dataclass
2from datetime import datetime, timedelta
3from bs4 import BeautifulSoup
4import requests
5import ics
7# Define column headers
8HEADERS = [
9 "Jour",
10 "Date",
11 "Quoi",
12 "Adresse",
13 "Besoins Humains",
14 "Horaires",
15 "Bénévole 1",
16 "Bénévole 2",
17 "Bénévole 3",
18 "Bénévole 4",
19]
22@dataclass
23class Event:
24 name: str
25 start_date: datetime
26 duration: timedelta
27 location: str
28 description: str
29 attendees: list[str]
32def get_html(url: str) -> str:
33 response = requests.get(url)
34 return response.content
37def parse_html(html: str) -> list[dict]:
38 soup = BeautifulSoup(html, "html.parser")
40 # Initialize an empty list to store dictionaries
41 events = []
43 # Find the header row to start processing
44 header_row = soup.find("td", string=lambda x: x and "Date" in x)
45 if header_row:
46 # Iterate over each subsequent <tr> for data extraction
47 for row in header_row.parent.find_next_siblings("tr"):
48 # Get all <td> elements in the row
49 columns = row.find_all("td")
51 # Create a dictionary for the row using headers as keys
52 row_dict = {
53 HEADERS[i]: col.get_text(strip=True)
54 for i, col in enumerate(columns[: len(HEADERS)])
55 }
57 # Skip header rows
58 if row_dict["Jour"] == "Date":
59 continue
61 events.append(row_dict)
62 return events
65def parse_events(raw_events: list[dict]) -> list[Event]:
66 events = []
67 for raw_event in raw_events:
68 start_date = datetime.strptime(raw_event["Date"], "%d/%m")
69 start_date = start_date.replace(year=datetime.today().year)
70 hour_begin = int(raw_event["Horaires"].split("-")[0].split("h")[0])
71 hour_end = int(raw_event["Horaires"].split("-")[1].split("h")[0])
72 start_date = start_date.replace(hour=hour_begin)
73 duration = timedelta(hours=(hour_end - hour_begin))
74 attendees = [
75 raw_event["Bénévole 1"],
76 raw_event["Bénévole 2"],
77 raw_event["Bénévole 3"],
78 raw_event["Bénévole 4"],
79 ]
81 event = Event(
82 name=raw_event["Quoi"],
83 description=raw_event["Besoins Humains"],
84 start_date=start_date,
85 duration=duration,
86 location=raw_event["Adresse"],
87 attendees=attendees,
88 )
89 events.append(event)
90 return events
93def create_ics(raw_events: list[Event]) -> ics.Calendar:
94 calendar = ics.Calendar()
95 for raw_event in raw_events:
96 event = ics.Event(
97 name=raw_event.name,
98 description=raw_event.description,
99 begin=raw_event.start_date,
100 duration=raw_event.duration,
101 location=raw_event.location,
102 attendees=raw_event.attendees,
103 )
104 calendar.events.add(event)
105 return calendar
108def write_ics(calendar: ics.Calendar, output="/dev/stdout"):
109 with open(output, "w") as f:
110 f.writelines(calendar.serialize_iter())