bookalimo 1.0.1__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.
- bookalimo/client.py +45 -22
- bookalimo/integrations/google_places/client_async.py +56 -102
- bookalimo/integrations/google_places/client_sync.py +56 -100
- bookalimo/integrations/google_places/common.py +290 -12
- bookalimo/integrations/google_places/resolve_airport.py +148 -119
- bookalimo/integrations/google_places/transports.py +14 -7
- bookalimo/logging.py +103 -0
- bookalimo/schemas/__init__.py +121 -35
- bookalimo/schemas/base.py +74 -14
- bookalimo/schemas/places/__init__.py +3 -1
- bookalimo/schemas/places/common.py +1 -1
- bookalimo/schemas/places/field_mask.py +0 -9
- bookalimo/schemas/places/google.py +165 -10
- bookalimo/schemas/requests.py +214 -0
- bookalimo/schemas/responses.py +196 -0
- bookalimo/schemas/{booking.py → shared.py} +55 -218
- bookalimo/services/pricing.py +9 -129
- bookalimo/services/reservations.py +10 -100
- bookalimo/transport/auth.py +2 -2
- bookalimo/transport/httpx_async.py +41 -125
- bookalimo/transport/httpx_sync.py +30 -109
- bookalimo/transport/utils.py +204 -3
- bookalimo-1.0.2.dist-info/METADATA +245 -0
- bookalimo-1.0.2.dist-info/RECORD +40 -0
- bookalimo-1.0.1.dist-info/METADATA +0 -370
- bookalimo-1.0.1.dist-info/RECORD +0 -38
- {bookalimo-1.0.1.dist-info → bookalimo-1.0.2.dist-info}/WHEEL +0 -0
- {bookalimo-1.0.1.dist-info → bookalimo-1.0.2.dist-info}/licenses/LICENSE +0 -0
- {bookalimo-1.0.1.dist-info → bookalimo-1.0.2.dist-info}/top_level.txt +0 -0
bookalimo/transport/utils.py
CHANGED
@@ -1,9 +1,18 @@
|
|
1
1
|
import logging
|
2
|
-
from
|
2
|
+
from contextlib import contextmanager
|
3
|
+
from time import perf_counter
|
4
|
+
from typing import Any, Callable, Generator, NoReturn, Optional, Union, cast, overload
|
3
5
|
|
4
6
|
import httpx
|
5
7
|
|
6
|
-
from ..exceptions import
|
8
|
+
from ..exceptions import (
|
9
|
+
BookalimoConnectionError,
|
10
|
+
BookalimoError,
|
11
|
+
BookalimoHTTPError,
|
12
|
+
BookalimoRequestError,
|
13
|
+
BookalimoTimeout,
|
14
|
+
)
|
15
|
+
from ..logging import configure_httpx_logging, redact_url
|
7
16
|
|
8
17
|
logger = logging.getLogger("bookalimo.transport")
|
9
18
|
|
@@ -31,7 +40,7 @@ def handle_api_errors(
|
|
31
40
|
|
32
41
|
def handle_http_error(
|
33
42
|
response: httpx.Response, req_id: Optional[str], path: str
|
34
|
-
) ->
|
43
|
+
) -> NoReturn:
|
35
44
|
"""Handle HTTP status errors."""
|
36
45
|
status = response.status_code
|
37
46
|
|
@@ -57,3 +66,195 @@ def handle_http_error(
|
|
57
66
|
status_code=status,
|
58
67
|
payload=payload if isinstance(payload, dict) else {"raw": payload},
|
59
68
|
)
|
69
|
+
|
70
|
+
|
71
|
+
def build_url(base_url: str, path: str) -> str:
|
72
|
+
"""Build full URL ensuring a single leading slash on path and no trailing slash on base."""
|
73
|
+
norm_base = base_url.rstrip("/")
|
74
|
+
norm_path = path if path.startswith("/") else f"/{path}"
|
75
|
+
return f"{norm_base}{norm_path}"
|
76
|
+
|
77
|
+
|
78
|
+
def get_request_id(resp: httpx.Response) -> Optional[str]:
|
79
|
+
"""Extract a request id header if present."""
|
80
|
+
return cast(Optional[str], resp.headers.get("x-request-id")) or cast(
|
81
|
+
Optional[str], resp.headers.get("request-id")
|
82
|
+
)
|
83
|
+
|
84
|
+
|
85
|
+
def parse_json_or_raise(
|
86
|
+
response: httpx.Response, path: str, req_id: Optional[str]
|
87
|
+
) -> Any:
|
88
|
+
"""Parse response JSON or raise a helpful error with preview.
|
89
|
+
|
90
|
+
Returns parsed JSON value on success; raises BookalimoError on invalid JSON.
|
91
|
+
"""
|
92
|
+
try:
|
93
|
+
return response.json()
|
94
|
+
except ValueError as e:
|
95
|
+
if logger.isEnabledFor(logging.DEBUG):
|
96
|
+
logger.warning("× [%s] %s invalid JSON", req_id or "-", path)
|
97
|
+
preview = (response.text or "")[:256] if hasattr(response, "text") else ""
|
98
|
+
raise BookalimoError(f"Invalid JSON response: {preview}") from e
|
99
|
+
|
100
|
+
|
101
|
+
def raise_if_retryable_status(
|
102
|
+
response: httpx.Response, should_retry_status: Callable[[int], bool]
|
103
|
+
) -> None:
|
104
|
+
"""Raise httpx.HTTPStatusError for retryable status codes so retry logic can handle it."""
|
105
|
+
if should_retry_status(response.status_code):
|
106
|
+
raise httpx.HTTPStatusError(
|
107
|
+
message=f"Retryable HTTP status: {response.status_code}",
|
108
|
+
request=response.request,
|
109
|
+
response=response,
|
110
|
+
)
|
111
|
+
|
112
|
+
|
113
|
+
def pre_log(url: str, body_keys: list[str], req_id: str) -> None:
|
114
|
+
"""Standard pre-request debug log."""
|
115
|
+
logger.debug("→ [%s] POST %s body_keys=%s", req_id, redact_url(url), body_keys)
|
116
|
+
|
117
|
+
|
118
|
+
def post_log(url: str, response: httpx.Response, start: float, req_id: str) -> None:
|
119
|
+
"""Standard post-response debug log."""
|
120
|
+
dur_ms = (perf_counter() - start) * 1000.0
|
121
|
+
content_len = len(response.content) if hasattr(response, "content") else None
|
122
|
+
logger.debug(
|
123
|
+
"← [%s] %s %s in %.1f ms len=%s reqid=%s",
|
124
|
+
req_id,
|
125
|
+
response.status_code,
|
126
|
+
redact_url(url),
|
127
|
+
dur_ms,
|
128
|
+
content_len,
|
129
|
+
get_request_id(response),
|
130
|
+
)
|
131
|
+
|
132
|
+
|
133
|
+
@contextmanager
|
134
|
+
def map_httpx_exceptions(
|
135
|
+
req_id: Optional[str], path: str
|
136
|
+
) -> Generator[None, None, None]:
|
137
|
+
"""Map common httpx exceptions to domain-specific exceptions.
|
138
|
+
|
139
|
+
Ensures we consistently translate low-level httpx errors.
|
140
|
+
"""
|
141
|
+
try:
|
142
|
+
yield
|
143
|
+
except httpx.TimeoutException:
|
144
|
+
if logger.isEnabledFor(logging.DEBUG):
|
145
|
+
logger.warning("× [%s] %s timeout", req_id or "-", path)
|
146
|
+
raise BookalimoTimeout("Request timeout") from None
|
147
|
+
except httpx.ConnectError:
|
148
|
+
if logger.isEnabledFor(logging.DEBUG):
|
149
|
+
logger.warning("× [%s] %s connection error", req_id or "-", path)
|
150
|
+
raise BookalimoConnectionError(
|
151
|
+
"Connection error - unable to reach Book-A-Limo API"
|
152
|
+
) from None
|
153
|
+
except httpx.RequestError as e:
|
154
|
+
if logger.isEnabledFor(logging.DEBUG):
|
155
|
+
logger.warning(
|
156
|
+
"× [%s] %s request error: %s", req_id or "-", path, e.__class__.__name__
|
157
|
+
)
|
158
|
+
# Preserve underlying message
|
159
|
+
raise BookalimoRequestError(f"Request Error: {e}") from e
|
160
|
+
except httpx.HTTPStatusError as e:
|
161
|
+
if logger.isEnabledFor(logging.DEBUG):
|
162
|
+
logger.warning(
|
163
|
+
"× [%s] %s HTTP error: %s", req_id or "-", path, e.__class__.__name__
|
164
|
+
)
|
165
|
+
status_code = getattr(getattr(e, "response", None), "status_code", None)
|
166
|
+
raise BookalimoHTTPError(f"HTTP Error: {e}", status_code=status_code) from e
|
167
|
+
|
168
|
+
|
169
|
+
def log_request(request: httpx.Request) -> None:
|
170
|
+
"""Event hook to log HTTP requests with redacted URLs (sync version)."""
|
171
|
+
if logger.isEnabledFor(logging.DEBUG):
|
172
|
+
logger.debug(
|
173
|
+
"HTTP Request: %s %s",
|
174
|
+
request.method,
|
175
|
+
redact_url(str(request.url)),
|
176
|
+
)
|
177
|
+
|
178
|
+
|
179
|
+
async def log_request_async(request: httpx.Request) -> None:
|
180
|
+
"""Event hook to log HTTP requests with redacted URLs (async version)."""
|
181
|
+
if logger.isEnabledFor(logging.DEBUG):
|
182
|
+
logger.debug(
|
183
|
+
"HTTP Request: %s %s",
|
184
|
+
request.method,
|
185
|
+
redact_url(str(request.url)),
|
186
|
+
)
|
187
|
+
|
188
|
+
|
189
|
+
def _log_response(response: httpx.Response) -> None:
|
190
|
+
"""Event hook to log HTTP responses with redacted URLs."""
|
191
|
+
if logger.isEnabledFor(logging.DEBUG):
|
192
|
+
request = response.request
|
193
|
+
logger.debug(
|
194
|
+
"HTTP Response: %s %s -> %d",
|
195
|
+
request.method,
|
196
|
+
redact_url(str(request.url)),
|
197
|
+
response.status_code,
|
198
|
+
)
|
199
|
+
|
200
|
+
|
201
|
+
def log_response(response: httpx.Response) -> None:
|
202
|
+
"""Event hook to log HTTP responses with redacted URLs."""
|
203
|
+
_log_response(response)
|
204
|
+
|
205
|
+
|
206
|
+
async def log_response_async(response: httpx.Response) -> None:
|
207
|
+
"""Event hook to log HTTP responses with redacted URLs."""
|
208
|
+
_log_response(response)
|
209
|
+
|
210
|
+
|
211
|
+
@overload
|
212
|
+
def setup_secure_logging_and_client(
|
213
|
+
*,
|
214
|
+
is_async: bool,
|
215
|
+
timeout: Any,
|
216
|
+
client: Optional[httpx.AsyncClient],
|
217
|
+
) -> tuple[httpx.AsyncClient, bool]: ...
|
218
|
+
|
219
|
+
|
220
|
+
@overload
|
221
|
+
def setup_secure_logging_and_client(
|
222
|
+
*,
|
223
|
+
is_async: bool,
|
224
|
+
timeout: Any,
|
225
|
+
client: Optional[httpx.Client],
|
226
|
+
) -> tuple[httpx.Client, bool]: ...
|
227
|
+
|
228
|
+
|
229
|
+
def setup_secure_logging_and_client(
|
230
|
+
*,
|
231
|
+
is_async: bool,
|
232
|
+
timeout: Any,
|
233
|
+
client: Optional[Union[httpx.Client, httpx.AsyncClient]] = None,
|
234
|
+
) -> tuple[Union[httpx.Client, httpx.AsyncClient], bool]:
|
235
|
+
"""
|
236
|
+
Configure secure logging and create httpx client with event hooks if needed.
|
237
|
+
|
238
|
+
Returns:
|
239
|
+
Tuple of (client, owns_client_flag)
|
240
|
+
"""
|
241
|
+
# Configure httpx logging to prevent sensitive data exposure
|
242
|
+
configure_httpx_logging()
|
243
|
+
|
244
|
+
if client is not None:
|
245
|
+
return client, False
|
246
|
+
|
247
|
+
# Create client with secure logging event hooks
|
248
|
+
event_hooks: dict[str, list[Callable[..., Any]]] = (
|
249
|
+
{
|
250
|
+
"request": [log_request_async if is_async else log_request],
|
251
|
+
"response": [log_response_async if is_async else log_response],
|
252
|
+
}
|
253
|
+
if logger.isEnabledFor(logging.DEBUG)
|
254
|
+
else {}
|
255
|
+
)
|
256
|
+
|
257
|
+
if is_async:
|
258
|
+
return httpx.AsyncClient(timeout=timeout, event_hooks=event_hooks), True
|
259
|
+
else:
|
260
|
+
return httpx.Client(timeout=timeout, event_hooks=event_hooks), True
|
@@ -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
|
+
[](https://codecov.io/gh/asparagusbeef/bookalimo-python)
|
66
|
+
[](https://asparagusbeef.github.io/bookalimo-python)
|
67
|
+
[](https://badge.fury.io/py/bookalimo)
|
68
|
+
[](https://pypi.org/project/bookalimo/)
|
69
|
+
[](https://opensource.org/licenses/MIT)
|
70
|
+
[](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,40 @@
|
|
1
|
+
bookalimo/__init__.py,sha256=ZFDpnSOo5VQEgusbVAxyF-neFxBptPZANZ-eE1PeIsU,516
|
2
|
+
bookalimo/_version.py,sha256=KcHRbOssHorjmpk3Xs1RTqGNSA-sw9tjYqwV19Zfa9c,259
|
3
|
+
bookalimo/client.py,sha256=g_Mep6yjwCE8l5cYTKsvuy0eW78TpP9NSsRmnqNdUDY,11414
|
4
|
+
bookalimo/config.py,sha256=K3HlCj8v34kFM2MaG9evGFomU95hRmenRi1zqe4h8EY,456
|
5
|
+
bookalimo/exceptions.py,sha256=pShnuvfMZEP_cChczWhNBLIqa7EOgr4ZNnWj6kphARU,4001
|
6
|
+
bookalimo/logging.py,sha256=Z6it7PxjdwQ5P6C8VtyKn14Lftt19WwwZAQ1n5zrMqM,10585
|
7
|
+
bookalimo/py.typed,sha256=8PjyZ1aVoQpRVvt71muvuq5qE-jTFZkK-GLHkhdebmc,26
|
8
|
+
bookalimo/integrations/__init__.py,sha256=edmQP2Uo8JiNIVaeB4rxM8vagz7BQBhyGEJo70OVS0M,51
|
9
|
+
bookalimo/integrations/google_places/__init__.py,sha256=A6jBfGk8ZLYgFiTCGBytBOsyzKVWHI_kjnuZOgdCONc,866
|
10
|
+
bookalimo/integrations/google_places/client_async.py,sha256=ai-tZJLsUpmgklRBt2-5n1_nDsBY34dzr2k_ZoqenH4,9144
|
11
|
+
bookalimo/integrations/google_places/client_sync.py,sha256=ZfACzI01IEH8w6LGdMui-_t1Kc8lV-VRrV3XOP06M_k,8958
|
12
|
+
bookalimo/integrations/google_places/common.py,sha256=lLRRgJnZ-uDincxv9vW5il3_LHhY0yY8eGYhkYItkNA,16140
|
13
|
+
bookalimo/integrations/google_places/proto_adapter.py,sha256=XuVDr-PH9fopykRwNZxQTS_kIBCdwPwcNYBIHCZjmRo,6809
|
14
|
+
bookalimo/integrations/google_places/resolve_airport.py,sha256=tnsZ5rFteu9HxOj72AQ7O9TJLQPKO3i0oLA_7hNNHDI,14580
|
15
|
+
bookalimo/integrations/google_places/transports.py,sha256=O3JB73kRm4BU7MT0eUFQhe5jocZ8Z_gI94bvgvjifJU,3342
|
16
|
+
bookalimo/schemas/__init__.py,sha256=7utetaurplWJ-w1PtsbARl2HkuGHhBq3EMorTUuF8Vg,4075
|
17
|
+
bookalimo/schemas/base.py,sha256=Qyq72xycTF1TR5ZZIOclUENJ6M9FYhXmnVBSabJ_XJc,3802
|
18
|
+
bookalimo/schemas/requests.py,sha256=EoB5GIMCd7eiddoHeV4uPjERRrK0iCXWB1dNNGvuneM,5490
|
19
|
+
bookalimo/schemas/responses.py,sha256=3tVfoOblezKcoz5s_CLm4LJwqe9qpO2W9jMVZysZHsQ,4691
|
20
|
+
bookalimo/schemas/shared.py,sha256=loXKjpbsTz1-LH17V_IeQ38bXQIplPz_E1Zkgj0gNRM,11053
|
21
|
+
bookalimo/schemas/places/__init__.py,sha256=EZvAPG69VDzrtmduvOkMA8mHiOf_bQh4XEsK7777ikk,1451
|
22
|
+
bookalimo/schemas/places/common.py,sha256=SjY3FbsAQKM5o6DDtLIBx1yvJJGc29UUVVtWglQoSh8,10927
|
23
|
+
bookalimo/schemas/places/field_mask.py,sha256=L6bDkGYpkX63drm4HgDtlNr-GLmgELGCCEWSznlNgWU,6628
|
24
|
+
bookalimo/schemas/places/google.py,sha256=_9HU67Coj2UAJyac5F7Cp0GflyjfLRso4tyIWa2rNns,35392
|
25
|
+
bookalimo/schemas/places/place.py,sha256=5jBqMbPHbRTtXeoFaUtRoIUdzvJeCgMRdeyVt88Axe0,10681
|
26
|
+
bookalimo/services/__init__.py,sha256=4wom7MpoeqKy5y99LYFKkl-CAJ7faDN9ZlXUhKVqlAg,303
|
27
|
+
bookalimo/services/pricing.py,sha256=MDgvYZGDuYYncEr8d2sZumVW3phFbj6GFXMGIaz3kuc,2095
|
28
|
+
bookalimo/services/reservations.py,sha256=CLfvHKl81jb50yk9kPuD37O1F4rmYzjoJ6aioQw-byY,4101
|
29
|
+
bookalimo/transport/__init__.py,sha256=yD5TDnoqg1xtex41jqJ7Hes849efiYgvW3nkaYr6ZjE,221
|
30
|
+
bookalimo/transport/auth.py,sha256=Uq9ybiBg51FMs4NWJ50idX8v2MOOomawluZ7Ca2Xs4I,1257
|
31
|
+
bookalimo/transport/base.py,sha256=qeX2HfLaE6gUT5evjOdPiBh8x7z7A84UuWVsgBK3Pyo,1394
|
32
|
+
bookalimo/transport/httpx_async.py,sha256=feVBMPzWBUA_bBT_oHLK1-lhYSuhWSGjW_E6s9ZhWZ4,4717
|
33
|
+
bookalimo/transport/httpx_sync.py,sha256=XVGlt4HTpNHFndPQi4cy0V2XzRhZ7G6VjZi-3yXv8fg,4868
|
34
|
+
bookalimo/transport/retry.py,sha256=YiJtcdNZUbkrLa1CtKsRtcFO273XJX8naKd8d6ht0LU,2688
|
35
|
+
bookalimo/transport/utils.py,sha256=YPAPRCC2FIPpR-AFuccQ0IZDvg5r3aNSvHWyXdYw-BM,8472
|
36
|
+
bookalimo-1.0.2.dist-info/licenses/LICENSE,sha256=dW9UYOWGfs9eFlJvwSSkJBDhPRic2mrgFkg6aA0xkMM,1070
|
37
|
+
bookalimo-1.0.2.dist-info/METADATA,sha256=DD52pPu_uOQVpq6PVgjP-tQ3ztO9eHfaouBKfpTlX-4,8136
|
38
|
+
bookalimo-1.0.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
39
|
+
bookalimo-1.0.2.dist-info/top_level.txt,sha256=ZgYiDX2GfZCp4pevWn4X2qyEr-Dh7-cq5Y1j2jMhB1s,10
|
40
|
+
bookalimo-1.0.2.dist-info/RECORD,,
|