bookalimo 0.1.4__py3-none-any.whl → 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bookalimo/__init__.py +17 -24
- bookalimo/_version.py +9 -0
- bookalimo/client.py +310 -0
- bookalimo/config.py +16 -0
- bookalimo/exceptions.py +115 -5
- bookalimo/integrations/__init__.py +1 -0
- bookalimo/integrations/google_places/__init__.py +31 -0
- bookalimo/integrations/google_places/client_async.py +258 -0
- bookalimo/integrations/google_places/client_sync.py +257 -0
- bookalimo/integrations/google_places/common.py +245 -0
- bookalimo/integrations/google_places/proto_adapter.py +224 -0
- bookalimo/{_logging.py → logging.py} +59 -62
- bookalimo/schemas/__init__.py +97 -0
- bookalimo/schemas/base.py +56 -0
- bookalimo/{models.py → schemas/booking.py} +88 -100
- bookalimo/schemas/places/__init__.py +37 -0
- bookalimo/schemas/places/common.py +198 -0
- bookalimo/schemas/places/google.py +596 -0
- bookalimo/schemas/places/place.py +337 -0
- bookalimo/services/__init__.py +11 -0
- bookalimo/services/pricing.py +191 -0
- bookalimo/services/reservations.py +227 -0
- bookalimo/transport/__init__.py +7 -0
- bookalimo/transport/auth.py +41 -0
- bookalimo/transport/base.py +44 -0
- bookalimo/transport/httpx_async.py +230 -0
- bookalimo/transport/httpx_sync.py +230 -0
- bookalimo/transport/retry.py +102 -0
- bookalimo/transport/utils.py +59 -0
- bookalimo-1.0.0.dist-info/METADATA +307 -0
- bookalimo-1.0.0.dist-info/RECORD +35 -0
- bookalimo/_client.py +0 -420
- bookalimo/wrapper.py +0 -444
- bookalimo-0.1.4.dist-info/METADATA +0 -392
- bookalimo-0.1.4.dist-info/RECORD +0 -12
- {bookalimo-0.1.4.dist-info → bookalimo-1.0.0.dist-info}/WHEEL +0 -0
- {bookalimo-0.1.4.dist-info → bookalimo-1.0.0.dist-info}/licenses/LICENSE +0 -0
- {bookalimo-0.1.4.dist-info → bookalimo-1.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
bookalimo/__init__.py,sha256=ZFDpnSOo5VQEgusbVAxyF-neFxBptPZANZ-eE1PeIsU,516
|
2
|
+
bookalimo/_version.py,sha256=KcHRbOssHorjmpk3Xs1RTqGNSA-sw9tjYqwV19Zfa9c,259
|
3
|
+
bookalimo/client.py,sha256=za9o_D1jkaq7atWpM5d3bguWO-rtMYr5StXrBZInsMg,10599
|
4
|
+
bookalimo/config.py,sha256=LSbWIeTZYc4b3XSCmPSEU-jEcYmo7GWAyxdOmA69X6A,509
|
5
|
+
bookalimo/exceptions.py,sha256=pShnuvfMZEP_cChczWhNBLIqa7EOgr4ZNnWj6kphARU,4001
|
6
|
+
bookalimo/logging.py,sha256=IF6RQRJvVHgmpXK1qMEGcd0BjU6GxvzbNUBrBKHe-v8,7409
|
7
|
+
bookalimo/py.typed,sha256=8PjyZ1aVoQpRVvt71muvuq5qE-jTFZkK-GLHkhdebmc,26
|
8
|
+
bookalimo/integrations/__init__.py,sha256=edmQP2Uo8JiNIVaeB4rxM8vagz7BQBhyGEJo70OVS0M,51
|
9
|
+
bookalimo/integrations/google_places/__init__.py,sha256=A6jBfGk8ZLYgFiTCGBytBOsyzKVWHI_kjnuZOgdCONc,866
|
10
|
+
bookalimo/integrations/google_places/client_async.py,sha256=6hfl3am2qtJLZHogPk57a-jFNqRzTJt3dyj58Mpt290,8956
|
11
|
+
bookalimo/integrations/google_places/client_sync.py,sha256=uscvNJuUb6iF8q29f_ZgftGmPWv2Zog72t0E8PCBmFY,8840
|
12
|
+
bookalimo/integrations/google_places/common.py,sha256=MphkEGarmM8AapjBrdsWRAg0yXyzMFZad_S8YB-esbI,7219
|
13
|
+
bookalimo/integrations/google_places/proto_adapter.py,sha256=XuVDr-PH9fopykRwNZxQTS_kIBCdwPwcNYBIHCZjmRo,6809
|
14
|
+
bookalimo/schemas/__init__.py,sha256=vS9skyuk5WV472TKgBqAg5Qzwvb0Bh0n4ff9BDSl8aE,1919
|
15
|
+
bookalimo/schemas/base.py,sha256=XEe0Qg7p-LzTmUOJ8CLVDsrry2lKn8sWNin7zwBiw-U,2022
|
16
|
+
bookalimo/schemas/booking.py,sha256=ll1usMa6Rfuz63LAWimWlz1UswWn26ZOPBpclN-8yGY,15861
|
17
|
+
bookalimo/schemas/places/__init__.py,sha256=SkUR6EIvnetNWqhLOiuq0k5Zy5XA4yZp8F2U92qCPOI,713
|
18
|
+
bookalimo/schemas/places/common.py,sha256=v39FpI3i7aDWRWsnb2zzSDddNE09XyQ5WVACBww3uC8,5425
|
19
|
+
bookalimo/schemas/places/google.py,sha256=HbQHKTj9bk6q-KaFWNMkKTgQIvp3kZF8dSnPqguy4Ng,20050
|
20
|
+
bookalimo/schemas/places/place.py,sha256=Y55QFhm7zjsqwjbPxHwNTl_02u30Yv2TqrhtBzgb6iM,10620
|
21
|
+
bookalimo/services/__init__.py,sha256=4wom7MpoeqKy5y99LYFKkl-CAJ7faDN9ZlXUhKVqlAg,303
|
22
|
+
bookalimo/services/pricing.py,sha256=MIUVzdnZsmxEEyw9qUdjj71gt3MsckiVLgfXqnPHmNE,5873
|
23
|
+
bookalimo/services/reservations.py,sha256=OsbVrVJRggjnifh1eER9PHGqt4PwxZ-Jq1-Dpo4wGKk,7147
|
24
|
+
bookalimo/transport/__init__.py,sha256=yD5TDnoqg1xtex41jqJ7Hes849efiYgvW3nkaYr6ZjE,221
|
25
|
+
bookalimo/transport/auth.py,sha256=n1XWtU3ddodsDuTuXnDw_pE0qaTe1zrOv7fqHGyOiCg,1249
|
26
|
+
bookalimo/transport/base.py,sha256=qeX2HfLaE6gUT5evjOdPiBh8x7z7A84UuWVsgBK3Pyo,1394
|
27
|
+
bookalimo/transport/httpx_async.py,sha256=XbXbxcAdUc_CQh_XEYsL0WH6vvECP4fcZWfFCeW5wEU,8100
|
28
|
+
bookalimo/transport/httpx_sync.py,sha256=SIlDfiIYKQgAvWsOVeEgxNxlqTKviN_LJX4r8i4Cl5M,7988
|
29
|
+
bookalimo/transport/retry.py,sha256=YiJtcdNZUbkrLa1CtKsRtcFO273XJX8naKd8d6ht0LU,2688
|
30
|
+
bookalimo/transport/utils.py,sha256=Yoj4P5AzuHbf6pzNPtiiswKab4nHZTCOpIff30-sgbw,1797
|
31
|
+
bookalimo-1.0.0.dist-info/licenses/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
32
|
+
bookalimo-1.0.0.dist-info/METADATA,sha256=J_p8zz2sgot7msNBGa8dxLSDG-7nYXoLsGQrZcmggnw,9754
|
33
|
+
bookalimo-1.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
34
|
+
bookalimo-1.0.0.dist-info/top_level.txt,sha256=ZgYiDX2GfZCp4pevWn4X2qyEr-Dh7-cq5Y1j2jMhB1s,10
|
35
|
+
bookalimo-1.0.0.dist-info/RECORD,,
|
bookalimo/_client.py
DELETED
@@ -1,420 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Base HTTP client for Book-A-Limo API.
|
3
|
-
Handles authentication, headers, and common request/response patterns.
|
4
|
-
"""
|
5
|
-
|
6
|
-
import logging
|
7
|
-
from enum import Enum
|
8
|
-
from functools import lru_cache
|
9
|
-
from time import perf_counter
|
10
|
-
from typing import Any, Optional, TypeVar, cast, overload
|
11
|
-
from uuid import uuid4
|
12
|
-
|
13
|
-
import httpx
|
14
|
-
from pydantic import BaseModel
|
15
|
-
|
16
|
-
from ._logging import get_logger
|
17
|
-
from .exceptions import BookALimoError
|
18
|
-
from .models import (
|
19
|
-
BookRequest,
|
20
|
-
BookResponse,
|
21
|
-
Credentials,
|
22
|
-
DetailsRequest,
|
23
|
-
DetailsResponse,
|
24
|
-
EditableReservationRequest,
|
25
|
-
EditableReservationRequestAuthenticated,
|
26
|
-
EditReservationResponse,
|
27
|
-
GetReservationRequest,
|
28
|
-
GetReservationResponse,
|
29
|
-
ListReservationsRequest,
|
30
|
-
ListReservationsResponse,
|
31
|
-
PriceRequest,
|
32
|
-
PriceRequestAuthenticated,
|
33
|
-
PriceResponse,
|
34
|
-
)
|
35
|
-
|
36
|
-
logger = get_logger("client")
|
37
|
-
|
38
|
-
T = TypeVar("T")
|
39
|
-
|
40
|
-
|
41
|
-
@lru_cache(maxsize=1)
|
42
|
-
def get_version() -> str:
|
43
|
-
"""Get the version of the BookALimo client."""
|
44
|
-
from bookalimo import __version__
|
45
|
-
|
46
|
-
return __version__
|
47
|
-
|
48
|
-
|
49
|
-
class BookALimoClient:
|
50
|
-
"""
|
51
|
-
Base HTTP client for Book-A-Limo API.
|
52
|
-
Centralizes headers, auth, request helpers, and error handling.
|
53
|
-
"""
|
54
|
-
|
55
|
-
def __init__(
|
56
|
-
self,
|
57
|
-
client: httpx.AsyncClient,
|
58
|
-
credentials: Credentials,
|
59
|
-
user_agent: str = "bookalimo-python",
|
60
|
-
version: Optional[str] = None,
|
61
|
-
base_url: str = "https://api.bookalimo.com",
|
62
|
-
http_timeout: float = 5.0,
|
63
|
-
):
|
64
|
-
"""Initialize the client with an HTTP client."""
|
65
|
-
self.client = client
|
66
|
-
version = version or get_version()
|
67
|
-
self.credentials = credentials
|
68
|
-
self.headers = {
|
69
|
-
"content-type": "application/json",
|
70
|
-
"user-agent": f"{user_agent}/{version}",
|
71
|
-
}
|
72
|
-
self.base_url = base_url
|
73
|
-
self.http_timeout = http_timeout
|
74
|
-
if logger.isEnabledFor(logging.DEBUG):
|
75
|
-
logger.debug(
|
76
|
-
"Client initialized (base_url=%s, timeout=%s, user_agent=%s)",
|
77
|
-
self.base_url,
|
78
|
-
self.http_timeout,
|
79
|
-
self.headers.get("user-agent"),
|
80
|
-
)
|
81
|
-
|
82
|
-
def _convert_model_to_api_dict(self, data: dict[str, Any]) -> dict[str, Any]:
|
83
|
-
"""
|
84
|
-
Convert Python model field names to API field names.
|
85
|
-
Handles snake_case to camelCase and other API-specific naming.
|
86
|
-
"""
|
87
|
-
converted: dict[str, Any] = {}
|
88
|
-
|
89
|
-
for key, value in data.items():
|
90
|
-
# Convert snake_case to camelCase for API
|
91
|
-
api_key = self._to_camel_case(key)
|
92
|
-
|
93
|
-
# Handle nested objects
|
94
|
-
if isinstance(value, dict):
|
95
|
-
converted[api_key] = self._convert_model_to_api_dict(value)
|
96
|
-
elif isinstance(value, list):
|
97
|
-
converted[api_key] = [
|
98
|
-
(
|
99
|
-
self._convert_model_to_api_dict(item)
|
100
|
-
if isinstance(item, dict)
|
101
|
-
else item
|
102
|
-
)
|
103
|
-
for item in value
|
104
|
-
]
|
105
|
-
else:
|
106
|
-
converted[api_key] = value
|
107
|
-
|
108
|
-
return converted
|
109
|
-
|
110
|
-
def _to_camel_case(self, snake_str: str) -> str:
|
111
|
-
"""Convert snake_case to camelCase."""
|
112
|
-
if "_" not in snake_str:
|
113
|
-
return snake_str
|
114
|
-
|
115
|
-
components = snake_str.split("_")
|
116
|
-
return components[0] + "".join(word.capitalize() for word in components[1:])
|
117
|
-
|
118
|
-
def _convert_api_to_model_dict(self, data: dict[str, Any]) -> dict[str, Any]:
|
119
|
-
"""
|
120
|
-
Convert API response field names to Python model field names.
|
121
|
-
Handles camelCase to snake_case conversion.
|
122
|
-
"""
|
123
|
-
converted: dict[str, Any] = {}
|
124
|
-
|
125
|
-
for key, value in data.items():
|
126
|
-
# Convert camelCase to snake_case
|
127
|
-
model_key = self._to_snake_case(key)
|
128
|
-
|
129
|
-
# Handle nested objects
|
130
|
-
if isinstance(value, dict):
|
131
|
-
converted[model_key] = self._convert_api_to_model_dict(value)
|
132
|
-
elif isinstance(value, list):
|
133
|
-
converted[model_key] = [
|
134
|
-
(
|
135
|
-
self._convert_api_to_model_dict(item)
|
136
|
-
if isinstance(item, dict)
|
137
|
-
else item
|
138
|
-
)
|
139
|
-
for item in value
|
140
|
-
]
|
141
|
-
else:
|
142
|
-
converted[model_key] = value
|
143
|
-
|
144
|
-
return converted
|
145
|
-
|
146
|
-
@overload
|
147
|
-
def handle_enums(self, obj: Enum) -> Any: ...
|
148
|
-
@overload
|
149
|
-
def handle_enums(self, obj: dict[str, Any]) -> dict[str, Any]: ...
|
150
|
-
@overload
|
151
|
-
def handle_enums(self, obj: list[Any]) -> list[Any]: ...
|
152
|
-
@overload
|
153
|
-
def handle_enums(self, obj: tuple[Any, ...]) -> tuple[Any, ...]: ...
|
154
|
-
@overload
|
155
|
-
def handle_enums(self, obj: set[Any]) -> set[Any]: ...
|
156
|
-
@overload
|
157
|
-
def handle_enums(self, obj: Any) -> Any: ...
|
158
|
-
|
159
|
-
def handle_enums(self, obj: Any) -> Any:
|
160
|
-
"""
|
161
|
-
Simple utility to convert enums to their values for JSON serialization.
|
162
|
-
|
163
|
-
Args:
|
164
|
-
obj: Any object that might contain enums
|
165
|
-
|
166
|
-
Returns:
|
167
|
-
Object with enums converted to their values
|
168
|
-
"""
|
169
|
-
if isinstance(obj, Enum):
|
170
|
-
return obj.value
|
171
|
-
elif isinstance(obj, dict):
|
172
|
-
return {k: self.handle_enums(v) for k, v in obj.items()}
|
173
|
-
elif isinstance(obj, (list, tuple)):
|
174
|
-
return type(obj)(self.handle_enums(item) for item in obj)
|
175
|
-
elif isinstance(obj, set):
|
176
|
-
return {self.handle_enums(item) for item in obj}
|
177
|
-
else:
|
178
|
-
return obj
|
179
|
-
|
180
|
-
def _to_snake_case(self, camel_str: str) -> str:
|
181
|
-
"""Convert camelCase to snake_case."""
|
182
|
-
result = []
|
183
|
-
for i, char in enumerate(camel_str):
|
184
|
-
if char.isupper() and i > 0:
|
185
|
-
result.append("_")
|
186
|
-
result.append(char.lower())
|
187
|
-
return "".join(result)
|
188
|
-
|
189
|
-
def prepare_data(self, data: BaseModel) -> dict[str, Any]:
|
190
|
-
"""
|
191
|
-
Prepare data for API requests by converting it to the appropriate format.
|
192
|
-
|
193
|
-
Args:
|
194
|
-
data: The data to prepare, as a Pydantic model instance.
|
195
|
-
|
196
|
-
Returns:
|
197
|
-
A dictionary representation of the data, ready for API consumption.
|
198
|
-
"""
|
199
|
-
api_data = self._convert_model_to_api_dict(data.model_dump())
|
200
|
-
api_data = self._remove_none_values(api_data)
|
201
|
-
api_data = self.handle_enums(api_data)
|
202
|
-
return cast(dict[str, Any], api_data)
|
203
|
-
|
204
|
-
async def _make_request(
|
205
|
-
self,
|
206
|
-
endpoint: str,
|
207
|
-
data: BaseModel,
|
208
|
-
model: type[BaseModel],
|
209
|
-
timeout: Optional[float] = None,
|
210
|
-
) -> BaseModel:
|
211
|
-
url = f"{self.base_url}{endpoint}"
|
212
|
-
|
213
|
-
# Convert model data to API format
|
214
|
-
api_data = self.prepare_data(data)
|
215
|
-
|
216
|
-
debug_on = logger.isEnabledFor(logging.DEBUG)
|
217
|
-
req_id = None
|
218
|
-
if debug_on:
|
219
|
-
req_id = uuid4().hex[:8]
|
220
|
-
start = perf_counter()
|
221
|
-
body_keys = sorted(k for k in api_data.keys() if k != "credentials")
|
222
|
-
logger.debug(
|
223
|
-
"→ [%s] POST %s timeout=%s body_keys=%s",
|
224
|
-
req_id,
|
225
|
-
endpoint,
|
226
|
-
timeout or self.http_timeout,
|
227
|
-
body_keys,
|
228
|
-
)
|
229
|
-
|
230
|
-
try:
|
231
|
-
response = await self.client.post(
|
232
|
-
url,
|
233
|
-
json=api_data,
|
234
|
-
headers=self.headers,
|
235
|
-
timeout=timeout or self.http_timeout,
|
236
|
-
)
|
237
|
-
response.raise_for_status()
|
238
|
-
|
239
|
-
# HTTP 4xx/5xx already raise in httpx, but keep defensive check:
|
240
|
-
if response.status_code >= 400:
|
241
|
-
error_msg = f"HTTP {response.status_code}"
|
242
|
-
if debug_on:
|
243
|
-
logger.warning("× [%s] %s %s", req_id or "-", endpoint, error_msg)
|
244
|
-
raise BookALimoError(
|
245
|
-
f"{error_msg}: {response.text}",
|
246
|
-
status_code=response.status_code,
|
247
|
-
response_data={"raw_response": response.text},
|
248
|
-
)
|
249
|
-
|
250
|
-
try:
|
251
|
-
json_data = response.json()
|
252
|
-
except ValueError as e:
|
253
|
-
if debug_on:
|
254
|
-
logger.warning("× [%s] %s invalid JSON", req_id or "-", endpoint)
|
255
|
-
raise BookALimoError(f"Invalid JSON response: {str(e)}") from e
|
256
|
-
|
257
|
-
# API-level errors
|
258
|
-
if isinstance(json_data, dict):
|
259
|
-
if json_data.get("error"):
|
260
|
-
if debug_on:
|
261
|
-
logger.warning("× [%s] %s API error", req_id or "-", endpoint)
|
262
|
-
raise BookALimoError(
|
263
|
-
f"API Error: {json_data['error']}", response_data=json_data
|
264
|
-
)
|
265
|
-
if "success" in json_data and not json_data["success"]:
|
266
|
-
msg = json_data.get("error", "Unknown API error")
|
267
|
-
if debug_on:
|
268
|
-
logger.warning("× [%s] %s API error", req_id or "-", endpoint)
|
269
|
-
raise BookALimoError(f"API Error: {msg}", response_data=json_data)
|
270
|
-
|
271
|
-
if debug_on:
|
272
|
-
dur_ms = (perf_counter() - start) * 1000.0
|
273
|
-
reqid_hdr = response.headers.get(
|
274
|
-
"x-request-id"
|
275
|
-
) or response.headers.get("request-id")
|
276
|
-
content_len = None
|
277
|
-
try:
|
278
|
-
content_len = len(response.content)
|
279
|
-
except Exception:
|
280
|
-
pass
|
281
|
-
logger.debug(
|
282
|
-
"← [%s] %s %s in %.1f ms len=%s reqid=%s",
|
283
|
-
req_id,
|
284
|
-
response.status_code,
|
285
|
-
endpoint,
|
286
|
-
dur_ms,
|
287
|
-
content_len,
|
288
|
-
reqid_hdr,
|
289
|
-
)
|
290
|
-
|
291
|
-
return model.model_validate(self._convert_api_to_model_dict(json_data))
|
292
|
-
|
293
|
-
except httpx.TimeoutException:
|
294
|
-
if debug_on:
|
295
|
-
logger.warning(
|
296
|
-
"× [%s] %s timeout after %ss",
|
297
|
-
req_id or "-",
|
298
|
-
endpoint,
|
299
|
-
timeout or self.http_timeout,
|
300
|
-
)
|
301
|
-
raise BookALimoError(
|
302
|
-
f"Request timeout after {timeout or self.http_timeout}s"
|
303
|
-
) from None
|
304
|
-
except httpx.ConnectError:
|
305
|
-
if debug_on:
|
306
|
-
logger.warning("× [%s] %s connection error", req_id or "-", endpoint)
|
307
|
-
raise BookALimoError(
|
308
|
-
"Connection error - unable to reach Book-A-Limo API"
|
309
|
-
) from None
|
310
|
-
except httpx.HTTPError as e:
|
311
|
-
if debug_on:
|
312
|
-
logger.warning(
|
313
|
-
"× [%s] %s HTTP error: %s",
|
314
|
-
req_id or "-",
|
315
|
-
endpoint,
|
316
|
-
e.__class__.__name__,
|
317
|
-
)
|
318
|
-
raise BookALimoError(f"HTTP Error: {str(e)}") from e
|
319
|
-
except BookALimoError:
|
320
|
-
# already logged above where relevant
|
321
|
-
raise
|
322
|
-
except Exception as e:
|
323
|
-
if debug_on:
|
324
|
-
logger.warning(
|
325
|
-
"× [%s] %s unexpected error: %s",
|
326
|
-
req_id or "-",
|
327
|
-
endpoint,
|
328
|
-
e.__class__.__name__,
|
329
|
-
)
|
330
|
-
raise BookALimoError(f"Unexpected error: {str(e)}") from e
|
331
|
-
|
332
|
-
@overload
|
333
|
-
def _remove_none_values(self, data: dict[str, Any]) -> dict[str, Any]: ...
|
334
|
-
@overload
|
335
|
-
def _remove_none_values(self, data: list[Any]) -> list[Any]: ...
|
336
|
-
@overload
|
337
|
-
def _remove_none_values(self, data: Any) -> Any: ...
|
338
|
-
|
339
|
-
def _remove_none_values(self, data: Any) -> Any:
|
340
|
-
"""Recursively remove None values from data structure."""
|
341
|
-
if isinstance(data, dict):
|
342
|
-
return {
|
343
|
-
k: self._remove_none_values(v) for k, v in data.items() if v is not None
|
344
|
-
}
|
345
|
-
elif isinstance(data, list):
|
346
|
-
return [self._remove_none_values(item) for item in data]
|
347
|
-
else:
|
348
|
-
return data
|
349
|
-
|
350
|
-
async def list_reservations(
|
351
|
-
self, is_archive: bool = False
|
352
|
-
) -> ListReservationsResponse:
|
353
|
-
"""List reservations for the given credentials."""
|
354
|
-
data = ListReservationsRequest(
|
355
|
-
credentials=self.credentials, is_archive=is_archive
|
356
|
-
)
|
357
|
-
return cast(
|
358
|
-
ListReservationsResponse,
|
359
|
-
await self._make_request(
|
360
|
-
"/booking/reservation/list/", data, model=ListReservationsResponse
|
361
|
-
),
|
362
|
-
)
|
363
|
-
|
364
|
-
async def get_reservation(self, confirmation: str) -> GetReservationResponse:
|
365
|
-
"""Get detailed reservation information."""
|
366
|
-
data = GetReservationRequest(
|
367
|
-
credentials=self.credentials, confirmation=confirmation
|
368
|
-
)
|
369
|
-
return cast(
|
370
|
-
GetReservationResponse,
|
371
|
-
await self._make_request(
|
372
|
-
"/booking/reservation/get/", data, model=GetReservationResponse
|
373
|
-
),
|
374
|
-
)
|
375
|
-
|
376
|
-
async def get_prices(self, price_request: PriceRequest) -> PriceResponse:
|
377
|
-
"""Get pricing for a trip."""
|
378
|
-
price_request_authenticated = PriceRequestAuthenticated(
|
379
|
-
credentials=self.credentials, **price_request.model_dump()
|
380
|
-
)
|
381
|
-
return cast(
|
382
|
-
PriceResponse,
|
383
|
-
await self._make_request(
|
384
|
-
"/booking/price/", price_request_authenticated, model=PriceResponse
|
385
|
-
),
|
386
|
-
)
|
387
|
-
|
388
|
-
async def set_details(self, details_request: DetailsRequest) -> DetailsResponse:
|
389
|
-
"""Set reservation details and get updated pricing."""
|
390
|
-
return cast(
|
391
|
-
DetailsResponse,
|
392
|
-
await self._make_request(
|
393
|
-
"/booking/details/", details_request, model=DetailsResponse
|
394
|
-
),
|
395
|
-
)
|
396
|
-
|
397
|
-
async def book_reservation(self, book_request: BookRequest) -> BookResponse:
|
398
|
-
"""Book a reservation."""
|
399
|
-
return cast(
|
400
|
-
BookResponse,
|
401
|
-
await self._make_request(
|
402
|
-
"/booking/book/", book_request, model=BookResponse
|
403
|
-
),
|
404
|
-
)
|
405
|
-
|
406
|
-
async def edit_reservation(
|
407
|
-
self, edit_request: EditableReservationRequest
|
408
|
-
) -> EditReservationResponse:
|
409
|
-
"""Edit or cancel a reservation."""
|
410
|
-
edit_request_authenticated = EditableReservationRequestAuthenticated(
|
411
|
-
credentials=self.credentials, **edit_request.model_dump()
|
412
|
-
)
|
413
|
-
return cast(
|
414
|
-
EditReservationResponse,
|
415
|
-
await self._make_request(
|
416
|
-
"/booking/edit/",
|
417
|
-
edit_request_authenticated,
|
418
|
-
model=EditReservationResponse,
|
419
|
-
),
|
420
|
-
)
|