geocodio-library-python 0.2.0__tar.gz → 0.5.0__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 (44) hide show
  1. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/CHANGELOG.md +17 -1
  2. geocodio_library_python-0.5.0/PKG-INFO +600 -0
  3. geocodio_library_python-0.5.0/README.md +565 -0
  4. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/pyproject.toml +1 -1
  5. geocodio_library_python-0.5.0/src/geocodio/__init__.py +55 -0
  6. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/src/geocodio/_version.py +1 -1
  7. geocodio_library_python-0.5.0/src/geocodio/client.py +1218 -0
  8. geocodio_library_python-0.5.0/src/geocodio/distance.py +270 -0
  9. geocodio_library_python-0.5.0/src/geocodio/models.py +717 -0
  10. geocodio_library_python-0.5.0/tests/e2e/__init__.py +1 -0
  11. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/tests/e2e/test_api.py +4 -2
  12. geocodio_library_python-0.5.0/tests/e2e/test_distance.py +232 -0
  13. geocodio_library_python-0.5.0/tests/unit/__init__.py +1 -0
  14. geocodio_library_python-0.5.0/tests/unit/test_distance.py +774 -0
  15. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/tests/unit/test_geocode.py +99 -1
  16. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/uv.lock +1 -1
  17. geocodio_library_python-0.2.0/PKG-INFO +0 -230
  18. geocodio_library_python-0.2.0/README.md +0 -195
  19. geocodio_library_python-0.2.0/src/geocodio/__init__.py +0 -9
  20. geocodio_library_python-0.2.0/src/geocodio/client.py +0 -583
  21. geocodio_library_python-0.2.0/src/geocodio/models.py +0 -400
  22. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/.github/workflows/ci.yml +0 -0
  23. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/.github/workflows/publish.yml +0 -0
  24. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/.github/workflows/test-act-event-ci.json +0 -0
  25. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/.github/workflows/test-act-event-publish.json +0 -0
  26. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/.gitignore +0 -0
  27. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/LICENSE +0 -0
  28. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/requirements-dev.txt +0 -0
  29. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/setup.cfg +0 -0
  30. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/smoke.py +0 -0
  31. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/smoke_lists.py +0 -0
  32. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/src/geocodio/exceptions.py +0 -0
  33. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/test_pypi_release.py +0 -0
  34. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/tests/__init__.py +0 -0
  35. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/tests/conftest.py +0 -0
  36. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/tests/e2e/test_batch_reverse.py +0 -0
  37. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/tests/e2e/test_lists_api.py +0 -0
  38. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/tests/test_workflows.py +0 -0
  39. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/tests/unit/test_client.py +0 -0
  40. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/tests/unit/test_errors.py +0 -0
  41. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/tests/unit/test_exceptions.py +0 -0
  42. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/tests/unit/test_geocoding.py +0 -0
  43. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/tests/unit/test_models.py +0 -0
  44. {geocodio_library_python-0.2.0 → geocodio_library_python-0.5.0}/tests/unit/test_reverse.py +0 -0
@@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.5.0] - 2026-01-06
11
+
12
+ ### Added
13
+ - **Distance API support** with new methods for calculating distances between coordinates:
14
+ - `distance()` - Calculate distances from a single origin to multiple destinations
15
+ - `distance_matrix()` - Calculate distances from multiple origins to multiple destinations
16
+ - Support for `straightline` (haversine) and `driving` distance modes
17
+ - Support for `miles` and `km` units
18
+ - Optional sorting by distance or duration
19
+ - New `Coordinate` class for representing geographic coordinates with optional IDs
20
+ - Distance parameters for `geocode()` and `reverse()` methods to calculate distances inline
21
+ - Comprehensive type definitions: `DistanceResponse`, `DistanceMatrixResponse`, `DistanceOrigin`, `DistanceDestination`
22
+ - Distance mode constants: `DISTANCE_MODE_STRAIGHTLINE`, `DISTANCE_MODE_DRIVING`
23
+ - Distance unit constants: `DISTANCE_UNITS_MILES`, `DISTANCE_UNITS_KM`
24
+
10
25
  ## [0.2.0] - 2025-08-08
11
26
 
12
27
  ### Changed
@@ -39,6 +54,7 @@ When ready to release:
39
54
  5. Push tags: `git push --tags`
40
55
  6. GitHub Actions will automatically publish to PyPI
41
56
 
42
- [Unreleased]: https://github.com/Geocodio/geocodio-library-python/compare/v0.2.0...HEAD
57
+ [Unreleased]: https://github.com/Geocodio/geocodio-library-python/compare/v0.5.0...HEAD
58
+ [0.5.0]: https://github.com/Geocodio/geocodio-library-python/compare/v0.4.0...v0.5.0
43
59
  [0.2.0]: https://github.com/Geocodio/geocodio-library-python/compare/v0.1.0...v0.2.0
44
60
  [0.1.0]: https://github.com/Geocodio/geocodio-library-python/releases/tag/v0.1.0
@@ -0,0 +1,600 @@
1
+ Metadata-Version: 2.4
2
+ Name: geocodio-library-python
3
+ Version: 0.5.0
4
+ Summary: A Python client for the Geocodio API
5
+ Project-URL: Homepage, https://www.geocod.io
6
+ Project-URL: Documentation, https://www.geocod.io/docs/?python
7
+ Project-URL: Repository, https://github.com/geocodio/geocodio-library-python
8
+ Project-URL: Issues, https://github.com/geocodio/geocodio-library-python/issues
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
20
+ Classifier: Topic :: Scientific/Engineering :: GIS
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Requires-Python: >=3.11
23
+ Requires-Dist: httpx>=0.24.0
24
+ Provides-Extra: dev
25
+ Requires-Dist: black>=23.0.0; extra == 'dev'
26
+ Requires-Dist: flake8>=6.0.0; extra == 'dev'
27
+ Requires-Dist: isort>=5.12.0; extra == 'dev'
28
+ Requires-Dist: mypy>=1.0.0; extra == 'dev'
29
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
30
+ Requires-Dist: pytest-httpx>=0.27.0; extra == 'dev'
31
+ Requires-Dist: pytest-mock>=3.10.0; extra == 'dev'
32
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
33
+ Requires-Dist: python-dotenv>=1.0.0; extra == 'dev'
34
+ Description-Content-Type: text/markdown
35
+
36
+ # geocodio
37
+
38
+ The official Python client for the Geocodio API.
39
+
40
+ Features
41
+ --------
42
+
43
+ - Forward geocoding of single addresses or in batches (up to 10,000 lookups).
44
+ - Reverse geocoding of coordinates (single or batch).
45
+ - Append additional data fields (e.g. congressional districts, timezone, census data).
46
+ - Distance calculations (single origin to multiple destinations, distance matrices).
47
+ - Async distance matrix jobs for large calculations.
48
+ - Automatic parsing of address components.
49
+ - Simple exception handling for authentication, data, and server errors.
50
+
51
+ Installation
52
+ ------------
53
+
54
+ Install via pip:
55
+
56
+ pip install geocodio-library-python
57
+
58
+ Usage
59
+ -----
60
+
61
+ > Don't have an API key yet? Sign up at [https://dash.geocod.io](https://dash.geocod.io) to get an API key. The first 2,500 lookups per day are free.
62
+
63
+ ### Geocoding
64
+
65
+ ```python
66
+ from geocodio import Geocodio
67
+
68
+ # Initialize the client with your API key
69
+ client = Geocodio("YOUR_API_KEY")
70
+ # client = Geocodio("YOUR_API_KEY", hostname="api-hipaa.geocod.io") # optionally overwrite the API hostname
71
+
72
+ # Single forward geocode
73
+ response = client.geocode("1600 Pennsylvania Ave, Washington, DC")
74
+ print(response.results[0].formatted_address)
75
+
76
+ # Batch forward geocode
77
+ addresses = [
78
+ "1600 Pennsylvania Ave, Washington, DC",
79
+ "1 Infinite Loop, Cupertino, CA"
80
+ ]
81
+ batch_response = client.geocode(addresses)
82
+ for result in batch_response.results:
83
+ print(result.formatted_address)
84
+
85
+ # Single reverse geocode
86
+ rev = client.reverse("38.9002898,-76.9990361")
87
+ print(rev.results[0].formatted_address)
88
+
89
+ # Reverse with tuple coordinates
90
+ rev = client.reverse((38.9002898, -76.9990361))
91
+ ```
92
+
93
+ > Note: You can read more about accuracy scores, accuracy types, input formats and more at https://www.geocod.io/docs/
94
+
95
+ ### Batch geocoding
96
+
97
+ To batch geocode, simply pass a list of addresses or coordinates instead of a single string:
98
+
99
+ ```python
100
+ response = client.geocode([
101
+ "1109 N Highland St, Arlington VA",
102
+ "525 University Ave, Toronto, ON, Canada",
103
+ "4410 S Highway 17 92, Casselberry FL",
104
+ "15000 NE 24th Street, Redmond WA",
105
+ "17015 Walnut Grove Drive, Morgan Hill CA"
106
+ ])
107
+
108
+ response = client.reverse([
109
+ "35.9746000,-77.9658000",
110
+ "32.8793700,-96.6303900",
111
+ "33.8337100,-117.8362320",
112
+ "35.4171240,-80.6784760"
113
+ ])
114
+
115
+ # Optionally supply a custom key that will be returned along with results
116
+ response = client.geocode({
117
+ "MyId1": "1109 N Highland St, Arlington VA",
118
+ "MyId2": "525 University Ave, Toronto, ON, Canada",
119
+ "MyId3": "4410 S Highway 17 92, Casselberry FL",
120
+ "MyId4": "15000 NE 24th Street, Redmond WA",
121
+ "MyId5": "17015 Walnut Grove Drive, Morgan Hill CA"
122
+ })
123
+ ```
124
+
125
+ ### Field appends
126
+
127
+ Geocodio allows you to append additional data points such as congressional districts, census codes, timezone, ACS survey results and [much more](https://www.geocod.io/docs/#fields).
128
+
129
+ To request additional fields, simply supply them as a list:
130
+
131
+ ```python
132
+ response = client.geocode(
133
+ [
134
+ "1109 N Highland St, Arlington VA",
135
+ "525 University Ave, Toronto, ON, Canada"
136
+ ],
137
+ fields=["cd", "timezone"]
138
+ )
139
+
140
+ response = client.reverse("38.9002898,-76.9990361", fields=["census2010"])
141
+ ```
142
+
143
+ ### Address components
144
+
145
+ For forward geocoding requests it is possible to supply [individual address components](https://www.geocod.io/docs/#single-address) instead of a full address string:
146
+
147
+ ```python
148
+ response = client.geocode({
149
+ "street": "1109 N Highland St",
150
+ "city": "Arlington",
151
+ "state": "VA",
152
+ "postal_code": "22201"
153
+ })
154
+
155
+ response = client.geocode([
156
+ {
157
+ "street": "1109 N Highland St",
158
+ "city": "Arlington",
159
+ "state": "VA"
160
+ },
161
+ {
162
+ "street": "525 University Ave",
163
+ "city": "Toronto",
164
+ "state": "ON",
165
+ "country": "Canada"
166
+ }
167
+ ])
168
+ ```
169
+
170
+ ### Limit results
171
+
172
+ Optionally limit the number of maximum geocoding results:
173
+
174
+ ```python
175
+ # Only get the first result
176
+ response = client.geocode("1109 N Highland St, Arlington, VA", limit=1)
177
+
178
+ # Return up to 5 geocoding results
179
+ response = client.reverse("38.9002898,-76.9990361", fields=["timezone"], limit=5)
180
+ ```
181
+
182
+ ### Distance calculations
183
+
184
+ Calculate distances from a single origin to multiple destinations, or compute full distance matrices.
185
+
186
+ #### Coordinate format with custom IDs
187
+
188
+ You can add custom identifiers to coordinates using the `lat,lng,id` format. The ID will be returned in the response, making it easy to match results back to your data:
189
+
190
+ ```python
191
+ from geocodio import Coordinate
192
+
193
+ # String format with ID
194
+ "37.7749,-122.4194,warehouse_1"
195
+
196
+ # Tuple format with ID
197
+ (37.7749, -122.4194, "warehouse_1")
198
+
199
+ # Using the Coordinate class
200
+ Coordinate(37.7749, -122.4194, "warehouse_1")
201
+
202
+ # The ID is returned in the response:
203
+ # DistanceDestination(
204
+ # query="37.7749,-122.4194,warehouse_1",
205
+ # location=(37.7749, -122.4194),
206
+ # id="warehouse_1",
207
+ # distance_miles=3.2,
208
+ # distance_km=5.1
209
+ # )
210
+ ```
211
+
212
+ #### Distance mode and units
213
+
214
+ The SDK provides constants for type-safe distance configuration:
215
+
216
+ ```python
217
+ from geocodio import (
218
+ DISTANCE_MODE_STRAIGHTLINE, # Default - great-circle (as the crow flies)
219
+ DISTANCE_MODE_DRIVING, # Road network routing with duration
220
+ DISTANCE_MODE_HAVERSINE, # Alias for Straightline (backward compat)
221
+ DISTANCE_UNITS_MILES, # Default
222
+ DISTANCE_UNITS_KM,
223
+ DISTANCE_ORDER_BY_DISTANCE, # Default
224
+ DISTANCE_ORDER_BY_DURATION,
225
+ DISTANCE_SORT_ASC, # Default
226
+ DISTANCE_SORT_DESC,
227
+ )
228
+ ```
229
+
230
+ > **Note:** The default mode is `straightline` (great-circle distance). Use `DISTANCE_MODE_DRIVING` if you need road network routing with duration estimates.
231
+
232
+ #### Add distance to geocoding requests
233
+
234
+ You can add distance calculations to existing geocode or reverse geocode requests. Each geocoded result will include distance data to each destination.
235
+
236
+ ```python
237
+ from geocodio import (
238
+ Geocodio,
239
+ DISTANCE_MODE_DRIVING,
240
+ DISTANCE_UNITS_MILES,
241
+ DISTANCE_ORDER_BY_DISTANCE,
242
+ DISTANCE_SORT_ASC,
243
+ )
244
+
245
+ client = Geocodio("YOUR_API_KEY")
246
+
247
+ # Geocode an address and calculate distances to store locations
248
+ response = client.geocode(
249
+ "1600 Pennsylvania Ave NW, Washington DC",
250
+ destinations=[
251
+ "38.9072,-77.0369,store_dc",
252
+ "39.2904,-76.6122,store_baltimore",
253
+ "39.9526,-75.1652,store_philly"
254
+ ],
255
+ distance_mode=DISTANCE_MODE_DRIVING,
256
+ distance_units=DISTANCE_UNITS_MILES
257
+ )
258
+
259
+ # Reverse geocode with distances
260
+ response = client.reverse(
261
+ "38.8977,-77.0365",
262
+ destinations=["38.9072,-77.0369,capitol", "38.8895,-77.0353,monument"],
263
+ distance_mode=DISTANCE_MODE_STRAIGHTLINE
264
+ )
265
+
266
+ # With filtering - find nearest 3 stores within 50 miles
267
+ response = client.geocode(
268
+ "1600 Pennsylvania Ave NW, Washington DC",
269
+ destinations=[
270
+ "38.9072,-77.0369,store_1",
271
+ "39.2904,-76.6122,store_2",
272
+ "39.9526,-75.1652,store_3",
273
+ "40.7128,-74.0060,store_4"
274
+ ],
275
+ distance_mode=DISTANCE_MODE_DRIVING,
276
+ distance_max_results=3,
277
+ distance_max_distance=50.0,
278
+ distance_order_by=DISTANCE_ORDER_BY_DISTANCE,
279
+ distance_sort_order=DISTANCE_SORT_ASC
280
+ )
281
+ ```
282
+
283
+ #### Single origin to multiple destinations
284
+
285
+ ```python
286
+ from geocodio import (
287
+ Geocodio,
288
+ Coordinate,
289
+ DISTANCE_MODE_DRIVING,
290
+ DISTANCE_UNITS_KM,
291
+ DISTANCE_ORDER_BY_DISTANCE,
292
+ DISTANCE_SORT_ASC,
293
+ )
294
+
295
+ client = Geocodio("YOUR_API_KEY")
296
+
297
+ # Calculate distances from one origin to multiple destinations
298
+ response = client.distance(
299
+ origin="37.7749,-122.4194,headquarters", # Origin with ID
300
+ destinations=[
301
+ "37.7849,-122.4094,customer_a",
302
+ "37.7949,-122.3994,customer_b",
303
+ "37.8049,-122.4294,customer_c"
304
+ ]
305
+ )
306
+
307
+ print(response.origin.id) # "headquarters"
308
+ for dest in response.destinations:
309
+ print(f"{dest.id}: {dest.distance_miles} miles")
310
+
311
+ # Use driving mode for road network routing (includes duration)
312
+ response = client.distance(
313
+ origin="37.7749,-122.4194",
314
+ destinations=["37.7849,-122.4094"],
315
+ mode=DISTANCE_MODE_DRIVING
316
+ )
317
+ print(response.destinations[0].duration_seconds) # e.g., 180
318
+
319
+ # With all filtering and sorting options
320
+ response = client.distance(
321
+ origin="37.7749,-122.4194,warehouse",
322
+ destinations=[
323
+ "37.7849,-122.4094,store_1",
324
+ "37.7949,-122.3994,store_2",
325
+ "37.8049,-122.4294,store_3"
326
+ ],
327
+ mode=DISTANCE_MODE_DRIVING,
328
+ units=DISTANCE_UNITS_KM,
329
+ max_results=2,
330
+ max_distance=10.0,
331
+ order_by=DISTANCE_ORDER_BY_DISTANCE,
332
+ sort_order=DISTANCE_SORT_ASC
333
+ )
334
+
335
+ # Using Coordinate class
336
+ origin = Coordinate(37.7749, -122.4194, "warehouse")
337
+ destinations = [
338
+ Coordinate(37.7849, -122.4094, "store_1"),
339
+ Coordinate(37.7949, -122.3994, "store_2")
340
+ ]
341
+ response = client.distance(origin=origin, destinations=destinations)
342
+
343
+ # Tuple format for coordinates (with or without ID)
344
+ response = client.distance(
345
+ origin=(37.7749, -122.4194), # Without ID
346
+ destinations=[(37.7849, -122.4094, "dest_1")] # With ID as third element
347
+ )
348
+ ```
349
+
350
+ #### Distance matrix (multiple origins × destinations)
351
+
352
+ ```python
353
+ from geocodio import Geocodio, Coordinate, DISTANCE_MODE_DRIVING, DISTANCE_UNITS_KM
354
+
355
+ client = Geocodio("YOUR_API_KEY")
356
+
357
+ # Calculate full distance matrix with custom IDs
358
+ response = client.distance_matrix(
359
+ origins=[
360
+ "37.7749,-122.4194,warehouse_sf",
361
+ "37.8049,-122.4294,warehouse_oak"
362
+ ],
363
+ destinations=[
364
+ "37.7849,-122.4094,customer_1",
365
+ "37.7949,-122.3994,customer_2"
366
+ ]
367
+ )
368
+
369
+ for result in response.results:
370
+ print(f"From {result.origin.id}:")
371
+ for dest in result.destinations:
372
+ print(f" To {dest.id}: {dest.distance_miles} miles")
373
+
374
+ # With driving mode and kilometers
375
+ response = client.distance_matrix(
376
+ origins=["37.7749,-122.4194"],
377
+ destinations=["37.7849,-122.4094"],
378
+ mode=DISTANCE_MODE_DRIVING,
379
+ units=DISTANCE_UNITS_KM
380
+ )
381
+
382
+ # Using Coordinate objects
383
+ origins = [
384
+ Coordinate(37.7749, -122.4194, "warehouse_sf"),
385
+ Coordinate(37.8049, -122.4294, "warehouse_oak")
386
+ ]
387
+ destinations = [
388
+ Coordinate(37.7849, -122.4094, "customer_1"),
389
+ Coordinate(37.7949, -122.3994, "customer_2")
390
+ ]
391
+ response = client.distance_matrix(origins=origins, destinations=destinations)
392
+ ```
393
+
394
+ #### Nearest mode (find closest destinations)
395
+
396
+ ```python
397
+ # Find up to 2 nearest destinations from each origin
398
+ response = client.distance_matrix(
399
+ origins=["37.7749,-122.4194"],
400
+ destinations=["37.7849,-122.4094", "37.7949,-122.3994", "37.8049,-122.4294"],
401
+ max_results=2
402
+ )
403
+
404
+ # Filter by maximum distance (in miles or km depending on units)
405
+ response = client.distance_matrix(
406
+ origins=["37.7749,-122.4194"],
407
+ destinations=[...],
408
+ max_distance=2.0
409
+ )
410
+
411
+ # Filter by minimum and maximum distance
412
+ response = client.distance_matrix(
413
+ origins=["37.7749,-122.4194"],
414
+ destinations=[...],
415
+ min_distance=1.0,
416
+ max_distance=10.0
417
+ )
418
+
419
+ # Filter by duration (seconds, driving mode only)
420
+ response = client.distance_matrix(
421
+ origins=["37.7749,-122.4194"],
422
+ destinations=[...],
423
+ mode=DISTANCE_MODE_DRIVING,
424
+ max_duration=300, # 5 minutes
425
+ min_duration=60 # 1 minute minimum
426
+ )
427
+
428
+ # Sort by duration descending
429
+ response = client.distance_matrix(
430
+ origins=["37.7749,-122.4194"],
431
+ destinations=[...],
432
+ mode=DISTANCE_MODE_DRIVING,
433
+ max_results=5,
434
+ order_by=DISTANCE_ORDER_BY_DURATION,
435
+ sort_order=DISTANCE_SORT_DESC
436
+ )
437
+ ```
438
+
439
+ #### Async distance matrix jobs
440
+
441
+ For large distance matrix calculations, use async jobs that process in the background.
442
+
443
+ ```python
444
+ from geocodio import Geocodio, DISTANCE_MODE_DRIVING, DISTANCE_UNITS_MILES
445
+
446
+ client = Geocodio("YOUR_API_KEY")
447
+
448
+ # Create a new distance matrix job
449
+ job = client.create_distance_matrix_job(
450
+ name="My Distance Calculation",
451
+ origins=["37.7749,-122.4194", "37.8049,-122.4294"],
452
+ destinations=["37.7849,-122.4094", "37.7949,-122.3994"],
453
+ mode=DISTANCE_MODE_DRIVING,
454
+ units=DISTANCE_UNITS_MILES,
455
+ callback_url="https://example.com/webhook" # Optional
456
+ )
457
+
458
+ print(job.id) # Job identifier
459
+ print(job.status) # "ENQUEUED"
460
+ print(job.total_calculations) # 4
461
+
462
+ # Or use list IDs from previously uploaded lists
463
+ job = client.create_distance_matrix_job(
464
+ name="Distance from List",
465
+ origins=12345, # List ID
466
+ destinations=67890, # List ID
467
+ mode=DISTANCE_MODE_STRAIGHTLINE
468
+ )
469
+
470
+ # Check job status
471
+ status = client.distance_matrix_job_status(job.id)
472
+ print(status.status) # "ENQUEUED", "PROCESSING", "COMPLETED", or "FAILED"
473
+ print(status.progress) # 0-100
474
+
475
+ # List all jobs (paginated)
476
+ jobs = client.distance_matrix_jobs()
477
+ jobs = client.distance_matrix_jobs(page=2) # Page 2
478
+
479
+ # Get results when complete (same format as distance_matrix response)
480
+ results = client.get_distance_matrix_job_results(job.id)
481
+ for result in results.results:
482
+ print(f"From {result.origin.id}:")
483
+ for dest in result.destinations:
484
+ print(f" To {dest.id}: {dest.distance_miles} miles")
485
+
486
+ # Or download to a file for very large results
487
+ client.download_distance_matrix_job(job.id, "results.json")
488
+
489
+ # Delete a job
490
+ client.delete_distance_matrix_job(job.id)
491
+ ```
492
+
493
+ ### List API
494
+
495
+ The List API allows you to manage lists of addresses or coordinates for batch processing.
496
+
497
+ ```python
498
+ from geocodio import Geocodio
499
+
500
+ client = Geocodio("YOUR_API_KEY")
501
+
502
+ # Get all lists
503
+ lists = client.get_lists()
504
+ print(f"Found {len(lists.data)} lists")
505
+
506
+ # Create a new list from a file
507
+ with open("addresses.csv", "rb") as f:
508
+ new_list = client.create_list(
509
+ file=f,
510
+ filename="addresses.csv",
511
+ direction="forward"
512
+ )
513
+ print(f"Created list: {new_list.id}")
514
+
515
+ # Get a specific list
516
+ list_details = client.get_list(new_list.id)
517
+ print(f"List status: {list_details.status}")
518
+
519
+ # Download a completed list
520
+ if list_details.status and list_details.status.get("state") == "COMPLETED":
521
+ file_content = client.download(new_list.id, "downloaded_results.csv")
522
+ print("List downloaded successfully")
523
+
524
+ # Delete a list
525
+ client.delete_list(new_list.id)
526
+ ```
527
+
528
+ Error Handling
529
+ --------------
530
+
531
+ ```python
532
+ from geocodio import Geocodio
533
+ from geocodio.exceptions import AuthenticationError, InvalidRequestError
534
+
535
+ try:
536
+ client = Geocodio("INVALID_API_KEY")
537
+ response = client.geocode("1600 Pennsylvania Ave, Washington, DC")
538
+ except AuthenticationError as e:
539
+ print(f"Authentication failed: {e}")
540
+
541
+ try:
542
+ client = Geocodio("YOUR_API_KEY")
543
+ response = client.geocode("") # Empty address
544
+ except InvalidRequestError as e:
545
+ print(f"Invalid request: {e}")
546
+ ```
547
+
548
+ Geocodio Enterprise
549
+ -------------------
550
+
551
+ To use this library with Geocodio Enterprise, pass `api.enterprise.geocod.io` as the `hostname` parameter when initializing the client:
552
+
553
+ ```python
554
+ from geocodio import Geocodio
555
+
556
+ # Initialize client for Geocodio Enterprise
557
+ client = Geocodio(
558
+ "YOUR_API_KEY",
559
+ hostname="api.enterprise.geocod.io"
560
+ )
561
+
562
+ # All methods work the same as with the standard API
563
+ response = client.geocode("1600 Pennsylvania Ave, Washington, DC")
564
+ print(response.results[0].formatted_address)
565
+ ```
566
+
567
+ Testing
568
+ -------
569
+
570
+ ```bash
571
+ $ pip install -e ".[dev]"
572
+ $ pytest
573
+ ```
574
+
575
+ Documentation
576
+ -------------
577
+
578
+ Full documentation is available at <https://www.geocod.io/docs/?python>.
579
+
580
+ Changelog
581
+ ---------
582
+
583
+ Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.
584
+
585
+ Security
586
+ --------
587
+
588
+ If you discover any security related issues, please email security@geocod.io instead of using the issue tracker.
589
+
590
+ License
591
+ -------
592
+
593
+ This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
594
+
595
+ Contributing
596
+ ------------
597
+
598
+ Contributions are welcome! Please open issues and pull requests on GitHub.
599
+
600
+ Issues: <https://github.com/geocodio/geocodio-library-python/issues>