bookalimo 1.0.0__tar.gz → 1.0.2__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 (71) hide show
  1. bookalimo-1.0.2/LICENSE +21 -0
  2. bookalimo-1.0.2/PKG-INFO +245 -0
  3. bookalimo-1.0.2/README.md +183 -0
  4. {bookalimo-1.0.0 → bookalimo-1.0.2}/pyproject.toml +7 -3
  5. {bookalimo-1.0.0 → bookalimo-1.0.2}/src/bookalimo/client.py +45 -22
  6. {bookalimo-1.0.0 → bookalimo-1.0.2}/src/bookalimo/config.py +1 -1
  7. bookalimo-1.0.2/src/bookalimo/integrations/google_places/client_async.py +243 -0
  8. bookalimo-1.0.2/src/bookalimo/integrations/google_places/client_sync.py +243 -0
  9. bookalimo-1.0.2/src/bookalimo/integrations/google_places/common.py +509 -0
  10. bookalimo-1.0.2/src/bookalimo/integrations/google_places/resolve_airport.py +426 -0
  11. bookalimo-1.0.2/src/bookalimo/integrations/google_places/transports.py +105 -0
  12. {bookalimo-1.0.0 → bookalimo-1.0.2}/src/bookalimo/logging.py +103 -0
  13. bookalimo-1.0.2/src/bookalimo/schemas/__init__.py +189 -0
  14. bookalimo-1.0.2/src/bookalimo/schemas/base.py +116 -0
  15. bookalimo-1.0.2/src/bookalimo/schemas/places/__init__.py +64 -0
  16. bookalimo-1.0.2/src/bookalimo/schemas/places/common.py +351 -0
  17. bookalimo-1.0.2/src/bookalimo/schemas/places/field_mask.py +212 -0
  18. {bookalimo-1.0.0 → bookalimo-1.0.2}/src/bookalimo/schemas/places/google.py +458 -16
  19. {bookalimo-1.0.0 → bookalimo-1.0.2}/src/bookalimo/schemas/places/place.py +25 -28
  20. bookalimo-1.0.2/src/bookalimo/schemas/requests.py +214 -0
  21. bookalimo-1.0.2/src/bookalimo/schemas/responses.py +196 -0
  22. bookalimo-1.0.0/src/bookalimo/schemas/booking.py → bookalimo-1.0.2/src/bookalimo/schemas/shared.py +55 -218
  23. bookalimo-1.0.2/src/bookalimo/services/pricing.py +71 -0
  24. bookalimo-1.0.2/src/bookalimo/services/reservations.py +137 -0
  25. {bookalimo-1.0.0 → bookalimo-1.0.2}/src/bookalimo/transport/auth.py +2 -2
  26. bookalimo-1.0.2/src/bookalimo/transport/httpx_async.py +146 -0
  27. bookalimo-1.0.2/src/bookalimo/transport/httpx_sync.py +151 -0
  28. bookalimo-1.0.2/src/bookalimo/transport/utils.py +260 -0
  29. bookalimo-1.0.2/src/bookalimo.egg-info/PKG-INFO +245 -0
  30. {bookalimo-1.0.0 → bookalimo-1.0.2}/src/bookalimo.egg-info/SOURCES.txt +6 -1
  31. {bookalimo-1.0.0 → bookalimo-1.0.2}/src/bookalimo.egg-info/requires.txt +5 -0
  32. {bookalimo-1.0.0 → bookalimo-1.0.2}/tests/test_client.py +6 -6
  33. {bookalimo-1.0.0 → bookalimo-1.0.2}/tests/test_google_places.py +204 -119
  34. {bookalimo-1.0.0 → bookalimo-1.0.2}/tests/test_integration.py +117 -81
  35. {bookalimo-1.0.0 → bookalimo-1.0.2}/tests/test_real_api_integration.py +110 -68
  36. {bookalimo-1.0.0 → bookalimo-1.0.2}/tests/test_schemas.py +11 -12
  37. bookalimo-1.0.2/tests/test_services.py +620 -0
  38. {bookalimo-1.0.0 → bookalimo-1.0.2}/tests/test_transport.py +5 -6
  39. bookalimo-1.0.0/LICENSE +0 -0
  40. bookalimo-1.0.0/PKG-INFO +0 -307
  41. bookalimo-1.0.0/README.md +0 -249
  42. bookalimo-1.0.0/src/bookalimo/integrations/google_places/client_async.py +0 -258
  43. bookalimo-1.0.0/src/bookalimo/integrations/google_places/client_sync.py +0 -257
  44. bookalimo-1.0.0/src/bookalimo/integrations/google_places/common.py +0 -245
  45. bookalimo-1.0.0/src/bookalimo/schemas/__init__.py +0 -97
  46. bookalimo-1.0.0/src/bookalimo/schemas/base.py +0 -56
  47. bookalimo-1.0.0/src/bookalimo/schemas/places/__init__.py +0 -37
  48. bookalimo-1.0.0/src/bookalimo/schemas/places/common.py +0 -198
  49. bookalimo-1.0.0/src/bookalimo/services/pricing.py +0 -191
  50. bookalimo-1.0.0/src/bookalimo/services/reservations.py +0 -227
  51. bookalimo-1.0.0/src/bookalimo/transport/httpx_async.py +0 -230
  52. bookalimo-1.0.0/src/bookalimo/transport/httpx_sync.py +0 -230
  53. bookalimo-1.0.0/src/bookalimo/transport/utils.py +0 -59
  54. bookalimo-1.0.0/src/bookalimo.egg-info/PKG-INFO +0 -307
  55. bookalimo-1.0.0/tests/test_services.py +0 -495
  56. {bookalimo-1.0.0 → bookalimo-1.0.2}/setup.cfg +0 -0
  57. {bookalimo-1.0.0 → bookalimo-1.0.2}/src/bookalimo/__init__.py +0 -0
  58. {bookalimo-1.0.0 → bookalimo-1.0.2}/src/bookalimo/_version.py +0 -0
  59. {bookalimo-1.0.0 → bookalimo-1.0.2}/src/bookalimo/exceptions.py +0 -0
  60. {bookalimo-1.0.0 → bookalimo-1.0.2}/src/bookalimo/integrations/__init__.py +0 -0
  61. {bookalimo-1.0.0 → bookalimo-1.0.2}/src/bookalimo/integrations/google_places/__init__.py +0 -0
  62. {bookalimo-1.0.0 → bookalimo-1.0.2}/src/bookalimo/integrations/google_places/proto_adapter.py +0 -0
  63. {bookalimo-1.0.0 → bookalimo-1.0.2}/src/bookalimo/py.typed +0 -0
  64. {bookalimo-1.0.0 → bookalimo-1.0.2}/src/bookalimo/services/__init__.py +0 -0
  65. {bookalimo-1.0.0 → bookalimo-1.0.2}/src/bookalimo/transport/__init__.py +0 -0
  66. {bookalimo-1.0.0 → bookalimo-1.0.2}/src/bookalimo/transport/base.py +0 -0
  67. {bookalimo-1.0.0 → bookalimo-1.0.2}/src/bookalimo/transport/retry.py +0 -0
  68. {bookalimo-1.0.0 → bookalimo-1.0.2}/src/bookalimo.egg-info/dependency_links.txt +0 -0
  69. {bookalimo-1.0.0 → bookalimo-1.0.2}/src/bookalimo.egg-info/top_level.txt +0 -0
  70. {bookalimo-1.0.0 → bookalimo-1.0.2}/tests/test_config.py +0 -0
  71. {bookalimo-1.0.0 → bookalimo-1.0.2}/tests/test_exceptions.py +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,245 @@
1
+ Metadata-Version: 2.4
2
+ Name: bookalimo
3
+ Version: 1.0.2
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
+ Requires-Dist: typing-extensions>=4.15.0; python_version < "3.11" and extra == "places"
40
+ Provides-Extra: dev
41
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
42
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
43
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
44
+ Requires-Dist: pytest-mock>=3.10.0; extra == "dev"
45
+ Requires-Dist: httpx[mock]>=0.25.0; extra == "dev"
46
+ Requires-Dist: respx>=0.20.0; extra == "dev"
47
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
48
+ Requires-Dist: mypy>=1.5.0; extra == "dev"
49
+ Requires-Dist: pre-commit>=3.0.0; extra == "dev"
50
+ Requires-Dist: build>=1.0.0; extra == "dev"
51
+ Requires-Dist: twine>=4.0.0; extra == "dev"
52
+ Requires-Dist: python-dotenv>=1.0.0; extra == "dev"
53
+ Requires-Dist: types-protobuf>=6.0.0; extra == "dev"
54
+ Provides-Extra: test
55
+ Requires-Dist: pytest>=7.0.0; extra == "test"
56
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "test"
57
+ Requires-Dist: pytest-cov>=4.0.0; extra == "test"
58
+ Requires-Dist: pytest-mock>=3.10.0; extra == "test"
59
+ Requires-Dist: httpx[mock]>=0.25.0; extra == "test"
60
+ Requires-Dist: respx>=0.20.0; extra == "test"
61
+ Dynamic: license-file
62
+
63
+ # Bookalimo Python SDK
64
+
65
+ [![codecov](https://codecov.io/gh/asparagusbeef/bookalimo-python/branch/main/graph/badge.svg?token=H588J8Q1M8)](https://codecov.io/gh/asparagusbeef/bookalimo-python)
66
+ [![Docs](https://img.shields.io/github/deployments/asparagusbeef/bookalimo-python/github-pages?label=docs&logo=github)](https://asparagusbeef.github.io/bookalimo-python)
67
+ [![PyPI version](https://badge.fury.io/py/bookalimo.svg)](https://badge.fury.io/py/bookalimo)
68
+ [![Python Support](https://img.shields.io/pypi/pyversions/bookalimo.svg)](https://pypi.org/project/bookalimo/)
69
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
70
+ [![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)
71
+
72
+ Python client library for the Book-A-Limo transportation booking API with async/sync support, type safety, and Google Places integration.
73
+
74
+ ## Design philosophy: IDE-first DX
75
+
76
+ The library is **comprehensively typed** and **richly documented** via docstrings. Most users can rely on IDE hints, docstrings, and autocomplete without reading the docs.
77
+
78
+ ## Features
79
+
80
+ - **Async & Sync Support** – `AsyncBookalimo` and `Bookalimo` clients
81
+ - **Type Safety** – Full Pydantic models with validation
82
+ - **Google Places Integration** – Location search and geocoding
83
+ - **Automatic Retry** – Built-in exponential backoff
84
+ - **Resource Management** – Context managers for proper cleanup
85
+
86
+ ## Installation
87
+
88
+ ```bash
89
+ pip install bookalimo
90
+
91
+ # With Google Places integration
92
+ pip install bookalimo[places]
93
+ ```
94
+
95
+ ## Quick Example
96
+
97
+ ```python
98
+ import asyncio
99
+ from bookalimo import (
100
+ AsyncBookalimo,
101
+ )
102
+ from bookalimo.transport.auth import (
103
+ Credentials,
104
+ )
105
+ from bookalimo.schemas import (
106
+ RateType,
107
+ Location,
108
+ LocationType,
109
+ Address,
110
+ City,
111
+ Airport,
112
+ PriceRequest,
113
+ BookRequest,
114
+ )
115
+
116
+
117
+ async def book_ride():
118
+ credentials = Credentials.create(
119
+ "your_id",
120
+ "your_password",
121
+ is_customer=False,
122
+ )
123
+
124
+ pickup = Location(
125
+ type=LocationType.ADDRESS,
126
+ address=Address(
127
+ place_name="Empire State Building",
128
+ city=City(
129
+ city_name="New York",
130
+ country_code="US",
131
+ state_code="NY",
132
+ ),
133
+ ),
134
+ )
135
+ dropoff = Location(
136
+ type=LocationType.AIRPORT,
137
+ airport=Airport(iata_code="JFK"),
138
+ )
139
+
140
+ async with AsyncBookalimo(credentials=credentials) as client:
141
+ # Get pricing
142
+ quote = await client.pricing.quote(
143
+ PriceRequest(
144
+ rate_type=RateType.P2P,
145
+ date_time="12/25/2024 03:00 PM",
146
+ pickup=pickup,
147
+ dropoff=dropoff,
148
+ passengers=2,
149
+ luggage=2,
150
+ )
151
+ )
152
+
153
+ # Book reservation
154
+ booking = await client.reservations.book(
155
+ BookRequest(
156
+ token=quote.token,
157
+ method="charge",
158
+ )
159
+ )
160
+ return booking.reservation_id
161
+
162
+
163
+ confirmation = asyncio.run(book_ride())
164
+ ```
165
+
166
+ ## Sync Usage
167
+
168
+ ```python
169
+ from bookalimo import (
170
+ Bookalimo,
171
+ )
172
+
173
+ with Bookalimo(credentials=credentials) as client:
174
+ quote = client.pricing.quote(PriceRequest(...))
175
+ booking = client.reservations.book(
176
+ BookRequest(
177
+ token=quote.token,
178
+ method="charge",
179
+ )
180
+ )
181
+ ```
182
+
183
+ ## Google Places Integration
184
+
185
+ ```python
186
+ async with AsyncBookalimo(
187
+ credentials=credentials,
188
+ google_places_api_key="your-google-places-key",
189
+ ) as client:
190
+ # Search locations
191
+ results = await client.places.search("Hilton Miami Beach")
192
+
193
+ # Resolve airports near landmarks
194
+ airports = await client.places.resolve_airport(query="eiffel tower")
195
+ top_airport = airports[0] # Closest airport with confidence scoring
196
+
197
+ # Use in booking flow
198
+ quote = await client.pricing.quote(...)
199
+ ```
200
+
201
+ ## Error Handling
202
+
203
+ ```python
204
+ from bookalimo.exceptions import (
205
+ BookalimoHTTPError,
206
+ BookalimoValidationError,
207
+ )
208
+
209
+ try:
210
+ booking = await client.reservations.book(...)
211
+ except BookalimoValidationError as e:
212
+ print(f"Invalid input: {e.message}")
213
+ except BookalimoHTTPError as e:
214
+ if e.status_code == 401:
215
+ print("Authentication failed")
216
+ ```
217
+
218
+ ## Environment
219
+
220
+ ```bash
221
+ export GOOGLE_PLACES_API_KEY="your_google_places_key"
222
+ export BOOKALIMO_LOG_LEVEL="DEBUG"
223
+ ```
224
+
225
+ ## Documentation
226
+
227
+ **📖 Complete Documentation:** [https://asparagusbeef.github.io/bookalimo-python](https://asparagusbeef.github.io/bookalimo-python)
228
+
229
+ ## Requirements
230
+
231
+ * Python 3.9+
232
+ * Book-A-Limo API credentials
233
+ * Dependencies: httpx, pydantic, pycountry, us, airportsdata, typing-extensions for Python 3.9-3.10
234
+ - Optional: google-maps-places, google-api-core, numpy, rapidfuzz
235
+
236
+ ## Support & Resources
237
+
238
+ * GitHub: [https://github.com/asparagusbeef/bookalimo-python](https://github.com/asparagusbeef/bookalimo-python)
239
+ * PyPI: [https://pypi.org/project/bookalimo/](https://pypi.org/project/bookalimo/)
240
+ * Issues: [https://github.com/asparagusbeef/bookalimo-python/issues](https://github.com/asparagusbeef/bookalimo-python/issues)
241
+ * Changelog: [CHANGELOG.md](./CHANGELOG.md)
242
+
243
+ ## License
244
+
245
+ MIT License — see [LICENSE](LICENSE) for details.
@@ -0,0 +1,183 @@
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
+ Python client library for the Book-A-Limo transportation booking API with async/sync support, type safety, and Google Places integration.
11
+
12
+ ## Design philosophy: IDE-first DX
13
+
14
+ The library is **comprehensively typed** and **richly documented** via docstrings. Most users can rely on IDE hints, docstrings, and autocomplete without reading the docs.
15
+
16
+ ## Features
17
+
18
+ - **Async & Sync Support** – `AsyncBookalimo` and `Bookalimo` clients
19
+ - **Type Safety** – Full Pydantic models with validation
20
+ - **Google Places Integration** – Location search and geocoding
21
+ - **Automatic Retry** – Built-in exponential backoff
22
+ - **Resource Management** – Context managers for proper cleanup
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ pip install bookalimo
28
+
29
+ # With Google Places integration
30
+ pip install bookalimo[places]
31
+ ```
32
+
33
+ ## Quick Example
34
+
35
+ ```python
36
+ import asyncio
37
+ from bookalimo import (
38
+ AsyncBookalimo,
39
+ )
40
+ from bookalimo.transport.auth import (
41
+ Credentials,
42
+ )
43
+ from bookalimo.schemas import (
44
+ RateType,
45
+ Location,
46
+ LocationType,
47
+ Address,
48
+ City,
49
+ Airport,
50
+ PriceRequest,
51
+ BookRequest,
52
+ )
53
+
54
+
55
+ async def book_ride():
56
+ credentials = Credentials.create(
57
+ "your_id",
58
+ "your_password",
59
+ is_customer=False,
60
+ )
61
+
62
+ pickup = Location(
63
+ type=LocationType.ADDRESS,
64
+ address=Address(
65
+ place_name="Empire State Building",
66
+ city=City(
67
+ city_name="New York",
68
+ country_code="US",
69
+ state_code="NY",
70
+ ),
71
+ ),
72
+ )
73
+ dropoff = Location(
74
+ type=LocationType.AIRPORT,
75
+ airport=Airport(iata_code="JFK"),
76
+ )
77
+
78
+ async with AsyncBookalimo(credentials=credentials) as client:
79
+ # Get pricing
80
+ quote = await client.pricing.quote(
81
+ PriceRequest(
82
+ rate_type=RateType.P2P,
83
+ date_time="12/25/2024 03:00 PM",
84
+ pickup=pickup,
85
+ dropoff=dropoff,
86
+ passengers=2,
87
+ luggage=2,
88
+ )
89
+ )
90
+
91
+ # Book reservation
92
+ booking = await client.reservations.book(
93
+ BookRequest(
94
+ token=quote.token,
95
+ method="charge",
96
+ )
97
+ )
98
+ return booking.reservation_id
99
+
100
+
101
+ confirmation = asyncio.run(book_ride())
102
+ ```
103
+
104
+ ## Sync Usage
105
+
106
+ ```python
107
+ from bookalimo import (
108
+ Bookalimo,
109
+ )
110
+
111
+ with Bookalimo(credentials=credentials) as client:
112
+ quote = client.pricing.quote(PriceRequest(...))
113
+ booking = client.reservations.book(
114
+ BookRequest(
115
+ token=quote.token,
116
+ method="charge",
117
+ )
118
+ )
119
+ ```
120
+
121
+ ## Google Places Integration
122
+
123
+ ```python
124
+ async with AsyncBookalimo(
125
+ credentials=credentials,
126
+ google_places_api_key="your-google-places-key",
127
+ ) as client:
128
+ # Search locations
129
+ results = await client.places.search("Hilton Miami Beach")
130
+
131
+ # Resolve airports near landmarks
132
+ airports = await client.places.resolve_airport(query="eiffel tower")
133
+ top_airport = airports[0] # Closest airport with confidence scoring
134
+
135
+ # Use in booking flow
136
+ quote = await client.pricing.quote(...)
137
+ ```
138
+
139
+ ## Error Handling
140
+
141
+ ```python
142
+ from bookalimo.exceptions import (
143
+ BookalimoHTTPError,
144
+ BookalimoValidationError,
145
+ )
146
+
147
+ try:
148
+ booking = await client.reservations.book(...)
149
+ except BookalimoValidationError as e:
150
+ print(f"Invalid input: {e.message}")
151
+ except BookalimoHTTPError as e:
152
+ if e.status_code == 401:
153
+ print("Authentication failed")
154
+ ```
155
+
156
+ ## Environment
157
+
158
+ ```bash
159
+ export GOOGLE_PLACES_API_KEY="your_google_places_key"
160
+ export BOOKALIMO_LOG_LEVEL="DEBUG"
161
+ ```
162
+
163
+ ## Documentation
164
+
165
+ **📖 Complete Documentation:** [https://asparagusbeef.github.io/bookalimo-python](https://asparagusbeef.github.io/bookalimo-python)
166
+
167
+ ## Requirements
168
+
169
+ * Python 3.9+
170
+ * Book-A-Limo API credentials
171
+ * Dependencies: httpx, pydantic, pycountry, us, airportsdata, typing-extensions for Python 3.9-3.10
172
+ - Optional: google-maps-places, google-api-core, numpy, rapidfuzz
173
+
174
+ ## Support & Resources
175
+
176
+ * GitHub: [https://github.com/asparagusbeef/bookalimo-python](https://github.com/asparagusbeef/bookalimo-python)
177
+ * PyPI: [https://pypi.org/project/bookalimo/](https://pypi.org/project/bookalimo/)
178
+ * Issues: [https://github.com/asparagusbeef/bookalimo-python/issues](https://github.com/asparagusbeef/bookalimo-python/issues)
179
+ * Changelog: [CHANGELOG.md](./CHANGELOG.md)
180
+
181
+ ## License
182
+
183
+ MIT License — see [LICENSE](LICENSE) for details.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "bookalimo"
7
- version = "1.0.0"
7
+ version = "1.0.2"
8
8
  description = "Python wrapper for the Book-A-Limo API"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -24,6 +24,7 @@ classifiers = [
24
24
  "Programming Language :: Python :: 3.10",
25
25
  "Programming Language :: Python :: 3.11",
26
26
  "Programming Language :: Python :: 3.12",
27
+ "Programming Language :: Python :: 3.13",
27
28
  "Topic :: Software Development :: Libraries :: Python Modules",
28
29
  "Topic :: Internet :: WWW/HTTP :: Dynamic Content",
29
30
  ]
@@ -41,6 +42,9 @@ requires-python = ">=3.9"
41
42
  places = [
42
43
  "google-maps-places>=0.1.0",
43
44
  "google-api-core>=2.0.0",
45
+ "numpy>=2.0.0",
46
+ "rapidfuzz>=3.0.0",
47
+ "typing-extensions>=4.15.0; python_version < '3.11'"
44
48
  ]
45
49
  dev = [
46
50
  "pytest>=7.0.0",
@@ -93,7 +97,7 @@ lint.select = [
93
97
  "UP", # pyupgrade
94
98
  ]
95
99
  lint.ignore = [
96
- "E501", # line too long, handled by black
100
+ "E501", # line too long, handled by ruff-format
97
101
  "B008", # do not perform function calls in argument defaults
98
102
  "C901", # too complex
99
103
  "UP045", # until I have time to Optional[] -> X | None everywhere.
@@ -124,7 +128,7 @@ warn_return_any = true
124
128
  warn_unreachable = true
125
129
  warn_unused_configs = true
126
130
  warn_unused_ignores = true
127
- mypy_path = "stubs"
131
+ mypy_path = "src:stubs"
128
132
  disable_error_code = ["prop-decorator"]
129
133
 
130
134
  [[tool.mypy.overrides]]
@@ -59,7 +59,7 @@ class AsyncBookalimo:
59
59
  google_places_api_key="your-google-api-key"
60
60
  ) as client:
61
61
  # Find locations using Google Places
62
- places = await client.places.search_text("Empire State Building")
62
+ places = await client.places.search("Empire State Building")
63
63
 
64
64
  # Use in booking
65
65
  quote = await client.pricing.quote(
@@ -93,8 +93,7 @@ class AsyncBookalimo:
93
93
  transport: Custom transport instance (optional)
94
94
  google_places_api_key: Google Places API key for location services (optional)
95
95
  """
96
-
97
- transport_credentials = transport.credentials if transport else None
96
+ transport_credentials = transport._credentials if transport else None
98
97
 
99
98
  both_provided = all([transport_credentials, credentials])
100
99
  both_missing = not any([transport_credentials, credentials])
@@ -113,18 +112,21 @@ class AsyncBookalimo:
113
112
  stacklevel=2,
114
113
  )
115
114
 
116
- # Use whichever exists when we need to build a transport ourselves
117
115
  effective_credentials = (
118
- credentials if credentials is not None else transport_credentials
116
+ transport_credentials if transport_credentials is not None else credentials
119
117
  )
118
+
120
119
  if transport:
121
- transport.credentials = effective_credentials
122
- self._transport = transport or AsyncTransport(
123
- base_url=base_url,
124
- timeouts=timeouts,
125
- user_agent=user_agent,
126
- credentials=effective_credentials,
127
- )
120
+ if transport_credentials is None and credentials is not None:
121
+ transport.credentials = credentials
122
+ self._transport = transport
123
+ else:
124
+ self._transport = AsyncTransport(
125
+ base_url=base_url,
126
+ timeouts=timeouts,
127
+ user_agent=user_agent,
128
+ credentials=effective_credentials,
129
+ )
128
130
 
129
131
  # Initialize service instances
130
132
  self.reservations = AsyncReservationsService(self._transport)
@@ -149,7 +151,7 @@ class AsyncBookalimo:
149
151
  Auth priority is as follows:
150
152
  - provided api key in constructor
151
153
  - GOOGLE_PLACES_API_KEY environment variable
152
- - Google ADC - Except for Geocoding API.
154
+ - Google ADC - Not yet implemented.
153
155
  """
154
156
  if not _GOOGLE_PLACES_AVAILABLE:
155
157
  raise ImportError(
@@ -207,7 +209,7 @@ class Bookalimo:
207
209
  google_places_api_key="your-google-api-key"
208
210
  ) as client:
209
211
  # Find locations using Google Places
210
- places = client.places.search_text("Empire State Building")
212
+ places = client.places.search("Empire State Building")
211
213
 
212
214
  # Use in booking
213
215
  quote = client.pricing.quote(
@@ -241,20 +243,41 @@ class Bookalimo:
241
243
  transport: Custom transport instance (optional)
242
244
  google_places_api_key: Google Places API key for location services (optional)
243
245
  """
244
- if transport and transport.credentials is not None and credentials is not None:
246
+ transport_credentials = transport.credentials if transport else None
247
+
248
+ both_provided = all([transport_credentials, credentials])
249
+ both_missing = not any([transport_credentials, credentials])
250
+
251
+ if both_provided:
245
252
  warnings.warn(
246
253
  "Credentials provided in both transport and constructor. "
247
254
  "The transport credentials will be used.",
248
- UserWarning,
255
+ DuplicateCredentialsWarning,
249
256
  stacklevel=2,
250
257
  )
251
- self._transport = transport or SyncTransport(
252
- base_url=base_url,
253
- timeouts=timeouts,
254
- user_agent=user_agent,
255
- credentials=credentials,
258
+ elif both_missing:
259
+ warnings.warn(
260
+ "No credentials provided in transport or constructor; proceeding unauthenticated.",
261
+ MissingCredentialsWarning,
262
+ stacklevel=2,
263
+ )
264
+
265
+ effective_credentials = (
266
+ transport_credentials if transport_credentials is not None else credentials
256
267
  )
257
268
 
269
+ if transport:
270
+ if transport_credentials is None and credentials is not None:
271
+ transport.credentials = credentials
272
+ self._transport = transport
273
+ else:
274
+ self._transport = SyncTransport(
275
+ base_url=base_url,
276
+ timeouts=timeouts,
277
+ user_agent=user_agent,
278
+ credentials=effective_credentials,
279
+ )
280
+
258
281
  # Initialize service instances
259
282
  self.reservations = ReservationsService(self._transport)
260
283
  self.pricing = PricingService(self._transport)
@@ -278,7 +301,7 @@ class Bookalimo:
278
301
  Auth priority is as follows:
279
302
  - provided api key in constructor
280
303
  - GOOGLE_PLACES_API_KEY environment variable
281
- - Google ADC - Except for Geocoding API.
304
+ - Google ADC - Not yet implemented.
282
305
  """
283
306
  if not _GOOGLE_PLACES_AVAILABLE:
284
307
  raise ImportError(
@@ -5,7 +5,7 @@ from ._version import __version__
5
5
  # Default API configuration
6
6
  DEFAULT_BASE_URL = "https://www.bookalimo.com/web/api"
7
7
  DEFAULT_TIMEOUT = 5.0
8
- DEFAULT_USER_AGENT = f"bookalimo-python/{__version__} (+https://github.com/asparagusbeef/bookalimo-python)"
8
+ DEFAULT_USER_AGENT = f"bookalimo-python/{__version__}"
9
9
 
10
10
  # Default retry configuration
11
11
  DEFAULT_RETRIES = 2