bookalimo 0.1.5__py3-none-any.whl → 1.0.1__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 +289 -0
- bookalimo/integrations/google_places/client_sync.py +287 -0
- bookalimo/integrations/google_places/common.py +231 -0
- bookalimo/integrations/google_places/proto_adapter.py +224 -0
- bookalimo/integrations/google_places/resolve_airport.py +397 -0
- bookalimo/integrations/google_places/transports.py +98 -0
- bookalimo/{_logging.py → logging.py} +45 -42
- bookalimo/schemas/__init__.py +103 -0
- bookalimo/schemas/base.py +56 -0
- bookalimo/{models.py → schemas/booking.py} +88 -100
- bookalimo/schemas/places/__init__.py +62 -0
- bookalimo/schemas/places/common.py +351 -0
- bookalimo/schemas/places/field_mask.py +221 -0
- bookalimo/schemas/places/google.py +883 -0
- bookalimo/schemas/places/place.py +334 -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.1.dist-info/METADATA +370 -0
- bookalimo-1.0.1.dist-info/RECORD +38 -0
- bookalimo-1.0.1.dist-info/licenses/LICENSE +21 -0
- bookalimo/_client.py +0 -420
- bookalimo/wrapper.py +0 -444
- bookalimo-0.1.5.dist-info/METADATA +0 -392
- bookalimo-0.1.5.dist-info/RECORD +0 -12
- bookalimo-0.1.5.dist-info/licenses/LICENSE +0 -0
- {bookalimo-0.1.5.dist-info → bookalimo-1.0.1.dist-info}/WHEEL +0 -0
- {bookalimo-0.1.5.dist-info → bookalimo-1.0.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,56 @@
|
|
1
|
+
"""
|
2
|
+
Shared base model for Book-A-Limo API data structures.
|
3
|
+
Handles automatic snake_case <-> camelCase conversion and enum serialization.
|
4
|
+
"""
|
5
|
+
|
6
|
+
from enum import Enum
|
7
|
+
from typing import Any, cast
|
8
|
+
|
9
|
+
from pydantic import BaseModel, ConfigDict, model_serializer
|
10
|
+
from pydantic.alias_generators import to_camel
|
11
|
+
from pydantic_core.core_schema import SerializationInfo, SerializerFunctionWrapHandler
|
12
|
+
|
13
|
+
|
14
|
+
class ApiModel(BaseModel):
|
15
|
+
"""
|
16
|
+
Base model for all Book-A-Limo API models.
|
17
|
+
|
18
|
+
Provides automatic field name conversion between Python snake_case
|
19
|
+
and API camelCase, plus proper enum handling.
|
20
|
+
"""
|
21
|
+
|
22
|
+
model_config = ConfigDict(
|
23
|
+
# Auto-generate camelCase aliases from snake_case field names
|
24
|
+
alias_generator=to_camel,
|
25
|
+
# Accept both alias (camel) and name (snake) on input (v2.11+)
|
26
|
+
validate_by_alias=True,
|
27
|
+
validate_by_name=True, # replaces populate_by_name
|
28
|
+
# Default to using aliases when dumping (wire format)
|
29
|
+
serialize_by_alias=True,
|
30
|
+
# Enums dumping handled in model_serializer
|
31
|
+
use_enum_values=False,
|
32
|
+
# Ignore unknown keys from the API
|
33
|
+
extra="ignore",
|
34
|
+
)
|
35
|
+
|
36
|
+
@model_serializer(mode="wrap")
|
37
|
+
def _serialize(
|
38
|
+
self, handler: SerializerFunctionWrapHandler, info: SerializationInfo
|
39
|
+
) -> dict[str, Any]:
|
40
|
+
# Run the normal serialization first (aliases, include/exclude, nested models, etc.)
|
41
|
+
data = handler(self)
|
42
|
+
|
43
|
+
# Decide how to emit enums based on context (default to 'value')
|
44
|
+
enum_out = (info.context or {}).get("enum_out", "value")
|
45
|
+
|
46
|
+
def convert(obj: Any) -> Any:
|
47
|
+
if isinstance(obj, Enum):
|
48
|
+
return obj.name if enum_out == "name" else obj.value
|
49
|
+
if isinstance(obj, dict):
|
50
|
+
return {k: convert(v) for k, v in obj.items()}
|
51
|
+
if isinstance(obj, (list, tuple)):
|
52
|
+
t = type(obj)
|
53
|
+
return t(convert(v) for v in obj)
|
54
|
+
return obj
|
55
|
+
|
56
|
+
return cast(dict[str, Any], convert(data))
|
@@ -1,20 +1,31 @@
|
|
1
1
|
"""
|
2
|
-
Pydantic
|
2
|
+
Pydantic schemas for Book-A-Limo booking operations.
|
3
|
+
Includes all models related to pricing, reservations, and booking requests.
|
3
4
|
"""
|
4
5
|
|
5
|
-
import hashlib
|
6
6
|
import warnings
|
7
7
|
from enum import Enum
|
8
|
+
from functools import lru_cache
|
8
9
|
from typing import Any, Optional
|
9
10
|
|
10
11
|
import airportsdata
|
11
12
|
import pycountry
|
12
13
|
import us
|
13
|
-
from pydantic import
|
14
|
+
from pydantic import Field, model_validator
|
14
15
|
from typing_extensions import Self
|
15
16
|
|
16
|
-
|
17
|
-
|
17
|
+
from .base import ApiModel
|
18
|
+
|
19
|
+
|
20
|
+
@lru_cache(maxsize=1)
|
21
|
+
def _load_iata_index() -> tuple[dict[str, Any], dict[str, list[str]]]:
|
22
|
+
"""Load and index airport data."""
|
23
|
+
data = airportsdata.load("IATA")
|
24
|
+
by_country: dict[str, list[str]] = {}
|
25
|
+
for code, rec in data.items():
|
26
|
+
c = (rec.get("country") or "").upper()
|
27
|
+
by_country.setdefault(c, []).append(code)
|
28
|
+
return data, by_country
|
18
29
|
|
19
30
|
|
20
31
|
class RateType(Enum):
|
@@ -67,7 +78,7 @@ class ReservationStatus(Enum):
|
|
67
78
|
class CardHolderType(Enum):
|
68
79
|
"""
|
69
80
|
Credit card holder types (API Documentation Unclear).
|
70
|
-
TODO: Update when API documentation is clarified by
|
81
|
+
TODO: Update when API documentation is clarified by the API author.
|
71
82
|
Best guess based on typical credit card processing:
|
72
83
|
"""
|
73
84
|
|
@@ -77,28 +88,13 @@ class CardHolderType(Enum):
|
|
77
88
|
UNKNOWN = 3 # From example in API doc
|
78
89
|
|
79
90
|
|
80
|
-
class
|
81
|
-
"""User credentials for API authentication."""
|
82
|
-
|
83
|
-
id: str
|
84
|
-
is_customer: bool = False
|
85
|
-
password_hash: str
|
86
|
-
|
87
|
-
@classmethod
|
88
|
-
def create_hash(cls, password: str, user_id: str) -> str:
|
89
|
-
"""Create password hash as required by API: Sha256(Sha256(Password) + LowerCase(Id))"""
|
90
|
-
inner_hash = hashlib.sha256(password.encode()).hexdigest()
|
91
|
-
full_string = inner_hash + user_id.lower()
|
92
|
-
return hashlib.sha256(full_string.encode()).hexdigest()
|
93
|
-
|
94
|
-
|
95
|
-
class City(BaseModel):
|
91
|
+
class City(ApiModel):
|
96
92
|
"""City information."""
|
97
93
|
|
98
94
|
city_name: str
|
99
95
|
country_code: str = Field(..., description="ISO 3166-1 alpha-2 country code")
|
100
|
-
state_code: Optional[str] = Field(None, description="US state code")
|
101
|
-
state_name: Optional[str] = Field(None, description="US state name")
|
96
|
+
state_code: Optional[str] = Field(default=None, description="US state code")
|
97
|
+
state_name: Optional[str] = Field(default=None, description="US state name")
|
102
98
|
|
103
99
|
@model_validator(mode="after")
|
104
100
|
def validate_country_code(self) -> Self:
|
@@ -111,6 +107,9 @@ class City(BaseModel):
|
|
111
107
|
@model_validator(mode="after")
|
112
108
|
def validate_us(self) -> Self:
|
113
109
|
"""Validate that state_code is a valid US state code and state_name is a valid US state name."""
|
110
|
+
if self.country_code != "US":
|
111
|
+
return self
|
112
|
+
|
114
113
|
code_match = us.states.lookup(str(self.state_code))
|
115
114
|
name_match = us.states.lookup(str(self.state_name))
|
116
115
|
if not code_match and not name_match:
|
@@ -131,28 +130,28 @@ class City(BaseModel):
|
|
131
130
|
)
|
132
131
|
|
133
132
|
|
134
|
-
class Address(
|
133
|
+
class Address(ApiModel):
|
135
134
|
"""
|
136
135
|
Address information.
|
137
|
-
|
138
|
-
Note: API documentation inconsistency - mentions 'googlePlaceId' in text
|
139
|
-
but examples use 'googleGeocode'. Following examples and using google_geocode.
|
140
|
-
TODO: Confirm with API author if this should be googlePlaceId instead.
|
141
136
|
"""
|
142
137
|
|
143
138
|
google_geocode: Optional[dict[str, Any]] = Field(
|
144
|
-
None, description="Raw Google Geocoding API response (recommended)"
|
139
|
+
default=None, description="Raw Google Geocoding API response (recommended)"
|
145
140
|
)
|
146
141
|
city: Optional[City] = Field(
|
147
|
-
None, description="Use only if google_geocode not available"
|
142
|
+
default=None, description="Use only if google_geocode not available"
|
143
|
+
)
|
144
|
+
district: Optional[str] = Field(default=None, description="e.g., Manhattan")
|
145
|
+
neighbourhood: Optional[str] = Field(
|
146
|
+
default=None, description="e.g., Lower Manhattan"
|
148
147
|
)
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
street_name: Optional[str] = Field(None, description="e.g., East 34th St")
|
153
|
-
building: Optional[str] = Field(None, description="e.g., 53")
|
154
|
-
suite: Optional[str] = Field(None, description="e.g., 5P")
|
155
|
-
zip: Optional[str] = Field(None, description="e.g., 10016")
|
148
|
+
place_name: Optional[str] = Field(
|
149
|
+
default=None, description="e.g., Empire State Building"
|
150
|
+
)
|
151
|
+
street_name: Optional[str] = Field(default=None, description="e.g., East 34th St")
|
152
|
+
building: Optional[str] = Field(default=None, description="e.g., 53")
|
153
|
+
suite: Optional[str] = Field(default=None, description="e.g., 5P")
|
154
|
+
zip: Optional[str] = Field(default=None, description="e.g., 10016")
|
156
155
|
|
157
156
|
@model_validator(mode="after")
|
158
157
|
def validate_address(self) -> Self:
|
@@ -173,37 +172,39 @@ class Address(BaseModel):
|
|
173
172
|
|
174
173
|
if self.city:
|
175
174
|
warnings.warn(
|
176
|
-
"
|
175
|
+
"Using google_geocode instead of city is recommended.",
|
177
176
|
stacklevel=3,
|
178
177
|
)
|
179
178
|
|
180
179
|
return self
|
181
180
|
|
182
181
|
|
183
|
-
class Airport(
|
182
|
+
class Airport(ApiModel):
|
184
183
|
"""Airport information."""
|
185
184
|
|
186
185
|
iata_code: str = Field(..., description="3-letter IATA code, e.g., JFK")
|
187
|
-
country_code: Optional[str] = Field(None, description="ISO 3166-1 alpha-2")
|
188
|
-
state_code: Optional[str] = Field(
|
186
|
+
country_code: Optional[str] = Field(default=None, description="ISO 3166-1 alpha-2")
|
187
|
+
state_code: Optional[str] = Field(
|
188
|
+
default=None, description="US state code, e.g., NY"
|
189
|
+
)
|
189
190
|
airline_iata_code: Optional[str] = Field(
|
190
|
-
None, description="2-letter IATA airline code"
|
191
|
+
default=None, description="2-letter IATA airline code"
|
191
192
|
)
|
192
193
|
airline_icao_code: Optional[str] = Field(
|
193
|
-
None, description="3-letter ICAO airline code"
|
194
|
+
default=None, description="3-letter ICAO airline code"
|
194
195
|
)
|
195
|
-
flight_number: Optional[str] = Field(None, description="e.g., UA1234")
|
196
|
-
terminal: Optional[str] = Field(None, description="e.g., 7")
|
196
|
+
flight_number: Optional[str] = Field(default=None, description="e.g., UA1234")
|
197
|
+
terminal: Optional[str] = Field(default=None, description="e.g., 7")
|
197
198
|
arriving_from_city: Optional[City] = None
|
198
199
|
meet_greet: Optional[int] = Field(
|
199
|
-
None,
|
200
|
+
default=None,
|
200
201
|
description="Meet & greet option ID. Leave empty on price request to see options.",
|
201
202
|
)
|
202
203
|
|
203
204
|
@model_validator(mode="after")
|
204
205
|
def validate_country_code(self) -> Self:
|
205
206
|
"""Validate that country_code is a valid ISO 3166-1 alpha-2 country code."""
|
206
|
-
if not pycountry.countries.get(alpha_2=self.country_code):
|
207
|
+
if self.country_code and not pycountry.countries.get(alpha_2=self.country_code):
|
207
208
|
raise ValueError(f"Invalid country code: {self.country_code}")
|
208
209
|
|
209
210
|
return self
|
@@ -218,16 +219,14 @@ class Airport(BaseModel):
|
|
218
219
|
|
219
220
|
@model_validator(mode="after")
|
220
221
|
def validate_airport(self) -> Self:
|
221
|
-
"""Validate that iata_code
|
222
|
-
if self.iata_code
|
222
|
+
"""Validate that iata_code is a valid IATA code."""
|
223
|
+
if self.iata_code not in _load_iata_index()[0]:
|
223
224
|
raise ValueError(f"Invalid IATA code: {self.iata_code}")
|
224
|
-
if self.airline_icao_code and self.airline_icao_code not in icao_data:
|
225
|
-
raise ValueError(f"Invalid ICAO code: {self.airline_icao_code}")
|
226
225
|
|
227
226
|
return self
|
228
227
|
|
229
228
|
|
230
|
-
class Location(
|
229
|
+
class Location(ApiModel):
|
231
230
|
"""Location (address or airport)."""
|
232
231
|
|
233
232
|
type: LocationType
|
@@ -245,14 +244,14 @@ class Location(BaseModel):
|
|
245
244
|
return self
|
246
245
|
|
247
246
|
|
248
|
-
class Stop(
|
247
|
+
class Stop(ApiModel):
|
249
248
|
"""Stop information."""
|
250
249
|
|
251
250
|
description: str = Field(..., description="Address, place name, or comment")
|
252
251
|
is_en_route: bool = Field(..., description="True if stop is en-route")
|
253
252
|
|
254
253
|
|
255
|
-
class Account(
|
254
|
+
class Account(ApiModel):
|
256
255
|
"""Travel agency or corporate account info."""
|
257
256
|
|
258
257
|
id: str = Field(..., description="TA or corporate account number")
|
@@ -260,10 +259,10 @@ class Account(BaseModel):
|
|
260
259
|
booker_first_name: Optional[str] = None
|
261
260
|
booker_last_name: Optional[str] = None
|
262
261
|
booker_email: Optional[str] = None
|
263
|
-
booker_phone: Optional[str] = Field(None, description="E164 format")
|
262
|
+
booker_phone: Optional[str] = Field(default=None, description="E164 format")
|
264
263
|
|
265
264
|
|
266
|
-
class Passenger(
|
265
|
+
class Passenger(ApiModel):
|
267
266
|
"""Passenger information."""
|
268
267
|
|
269
268
|
first_name: str
|
@@ -272,14 +271,14 @@ class Passenger(BaseModel):
|
|
272
271
|
phone: str = Field(..., description="E164 format recommended")
|
273
272
|
|
274
273
|
|
275
|
-
class Reward(
|
274
|
+
class Reward(ApiModel):
|
276
275
|
"""Reward account information."""
|
277
276
|
|
278
277
|
type: RewardType
|
279
278
|
value: str = Field(..., description="Reward account number")
|
280
279
|
|
281
280
|
|
282
|
-
class CreditCard(
|
281
|
+
class CreditCard(ApiModel):
|
283
282
|
"""Credit card information."""
|
284
283
|
|
285
284
|
number: str
|
@@ -288,12 +287,12 @@ class CreditCard(BaseModel):
|
|
288
287
|
card_holder: str
|
289
288
|
zip: Optional[str] = None
|
290
289
|
holder_type: Optional[CardHolderType] = Field(
|
291
|
-
None,
|
290
|
+
default=None,
|
292
291
|
description="Card holder type - API documentation unclear, using best guess",
|
293
292
|
)
|
294
293
|
|
295
294
|
|
296
|
-
class BreakdownItem(
|
295
|
+
class BreakdownItem(ApiModel):
|
297
296
|
"""Price breakdown item."""
|
298
297
|
|
299
298
|
name: str
|
@@ -303,14 +302,14 @@ class BreakdownItem(BaseModel):
|
|
303
302
|
)
|
304
303
|
|
305
304
|
|
306
|
-
class MeetGreetAdditional(
|
305
|
+
class MeetGreetAdditional(ApiModel):
|
307
306
|
"""Additional meet & greet charges."""
|
308
307
|
|
309
308
|
name: str
|
310
309
|
price: float
|
311
310
|
|
312
311
|
|
313
|
-
class MeetGreet(
|
312
|
+
class MeetGreet(ApiModel):
|
314
313
|
"""Meet & greet option."""
|
315
314
|
|
316
315
|
id: int
|
@@ -323,7 +322,7 @@ class MeetGreet(BaseModel):
|
|
323
322
|
reservation_price: float
|
324
323
|
|
325
324
|
|
326
|
-
class Price(
|
325
|
+
class Price(ApiModel):
|
327
326
|
"""Car class pricing information."""
|
328
327
|
|
329
328
|
car_class: str
|
@@ -339,7 +338,7 @@ class Price(BaseModel):
|
|
339
338
|
meet_greets: list[MeetGreet] = Field(default_factory=list)
|
340
339
|
|
341
340
|
|
342
|
-
class Reservation(
|
341
|
+
class Reservation(ApiModel):
|
343
342
|
"""Basic reservation information."""
|
344
343
|
|
345
344
|
confirmation_number: str
|
@@ -356,7 +355,7 @@ class Reservation(BaseModel):
|
|
356
355
|
status: Optional[ReservationStatus] = None
|
357
356
|
|
358
357
|
|
359
|
-
class EditableReservationRequest(
|
358
|
+
class EditableReservationRequest(ApiModel):
|
360
359
|
"""
|
361
360
|
Editable reservation for modifications.
|
362
361
|
|
@@ -368,11 +367,12 @@ class EditableReservationRequest(BaseModel):
|
|
368
367
|
confirmation: str
|
369
368
|
is_cancel_request: bool = False
|
370
369
|
rate_type: Optional[RateType] = None
|
371
|
-
pickup_date: Optional[str] = Field(None, description="MM/dd/yyyy format")
|
372
|
-
pickup_time: Optional[str] = Field(None, description="hh:mm tt format")
|
370
|
+
pickup_date: Optional[str] = Field(default=None, description="MM/dd/yyyy format")
|
371
|
+
pickup_time: Optional[str] = Field(default=None, description="hh:mm tt format")
|
373
372
|
stops: Optional[list[Stop]] = None
|
374
373
|
credit_card: Optional[CreditCard] = Field(
|
375
|
-
None,
|
374
|
+
default=None,
|
375
|
+
description="Conditionally required - unclear from API docs when exactly",
|
376
376
|
)
|
377
377
|
passengers: Optional[int] = None
|
378
378
|
luggage: Optional[int] = None
|
@@ -380,36 +380,30 @@ class EditableReservationRequest(BaseModel):
|
|
380
380
|
car_seats: Optional[int] = None
|
381
381
|
boosters: Optional[int] = None
|
382
382
|
infants: Optional[int] = None
|
383
|
-
other: Optional[str] = Field(None, description="Other changes not listed")
|
384
|
-
|
385
|
-
|
386
|
-
class EditableReservationRequestAuthenticated(EditableReservationRequest):
|
387
|
-
"""Request for editing reservation with authenticated credentials."""
|
388
|
-
|
389
|
-
credentials: Credentials
|
383
|
+
other: Optional[str] = Field(default=None, description="Other changes not listed")
|
390
384
|
|
391
385
|
|
392
386
|
# Request/Response Models
|
393
387
|
|
394
388
|
|
395
|
-
class PriceRequest(
|
389
|
+
class PriceRequest(ApiModel):
|
396
390
|
"""Request for getting prices."""
|
397
391
|
|
398
392
|
rate_type: RateType
|
399
393
|
date_time: str = Field(..., description="MM/dd/yyyy hh:mm tt format")
|
400
394
|
pickup: Location
|
401
395
|
dropoff: Location
|
402
|
-
hours: Optional[int] = Field(None, description="For hourly rate_type only")
|
396
|
+
hours: Optional[int] = Field(default=None, description="For hourly rate_type only")
|
403
397
|
passengers: int
|
404
398
|
luggage: int
|
405
399
|
stops: Optional[list[Stop]] = None
|
406
400
|
account: Optional[Account] = Field(
|
407
|
-
None, description="TAs must provide for commission"
|
401
|
+
default=None, description="TAs must provide for commission"
|
408
402
|
)
|
409
403
|
passenger: Optional[Passenger] = None
|
410
404
|
rewards: Optional[list[Reward]] = None
|
411
405
|
car_class_code: Optional[str] = Field(
|
412
|
-
None, description="e.g., 'SD' for specific car class"
|
406
|
+
default=None, description="e.g., 'SD' for specific car class"
|
413
407
|
)
|
414
408
|
pets: Optional[int] = None
|
415
409
|
car_seats: Optional[int] = None
|
@@ -418,20 +412,14 @@ class PriceRequest(BaseModel):
|
|
418
412
|
customer_comment: Optional[str] = None
|
419
413
|
|
420
414
|
|
421
|
-
class
|
422
|
-
"""Request for getting prices with authenticated credentials."""
|
423
|
-
|
424
|
-
credentials: Credentials
|
425
|
-
|
426
|
-
|
427
|
-
class PriceResponse(BaseModel):
|
415
|
+
class PriceResponse(ApiModel):
|
428
416
|
"""Response from get prices."""
|
429
417
|
|
430
418
|
token: str
|
431
419
|
prices: list[Price]
|
432
420
|
|
433
421
|
|
434
|
-
class DetailsRequest(
|
422
|
+
class DetailsRequest(ApiModel):
|
435
423
|
"""Request for setting reservation details."""
|
436
424
|
|
437
425
|
token: str
|
@@ -448,23 +436,25 @@ class DetailsRequest(BaseModel):
|
|
448
436
|
infants: Optional[int] = None
|
449
437
|
customer_comment: Optional[str] = None
|
450
438
|
ta_fee: Optional[float] = Field(
|
451
|
-
None, description="For Travel Agencies - additional fee in USD"
|
439
|
+
default=None, description="For Travel Agencies - additional fee in USD"
|
452
440
|
)
|
453
441
|
|
454
442
|
|
455
|
-
class DetailsResponse(
|
443
|
+
class DetailsResponse(ApiModel):
|
456
444
|
"""Response from set details."""
|
457
445
|
|
458
446
|
price: float
|
459
447
|
breakdown: list[BreakdownItem]
|
460
448
|
|
461
449
|
|
462
|
-
class BookRequest(
|
450
|
+
class BookRequest(ApiModel):
|
463
451
|
"""Request for booking reservation."""
|
464
452
|
|
465
453
|
token: str
|
466
454
|
promo: Optional[str] = None
|
467
|
-
method: Optional[str] = Field(
|
455
|
+
method: Optional[str] = Field(
|
456
|
+
default=None, description="'charge' for charge accounts"
|
457
|
+
)
|
468
458
|
credit_card: Optional[CreditCard] = None
|
469
459
|
|
470
460
|
@model_validator(mode="after")
|
@@ -476,20 +466,19 @@ class BookRequest(BaseModel):
|
|
476
466
|
return self
|
477
467
|
|
478
468
|
|
479
|
-
class BookResponse(
|
469
|
+
class BookResponse(ApiModel):
|
480
470
|
"""Response from book reservation."""
|
481
471
|
|
482
472
|
reservation_id: str
|
483
473
|
|
484
474
|
|
485
|
-
class ListReservationsRequest(
|
475
|
+
class ListReservationsRequest(ApiModel):
|
486
476
|
"""Request for listing reservations."""
|
487
477
|
|
488
|
-
credentials: Credentials
|
489
478
|
is_archive: bool = False
|
490
479
|
|
491
480
|
|
492
|
-
class ListReservationsResponse(
|
481
|
+
class ListReservationsResponse(ApiModel):
|
493
482
|
"""Response from list reservations."""
|
494
483
|
|
495
484
|
success: bool
|
@@ -497,14 +486,13 @@ class ListReservationsResponse(BaseModel):
|
|
497
486
|
error: Optional[str] = None
|
498
487
|
|
499
488
|
|
500
|
-
class GetReservationRequest(
|
489
|
+
class GetReservationRequest(ApiModel):
|
501
490
|
"""Request for getting reservation details."""
|
502
491
|
|
503
|
-
credentials: Credentials
|
504
492
|
confirmation: str
|
505
493
|
|
506
494
|
|
507
|
-
class GetReservationResponse(
|
495
|
+
class GetReservationResponse(ApiModel):
|
508
496
|
"""Response from get reservation."""
|
509
497
|
|
510
498
|
reservation: EditableReservationRequest
|
@@ -526,7 +514,7 @@ class GetReservationResponse(BaseModel):
|
|
526
514
|
pending_changes: list[list[str]] = Field(default_factory=list)
|
527
515
|
|
528
516
|
|
529
|
-
class EditReservationResponse(
|
517
|
+
class EditReservationResponse(ApiModel):
|
530
518
|
"""Response from edit reservation."""
|
531
519
|
|
532
520
|
success: bool
|
@@ -0,0 +1,62 @@
|
|
1
|
+
"""Google Places API schemas."""
|
2
|
+
|
3
|
+
from .common import AddressDescriptor
|
4
|
+
from .field_mask import FieldMaskInput, FieldPath, compile_field_mask
|
5
|
+
from .google import (
|
6
|
+
AutocompletePlacesRequest,
|
7
|
+
AutocompletePlacesResponse,
|
8
|
+
Circle,
|
9
|
+
EVConnectorType,
|
10
|
+
EVOptions,
|
11
|
+
FormattableText,
|
12
|
+
GeocodingRequest,
|
13
|
+
GetPlaceRequest,
|
14
|
+
LocationBias,
|
15
|
+
LocationRestriction,
|
16
|
+
Place,
|
17
|
+
PlacePrediction,
|
18
|
+
PlaceType,
|
19
|
+
QueryPrediction,
|
20
|
+
RankPreference,
|
21
|
+
ResolvedAirport,
|
22
|
+
RoutingParameters,
|
23
|
+
SearchTextLocationRestriction,
|
24
|
+
SearchTextRequest,
|
25
|
+
SearchTextResponse,
|
26
|
+
StringRange,
|
27
|
+
StructuredFormat,
|
28
|
+
Suggestion,
|
29
|
+
)
|
30
|
+
from .place import AddressComponent, GooglePlace
|
31
|
+
|
32
|
+
__all__ = [
|
33
|
+
"PlaceType",
|
34
|
+
"RankPreference",
|
35
|
+
"EVConnectorType",
|
36
|
+
"StringRange",
|
37
|
+
"FormattableText",
|
38
|
+
"StructuredFormat",
|
39
|
+
"Circle",
|
40
|
+
"LocationBias",
|
41
|
+
"LocationRestriction",
|
42
|
+
"SearchTextLocationRestriction",
|
43
|
+
"Place",
|
44
|
+
"GooglePlace",
|
45
|
+
"AutocompletePlacesResponse",
|
46
|
+
"PlacePrediction",
|
47
|
+
"QueryPrediction",
|
48
|
+
"Suggestion",
|
49
|
+
"GetPlaceRequest",
|
50
|
+
"AutocompletePlacesRequest",
|
51
|
+
"GeocodingRequest",
|
52
|
+
"SearchTextRequest",
|
53
|
+
"ResolvedAirport",
|
54
|
+
"AddressDescriptor",
|
55
|
+
"AddressComponent",
|
56
|
+
"FieldMaskInput",
|
57
|
+
"FieldPath",
|
58
|
+
"compile_field_mask",
|
59
|
+
"EVOptions",
|
60
|
+
"RoutingParameters",
|
61
|
+
"SearchTextResponse",
|
62
|
+
]
|