bookalimo 0.1.5__tar.gz → 1.0.1__tar.gz

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.
Files changed (64) hide show
  1. bookalimo-1.0.1/LICENSE +21 -0
  2. bookalimo-1.0.1/PKG-INFO +370 -0
  3. bookalimo-1.0.1/README.md +309 -0
  4. {bookalimo-0.1.5 → bookalimo-1.0.1}/pyproject.toml +25 -15
  5. bookalimo-1.0.1/src/bookalimo/__init__.py +24 -0
  6. bookalimo-1.0.1/src/bookalimo/_version.py +9 -0
  7. bookalimo-1.0.1/src/bookalimo/client.py +310 -0
  8. bookalimo-1.0.1/src/bookalimo/config.py +16 -0
  9. bookalimo-1.0.1/src/bookalimo/exceptions.py +125 -0
  10. bookalimo-1.0.1/src/bookalimo/integrations/__init__.py +1 -0
  11. bookalimo-1.0.1/src/bookalimo/integrations/google_places/__init__.py +31 -0
  12. bookalimo-1.0.1/src/bookalimo/integrations/google_places/client_async.py +289 -0
  13. bookalimo-1.0.1/src/bookalimo/integrations/google_places/client_sync.py +287 -0
  14. bookalimo-1.0.1/src/bookalimo/integrations/google_places/common.py +231 -0
  15. bookalimo-1.0.1/src/bookalimo/integrations/google_places/proto_adapter.py +224 -0
  16. bookalimo-1.0.1/src/bookalimo/integrations/google_places/resolve_airport.py +397 -0
  17. bookalimo-1.0.1/src/bookalimo/integrations/google_places/transports.py +98 -0
  18. bookalimo-0.1.5/src/bookalimo/_logging.py → bookalimo-1.0.1/src/bookalimo/logging.py +45 -42
  19. bookalimo-1.0.1/src/bookalimo/schemas/__init__.py +103 -0
  20. bookalimo-1.0.1/src/bookalimo/schemas/base.py +56 -0
  21. bookalimo-0.1.5/src/bookalimo/models.py → bookalimo-1.0.1/src/bookalimo/schemas/booking.py +88 -100
  22. bookalimo-1.0.1/src/bookalimo/schemas/places/__init__.py +62 -0
  23. bookalimo-1.0.1/src/bookalimo/schemas/places/common.py +351 -0
  24. bookalimo-1.0.1/src/bookalimo/schemas/places/field_mask.py +221 -0
  25. bookalimo-1.0.1/src/bookalimo/schemas/places/google.py +883 -0
  26. bookalimo-1.0.1/src/bookalimo/schemas/places/place.py +334 -0
  27. bookalimo-1.0.1/src/bookalimo/services/__init__.py +11 -0
  28. bookalimo-1.0.1/src/bookalimo/services/pricing.py +191 -0
  29. bookalimo-1.0.1/src/bookalimo/services/reservations.py +227 -0
  30. bookalimo-1.0.1/src/bookalimo/transport/__init__.py +7 -0
  31. bookalimo-1.0.1/src/bookalimo/transport/auth.py +41 -0
  32. bookalimo-1.0.1/src/bookalimo/transport/base.py +44 -0
  33. bookalimo-1.0.1/src/bookalimo/transport/httpx_async.py +230 -0
  34. bookalimo-1.0.1/src/bookalimo/transport/httpx_sync.py +230 -0
  35. bookalimo-1.0.1/src/bookalimo/transport/retry.py +102 -0
  36. bookalimo-1.0.1/src/bookalimo/transport/utils.py +59 -0
  37. bookalimo-1.0.1/src/bookalimo.egg-info/PKG-INFO +370 -0
  38. bookalimo-1.0.1/src/bookalimo.egg-info/SOURCES.txt +50 -0
  39. {bookalimo-0.1.5 → bookalimo-1.0.1}/src/bookalimo.egg-info/requires.txt +10 -8
  40. bookalimo-1.0.1/tests/test_client.py +327 -0
  41. bookalimo-1.0.1/tests/test_config.py +347 -0
  42. bookalimo-1.0.1/tests/test_exceptions.py +392 -0
  43. bookalimo-1.0.1/tests/test_google_places.py +762 -0
  44. bookalimo-1.0.1/tests/test_integration.py +870 -0
  45. bookalimo-1.0.1/tests/test_real_api_integration.py +454 -0
  46. bookalimo-1.0.1/tests/test_schemas.py +585 -0
  47. bookalimo-1.0.1/tests/test_services.py +495 -0
  48. bookalimo-1.0.1/tests/test_transport.py +722 -0
  49. bookalimo-0.1.5/LICENSE +0 -0
  50. bookalimo-0.1.5/PKG-INFO +0 -392
  51. bookalimo-0.1.5/README.md +0 -334
  52. bookalimo-0.1.5/src/bookalimo/__init__.py +0 -31
  53. bookalimo-0.1.5/src/bookalimo/_client.py +0 -420
  54. bookalimo-0.1.5/src/bookalimo/exceptions.py +0 -15
  55. bookalimo-0.1.5/src/bookalimo/wrapper.py +0 -444
  56. bookalimo-0.1.5/src/bookalimo.egg-info/PKG-INFO +0 -392
  57. bookalimo-0.1.5/src/bookalimo.egg-info/SOURCES.txt +0 -18
  58. bookalimo-0.1.5/tests/test_client.py +0 -70
  59. bookalimo-0.1.5/tests/test_models.py +0 -50
  60. bookalimo-0.1.5/tests/test_wrapper.py +0 -69
  61. {bookalimo-0.1.5 → bookalimo-1.0.1}/setup.cfg +0 -0
  62. {bookalimo-0.1.5 → bookalimo-1.0.1}/src/bookalimo/py.typed +0 -0
  63. {bookalimo-0.1.5 → bookalimo-1.0.1}/src/bookalimo.egg-info/dependency_links.txt +0 -0
  64. {bookalimo-0.1.5 → bookalimo-1.0.1}/src/bookalimo.egg-info/top_level.txt +0 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Jonathan Oren
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,370 @@
1
+ Metadata-Version: 2.4
2
+ Name: bookalimo
3
+ Version: 1.0.1
4
+ Summary: Python wrapper for the Book-A-Limo API
5
+ Author-email: Jonathan Oren <jonathan@bookalimo.com>
6
+ Maintainer-email: Jonathan Oren <jonathan@bookalimo.com>
7
+ License: MIT
8
+ Project-URL: Homepage, https://github.com/asparagusbeef/bookalimo-python
9
+ Project-URL: Documentation, https://asparagusbeef.github.io/bookalimo-python
10
+ Project-URL: Repository, https://github.com/asparagusbeef/bookalimo-python
11
+ Project-URL: Issues, https://github.com/asparagusbeef/bookalimo-python/issues
12
+ Project-URL: Changelog, https://github.com/asparagusbeef/bookalimo-python/blob/main/CHANGELOG.md
13
+ Keywords: bookalimo,api,transportation,booking
14
+ Classifier: Development Status :: 3 - Alpha
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
25
+ Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
26
+ Requires-Python: >=3.9
27
+ Description-Content-Type: text/markdown
28
+ License-File: LICENSE
29
+ Requires-Dist: httpx>=0.25.0
30
+ Requires-Dist: pydantic>=2.11.0
31
+ Requires-Dist: pycountry>=22.0.0
32
+ Requires-Dist: us>=3.0.0
33
+ Requires-Dist: airportsdata>=20230101
34
+ Provides-Extra: places
35
+ Requires-Dist: google-maps-places>=0.1.0; extra == "places"
36
+ Requires-Dist: google-api-core>=2.0.0; extra == "places"
37
+ Requires-Dist: numpy>=2.0.0; extra == "places"
38
+ Requires-Dist: rapidfuzz>=3.0.0; extra == "places"
39
+ Provides-Extra: dev
40
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
41
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
42
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
43
+ Requires-Dist: pytest-mock>=3.10.0; extra == "dev"
44
+ Requires-Dist: httpx[mock]>=0.25.0; extra == "dev"
45
+ Requires-Dist: respx>=0.20.0; extra == "dev"
46
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
47
+ Requires-Dist: mypy>=1.5.0; extra == "dev"
48
+ Requires-Dist: pre-commit>=3.0.0; extra == "dev"
49
+ Requires-Dist: build>=1.0.0; extra == "dev"
50
+ Requires-Dist: twine>=4.0.0; extra == "dev"
51
+ Requires-Dist: python-dotenv>=1.0.0; extra == "dev"
52
+ Requires-Dist: types-protobuf>=6.0.0; extra == "dev"
53
+ Provides-Extra: test
54
+ Requires-Dist: pytest>=7.0.0; extra == "test"
55
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "test"
56
+ Requires-Dist: pytest-cov>=4.0.0; extra == "test"
57
+ Requires-Dist: pytest-mock>=3.10.0; extra == "test"
58
+ Requires-Dist: httpx[mock]>=0.25.0; extra == "test"
59
+ Requires-Dist: respx>=0.20.0; extra == "test"
60
+ Dynamic: license-file
61
+
62
+ # Bookalimo Python SDK
63
+
64
+ [![codecov](https://codecov.io/gh/asparagusbeef/bookalimo-python/branch/main/graph/badge.svg?token=H588J8Q1M8)](https://codecov.io/gh/asparagusbeef/bookalimo-python)
65
+ [![Docs](https://img.shields.io/github/deployments/asparagusbeef/bookalimo-python/github-pages?label=docs&logo=github)](https://asparagusbeef.github.io/bookalimo-python)
66
+ [![PyPI version](https://badge.fury.io/py/bookalimo.svg)](https://badge.fury.io/py/bookalimo)
67
+ [![Python Support](https://img.shields.io/pypi/pyversions/bookalimo.svg)](https://pypi.org/project/bookalimo/)
68
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
69
+ [![Code style: ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
70
+
71
+ A modern, fully-typed Python SDK for the Book-A-Limo transportation booking API with async/sync support, type safety, Google Places integration, and ergonomic resource management via context managers.
72
+
73
+ ## Important notes
74
+
75
+ - **Docs are in preview**: Many pages were AI-generated from the codebase and haven’t had a full manual review yet. In case of conflict, the code and docstrings are the source of truth. Please [report issues](https://github.com/asparagusbeef/bookalimo-python/issues) you find.
76
+ - **Terms & credentials**: Use of Book-A-Limo API and Google APIs are subject to their respective Terms of Service.
77
+
78
+ ## Design philosophy: IDE-first DX
79
+
80
+ The library is **comprehensively typed** and **richly documented** via docstrings. Most users can rely on IDE hints, docstrings, and autocomplete without reading the docs.
81
+
82
+ ## Features
83
+
84
+ - **Async & Sync Support** – Choose the right client for your use case
85
+ - **Type Safety** – Full Pydantic models with validation
86
+ - **Google Places Integration** – Autocomplete, search, details, and geocoding
87
+ - **Automatic Retry** – Built-in exponential backoff for reliability
88
+ - **Comprehensive Error Handling** – Detailed exceptions with context
89
+ - **Resource Management** – Context managers for proper cleanup
90
+
91
+ ## Installation
92
+
93
+ ```bash
94
+ pip install bookalimo
95
+
96
+ # With Google Places integration
97
+ pip install bookalimo[places]
98
+ ```
99
+
100
+ ## Core API
101
+
102
+ ### Clients
103
+
104
+ * `AsyncBookalimo` – Async client for high-concurrency applications
105
+ * `Bookalimo` – Sync client for simple scripts and legacy code
106
+
107
+ ### Services
108
+
109
+ * `client.pricing` – Get quotes and update booking details
110
+ * `client.reservations` – Book, list, modify, and cancel reservations
111
+ * `client.places` – Google Places search and geocoding (optional)
112
+
113
+ ### Authentication
114
+
115
+ SHA256-based credential system with automatic password hashing:
116
+
117
+ ```python
118
+ from bookalimo.transport.auth import Credentials
119
+
120
+ # Agency account
121
+ agency = Credentials.create("AGENCY123", "password", is_customer=False)
122
+
123
+ # Customer account
124
+ customer = Credentials.create("user@email.com", "password", is_customer=True)
125
+ ```
126
+
127
+ ### Booking Flow
128
+
129
+ 1. **Get Pricing** – `client.pricing.quote()` returns session token + vehicle options
130
+ 2. **Update Details** – `client.pricing.update_details()` finalize booking details
131
+ 3. **Book Reservation** – `client.reservations.book()` confirms with payment
132
+
133
+ ## Quick Examples
134
+
135
+ ### Async example
136
+
137
+ ```python
138
+ import asyncio
139
+ from bookalimo import AsyncBookalimo
140
+ from bookalimo.transport.auth import Credentials
141
+ from bookalimo.schemas.booking import (
142
+ RateType,
143
+ Location,
144
+ LocationType,
145
+ Address,
146
+ City,
147
+ Airport,
148
+ )
149
+
150
+
151
+ async def book_ride():
152
+ credentials = Credentials.create("your_id", "your_password", is_customer=False)
153
+
154
+ pickup = Location(
155
+ type=LocationType.ADDRESS,
156
+ address=Address(
157
+ place_name="Empire State Building",
158
+ city=City(city_name="New York", country_code="US", state_code="NY"),
159
+ ),
160
+ )
161
+
162
+ dropoff = Location(type=LocationType.AIRPORT, airport=Airport(iata_code="JFK"))
163
+
164
+ async with AsyncBookalimo(credentials=credentials) as client:
165
+ # 1) Get pricing
166
+ quote = await client.pricing.quote(
167
+ rate_type=RateType.P2P,
168
+ date_time="12/25/2024 03:00 PM",
169
+ pickup=pickup,
170
+ dropoff=dropoff,
171
+ passengers=2,
172
+ luggage=2,
173
+ )
174
+
175
+ # 2) Book reservation
176
+ booking = await client.reservations.book(
177
+ token=quote.token, method="charge" # or credit_card=CreditCard(...)
178
+ )
179
+ return booking.reservation_id
180
+
181
+
182
+ confirmation = asyncio.run(book_ride())
183
+ ```
184
+
185
+ ### Sync example
186
+
187
+ ```python
188
+ from bookalimo import Bookalimo
189
+ from bookalimo.transport.auth import Credentials
190
+
191
+ credentials = Credentials.create("your_id", "your_password", is_customer=False)
192
+
193
+ with Bookalimo(credentials=credentials) as client:
194
+ quote = client.pricing.quote(...)
195
+ booking = client.reservations.book(token=quote.token, method="charge")
196
+ ```
197
+
198
+ ## Rate Types & Options
199
+
200
+ ```python
201
+ from bookalimo.schemas.booking import RateType
202
+
203
+ # Point-to-point transfer
204
+ quote = await client.pricing.quote(
205
+ rate_type=RateType.P2P,
206
+ pickup=pickup_location,
207
+ dropoff=dropoff_location,
208
+ # ...
209
+ )
210
+
211
+ # Hourly service (minimum 2 hours)
212
+ quote = await client.pricing.quote(
213
+ rate_type=RateType.HOURLY,
214
+ hours=4,
215
+ pickup=pickup_location,
216
+ dropoff=pickup_location, # Same for hourly
217
+ # ...
218
+ )
219
+
220
+ # Daily service
221
+ quote = await client.pricing.quote(
222
+ rate_type=RateType.DAILY,
223
+ pickup=hotel_location,
224
+ dropoff=hotel_location,
225
+ # ...
226
+ )
227
+ ```
228
+
229
+ ## Location Types
230
+
231
+ ```python
232
+ from bookalimo.schemas.booking import Location, LocationType, Address, Airport, City
233
+
234
+ # Street address
235
+ address_location = Location(
236
+ type=LocationType.ADDRESS,
237
+ address=Address(
238
+ place_name="Empire State Building",
239
+ street_name="350 5th Ave",
240
+ city=City(city_name="New York", country_code="US", state_code="NY"),
241
+ ),
242
+ )
243
+
244
+ # Airport with flight details
245
+ airport_location = Location(
246
+ type=LocationType.AIRPORT,
247
+ airport=Airport(iata_code="JFK", flight_number="UA123", terminal="4"),
248
+ )
249
+ ```
250
+
251
+ ## Google Places Integration (Recommended flow)
252
+
253
+ ```python
254
+ async with AsyncBookalimo(
255
+ credentials=credentials, google_places_api_key="your-google-places-key"
256
+ ) as client:
257
+ # Search locations
258
+ results = await client.places.search("Hilton Miami Beach")
259
+
260
+ # OR
261
+ # autocomplete = await client.places.autocomplete(input="Hilton Miami Beach")
262
+ # top_result = autocomplete.suggestions[0].place_prediction.place
263
+ # top_result_place_id = top_result.id
264
+
265
+ # OR
266
+ # resolve_airport = await client.places.resolve_airport(query="Hilton Miami Beach")
267
+ # top_result = resolve_airport[0]
268
+ # iata_code = top_result.iata_code
269
+
270
+ # Get the top result
271
+ top_result = results[0]
272
+
273
+ # Get the top result geocode
274
+
275
+ # By place_id
276
+ top_result_place_id = top_result.google_place.id
277
+ top_result_geocode = await client.places.geocode(place_id=top_result_place_id)
278
+
279
+ # By lat-lng
280
+ top_result_geocode = await client.places.geocode(
281
+ lat=top_result.lat, lng=top_result.lng
282
+ )
283
+
284
+ # Convert to booking location
285
+ location = Location(
286
+ type=LocationType.ADDRESS,
287
+ address=Address(
288
+ google_geocode=top_result_geocode, place_name=top_result.formatted_address
289
+ ),
290
+ )
291
+ ```
292
+
293
+ *(You can also search independent pickup/dropoff locations and feed them into the booking flow.)*
294
+
295
+ ## Reservation Management
296
+
297
+ ```python
298
+ # List reservations
299
+ reservations = await client.reservations.list(is_archive=False)
300
+
301
+ # Get details
302
+ details = await client.reservations.get("ABC123")
303
+
304
+ # Modify reservation
305
+ edit_result = await client.reservations.edit(
306
+ confirmation="ABC123", passengers=3, pickup_date="12/26/2024"
307
+ )
308
+
309
+ # Cancel reservation
310
+ cancel_result = await client.reservations.edit(confirmation="ABC123", is_cancel=True)
311
+ ```
312
+
313
+ ## Error Handling
314
+
315
+ ```python
316
+ from bookalimo.exceptions import (
317
+ BookalimoError, # base SDK error
318
+ BookalimoHTTPError, # HTTP/transport errors
319
+ BookalimoValidationError, # input/schema validation errors
320
+ )
321
+
322
+ try:
323
+ booking = await client.reservations.book(...)
324
+ except BookalimoValidationError as e:
325
+ print(f"Invalid input: {e.message}")
326
+ for error in e.errors():
327
+ print(f" {error['loc']}: {error['msg']}")
328
+ except BookalimoHTTPError as e:
329
+ if e.status_code == 401:
330
+ print("Authentication failed")
331
+ elif e.status_code == 400:
332
+ print(f"Bad request: {e.payload}")
333
+ else:
334
+ print(f"API error: {e}")
335
+ except BookalimoError as e:
336
+ print(f"SDK error: {e}")
337
+ ```
338
+
339
+ ## Documentation
340
+
341
+ **📖 Complete Documentation:** [https://asparagusbeef.github.io/bookalimo-python](https://asparagusbeef.github.io/bookalimo-python)
342
+
343
+ * Quick Start Guide: [https://asparagusbeef.github.io/bookalimo-python/guide/quickstart/](https://asparagusbeef.github.io/bookalimo-python/guide/quickstart/)
344
+ * API Reference: [https://asparagusbeef.github.io/bookalimo-python/api/](https://asparagusbeef.github.io/bookalimo-python/api/)
345
+ * Examples: [https://asparagusbeef.github.io/bookalimo-python/examples/basic/](https://asparagusbeef.github.io/bookalimo-python/examples/basic/)
346
+
347
+ ## Environment
348
+
349
+ ```bash
350
+ export GOOGLE_PLACES_API_KEY="your_google_places_key"
351
+ export BOOKALIMO_LOG_LEVEL="DEBUG"
352
+ ```
353
+
354
+ ## Requirements
355
+
356
+ * Python 3.9+
357
+ * Book-A-Limo API credentials
358
+ * Dependencies: httpx, pydantic, pycountry, us, airportsdata
359
+ - Optional: google-maps-places, google-api-core, numpy, rapidfuzz
360
+
361
+ ## Support & Resources
362
+
363
+ * GitHub: [https://github.com/asparagusbeef/bookalimo-python](https://github.com/asparagusbeef/bookalimo-python)
364
+ * PyPI: [https://pypi.org/project/bookalimo/](https://pypi.org/project/bookalimo/)
365
+ * Issues: [https://github.com/asparagusbeef/bookalimo-python/issues](https://github.com/asparagusbeef/bookalimo-python/issues)
366
+ * Changelog: [CHANGELOG.md](./CHANGELOG.md)
367
+
368
+ ## License
369
+
370
+ MIT License — see [LICENSE](LICENSE) for details.
@@ -0,0 +1,309 @@
1
+ # Bookalimo Python SDK
2
+
3
+ [![codecov](https://codecov.io/gh/asparagusbeef/bookalimo-python/branch/main/graph/badge.svg?token=H588J8Q1M8)](https://codecov.io/gh/asparagusbeef/bookalimo-python)
4
+ [![Docs](https://img.shields.io/github/deployments/asparagusbeef/bookalimo-python/github-pages?label=docs&logo=github)](https://asparagusbeef.github.io/bookalimo-python)
5
+ [![PyPI version](https://badge.fury.io/py/bookalimo.svg)](https://badge.fury.io/py/bookalimo)
6
+ [![Python Support](https://img.shields.io/pypi/pyversions/bookalimo.svg)](https://pypi.org/project/bookalimo/)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
+ [![Code style: ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
9
+
10
+ A modern, fully-typed Python SDK for the Book-A-Limo transportation booking API with async/sync support, type safety, Google Places integration, and ergonomic resource management via context managers.
11
+
12
+ ## Important notes
13
+
14
+ - **Docs are in preview**: Many pages were AI-generated from the codebase and haven’t had a full manual review yet. In case of conflict, the code and docstrings are the source of truth. Please [report issues](https://github.com/asparagusbeef/bookalimo-python/issues) you find.
15
+ - **Terms & credentials**: Use of Book-A-Limo API and Google APIs are subject to their respective Terms of Service.
16
+
17
+ ## Design philosophy: IDE-first DX
18
+
19
+ The library is **comprehensively typed** and **richly documented** via docstrings. Most users can rely on IDE hints, docstrings, and autocomplete without reading the docs.
20
+
21
+ ## Features
22
+
23
+ - **Async & Sync Support** – Choose the right client for your use case
24
+ - **Type Safety** – Full Pydantic models with validation
25
+ - **Google Places Integration** – Autocomplete, search, details, and geocoding
26
+ - **Automatic Retry** – Built-in exponential backoff for reliability
27
+ - **Comprehensive Error Handling** – Detailed exceptions with context
28
+ - **Resource Management** – Context managers for proper cleanup
29
+
30
+ ## Installation
31
+
32
+ ```bash
33
+ pip install bookalimo
34
+
35
+ # With Google Places integration
36
+ pip install bookalimo[places]
37
+ ```
38
+
39
+ ## Core API
40
+
41
+ ### Clients
42
+
43
+ * `AsyncBookalimo` – Async client for high-concurrency applications
44
+ * `Bookalimo` – Sync client for simple scripts and legacy code
45
+
46
+ ### Services
47
+
48
+ * `client.pricing` – Get quotes and update booking details
49
+ * `client.reservations` – Book, list, modify, and cancel reservations
50
+ * `client.places` – Google Places search and geocoding (optional)
51
+
52
+ ### Authentication
53
+
54
+ SHA256-based credential system with automatic password hashing:
55
+
56
+ ```python
57
+ from bookalimo.transport.auth import Credentials
58
+
59
+ # Agency account
60
+ agency = Credentials.create("AGENCY123", "password", is_customer=False)
61
+
62
+ # Customer account
63
+ customer = Credentials.create("user@email.com", "password", is_customer=True)
64
+ ```
65
+
66
+ ### Booking Flow
67
+
68
+ 1. **Get Pricing** – `client.pricing.quote()` returns session token + vehicle options
69
+ 2. **Update Details** – `client.pricing.update_details()` finalize booking details
70
+ 3. **Book Reservation** – `client.reservations.book()` confirms with payment
71
+
72
+ ## Quick Examples
73
+
74
+ ### Async example
75
+
76
+ ```python
77
+ import asyncio
78
+ from bookalimo import AsyncBookalimo
79
+ from bookalimo.transport.auth import Credentials
80
+ from bookalimo.schemas.booking import (
81
+ RateType,
82
+ Location,
83
+ LocationType,
84
+ Address,
85
+ City,
86
+ Airport,
87
+ )
88
+
89
+
90
+ async def book_ride():
91
+ credentials = Credentials.create("your_id", "your_password", is_customer=False)
92
+
93
+ pickup = Location(
94
+ type=LocationType.ADDRESS,
95
+ address=Address(
96
+ place_name="Empire State Building",
97
+ city=City(city_name="New York", country_code="US", state_code="NY"),
98
+ ),
99
+ )
100
+
101
+ dropoff = Location(type=LocationType.AIRPORT, airport=Airport(iata_code="JFK"))
102
+
103
+ async with AsyncBookalimo(credentials=credentials) as client:
104
+ # 1) Get pricing
105
+ quote = await client.pricing.quote(
106
+ rate_type=RateType.P2P,
107
+ date_time="12/25/2024 03:00 PM",
108
+ pickup=pickup,
109
+ dropoff=dropoff,
110
+ passengers=2,
111
+ luggage=2,
112
+ )
113
+
114
+ # 2) Book reservation
115
+ booking = await client.reservations.book(
116
+ token=quote.token, method="charge" # or credit_card=CreditCard(...)
117
+ )
118
+ return booking.reservation_id
119
+
120
+
121
+ confirmation = asyncio.run(book_ride())
122
+ ```
123
+
124
+ ### Sync example
125
+
126
+ ```python
127
+ from bookalimo import Bookalimo
128
+ from bookalimo.transport.auth import Credentials
129
+
130
+ credentials = Credentials.create("your_id", "your_password", is_customer=False)
131
+
132
+ with Bookalimo(credentials=credentials) as client:
133
+ quote = client.pricing.quote(...)
134
+ booking = client.reservations.book(token=quote.token, method="charge")
135
+ ```
136
+
137
+ ## Rate Types & Options
138
+
139
+ ```python
140
+ from bookalimo.schemas.booking import RateType
141
+
142
+ # Point-to-point transfer
143
+ quote = await client.pricing.quote(
144
+ rate_type=RateType.P2P,
145
+ pickup=pickup_location,
146
+ dropoff=dropoff_location,
147
+ # ...
148
+ )
149
+
150
+ # Hourly service (minimum 2 hours)
151
+ quote = await client.pricing.quote(
152
+ rate_type=RateType.HOURLY,
153
+ hours=4,
154
+ pickup=pickup_location,
155
+ dropoff=pickup_location, # Same for hourly
156
+ # ...
157
+ )
158
+
159
+ # Daily service
160
+ quote = await client.pricing.quote(
161
+ rate_type=RateType.DAILY,
162
+ pickup=hotel_location,
163
+ dropoff=hotel_location,
164
+ # ...
165
+ )
166
+ ```
167
+
168
+ ## Location Types
169
+
170
+ ```python
171
+ from bookalimo.schemas.booking import Location, LocationType, Address, Airport, City
172
+
173
+ # Street address
174
+ address_location = Location(
175
+ type=LocationType.ADDRESS,
176
+ address=Address(
177
+ place_name="Empire State Building",
178
+ street_name="350 5th Ave",
179
+ city=City(city_name="New York", country_code="US", state_code="NY"),
180
+ ),
181
+ )
182
+
183
+ # Airport with flight details
184
+ airport_location = Location(
185
+ type=LocationType.AIRPORT,
186
+ airport=Airport(iata_code="JFK", flight_number="UA123", terminal="4"),
187
+ )
188
+ ```
189
+
190
+ ## Google Places Integration (Recommended flow)
191
+
192
+ ```python
193
+ async with AsyncBookalimo(
194
+ credentials=credentials, google_places_api_key="your-google-places-key"
195
+ ) as client:
196
+ # Search locations
197
+ results = await client.places.search("Hilton Miami Beach")
198
+
199
+ # OR
200
+ # autocomplete = await client.places.autocomplete(input="Hilton Miami Beach")
201
+ # top_result = autocomplete.suggestions[0].place_prediction.place
202
+ # top_result_place_id = top_result.id
203
+
204
+ # OR
205
+ # resolve_airport = await client.places.resolve_airport(query="Hilton Miami Beach")
206
+ # top_result = resolve_airport[0]
207
+ # iata_code = top_result.iata_code
208
+
209
+ # Get the top result
210
+ top_result = results[0]
211
+
212
+ # Get the top result geocode
213
+
214
+ # By place_id
215
+ top_result_place_id = top_result.google_place.id
216
+ top_result_geocode = await client.places.geocode(place_id=top_result_place_id)
217
+
218
+ # By lat-lng
219
+ top_result_geocode = await client.places.geocode(
220
+ lat=top_result.lat, lng=top_result.lng
221
+ )
222
+
223
+ # Convert to booking location
224
+ location = Location(
225
+ type=LocationType.ADDRESS,
226
+ address=Address(
227
+ google_geocode=top_result_geocode, place_name=top_result.formatted_address
228
+ ),
229
+ )
230
+ ```
231
+
232
+ *(You can also search independent pickup/dropoff locations and feed them into the booking flow.)*
233
+
234
+ ## Reservation Management
235
+
236
+ ```python
237
+ # List reservations
238
+ reservations = await client.reservations.list(is_archive=False)
239
+
240
+ # Get details
241
+ details = await client.reservations.get("ABC123")
242
+
243
+ # Modify reservation
244
+ edit_result = await client.reservations.edit(
245
+ confirmation="ABC123", passengers=3, pickup_date="12/26/2024"
246
+ )
247
+
248
+ # Cancel reservation
249
+ cancel_result = await client.reservations.edit(confirmation="ABC123", is_cancel=True)
250
+ ```
251
+
252
+ ## Error Handling
253
+
254
+ ```python
255
+ from bookalimo.exceptions import (
256
+ BookalimoError, # base SDK error
257
+ BookalimoHTTPError, # HTTP/transport errors
258
+ BookalimoValidationError, # input/schema validation errors
259
+ )
260
+
261
+ try:
262
+ booking = await client.reservations.book(...)
263
+ except BookalimoValidationError as e:
264
+ print(f"Invalid input: {e.message}")
265
+ for error in e.errors():
266
+ print(f" {error['loc']}: {error['msg']}")
267
+ except BookalimoHTTPError as e:
268
+ if e.status_code == 401:
269
+ print("Authentication failed")
270
+ elif e.status_code == 400:
271
+ print(f"Bad request: {e.payload}")
272
+ else:
273
+ print(f"API error: {e}")
274
+ except BookalimoError as e:
275
+ print(f"SDK error: {e}")
276
+ ```
277
+
278
+ ## Documentation
279
+
280
+ **📖 Complete Documentation:** [https://asparagusbeef.github.io/bookalimo-python](https://asparagusbeef.github.io/bookalimo-python)
281
+
282
+ * Quick Start Guide: [https://asparagusbeef.github.io/bookalimo-python/guide/quickstart/](https://asparagusbeef.github.io/bookalimo-python/guide/quickstart/)
283
+ * API Reference: [https://asparagusbeef.github.io/bookalimo-python/api/](https://asparagusbeef.github.io/bookalimo-python/api/)
284
+ * Examples: [https://asparagusbeef.github.io/bookalimo-python/examples/basic/](https://asparagusbeef.github.io/bookalimo-python/examples/basic/)
285
+
286
+ ## Environment
287
+
288
+ ```bash
289
+ export GOOGLE_PLACES_API_KEY="your_google_places_key"
290
+ export BOOKALIMO_LOG_LEVEL="DEBUG"
291
+ ```
292
+
293
+ ## Requirements
294
+
295
+ * Python 3.9+
296
+ * Book-A-Limo API credentials
297
+ * Dependencies: httpx, pydantic, pycountry, us, airportsdata
298
+ - Optional: google-maps-places, google-api-core, numpy, rapidfuzz
299
+
300
+ ## Support & Resources
301
+
302
+ * GitHub: [https://github.com/asparagusbeef/bookalimo-python](https://github.com/asparagusbeef/bookalimo-python)
303
+ * PyPI: [https://pypi.org/project/bookalimo/](https://pypi.org/project/bookalimo/)
304
+ * Issues: [https://github.com/asparagusbeef/bookalimo-python/issues](https://github.com/asparagusbeef/bookalimo-python/issues)
305
+ * Changelog: [CHANGELOG.md](./CHANGELOG.md)
306
+
307
+ ## License
308
+
309
+ MIT License — see [LICENSE](LICENSE) for details.