-
Notifications
You must be signed in to change notification settings - Fork 1
/
client.py
99 lines (80 loc) 路 3.17 KB
/
client.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
"""Define an client to interact with Recollect Waste."""
from dataclasses import dataclass
from datetime import date
import logging
from typing import List, Optional
from aiohttp import ClientSession, ClientTimeout
from aiohttp.client_exceptions import ClientError
from aiorecollect.errors import DataError, RequestError
_LOGGER = logging.getLogger(__name__)
API_URL_SCAFFOLD = "https://api.recollect.net/api/places/{0}/services/{1}/events"
DEFAULT_TIMEOUT = 10
@dataclass(frozen=True)
class PickupEvent:
"""Define a waste pickup."""
date: date
pickup_types: list
area_name: str
class Client:
"""Define a client."""
def __init__(
self, place_id: str, service_id: int, *, session: ClientSession = None
) -> None:
"""Initialize."""
self._api_url = API_URL_SCAFFOLD.format(place_id, service_id)
self._session = session
self.place_id = place_id
self.service_id = service_id
async def _async_get_pickup_data(
self, *, start_date: Optional[date] = None, end_date: Optional[date] = None
) -> dict:
"""Get pickup data (with an optional start and/or end date)."""
url = self._api_url
if start_date and end_date:
url += f"?after={start_date.isoformat()}&before={end_date.isoformat()}"
return await self._async_request("get", url)
async def _async_request(self, method: str, url: str, **kwargs) -> dict:
"""Make an API request."""
use_running_session = self._session and not self._session.closed
session: ClientSession
if use_running_session:
session = self._session
else:
session = ClientSession(timeout=ClientTimeout(total=DEFAULT_TIMEOUT))
try:
async with session.request(method, url, **kwargs) as resp:
data = await resp.json()
resp.raise_for_status()
return data
except ClientError as err:
raise RequestError(err) from None
finally:
if not use_running_session:
await session.close()
async def async_get_next_pickup_event(self) -> PickupEvent:
"""Get the very next pickup event."""
pickup_events = await self.async_get_pickup_events()
for event in pickup_events:
if event.date >= date.today():
return event
raise DataError("No pickup events found after today")
async def async_get_pickup_events(
self, *, start_date: Optional[date] = None, end_date: Optional[date] = None
) -> List[PickupEvent]:
"""Get pickup events."""
pickup_data = await self._async_get_pickup_data(
start_date=start_date, end_date=end_date
)
return [
PickupEvent(
date.fromisoformat(event["day"]),
[
pickup["name"]
for pickup in [
f for f in event["flags"] if f.get("event_type") == "pickup"
]
],
pickup_data["parcel_opts"]["_original"]["city"],
)
for event in [e for e in pickup_data["events"] if "flags" in e]
]