shipthisapi-python 2.2.0__tar.gz → 3.0.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.
- {shipthisapi_python-2.2.0 → shipthisapi_python-3.0.0}/PKG-INFO +4 -2
- {shipthisapi_python-2.2.0 → shipthisapi_python-3.0.0}/ShipthisAPI/__init__.py +1 -1
- {shipthisapi_python-2.2.0 → shipthisapi_python-3.0.0}/ShipthisAPI/shipthisapi.py +113 -188
- {shipthisapi_python-2.2.0 → shipthisapi_python-3.0.0}/setup.py +6 -3
- {shipthisapi_python-2.2.0 → shipthisapi_python-3.0.0}/shipthisapi_python.egg-info/PKG-INFO +4 -2
- {shipthisapi_python-2.2.0 → shipthisapi_python-3.0.0}/shipthisapi_python.egg-info/SOURCES.txt +1 -0
- shipthisapi_python-3.0.0/shipthisapi_python.egg-info/requires.txt +1 -0
- {shipthisapi_python-2.2.0 → shipthisapi_python-3.0.0}/README.md +0 -0
- {shipthisapi_python-2.2.0 → shipthisapi_python-3.0.0}/setup.cfg +0 -0
- {shipthisapi_python-2.2.0 → shipthisapi_python-3.0.0}/shipthisapi_python.egg-info/dependency_links.txt +0 -0
- {shipthisapi_python-2.2.0 → shipthisapi_python-3.0.0}/shipthisapi_python.egg-info/top_level.txt +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: shipthisapi-python
|
|
3
|
-
Version:
|
|
4
|
-
Summary: ShipthisAPI utility package
|
|
3
|
+
Version: 3.0.0
|
|
4
|
+
Summary: ShipthisAPI async utility package
|
|
5
5
|
Home-page: https://github.com/shipthisco/shipthisapi-python
|
|
6
6
|
Author: Mayur Rawte
|
|
7
7
|
Author-email: mayur@shipthis.co
|
|
@@ -9,12 +9,14 @@ Classifier: Programming Language :: Python :: 3
|
|
|
9
9
|
Classifier: License :: OSI Approved :: MIT License
|
|
10
10
|
Classifier: Operating System :: OS Independent
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
|
+
Requires-Dist: httpx>=0.24.0
|
|
12
13
|
Dynamic: author
|
|
13
14
|
Dynamic: author-email
|
|
14
15
|
Dynamic: classifier
|
|
15
16
|
Dynamic: description
|
|
16
17
|
Dynamic: description-content-type
|
|
17
18
|
Dynamic: home-page
|
|
19
|
+
Dynamic: requires-dist
|
|
18
20
|
Dynamic: summary
|
|
19
21
|
|
|
20
22
|
# ShipthisAPI Python
|
|
@@ -1,43 +1,35 @@
|
|
|
1
1
|
"""Shipthis API Client.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
An async Python client for the Shipthis public API.
|
|
4
4
|
|
|
5
5
|
Usage:
|
|
6
|
+
import asyncio
|
|
6
7
|
from ShipthisAPI import ShipthisAPI
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
# Server-to-server usage with custom headers
|
|
17
|
-
client = ShipthisAPI(
|
|
18
|
-
organisation="your_org_id",
|
|
19
|
-
custom_headers={
|
|
20
|
-
"st-server-key": "your_server_key",
|
|
21
|
-
"st-server-name": "your_service_name",
|
|
22
|
-
}
|
|
23
|
-
)
|
|
9
|
+
async def main():
|
|
10
|
+
# Initialize the client
|
|
11
|
+
client = ShipthisAPI(
|
|
12
|
+
organisation="your_org_id",
|
|
13
|
+
x_api_key="your_api_key",
|
|
14
|
+
region_id="your_region",
|
|
15
|
+
location_id="your_location"
|
|
16
|
+
)
|
|
24
17
|
|
|
25
|
-
|
|
26
|
-
|
|
18
|
+
# Connect and validate
|
|
19
|
+
await client.connect()
|
|
27
20
|
|
|
28
|
-
|
|
29
|
-
|
|
21
|
+
# Get items from a collection
|
|
22
|
+
items = await client.get_list("shipment")
|
|
30
23
|
|
|
31
|
-
|
|
32
|
-
|
|
24
|
+
# Patch document fields
|
|
25
|
+
await client.patch_item("fcl_load", doc_id, {"status": "completed"})
|
|
33
26
|
|
|
34
|
-
|
|
35
|
-
client.webhook_sync("fcl_load", doc_id, fields=[{"status": "completed"}])
|
|
27
|
+
asyncio.run(main())
|
|
36
28
|
"""
|
|
37
29
|
|
|
38
|
-
from typing import Any, Dict, List, Optional
|
|
30
|
+
from typing import Any, Dict, List, Optional
|
|
39
31
|
import json
|
|
40
|
-
import
|
|
32
|
+
import httpx
|
|
41
33
|
|
|
42
34
|
|
|
43
35
|
class ShipthisAPIError(Exception):
|
|
@@ -63,7 +55,7 @@ class ShipthisRequestError(ShipthisAPIError):
|
|
|
63
55
|
|
|
64
56
|
|
|
65
57
|
class ShipthisAPI:
|
|
66
|
-
"""Shipthis API client for public API access.
|
|
58
|
+
"""Async Shipthis API client for public API access.
|
|
67
59
|
|
|
68
60
|
Attributes:
|
|
69
61
|
base_api_endpoint: The base URL for the API.
|
|
@@ -100,7 +92,7 @@ class ShipthisAPI:
|
|
|
100
92
|
location_id: Location ID for requests.
|
|
101
93
|
timeout: Request timeout in seconds (default: 30).
|
|
102
94
|
base_url: Custom base URL (optional, for testing).
|
|
103
|
-
custom_headers: Custom headers that override defaults
|
|
95
|
+
custom_headers: Custom headers that override defaults.
|
|
104
96
|
"""
|
|
105
97
|
if not organisation:
|
|
106
98
|
raise ValueError("organisation is required")
|
|
@@ -154,7 +146,7 @@ class ShipthisAPI:
|
|
|
154
146
|
headers.update(override_headers)
|
|
155
147
|
return headers
|
|
156
148
|
|
|
157
|
-
def _make_request(
|
|
149
|
+
async def _make_request(
|
|
158
150
|
self,
|
|
159
151
|
method: str,
|
|
160
152
|
path: str,
|
|
@@ -162,7 +154,7 @@ class ShipthisAPI:
|
|
|
162
154
|
request_data: Dict[str, Any] = None,
|
|
163
155
|
headers: Dict[str, str] = None,
|
|
164
156
|
) -> Dict[str, Any]:
|
|
165
|
-
"""Make an HTTP request to the API.
|
|
157
|
+
"""Make an async HTTP request to the API.
|
|
166
158
|
|
|
167
159
|
Args:
|
|
168
160
|
method: HTTP method (GET, POST, PUT, PATCH, DELETE).
|
|
@@ -181,39 +173,30 @@ class ShipthisAPI:
|
|
|
181
173
|
url = self.base_api_endpoint + path
|
|
182
174
|
request_headers = self._get_headers(headers)
|
|
183
175
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
response =
|
|
176
|
+
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
|
177
|
+
try:
|
|
178
|
+
response = await client.request(
|
|
187
179
|
method,
|
|
188
180
|
url,
|
|
189
|
-
json=request_data,
|
|
190
181
|
headers=request_headers,
|
|
191
182
|
params=query_params,
|
|
192
|
-
|
|
183
|
+
json=request_data,
|
|
193
184
|
)
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
185
|
+
except httpx.TimeoutException:
|
|
186
|
+
raise ShipthisRequestError(
|
|
187
|
+
message="Request timed out",
|
|
188
|
+
status_code=408,
|
|
189
|
+
)
|
|
190
|
+
except httpx.ConnectError as e:
|
|
191
|
+
raise ShipthisRequestError(
|
|
192
|
+
message=f"Connection error: {str(e)}",
|
|
193
|
+
status_code=0,
|
|
194
|
+
)
|
|
195
|
+
except httpx.RequestError as e:
|
|
196
|
+
raise ShipthisRequestError(
|
|
197
|
+
message=f"Request failed: {str(e)}",
|
|
198
|
+
status_code=0,
|
|
201
199
|
)
|
|
202
|
-
except requests.exceptions.Timeout:
|
|
203
|
-
raise ShipthisRequestError(
|
|
204
|
-
message="Request timed out",
|
|
205
|
-
status_code=408,
|
|
206
|
-
)
|
|
207
|
-
except requests.exceptions.ConnectionError as e:
|
|
208
|
-
raise ShipthisRequestError(
|
|
209
|
-
message=f"Connection error: {str(e)}",
|
|
210
|
-
status_code=0,
|
|
211
|
-
)
|
|
212
|
-
except requests.exceptions.RequestException as e:
|
|
213
|
-
raise ShipthisRequestError(
|
|
214
|
-
message=f"Request failed: {str(e)}",
|
|
215
|
-
status_code=0,
|
|
216
|
-
)
|
|
217
200
|
|
|
218
201
|
# Handle authentication errors
|
|
219
202
|
if response.status_code == 401:
|
|
@@ -261,7 +244,7 @@ class ShipthisAPI:
|
|
|
261
244
|
|
|
262
245
|
# ==================== Connection ====================
|
|
263
246
|
|
|
264
|
-
def connect(self) -> Dict[str, Any]:
|
|
247
|
+
async def connect(self) -> Dict[str, Any]:
|
|
265
248
|
"""Connect and validate the API connection.
|
|
266
249
|
|
|
267
250
|
Fetches organisation info and validates region/location.
|
|
@@ -273,7 +256,7 @@ class ShipthisAPI:
|
|
|
273
256
|
Raises:
|
|
274
257
|
ShipthisAPIError: If connection fails.
|
|
275
258
|
"""
|
|
276
|
-
info = self.info()
|
|
259
|
+
info = await self.info()
|
|
277
260
|
self.organisation_info = info.get("organisation")
|
|
278
261
|
|
|
279
262
|
if not self.region_id or not self.location_id:
|
|
@@ -299,7 +282,7 @@ class ShipthisAPI:
|
|
|
299
282
|
|
|
300
283
|
# ==================== Info ====================
|
|
301
284
|
|
|
302
|
-
def info(self) -> Dict[str, Any]:
|
|
285
|
+
async def info(self) -> Dict[str, Any]:
|
|
303
286
|
"""Get organisation and user info.
|
|
304
287
|
|
|
305
288
|
Returns:
|
|
@@ -308,11 +291,11 @@ class ShipthisAPI:
|
|
|
308
291
|
Raises:
|
|
309
292
|
ShipthisAPIError: If the request fails.
|
|
310
293
|
"""
|
|
311
|
-
return self._make_request("GET", "user-auth/info")
|
|
294
|
+
return await self._make_request("GET", "user-auth/info")
|
|
312
295
|
|
|
313
296
|
# ==================== Collection CRUD ====================
|
|
314
297
|
|
|
315
|
-
def get_one_item(
|
|
298
|
+
async def get_one_item(
|
|
316
299
|
self,
|
|
317
300
|
collection_name: str,
|
|
318
301
|
doc_id: str = None,
|
|
@@ -338,19 +321,19 @@ class ShipthisAPI:
|
|
|
338
321
|
params = {}
|
|
339
322
|
if only_fields:
|
|
340
323
|
params["only"] = only_fields
|
|
341
|
-
return self._make_request("GET", path, query_params=params if params else None)
|
|
324
|
+
return await self._make_request("GET", path, query_params=params if params else None)
|
|
342
325
|
else:
|
|
343
326
|
params = {}
|
|
344
327
|
if filters:
|
|
345
328
|
params["query_filter_v2"] = json.dumps(filters)
|
|
346
329
|
if only_fields:
|
|
347
330
|
params["only"] = only_fields
|
|
348
|
-
resp = self._make_request("GET", f"incollection/{collection_name}", params)
|
|
331
|
+
resp = await self._make_request("GET", f"incollection/{collection_name}", params)
|
|
349
332
|
if isinstance(resp, dict) and resp.get("items"):
|
|
350
333
|
return resp.get("items")[0]
|
|
351
334
|
return None
|
|
352
335
|
|
|
353
|
-
def get_list(
|
|
336
|
+
async def get_list(
|
|
354
337
|
self,
|
|
355
338
|
collection_name: str,
|
|
356
339
|
filters: Dict[str, Any] = None,
|
|
@@ -395,13 +378,13 @@ class ShipthisAPI:
|
|
|
395
378
|
if not meta:
|
|
396
379
|
params["meta"] = "false"
|
|
397
380
|
|
|
398
|
-
response = self._make_request("GET", f"incollection/{collection_name}", params)
|
|
381
|
+
response = await self._make_request("GET", f"incollection/{collection_name}", params)
|
|
399
382
|
|
|
400
383
|
if isinstance(response, dict):
|
|
401
384
|
return response.get("items", [])
|
|
402
385
|
return []
|
|
403
386
|
|
|
404
|
-
def search(
|
|
387
|
+
async def search(
|
|
405
388
|
self,
|
|
406
389
|
collection_name: str,
|
|
407
390
|
query: str,
|
|
@@ -424,7 +407,7 @@ class ShipthisAPI:
|
|
|
424
407
|
Raises:
|
|
425
408
|
ShipthisAPIError: If the request fails.
|
|
426
409
|
"""
|
|
427
|
-
return self.get_list(
|
|
410
|
+
return await self.get_list(
|
|
428
411
|
collection_name,
|
|
429
412
|
search_query=query,
|
|
430
413
|
page=page,
|
|
@@ -432,7 +415,7 @@ class ShipthisAPI:
|
|
|
432
415
|
only_fields=only_fields,
|
|
433
416
|
)
|
|
434
417
|
|
|
435
|
-
def create_item(
|
|
418
|
+
async def create_item(
|
|
436
419
|
self, collection_name: str, data: Dict[str, Any]
|
|
437
420
|
) -> Dict[str, Any]:
|
|
438
421
|
"""Create a new item in a collection.
|
|
@@ -447,7 +430,7 @@ class ShipthisAPI:
|
|
|
447
430
|
Raises:
|
|
448
431
|
ShipthisAPIError: If the request fails.
|
|
449
432
|
"""
|
|
450
|
-
resp = self._make_request(
|
|
433
|
+
resp = await self._make_request(
|
|
451
434
|
"POST",
|
|
452
435
|
f"incollection/{collection_name}",
|
|
453
436
|
request_data={"reqbody": data},
|
|
@@ -456,7 +439,7 @@ class ShipthisAPI:
|
|
|
456
439
|
return resp.get("data")
|
|
457
440
|
return resp
|
|
458
441
|
|
|
459
|
-
def update_item(
|
|
442
|
+
async def update_item(
|
|
460
443
|
self,
|
|
461
444
|
collection_name: str,
|
|
462
445
|
object_id: str,
|
|
@@ -475,7 +458,7 @@ class ShipthisAPI:
|
|
|
475
458
|
Raises:
|
|
476
459
|
ShipthisAPIError: If the request fails.
|
|
477
460
|
"""
|
|
478
|
-
resp = self._make_request(
|
|
461
|
+
resp = await self._make_request(
|
|
479
462
|
"PUT",
|
|
480
463
|
f"incollection/{collection_name}/{object_id}",
|
|
481
464
|
request_data={"reqbody": updated_data},
|
|
@@ -484,7 +467,7 @@ class ShipthisAPI:
|
|
|
484
467
|
return resp.get("data")
|
|
485
468
|
return resp
|
|
486
469
|
|
|
487
|
-
def patch_item(
|
|
470
|
+
async def patch_item(
|
|
488
471
|
self,
|
|
489
472
|
collection_name: str,
|
|
490
473
|
object_id: str,
|
|
@@ -492,24 +475,34 @@ class ShipthisAPI:
|
|
|
492
475
|
) -> Dict[str, Any]:
|
|
493
476
|
"""Patch specific fields of an item.
|
|
494
477
|
|
|
478
|
+
This is the recommended way to update document fields. It goes through
|
|
479
|
+
full field validation, workflow triggers, audit logging, and business logic.
|
|
480
|
+
|
|
495
481
|
Args:
|
|
496
|
-
collection_name: Name of the collection.
|
|
482
|
+
collection_name: Name of the collection (e.g., "sea_shipment", "fcl_load").
|
|
497
483
|
object_id: Document ID.
|
|
498
|
-
update_fields:
|
|
484
|
+
update_fields: Dictionary of field_id to value mappings.
|
|
499
485
|
|
|
500
486
|
Returns:
|
|
501
487
|
Updated document data.
|
|
502
488
|
|
|
503
489
|
Raises:
|
|
504
490
|
ShipthisAPIError: If the request fails.
|
|
491
|
+
|
|
492
|
+
Example:
|
|
493
|
+
await client.patch_item(
|
|
494
|
+
"fcl_load",
|
|
495
|
+
"68a4f906743189ad061429a7",
|
|
496
|
+
update_fields={"container_no": "CONT123", "seal_no": "SEAL456"}
|
|
497
|
+
)
|
|
505
498
|
"""
|
|
506
|
-
return self._make_request(
|
|
499
|
+
return await self._make_request(
|
|
507
500
|
"PATCH",
|
|
508
501
|
f"incollection/{collection_name}/{object_id}",
|
|
509
502
|
request_data={"update_fields": update_fields},
|
|
510
503
|
)
|
|
511
504
|
|
|
512
|
-
def delete_item(self, collection_name: str, object_id: str) -> Dict[str, Any]:
|
|
505
|
+
async def delete_item(self, collection_name: str, object_id: str) -> Dict[str, Any]:
|
|
513
506
|
"""Delete an item.
|
|
514
507
|
|
|
515
508
|
Args:
|
|
@@ -522,14 +515,14 @@ class ShipthisAPI:
|
|
|
522
515
|
Raises:
|
|
523
516
|
ShipthisAPIError: If the request fails.
|
|
524
517
|
"""
|
|
525
|
-
return self._make_request(
|
|
518
|
+
return await self._make_request(
|
|
526
519
|
"DELETE",
|
|
527
520
|
f"incollection/{collection_name}/{object_id}",
|
|
528
521
|
)
|
|
529
522
|
|
|
530
523
|
# ==================== Workflow Operations ====================
|
|
531
524
|
|
|
532
|
-
def get_job_status(
|
|
525
|
+
async def get_job_status(
|
|
533
526
|
self, collection_name: str, object_id: str
|
|
534
527
|
) -> Dict[str, Any]:
|
|
535
528
|
"""Get the job status for a document.
|
|
@@ -544,12 +537,12 @@ class ShipthisAPI:
|
|
|
544
537
|
Raises:
|
|
545
538
|
ShipthisAPIError: If the request fails.
|
|
546
539
|
"""
|
|
547
|
-
return self._make_request(
|
|
540
|
+
return await self._make_request(
|
|
548
541
|
"GET",
|
|
549
542
|
f"workflow/{collection_name}/job_status/{object_id}",
|
|
550
543
|
)
|
|
551
544
|
|
|
552
|
-
def set_job_status(
|
|
545
|
+
async def set_job_status(
|
|
553
546
|
self,
|
|
554
547
|
collection_name: str,
|
|
555
548
|
object_id: str,
|
|
@@ -568,13 +561,13 @@ class ShipthisAPI:
|
|
|
568
561
|
Raises:
|
|
569
562
|
ShipthisAPIError: If the request fails.
|
|
570
563
|
"""
|
|
571
|
-
return self._make_request(
|
|
564
|
+
return await self._make_request(
|
|
572
565
|
"POST",
|
|
573
566
|
f"workflow/{collection_name}/job_status/{object_id}",
|
|
574
567
|
request_data={"action_index": action_index},
|
|
575
568
|
)
|
|
576
569
|
|
|
577
|
-
def get_workflow(self, object_id: str) -> Dict[str, Any]:
|
|
570
|
+
async def get_workflow(self, object_id: str) -> Dict[str, Any]:
|
|
578
571
|
"""Get a workflow configuration.
|
|
579
572
|
|
|
580
573
|
Args:
|
|
@@ -586,11 +579,11 @@ class ShipthisAPI:
|
|
|
586
579
|
Raises:
|
|
587
580
|
ShipthisAPIError: If the request fails.
|
|
588
581
|
"""
|
|
589
|
-
return self._make_request("GET", f"incollection/workflow/{object_id}")
|
|
582
|
+
return await self._make_request("GET", f"incollection/workflow/{object_id}")
|
|
590
583
|
|
|
591
584
|
# ==================== Reports ====================
|
|
592
585
|
|
|
593
|
-
def get_report_view(
|
|
586
|
+
async def get_report_view(
|
|
594
587
|
self,
|
|
595
588
|
report_name: str,
|
|
596
589
|
start_date: str,
|
|
@@ -624,7 +617,7 @@ class ShipthisAPI:
|
|
|
624
617
|
if self.location_id:
|
|
625
618
|
params["location"] = self.location_id
|
|
626
619
|
|
|
627
|
-
return self._make_request(
|
|
620
|
+
return await self._make_request(
|
|
628
621
|
"POST",
|
|
629
622
|
f"report-view/{report_name}",
|
|
630
623
|
query_params=params,
|
|
@@ -633,7 +626,7 @@ class ShipthisAPI:
|
|
|
633
626
|
|
|
634
627
|
# ==================== Third-party Services ====================
|
|
635
628
|
|
|
636
|
-
def get_exchange_rate(
|
|
629
|
+
async def get_exchange_rate(
|
|
637
630
|
self,
|
|
638
631
|
source_currency: str,
|
|
639
632
|
target_currency: str = "USD",
|
|
@@ -656,12 +649,12 @@ class ShipthisAPI:
|
|
|
656
649
|
if date is None:
|
|
657
650
|
date = int(time.time() * 1000)
|
|
658
651
|
|
|
659
|
-
return self._make_request(
|
|
652
|
+
return await self._make_request(
|
|
660
653
|
"GET",
|
|
661
654
|
f"thirdparty/currency?source={source_currency}&target={target_currency}&date={date}",
|
|
662
655
|
)
|
|
663
656
|
|
|
664
|
-
def autocomplete(
|
|
657
|
+
async def autocomplete(
|
|
665
658
|
self,
|
|
666
659
|
reference_name: str,
|
|
667
660
|
data: Dict[str, Any],
|
|
@@ -682,14 +675,14 @@ class ShipthisAPI:
|
|
|
682
675
|
if self.location_id:
|
|
683
676
|
params["location"] = self.location_id
|
|
684
677
|
|
|
685
|
-
return self._make_request(
|
|
678
|
+
return await self._make_request(
|
|
686
679
|
"POST",
|
|
687
680
|
f"autocomplete-reference/{reference_name}",
|
|
688
681
|
query_params=params if params else None,
|
|
689
682
|
request_data=data,
|
|
690
683
|
)
|
|
691
684
|
|
|
692
|
-
def search_location(self, query: str) -> List[Dict[str, Any]]:
|
|
685
|
+
async def search_location(self, query: str) -> List[Dict[str, Any]]:
|
|
693
686
|
"""Search for locations using Google Places.
|
|
694
687
|
|
|
695
688
|
Args:
|
|
@@ -701,12 +694,12 @@ class ShipthisAPI:
|
|
|
701
694
|
Raises:
|
|
702
695
|
ShipthisAPIError: If the request fails.
|
|
703
696
|
"""
|
|
704
|
-
return self._make_request(
|
|
697
|
+
return await self._make_request(
|
|
705
698
|
"GET",
|
|
706
699
|
f"thirdparty/search-place-autocomplete?query={query}",
|
|
707
700
|
)
|
|
708
701
|
|
|
709
|
-
def get_place_details(
|
|
702
|
+
async def get_place_details(
|
|
710
703
|
self,
|
|
711
704
|
place_id: str,
|
|
712
705
|
description: str = "",
|
|
@@ -723,14 +716,14 @@ class ShipthisAPI:
|
|
|
723
716
|
Raises:
|
|
724
717
|
ShipthisAPIError: If the request fails.
|
|
725
718
|
"""
|
|
726
|
-
return self._make_request(
|
|
719
|
+
return await self._make_request(
|
|
727
720
|
"GET",
|
|
728
721
|
f"thirdparty/select-google-place?query={place_id}&description={description}",
|
|
729
722
|
)
|
|
730
723
|
|
|
731
724
|
# ==================== Conversations ====================
|
|
732
725
|
|
|
733
|
-
def create_conversation(
|
|
726
|
+
async def create_conversation(
|
|
734
727
|
self,
|
|
735
728
|
view_name: str,
|
|
736
729
|
document_id: str,
|
|
@@ -755,9 +748,9 @@ class ShipthisAPI:
|
|
|
755
748
|
"view_name": view_name,
|
|
756
749
|
"message_type": conversation_data.get("type", ""),
|
|
757
750
|
}
|
|
758
|
-
return self._make_request("POST", "conversation", request_data=payload)
|
|
751
|
+
return await self._make_request("POST", "conversation", request_data=payload)
|
|
759
752
|
|
|
760
|
-
def get_conversations(
|
|
753
|
+
async def get_conversations(
|
|
761
754
|
self,
|
|
762
755
|
view_name: str,
|
|
763
756
|
document_id: str,
|
|
@@ -788,11 +781,11 @@ class ShipthisAPI:
|
|
|
788
781
|
"message_type": message_type,
|
|
789
782
|
"version": "2",
|
|
790
783
|
}
|
|
791
|
-
return self._make_request("GET", "conversation", query_params=params)
|
|
784
|
+
return await self._make_request("GET", "conversation", query_params=params)
|
|
792
785
|
|
|
793
786
|
# ==================== Bulk Operations ====================
|
|
794
787
|
|
|
795
|
-
def bulk_edit(
|
|
788
|
+
async def bulk_edit(
|
|
796
789
|
self,
|
|
797
790
|
collection_name: str,
|
|
798
791
|
ids: List[str],
|
|
@@ -814,7 +807,7 @@ class ShipthisAPI:
|
|
|
814
807
|
ShipthisAPIError: If the request fails.
|
|
815
808
|
|
|
816
809
|
Example:
|
|
817
|
-
client.bulk_edit(
|
|
810
|
+
await client.bulk_edit(
|
|
818
811
|
"customer",
|
|
819
812
|
ids=["5fdc00487f7636c97b9fa064", "608fe19fc33215427867f34e"],
|
|
820
813
|
update_data={"company.fax_no": "12323231", "address.state": "California"}
|
|
@@ -829,7 +822,7 @@ class ShipthisAPI:
|
|
|
829
822
|
if external_update_data:
|
|
830
823
|
payload["data"]["external_update_data"] = external_update_data
|
|
831
824
|
|
|
832
|
-
return self._make_request(
|
|
825
|
+
return await self._make_request(
|
|
833
826
|
"POST",
|
|
834
827
|
f"incollection_group_edit/{collection_name}",
|
|
835
828
|
request_data=payload,
|
|
@@ -837,7 +830,7 @@ class ShipthisAPI:
|
|
|
837
830
|
|
|
838
831
|
# ==================== Workflow Actions ====================
|
|
839
832
|
|
|
840
|
-
def primary_workflow_action(
|
|
833
|
+
async def primary_workflow_action(
|
|
841
834
|
self,
|
|
842
835
|
collection: str,
|
|
843
836
|
workflow_id: str,
|
|
@@ -863,7 +856,7 @@ class ShipthisAPI:
|
|
|
863
856
|
ShipthisAPIError: If the request fails.
|
|
864
857
|
|
|
865
858
|
Example:
|
|
866
|
-
client.primary_workflow_action(
|
|
859
|
+
await client.primary_workflow_action(
|
|
867
860
|
collection="pickup_delivery",
|
|
868
861
|
workflow_id="job_status",
|
|
869
862
|
object_id="68a4f906743189ad061429a7",
|
|
@@ -879,13 +872,13 @@ class ShipthisAPI:
|
|
|
879
872
|
if start_state_id:
|
|
880
873
|
payload["start_state_id"] = start_state_id
|
|
881
874
|
|
|
882
|
-
return self._make_request(
|
|
875
|
+
return await self._make_request(
|
|
883
876
|
"POST",
|
|
884
877
|
f"workflow/{collection}/{workflow_id}/{object_id}",
|
|
885
878
|
request_data=payload,
|
|
886
879
|
)
|
|
887
880
|
|
|
888
|
-
def secondary_workflow_action(
|
|
881
|
+
async def secondary_workflow_action(
|
|
889
882
|
self,
|
|
890
883
|
collection: str,
|
|
891
884
|
workflow_id: str,
|
|
@@ -909,7 +902,7 @@ class ShipthisAPI:
|
|
|
909
902
|
ShipthisAPIError: If the request fails.
|
|
910
903
|
|
|
911
904
|
Example:
|
|
912
|
-
client.secondary_workflow_action(
|
|
905
|
+
await client.secondary_workflow_action(
|
|
913
906
|
collection="pickup_delivery",
|
|
914
907
|
workflow_id="driver_status",
|
|
915
908
|
object_id="67ed10859b7cf551a19f813e",
|
|
@@ -918,7 +911,7 @@ class ShipthisAPI:
|
|
|
918
911
|
"""
|
|
919
912
|
payload = additional_data or {}
|
|
920
913
|
|
|
921
|
-
return self._make_request(
|
|
914
|
+
return await self._make_request(
|
|
922
915
|
"POST",
|
|
923
916
|
f"workflow/{collection}/{workflow_id}/{object_id}/{target_state}",
|
|
924
917
|
request_data=payload,
|
|
@@ -926,7 +919,7 @@ class ShipthisAPI:
|
|
|
926
919
|
|
|
927
920
|
# ==================== File Upload ====================
|
|
928
921
|
|
|
929
|
-
def upload_file(
|
|
922
|
+
async def upload_file(
|
|
930
923
|
self,
|
|
931
924
|
file_path: str,
|
|
932
925
|
file_name: str = None,
|
|
@@ -959,18 +952,18 @@ class ShipthisAPI:
|
|
|
959
952
|
try:
|
|
960
953
|
with open(file_path, "rb") as f:
|
|
961
954
|
files = {"file": (file_name, f)}
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
955
|
+
async with httpx.AsyncClient(timeout=self.timeout * 2) as client:
|
|
956
|
+
response = await client.post(
|
|
957
|
+
upload_url,
|
|
958
|
+
headers=headers,
|
|
959
|
+
files=files,
|
|
960
|
+
)
|
|
968
961
|
except FileNotFoundError:
|
|
969
962
|
raise ShipthisRequestError(
|
|
970
963
|
message=f"File not found: {file_path}",
|
|
971
964
|
status_code=0,
|
|
972
965
|
)
|
|
973
|
-
except
|
|
966
|
+
except httpx.RequestError as e:
|
|
974
967
|
raise ShipthisRequestError(
|
|
975
968
|
message=f"Upload failed: {str(e)}",
|
|
976
969
|
status_code=0,
|
|
@@ -987,77 +980,9 @@ class ShipthisAPI:
|
|
|
987
980
|
status_code=response.status_code,
|
|
988
981
|
)
|
|
989
982
|
|
|
990
|
-
# ==================== Webhook Operations ====================
|
|
991
|
-
|
|
992
|
-
def webhook_sync(
|
|
993
|
-
self,
|
|
994
|
-
view_name: str,
|
|
995
|
-
doc_id: str,
|
|
996
|
-
fields: List[Dict[str, Any]],
|
|
997
|
-
) -> Dict[str, Any]:
|
|
998
|
-
"""Update document via webhook-sync (synchronous update).
|
|
999
|
-
|
|
1000
|
-
Args:
|
|
1001
|
-
view_name: View/collection name (e.g., "sea_shipment", "fcl_load").
|
|
1002
|
-
doc_id: Document ID.
|
|
1003
|
-
fields: List of field dicts to update.
|
|
1004
|
-
|
|
1005
|
-
Returns:
|
|
1006
|
-
API response with success status and data.
|
|
1007
|
-
|
|
1008
|
-
Raises:
|
|
1009
|
-
ShipthisAPIError: If the request fails.
|
|
1010
|
-
|
|
1011
|
-
Example:
|
|
1012
|
-
client.webhook_sync(
|
|
1013
|
-
"fcl_load",
|
|
1014
|
-
"68a4f906743189ad061429a7",
|
|
1015
|
-
fields=[{"container_no": "CONT123"}, {"seal_no": "SEAL456"}]
|
|
1016
|
-
)
|
|
1017
|
-
"""
|
|
1018
|
-
payload = {"fields": fields}
|
|
1019
|
-
return self._make_request(
|
|
1020
|
-
"PUT",
|
|
1021
|
-
f"webhook-sync/{self.organisation_id}/{view_name}/{doc_id}",
|
|
1022
|
-
request_data=payload,
|
|
1023
|
-
)
|
|
1024
|
-
|
|
1025
|
-
def webhook_update(
|
|
1026
|
-
self,
|
|
1027
|
-
view_name: str,
|
|
1028
|
-
doc_id: str,
|
|
1029
|
-
actions: List[Dict[str, Any]],
|
|
1030
|
-
) -> Dict[str, Any]:
|
|
1031
|
-
"""Update document via webhook (async update with actions).
|
|
1032
|
-
|
|
1033
|
-
Args:
|
|
1034
|
-
view_name: View/collection name.
|
|
1035
|
-
doc_id: Document ID.
|
|
1036
|
-
actions: List of action dicts to execute.
|
|
1037
|
-
|
|
1038
|
-
Returns:
|
|
1039
|
-
API response with success status and data.
|
|
1040
|
-
|
|
1041
|
-
Raises:
|
|
1042
|
-
ShipthisAPIError: If the request fails.
|
|
1043
|
-
|
|
1044
|
-
Example:
|
|
1045
|
-
client.webhook_update(
|
|
1046
|
-
"sea_shipment",
|
|
1047
|
-
"68a4f906743189ad061429a7",
|
|
1048
|
-
actions=[{"action": "update_status", "value": "completed"}]
|
|
1049
|
-
)
|
|
1050
|
-
"""
|
|
1051
|
-
payload = {"actions": actions}
|
|
1052
|
-
return self._make_request(
|
|
1053
|
-
"PUT",
|
|
1054
|
-
f"webhook/{self.organisation_id}/{view_name}/{doc_id}",
|
|
1055
|
-
request_data=payload,
|
|
1056
|
-
)
|
|
1057
|
-
|
|
1058
983
|
# ==================== Reference Linked Fields ====================
|
|
1059
984
|
|
|
1060
|
-
def create_reference_linked_field(
|
|
985
|
+
async def create_reference_linked_field(
|
|
1061
986
|
self,
|
|
1062
987
|
collection_name: str,
|
|
1063
988
|
doc_id: str,
|
|
@@ -1077,14 +1002,14 @@ class ShipthisAPI:
|
|
|
1077
1002
|
ShipthisAPIError: If the request fails.
|
|
1078
1003
|
|
|
1079
1004
|
Example:
|
|
1080
|
-
client.create_reference_linked_field(
|
|
1005
|
+
await client.create_reference_linked_field(
|
|
1081
1006
|
"sea_shipment",
|
|
1082
1007
|
"68a4f906743189ad061429a7",
|
|
1083
1008
|
payload={"field_name": "containers", "data": {...}}
|
|
1084
1009
|
)
|
|
1085
1010
|
"""
|
|
1086
|
-
return self._make_request(
|
|
1011
|
+
return await self._make_request(
|
|
1087
1012
|
"POST",
|
|
1088
1013
|
f"incollection/create-reference-linked-field/{collection_name}/{doc_id}",
|
|
1089
1014
|
request_data=payload,
|
|
1090
|
-
)
|
|
1015
|
+
)
|
|
@@ -5,15 +5,18 @@ with open("README.md", "r") as fh:
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
setuptools.setup(
|
|
8
|
-
name='shipthisapi-python',
|
|
9
|
-
version='
|
|
8
|
+
name='shipthisapi-python',
|
|
9
|
+
version='3.0.0',
|
|
10
10
|
author="Mayur Rawte",
|
|
11
11
|
author_email="mayur@shipthis.co",
|
|
12
|
-
description="ShipthisAPI utility package",
|
|
12
|
+
description="ShipthisAPI async utility package",
|
|
13
13
|
long_description=long_description,
|
|
14
14
|
long_description_content_type="text/markdown",
|
|
15
15
|
url="https://github.com/shipthisco/shipthisapi-python",
|
|
16
16
|
packages=setuptools.find_packages(),
|
|
17
|
+
install_requires=[
|
|
18
|
+
"httpx>=0.24.0",
|
|
19
|
+
],
|
|
17
20
|
classifiers=[
|
|
18
21
|
"Programming Language :: Python :: 3",
|
|
19
22
|
"License :: OSI Approved :: MIT License",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: shipthisapi-python
|
|
3
|
-
Version:
|
|
4
|
-
Summary: ShipthisAPI utility package
|
|
3
|
+
Version: 3.0.0
|
|
4
|
+
Summary: ShipthisAPI async utility package
|
|
5
5
|
Home-page: https://github.com/shipthisco/shipthisapi-python
|
|
6
6
|
Author: Mayur Rawte
|
|
7
7
|
Author-email: mayur@shipthis.co
|
|
@@ -9,12 +9,14 @@ Classifier: Programming Language :: Python :: 3
|
|
|
9
9
|
Classifier: License :: OSI Approved :: MIT License
|
|
10
10
|
Classifier: Operating System :: OS Independent
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
|
+
Requires-Dist: httpx>=0.24.0
|
|
12
13
|
Dynamic: author
|
|
13
14
|
Dynamic: author-email
|
|
14
15
|
Dynamic: classifier
|
|
15
16
|
Dynamic: description
|
|
16
17
|
Dynamic: description-content-type
|
|
17
18
|
Dynamic: home-page
|
|
19
|
+
Dynamic: requires-dist
|
|
18
20
|
Dynamic: summary
|
|
19
21
|
|
|
20
22
|
# ShipthisAPI Python
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
httpx>=0.24.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{shipthisapi_python-2.2.0 → shipthisapi_python-3.0.0}/shipthisapi_python.egg-info/top_level.txt
RENAMED
|
File without changes
|