bookalimo 1.0.0__py3-none-any.whl → 1.0.2__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.
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import List, Optional
3
+ from enum import IntEnum
4
+ from typing import Optional
4
5
 
5
6
  from pydantic import (
6
7
  AnyUrl,
@@ -24,6 +25,7 @@ from .common import (
24
25
  EVChargeOptions,
25
26
  FuelOptions,
26
27
  LatLng,
28
+ LocalizedText,
27
29
  OpeningHours,
28
30
  ParkingOptions,
29
31
  PaymentOptions,
@@ -38,7 +40,7 @@ from .common import (
38
40
  )
39
41
 
40
42
 
41
- class PriceLevel(int):
43
+ class PriceLevel(IntEnum):
42
44
  PRICE_LEVEL_UNSPECIFIED = 0
43
45
  PRICE_LEVEL_FREE = 1
44
46
  PRICE_LEVEL_INEXPENSIVE = 2
@@ -47,7 +49,7 @@ class PriceLevel(int):
47
49
  PRICE_LEVEL_VERY_EXPENSIVE = 5
48
50
 
49
51
 
50
- class BusinessStatus(int):
52
+ class BusinessStatus(IntEnum):
51
53
  BUSINESS_STATUS_UNSPECIFIED = 0
52
54
  OPERATIONAL = 1
53
55
  CLOSED_TEMPORARILY = 2
@@ -59,12 +61,14 @@ class AddressComponent(BaseModel):
59
61
 
60
62
  long_text: str
61
63
  short_text: Optional[str] = None
62
- types: List[str] = Field(default_factory=list)
64
+ types: list[str] = Field(
65
+ default_factory=list
66
+ ) # limited to https://developers.google.com/maps/documentation/places/web-service/place-types
63
67
  language_code: Optional[str] = None
64
68
 
65
69
  @field_validator("types")
66
70
  @classmethod
67
- def _types(cls, v: List[str]) -> List[str]:
71
+ def _types(cls, v: list[str]) -> list[str]:
68
72
  out, seen = [], set()
69
73
  for raw in v:
70
74
  t = raw.strip()
@@ -114,13 +118,6 @@ class NeighborhoodSummary(BaseModel):
114
118
  disclosure_text: Optional[LocalizedText] = None
115
119
 
116
120
 
117
- class LocalizedText(BaseModel):
118
- model_config = ConfigDict(extra="allow")
119
-
120
- text: str
121
- language_code: str
122
-
123
-
124
121
  class ContainingPlace(BaseModel):
125
122
  model_config = ConfigDict(extra="forbid", str_strip_whitespace=True)
126
123
 
@@ -148,7 +145,7 @@ class ContainingPlace(BaseModel):
148
145
  return self
149
146
 
150
147
 
151
- class Place(BaseModel):
148
+ class GooglePlace(BaseModel):
152
149
  model_config = ConfigDict(extra="allow", str_strip_whitespace=True)
153
150
 
154
151
  # Identity
@@ -157,7 +154,7 @@ class Place(BaseModel):
157
154
 
158
155
  # Labels & typing
159
156
  display_name: Optional[LocalizedText] = None
160
- types: List[str] = Field(default_factory=list)
157
+ types: list[str] = Field(default_factory=list)
161
158
  primary_type: Optional[str] = None
162
159
  primary_type_display_name: Optional[LocalizedText] = None
163
160
 
@@ -165,9 +162,10 @@ class Place(BaseModel):
165
162
  national_phone_number: Optional[str] = None
166
163
  international_phone_number: Optional[str] = None
167
164
  formatted_address: Optional[str] = None
165
+ address_descriptor: Optional[AddressDescriptor] = None
168
166
  short_formatted_address: Optional[str] = None
169
167
  postal_address: Optional[PostalAddress] = None
170
- address_components: List[AddressComponent] = Field(default_factory=list)
168
+ address_components: list[AddressComponent] = Field(default_factory=list)
171
169
  plus_code: Optional[PlusCode] = None
172
170
 
173
171
  # Location & map
@@ -178,22 +176,22 @@ class Place(BaseModel):
178
176
  rating: Optional[float] = None
179
177
  google_maps_uri: Optional[AnyUrl] = None
180
178
  website_uri: Optional[AnyUrl] = None
181
- reviews: List[Review] = Field(default_factory=list)
182
- photos: List[Photo] = Field(default_factory=list)
179
+ reviews: list[Review] = Field(default_factory=list)
180
+ photos: list[Photo] = Field(default_factory=list)
183
181
 
184
182
  # Hours
185
183
  regular_opening_hours: Optional[OpeningHours] = None
186
184
  current_opening_hours: Optional[OpeningHours] = None
187
- current_secondary_opening_hours: List[OpeningHours] = Field(default_factory=list)
188
- regular_secondary_opening_hours: List[OpeningHours] = Field(default_factory=list)
185
+ current_secondary_opening_hours: list[OpeningHours] = Field(default_factory=list)
186
+ regular_secondary_opening_hours: list[OpeningHours] = Field(default_factory=list)
189
187
  utc_offset_minutes: Optional[int] = None
190
188
  time_zone: Optional[TimeZone] = None
191
189
 
192
190
  # Misc attributes
193
191
  adr_format_address: Optional[str] = None
194
- business_status: Optional[int] = None
195
- price_level: Optional[int] = None
196
- attributions: List[Attribution] = Field(default_factory=list)
192
+ business_status: Optional[BusinessStatus] = None
193
+ price_level: Optional[PriceLevel] = None
194
+ attributions: list[Attribution] = Field(default_factory=list)
197
195
  user_rating_count: Optional[int] = None
198
196
  icon_mask_base_uri: Optional[AnyUrl] = None
199
197
  icon_background_color: Optional[str] = None
@@ -227,7 +225,7 @@ class Place(BaseModel):
227
225
  # Options & related places
228
226
  payment_options: Optional[PaymentOptions] = None
229
227
  parking_options: Optional[ParkingOptions] = None
230
- sub_destinations: List[SubDestination] = Field(default_factory=list)
228
+ sub_destinations: list[SubDestination] = Field(default_factory=list)
231
229
  accessibility_options: Optional[AccessibilityOptions] = None
232
230
 
233
231
  # Fuel/EV & AI summaries
@@ -239,9 +237,8 @@ class Place(BaseModel):
239
237
  neighborhood_summary: Optional[NeighborhoodSummary] = None
240
238
 
241
239
  # Context
242
- containing_places: List[ContainingPlace] = Field(default_factory=list)
240
+ containing_places: list[ContainingPlace] = Field(default_factory=list)
243
241
  pure_service_area_business: Optional[bool] = None
244
- address_descriptor: Optional[AddressDescriptor] = None
245
242
  price_range: Optional[PriceRange] = None
246
243
 
247
244
  # ---------- Validators ----------
@@ -273,7 +270,7 @@ class Place(BaseModel):
273
270
 
274
271
  @field_validator("types")
275
272
  @classmethod
276
- def _types(cls, v: List[str]) -> List[str]:
273
+ def _types(cls, v: list[str]) -> list[str]:
277
274
  out, seen = [], set()
278
275
  for raw in v:
279
276
  t = raw.strip()
@@ -324,14 +321,14 @@ class Place(BaseModel):
324
321
 
325
322
  @field_validator("reviews")
326
323
  @classmethod
327
- def _max_reviews(cls, v: List[Review]) -> List[Review]:
324
+ def _max_reviews(cls, v: list[Review]) -> list[Review]:
328
325
  if len(v) > 5:
329
326
  raise ValueError("reviews can contain at most 5 items")
330
327
  return v
331
328
 
332
329
  @field_validator("photos")
333
330
  @classmethod
334
- def _max_photos(cls, v: List[Photo]) -> List[Photo]:
331
+ def _max_photos(cls, v: list[Photo]) -> list[Photo]:
335
332
  if len(v) > 10:
336
333
  raise ValueError("photos can contain at most 10 items")
337
334
  return v
@@ -0,0 +1,214 @@
1
+ """
2
+ Request models for Book-A-Limo API operations.
3
+ These models serialize to camelCase by default for API compatibility.
4
+ """
5
+
6
+ from typing import Optional
7
+
8
+ from pydantic import Field, model_validator
9
+ from typing_extensions import Self
10
+
11
+ from .base import RequestModel
12
+ from .shared import (
13
+ AccountBase,
14
+ AddressBase,
15
+ AirportBase,
16
+ BreakdownItemBase,
17
+ CityBase,
18
+ CreditCardBase,
19
+ LocationBase,
20
+ MeetGreetAdditionalBase,
21
+ MeetGreetBase,
22
+ PassengerBase,
23
+ PriceBase,
24
+ RateType,
25
+ ReservationBase,
26
+ RewardBase,
27
+ StopBase,
28
+ )
29
+
30
+
31
+ # Request versions of shared models (serialize to camelCase)
32
+ class City(CityBase, RequestModel):
33
+ """City information for requests."""
34
+
35
+ pass
36
+
37
+
38
+ class Address(AddressBase, RequestModel):
39
+ """Address information for requests."""
40
+
41
+ city: Optional[City] = Field(
42
+ default=None, description="Use only if google_geocode not available"
43
+ )
44
+
45
+
46
+ class Airport(AirportBase, RequestModel):
47
+ """Airport information for requests."""
48
+
49
+ arriving_from_city: Optional[City] = None
50
+
51
+
52
+ class Location(LocationBase, RequestModel):
53
+ """Location (address or airport) for requests."""
54
+
55
+ address: Optional[Address] = None
56
+ airport: Optional[Airport] = None
57
+
58
+
59
+ class Stop(StopBase, RequestModel):
60
+ """Stop information for requests."""
61
+
62
+ pass
63
+
64
+
65
+ class Account(AccountBase, RequestModel):
66
+ """Travel agency or corporate account info for requests."""
67
+
68
+ pass
69
+
70
+
71
+ class Passenger(PassengerBase, RequestModel):
72
+ """Passenger information for requests."""
73
+
74
+ pass
75
+
76
+
77
+ class Reward(RewardBase, RequestModel):
78
+ """Reward account information for requests."""
79
+
80
+ pass
81
+
82
+
83
+ class CreditCard(CreditCardBase, RequestModel):
84
+ """Credit card information for requests."""
85
+
86
+ pass
87
+
88
+
89
+ class BreakdownItem(BreakdownItemBase, RequestModel):
90
+ """Price breakdown item for requests."""
91
+
92
+ pass
93
+
94
+
95
+ class MeetGreetAdditional(MeetGreetAdditionalBase, RequestModel):
96
+ """Additional meet & greet charges for requests."""
97
+
98
+ pass
99
+
100
+
101
+ class MeetGreet(MeetGreetBase, RequestModel):
102
+ """Meet & greet option for requests."""
103
+
104
+ pass
105
+
106
+
107
+ class Price(PriceBase, RequestModel):
108
+ """Car class pricing information for requests."""
109
+
110
+ pass
111
+
112
+
113
+ class Reservation(ReservationBase, RequestModel):
114
+ """Basic reservation information for requests."""
115
+
116
+ pass
117
+
118
+
119
+ class EditReservationRequest(RequestModel):
120
+ """Editable reservation for modifications (requests)."""
121
+
122
+ confirmation: str
123
+ is_cancel_request: bool = False
124
+ rate_type: Optional[RateType] = None
125
+ pickup_date: Optional[str] = Field(default=None, description="MM/dd/yyyy format")
126
+ pickup_time: Optional[str] = Field(default=None, description="hh:mm tt format")
127
+ stops: Optional[list[Stop]] = None
128
+ credit_card: Optional[CreditCard] = None
129
+ passengers: Optional[int] = None
130
+ luggage: Optional[int] = None
131
+ pets: Optional[int] = None
132
+ car_seats: Optional[int] = None
133
+ boosters: Optional[int] = None
134
+ infants: Optional[int] = None
135
+ other: Optional[str] = Field(default=None, description="Other changes not listed")
136
+
137
+
138
+ # Pure Request Models
139
+ class PriceRequest(RequestModel):
140
+ """Request for getting prices."""
141
+
142
+ rate_type: RateType
143
+ date_time: str = Field(..., description="MM/dd/yyyy hh:mm tt format")
144
+ pickup: Location
145
+ dropoff: Location
146
+ hours: Optional[int] = Field(default=None, description="For hourly rate_type only")
147
+ passengers: int
148
+ luggage: int
149
+ stops: Optional[list[Stop]] = None
150
+ account: Optional[Account] = Field(
151
+ default=None, description="TAs must provide for commission"
152
+ )
153
+ passenger: Optional[Passenger] = None
154
+ rewards: Optional[list[Reward]] = None
155
+ car_class_code: Optional[str] = Field(
156
+ default=None, description="e.g., 'SD' for specific car class"
157
+ )
158
+ pets: Optional[int] = None
159
+ car_seats: Optional[int] = None
160
+ boosters: Optional[int] = None
161
+ infants: Optional[int] = None
162
+ customer_comment: Optional[str] = None
163
+
164
+
165
+ class DetailsRequest(RequestModel):
166
+ """Request for setting reservation details."""
167
+
168
+ token: str
169
+ car_class_code: Optional[str] = None
170
+ pickup: Optional[Location] = None
171
+ dropoff: Optional[Location] = None
172
+ stops: Optional[list[Stop]] = None
173
+ account: Optional[Account] = None
174
+ passenger: Optional[Passenger] = None
175
+ rewards: Optional[list[Reward]] = None
176
+ pets: Optional[int] = None
177
+ car_seats: Optional[int] = None
178
+ boosters: Optional[int] = None
179
+ infants: Optional[int] = None
180
+ customer_comment: Optional[str] = None
181
+ ta_fee: Optional[float] = Field(
182
+ default=None, description="For Travel Agencies - additional fee in USD"
183
+ )
184
+
185
+
186
+ class BookRequest(RequestModel):
187
+ """Request for booking reservation."""
188
+
189
+ token: str
190
+ promo: Optional[str] = None
191
+ method: Optional[str] = Field(
192
+ default=None, description="'charge' for charge accounts"
193
+ )
194
+ credit_card: Optional[CreditCard] = None
195
+
196
+ @model_validator(mode="after")
197
+ def validate_book_request(self) -> Self:
198
+ """Validate that either method or credit_card is provided."""
199
+ if not self.method and not self.credit_card:
200
+ raise ValueError("Either method='charge' or credit_card must be provided")
201
+
202
+ return self
203
+
204
+
205
+ class ListReservationsRequest(RequestModel):
206
+ """Request for listing reservations."""
207
+
208
+ is_archive: bool = False
209
+
210
+
211
+ class GetReservationRequest(RequestModel):
212
+ """Request for getting reservation details."""
213
+
214
+ confirmation: str
@@ -0,0 +1,196 @@
1
+ """
2
+ Response models for Book-A-Limo API operations.
3
+ These models serialize to snake_case by default for better Python DX.
4
+ """
5
+
6
+ from typing import Optional
7
+
8
+ from pydantic import Field
9
+
10
+ from .base import ResponseModel
11
+ from .shared import (
12
+ AccountBase,
13
+ AddressBase,
14
+ AirportBase,
15
+ BreakdownItemBase,
16
+ CityBase,
17
+ CreditCardBase,
18
+ LocationBase,
19
+ LocationType,
20
+ MeetGreetAdditionalBase,
21
+ MeetGreetBase,
22
+ PassengerBase,
23
+ PriceBase,
24
+ RateType,
25
+ ReservationBase,
26
+ ReservationStatus,
27
+ RewardBase,
28
+ StopBase,
29
+ )
30
+
31
+
32
+ # Response versions of shared models (serialize to snake_case)
33
+ class City(CityBase, ResponseModel):
34
+ """City information for responses."""
35
+
36
+ pass
37
+
38
+
39
+ class Address(AddressBase, ResponseModel):
40
+ """Address information for responses."""
41
+
42
+ city: Optional[City] = Field(
43
+ default=None, description="Use only if google_geocode not available"
44
+ )
45
+
46
+
47
+ class Airport(AirportBase, ResponseModel):
48
+ """Airport information for responses."""
49
+
50
+ arriving_from_city: Optional[City] = None
51
+
52
+
53
+ class Location(LocationBase, ResponseModel):
54
+ """Location (address or airport) for responses."""
55
+
56
+ address: Optional[Address] = None
57
+ airport: Optional[Airport] = None
58
+
59
+
60
+ class Stop(StopBase, ResponseModel):
61
+ """Stop information for responses."""
62
+
63
+ pass
64
+
65
+
66
+ class Account(AccountBase, ResponseModel):
67
+ """Travel agency or corporate account info for responses."""
68
+
69
+ pass
70
+
71
+
72
+ class Passenger(PassengerBase, ResponseModel):
73
+ """Passenger information for responses."""
74
+
75
+ pass
76
+
77
+
78
+ class Reward(RewardBase, ResponseModel):
79
+ """Reward account information for responses."""
80
+
81
+ pass
82
+
83
+
84
+ class CreditCard(CreditCardBase, ResponseModel):
85
+ """Credit card information for responses."""
86
+
87
+ pass
88
+
89
+
90
+ class BreakdownItem(BreakdownItemBase, ResponseModel):
91
+ """Price breakdown item for responses."""
92
+
93
+ pass
94
+
95
+
96
+ class MeetGreetAdditional(MeetGreetAdditionalBase, ResponseModel):
97
+ """Additional meet & greet charges for responses."""
98
+
99
+ pass
100
+
101
+
102
+ class MeetGreet(MeetGreetBase, ResponseModel):
103
+ """Meet & greet option for responses."""
104
+
105
+ pass
106
+
107
+
108
+ class CarClassPrice(PriceBase, ResponseModel):
109
+ """Car class pricing information for responses."""
110
+
111
+ pass
112
+
113
+
114
+ class Reservation(ReservationBase, ResponseModel):
115
+ """Basic reservation information for responses."""
116
+
117
+ pass
118
+
119
+
120
+ # Pure Response Models
121
+ class ReservationData(ResponseModel):
122
+ """Editable reservation data returned in get reservation response."""
123
+
124
+ confirmation: str
125
+ is_cancel_request: bool = False
126
+ rate_type: Optional[RateType] = None
127
+ pickup_date: Optional[str] = Field(default=None, description="MM/dd/yyyy format")
128
+ pickup_time: Optional[str] = Field(default=None, description="hh:mm tt format")
129
+ stops: Optional[list[Stop]] = None
130
+ credit_card: Optional[CreditCard] = Field(
131
+ default=None,
132
+ description="Conditionally required - unclear from API docs when exactly",
133
+ )
134
+ passengers: Optional[int] = None
135
+ luggage: Optional[int] = None
136
+ pets: Optional[int] = None
137
+ car_seats: Optional[int] = None
138
+ boosters: Optional[int] = None
139
+ infants: Optional[int] = None
140
+ other: Optional[str] = Field(default=None, description="Other changes not listed")
141
+
142
+
143
+ class PriceResponse(ResponseModel):
144
+ """Response from get prices."""
145
+
146
+ token: str
147
+ prices: list[CarClassPrice]
148
+
149
+
150
+ class DetailsResponse(ResponseModel):
151
+ """Response from set details."""
152
+
153
+ price: float
154
+ breakdown: list[BreakdownItem]
155
+
156
+
157
+ class BookResponse(ResponseModel):
158
+ """Response from book reservation."""
159
+
160
+ reservation_id: str
161
+
162
+
163
+ class ListReservationsResponse(ResponseModel):
164
+ """Response from list reservations."""
165
+
166
+ success: bool
167
+ reservations: list[Reservation] = Field(default_factory=list)
168
+ error: Optional[str] = None
169
+
170
+
171
+ class GetReservationResponse(ResponseModel):
172
+ """Response from get reservation."""
173
+
174
+ reservation: "ReservationData"
175
+ is_editable: bool
176
+ status: Optional[ReservationStatus] = None
177
+ is_cancellation_pending: bool
178
+ car_description: Optional[str] = None
179
+ cancellation_policy: Optional[str] = None
180
+ pickup_type: LocationType
181
+ pickup_description: str
182
+ dropoff_type: LocationType
183
+ dropoff_description: str
184
+ additional_services: Optional[str] = None
185
+ payment_method: Optional[str] = None
186
+ breakdown: list[BreakdownItem] = Field(default_factory=list)
187
+ passenger_name: Optional[str] = None
188
+ evoucher_url: Optional[str] = None
189
+ receipt_url: Optional[str] = None
190
+ pending_changes: list[list[str]] = Field(default_factory=list)
191
+
192
+
193
+ class EditReservationResponse(ResponseModel):
194
+ """Response from edit reservation."""
195
+
196
+ success: bool