karrio-cli 2025.5rc3__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.
- karrio_cli/__init__.py +0 -0
- karrio_cli/__main__.py +105 -0
- karrio_cli/ai/README.md +335 -0
- karrio_cli/ai/__init__.py +0 -0
- karrio_cli/ai/commands.py +102 -0
- karrio_cli/ai/karrio_ai/__init__.py +1 -0
- karrio_cli/ai/karrio_ai/agent.py +972 -0
- karrio_cli/ai/karrio_ai/architecture/INTEGRATION_AGENT_PROMPT.md +497 -0
- karrio_cli/ai/karrio_ai/architecture/MAPPING_AGENT_PROMPT.md +355 -0
- karrio_cli/ai/karrio_ai/architecture/REAL_WORLD_TESTING.md +305 -0
- karrio_cli/ai/karrio_ai/architecture/SCHEMA_AGENT_PROMPT.md +183 -0
- karrio_cli/ai/karrio_ai/architecture/TESTING_AGENT_PROMPT.md +448 -0
- karrio_cli/ai/karrio_ai/architecture/TESTING_GUIDE.md +271 -0
- karrio_cli/ai/karrio_ai/enhanced_tools.py +943 -0
- karrio_cli/ai/karrio_ai/rag_system.py +503 -0
- karrio_cli/ai/karrio_ai/tests/test_agent.py +350 -0
- karrio_cli/ai/karrio_ai/tests/test_real_integration.py +360 -0
- karrio_cli/ai/karrio_ai/tests/test_real_world_scenarios.py +513 -0
- karrio_cli/commands/__init__.py +0 -0
- karrio_cli/commands/codegen.py +336 -0
- karrio_cli/commands/login.py +139 -0
- karrio_cli/commands/plugins.py +168 -0
- karrio_cli/commands/sdk.py +870 -0
- karrio_cli/common/queries.py +101 -0
- karrio_cli/common/utils.py +368 -0
- karrio_cli/resources/__init__.py +0 -0
- karrio_cli/resources/carriers.py +91 -0
- karrio_cli/resources/connections.py +207 -0
- karrio_cli/resources/events.py +151 -0
- karrio_cli/resources/logs.py +151 -0
- karrio_cli/resources/orders.py +144 -0
- karrio_cli/resources/shipments.py +210 -0
- karrio_cli/resources/trackers.py +287 -0
- karrio_cli/templates/__init__.py +9 -0
- karrio_cli/templates/__pycache__/__init__.cpython-311.pyc +0 -0
- karrio_cli/templates/__pycache__/__init__.cpython-312.pyc +0 -0
- karrio_cli/templates/__pycache__/address.cpython-311.pyc +0 -0
- karrio_cli/templates/__pycache__/address.cpython-312.pyc +0 -0
- karrio_cli/templates/__pycache__/docs.cpython-311.pyc +0 -0
- karrio_cli/templates/__pycache__/docs.cpython-312.pyc +0 -0
- karrio_cli/templates/__pycache__/documents.cpython-311.pyc +0 -0
- karrio_cli/templates/__pycache__/documents.cpython-312.pyc +0 -0
- karrio_cli/templates/__pycache__/manifest.cpython-311.pyc +0 -0
- karrio_cli/templates/__pycache__/manifest.cpython-312.pyc +0 -0
- karrio_cli/templates/__pycache__/pickup.cpython-311.pyc +0 -0
- karrio_cli/templates/__pycache__/pickup.cpython-312.pyc +0 -0
- karrio_cli/templates/__pycache__/rates.cpython-311.pyc +0 -0
- karrio_cli/templates/__pycache__/rates.cpython-312.pyc +0 -0
- karrio_cli/templates/__pycache__/sdk.cpython-311.pyc +0 -0
- karrio_cli/templates/__pycache__/sdk.cpython-312.pyc +0 -0
- karrio_cli/templates/__pycache__/shipments.cpython-311.pyc +0 -0
- karrio_cli/templates/__pycache__/shipments.cpython-312.pyc +0 -0
- karrio_cli/templates/__pycache__/tracking.cpython-311.pyc +0 -0
- karrio_cli/templates/__pycache__/tracking.cpython-312.pyc +0 -0
- karrio_cli/templates/address.py +308 -0
- karrio_cli/templates/docs.py +150 -0
- karrio_cli/templates/documents.py +428 -0
- karrio_cli/templates/manifest.py +396 -0
- karrio_cli/templates/pickup.py +839 -0
- karrio_cli/templates/rates.py +638 -0
- karrio_cli/templates/sdk.py +947 -0
- karrio_cli/templates/shipments.py +892 -0
- karrio_cli/templates/tracking.py +437 -0
- karrio_cli-2025.5rc3.dist-info/METADATA +165 -0
- karrio_cli-2025.5rc3.dist-info/RECORD +68 -0
- karrio_cli-2025.5rc3.dist-info/WHEEL +5 -0
- karrio_cli-2025.5rc3.dist-info/entry_points.txt +2 -0
- karrio_cli-2025.5rc3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,437 @@
|
|
1
|
+
from jinja2 import Template
|
2
|
+
|
3
|
+
PROVIDER_TRACKING_TEMPLATE = Template('''"""Karrio {{name}} tracking API implementation."""
|
4
|
+
|
5
|
+
# IMPLEMENTATION INSTRUCTIONS:
|
6
|
+
# 1. Uncomment the imports when the schema types are generated
|
7
|
+
# 2. Import the specific request and response types you need
|
8
|
+
# 3. Create a request instance with the appropriate request type
|
9
|
+
# 4. Extract tracking details and events from the response to populate TrackingDetails
|
10
|
+
#
|
11
|
+
# NOTE: JSON schema types are generated with "Type" suffix (e.g., TrackingRequestType),
|
12
|
+
# while XML schema types don't have this suffix (e.g., TrackingRequest).
|
13
|
+
|
14
|
+
import karrio.schemas.{{id}}.tracking_request as {{id}}_req
|
15
|
+
import karrio.schemas.{{id}}.tracking_response as {{id}}_res
|
16
|
+
|
17
|
+
import typing
|
18
|
+
import karrio.lib as lib
|
19
|
+
import karrio.core.units as units
|
20
|
+
import karrio.core.models as models
|
21
|
+
import karrio.providers.{{id}}.error as error
|
22
|
+
import karrio.providers.{{id}}.utils as provider_utils
|
23
|
+
import karrio.providers.{{id}}.units as provider_units
|
24
|
+
|
25
|
+
|
26
|
+
def parse_tracking_response(
|
27
|
+
_response: lib.Deserializable[typing.List[typing.Tuple[str, {% if is_xml_api %}lib.Element{% else %}dict{% endif %}]]],
|
28
|
+
settings: provider_utils.Settings,
|
29
|
+
) -> typing.Tuple[typing.List[models.TrackingDetails], typing.List[models.Message]]:
|
30
|
+
responses = _response.deserialize()
|
31
|
+
|
32
|
+
messages: typing.List[models.Message] = sum(
|
33
|
+
[
|
34
|
+
error.parse_error_response(response, settings, tracking_number=tracking_number)
|
35
|
+
for tracking_number, response in responses
|
36
|
+
],
|
37
|
+
start=[],
|
38
|
+
)
|
39
|
+
|
40
|
+
tracking_details = [
|
41
|
+
_extract_details(details, settings, tracking_number)
|
42
|
+
for tracking_number, details in responses
|
43
|
+
]
|
44
|
+
|
45
|
+
return tracking_details, messages
|
46
|
+
|
47
|
+
|
48
|
+
def _extract_details(
|
49
|
+
data: {% if is_xml_api %}lib.Element{% else %}dict{% endif %},
|
50
|
+
settings: provider_utils.Settings,
|
51
|
+
tracking_number: str = None,
|
52
|
+
) -> models.TrackingDetails:
|
53
|
+
"""
|
54
|
+
Extract tracking details from carrier response data
|
55
|
+
|
56
|
+
data: The carrier-specific tracking data structure
|
57
|
+
settings: The carrier connection settings
|
58
|
+
tracking_number: The tracking number being tracked
|
59
|
+
|
60
|
+
Returns a TrackingDetails object with extracted tracking information
|
61
|
+
"""
|
62
|
+
# Convert the carrier data to a proper object for easy attribute access
|
63
|
+
{% if is_xml_api %}
|
64
|
+
# For XML APIs, convert Element to proper response object
|
65
|
+
tracking_details = lib.to_object({{id}}_res.TrackingDetails, data)
|
66
|
+
|
67
|
+
# Extract tracking status and information
|
68
|
+
status_code = tracking_details.status_code if hasattr(tracking_details, 'status_code') else ""
|
69
|
+
status_detail = tracking_details.status_description if hasattr(tracking_details, 'status_description') else ""
|
70
|
+
est_delivery = tracking_details.estimated_delivery_date if hasattr(tracking_details, 'estimated_delivery_date') else None
|
71
|
+
|
72
|
+
# Extract events
|
73
|
+
events = []
|
74
|
+
if hasattr(tracking_details, 'events') and tracking_details.events:
|
75
|
+
for event in tracking_details.events.event:
|
76
|
+
events.append({
|
77
|
+
"date": event.date if hasattr(event, 'date') else "",
|
78
|
+
"time": event.time if hasattr(event, 'time') else "",
|
79
|
+
"code": event.code if hasattr(event, 'code') else "",
|
80
|
+
"description": event.description if hasattr(event, 'description') else "",
|
81
|
+
"location": event.location if hasattr(event, 'location') else ""
|
82
|
+
})
|
83
|
+
{% else %}
|
84
|
+
# For JSON APIs, convert dict to proper response object
|
85
|
+
tracking_details = lib.to_object({{id}}_res.TrackingResponseType, data)
|
86
|
+
|
87
|
+
# Extract tracking status and information
|
88
|
+
status_code = tracking_details.statusCode if hasattr(tracking_details, 'statusCode') else ""
|
89
|
+
status_detail = tracking_details.statusDescription if hasattr(tracking_details, 'statusDescription') else ""
|
90
|
+
est_delivery = tracking_details.estimatedDeliveryDate if hasattr(tracking_details, 'estimatedDeliveryDate') else None
|
91
|
+
|
92
|
+
# Extract events
|
93
|
+
events = []
|
94
|
+
if hasattr(tracking_details, 'events') and tracking_details.events:
|
95
|
+
for event in tracking_details.events:
|
96
|
+
events.append({
|
97
|
+
"date": event.date if hasattr(event, 'date') else "",
|
98
|
+
"time": event.time if hasattr(event, 'time') else "",
|
99
|
+
"code": event.code if hasattr(event, 'code') else "",
|
100
|
+
"description": event.description if hasattr(event, 'description') else "",
|
101
|
+
"location": event.location if hasattr(event, 'location') else ""
|
102
|
+
})
|
103
|
+
{% endif %}
|
104
|
+
|
105
|
+
# Map carrier status to karrio standard tracking status
|
106
|
+
status = next(
|
107
|
+
(
|
108
|
+
status.name
|
109
|
+
for status in list(provider_units.TrackingStatus)
|
110
|
+
if status_code in status.value
|
111
|
+
),
|
112
|
+
provider_units.TrackingStatus.in_transit.name,
|
113
|
+
)
|
114
|
+
|
115
|
+
return models.TrackingDetails(
|
116
|
+
carrier_id=settings.carrier_id,
|
117
|
+
carrier_name=settings.carrier_name,
|
118
|
+
tracking_number=tracking_number,
|
119
|
+
events=[
|
120
|
+
models.TrackingEvent(
|
121
|
+
date=lib.fdate(event["date"]),
|
122
|
+
description=event["description"],
|
123
|
+
code=event["code"],
|
124
|
+
time=lib.flocaltime(event["time"]),
|
125
|
+
location=event["location"],
|
126
|
+
)
|
127
|
+
for event in events
|
128
|
+
],
|
129
|
+
estimated_delivery=lib.fdate(est_delivery) if est_delivery else None,
|
130
|
+
delivered=status == "delivered",
|
131
|
+
status=status,
|
132
|
+
)
|
133
|
+
|
134
|
+
|
135
|
+
def tracking_request(
|
136
|
+
payload: models.TrackingRequest,
|
137
|
+
settings: provider_utils.Settings,
|
138
|
+
) -> lib.Serializable:
|
139
|
+
"""
|
140
|
+
Create a tracking request for the carrier API
|
141
|
+
|
142
|
+
payload: The standardized TrackingRequest from karrio
|
143
|
+
settings: The carrier connection settings
|
144
|
+
|
145
|
+
Returns a Serializable object that can be sent to the carrier API
|
146
|
+
"""
|
147
|
+
# Extract the tracking number(s) from payload
|
148
|
+
tracking_numbers = payload.tracking_numbers
|
149
|
+
reference = payload.reference
|
150
|
+
|
151
|
+
{% if is_xml_api %}
|
152
|
+
# For XML API request
|
153
|
+
request = {{id}}_req.TrackingRequest(
|
154
|
+
tracking_numbers=tracking_numbers,
|
155
|
+
# Add required tracking request details
|
156
|
+
reference=reference,
|
157
|
+
language=payload.language_code or "en",
|
158
|
+
# Add account credentials
|
159
|
+
account_number=settings.account_number,
|
160
|
+
)
|
161
|
+
{% else %}
|
162
|
+
# For JSON API request
|
163
|
+
request = {{id}}_req.TrackingRequestType(
|
164
|
+
trackingInfo={
|
165
|
+
"trackingNumbers": tracking_numbers,
|
166
|
+
"reference": reference,
|
167
|
+
"language": payload.language_code or "en",
|
168
|
+
},
|
169
|
+
# Add account credentials
|
170
|
+
accountNumber=settings.account_number,
|
171
|
+
)
|
172
|
+
{% endif %}
|
173
|
+
|
174
|
+
return lib.Serializable(request, {% if is_xml_api %}lib.to_xml{% else %}lib.to_dict{% endif %})
|
175
|
+
|
176
|
+
'''
|
177
|
+
)
|
178
|
+
|
179
|
+
TEST_TRACKING_TEMPLATE = Template('''"""{{name}} carrier tracking tests."""
|
180
|
+
|
181
|
+
import unittest
|
182
|
+
from unittest.mock import patch, ANY
|
183
|
+
from .fixture import gateway
|
184
|
+
|
185
|
+
import karrio.sdk as karrio
|
186
|
+
import karrio.lib as lib
|
187
|
+
import karrio.core.models as models
|
188
|
+
|
189
|
+
|
190
|
+
class Test{{compact_name}}Tracking(unittest.TestCase):
|
191
|
+
def setUp(self):
|
192
|
+
self.maxDiff = None
|
193
|
+
self.TrackingRequest = models.TrackingRequest(**TrackingPayload)
|
194
|
+
|
195
|
+
def test_create_tracking_request(self):
|
196
|
+
request = gateway.mapper.create_tracking_request(self.TrackingRequest)
|
197
|
+
self.assertEqual(lib.to_dict(request.serialize()), TrackingRequest)
|
198
|
+
|
199
|
+
def test_get_tracking(self):
|
200
|
+
with patch("karrio.mappers.{{id}}.proxy.lib.request") as mock:
|
201
|
+
mock.return_value = {% if is_xml_api %}"<r></r>"{% else %}"{}"{% endif %}
|
202
|
+
karrio.Tracking.fetch(self.TrackingRequest).from_(gateway)
|
203
|
+
self.assertEqual(
|
204
|
+
mock.call_args[1]["url"],
|
205
|
+
f"{gateway.settings.server_url}/tracking"
|
206
|
+
)
|
207
|
+
|
208
|
+
def test_parse_tracking_response(self):
|
209
|
+
with patch("karrio.mappers.{{id}}.proxy.lib.request") as mock:
|
210
|
+
mock.return_value = TrackingResponse
|
211
|
+
parsed_response = (
|
212
|
+
karrio.Tracking.fetch(self.TrackingRequest).from_(gateway).parse()
|
213
|
+
)
|
214
|
+
self.assertListEqual(lib.to_dict(parsed_response), ParsedTrackingResponse)
|
215
|
+
|
216
|
+
def test_parse_error_response(self):
|
217
|
+
with patch("karrio.mappers.{{id}}.proxy.lib.request") as mock:
|
218
|
+
mock.return_value = ErrorResponse
|
219
|
+
parsed_response = (
|
220
|
+
karrio.Tracking.fetch(self.TrackingRequest).from_(gateway).parse()
|
221
|
+
)
|
222
|
+
self.assertListEqual(lib.to_dict(parsed_response), ParsedErrorResponse)
|
223
|
+
|
224
|
+
|
225
|
+
if __name__ == "__main__":
|
226
|
+
unittest.main()
|
227
|
+
|
228
|
+
|
229
|
+
TrackingPayload = {
|
230
|
+
"tracking_numbers": ["TRACK123"],
|
231
|
+
"reference": "ORDER123"
|
232
|
+
}
|
233
|
+
|
234
|
+
TrackingRequest = {% if is_xml_api %}{
|
235
|
+
"tracking_numbers": [
|
236
|
+
"TRACK123"
|
237
|
+
],
|
238
|
+
"reference": "ORDER123"
|
239
|
+
}{% else %}{
|
240
|
+
"trackingNumbers": [
|
241
|
+
"TRACK123"
|
242
|
+
],
|
243
|
+
"reference": "ORDER123"
|
244
|
+
}{% endif %}
|
245
|
+
|
246
|
+
TrackingResponse = {% if is_xml_api %}"""<?xml version="1.0"?>
|
247
|
+
<tracking-response>
|
248
|
+
<tracking-info>
|
249
|
+
<tracking-number>TRACK123</tracking-number>
|
250
|
+
<status>in_transit</status>
|
251
|
+
<status-details>Package is in transit</status-details>
|
252
|
+
<estimated-delivery>2024-04-15</estimated-delivery>
|
253
|
+
<events>
|
254
|
+
<event>
|
255
|
+
<date>2024-04-12</date>
|
256
|
+
<time>14:30:00</time>
|
257
|
+
<code>PU</code>
|
258
|
+
<description>Package picked up</description>
|
259
|
+
<location>San Francisco, CA</location>
|
260
|
+
</event>
|
261
|
+
</events>
|
262
|
+
</tracking-info>
|
263
|
+
</tracking-response>"""{% else %}"""{
|
264
|
+
"trackingInfo": [
|
265
|
+
{
|
266
|
+
"trackingNumber": "TRACK123",
|
267
|
+
"status": "in_transit",
|
268
|
+
"statusDetails": "Package is in transit",
|
269
|
+
"estimatedDelivery": "2024-04-15",
|
270
|
+
"events": [
|
271
|
+
{
|
272
|
+
"date": "2024-04-12",
|
273
|
+
"time": "14:30:00",
|
274
|
+
"code": "PU",
|
275
|
+
"description": "Package picked up",
|
276
|
+
"location": "San Francisco, CA"
|
277
|
+
}
|
278
|
+
]
|
279
|
+
}
|
280
|
+
]
|
281
|
+
}"""{% endif %}
|
282
|
+
|
283
|
+
ErrorResponse = {% if is_xml_api %}"""<?xml version="1.0"?>
|
284
|
+
<error-response>
|
285
|
+
<e>
|
286
|
+
<code>tracking_error</code>
|
287
|
+
<message>Unable to track shipment</message>
|
288
|
+
<details>Invalid tracking number</details>
|
289
|
+
</e>
|
290
|
+
</error-response>"""{% else %}"""{
|
291
|
+
"error": {
|
292
|
+
"code": "tracking_error",
|
293
|
+
"message": "Unable to track shipment",
|
294
|
+
"details": "Invalid tracking number"
|
295
|
+
}
|
296
|
+
}"""{% endif %}
|
297
|
+
|
298
|
+
ParsedTrackingResponse = [
|
299
|
+
[
|
300
|
+
{
|
301
|
+
"carrier_id": "{{id}}",
|
302
|
+
"carrier_name": "{{id}}",
|
303
|
+
"tracking_number": "TRACK123",
|
304
|
+
"events": [
|
305
|
+
{
|
306
|
+
"date": "2024-04-12",
|
307
|
+
"time": "14:30:00",
|
308
|
+
"code": "PU",
|
309
|
+
"description": "Package picked up",
|
310
|
+
"location": "San Francisco, CA"
|
311
|
+
}
|
312
|
+
],
|
313
|
+
"estimated_delivery": "2024-04-15",
|
314
|
+
"status": "in_transit"
|
315
|
+
}
|
316
|
+
],
|
317
|
+
[]
|
318
|
+
]
|
319
|
+
|
320
|
+
ParsedErrorResponse = [
|
321
|
+
[],
|
322
|
+
[
|
323
|
+
{
|
324
|
+
"carrier_id": "{{id}}",
|
325
|
+
"carrier_name": "{{id}}",
|
326
|
+
"code": "tracking_error",
|
327
|
+
"message": "Unable to track shipment",
|
328
|
+
"details": {
|
329
|
+
"details": "Invalid tracking number"
|
330
|
+
}
|
331
|
+
}
|
332
|
+
]
|
333
|
+
]'''
|
334
|
+
)
|
335
|
+
|
336
|
+
XML_SCHEMA_TRACKING_REQUEST_TEMPLATE = Template("""<?xml version="1.0"?>
|
337
|
+
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://{{id}}.com/ws/tracking" xmlns="http://{{id}}.com/ws/tracking" elementFormDefault="qualified">
|
338
|
+
<xsd:element name="tracking-request">
|
339
|
+
<xsd:complexType>
|
340
|
+
<xsd:all>
|
341
|
+
<xsd:element name="tracking-numbers">
|
342
|
+
<xsd:complexType>
|
343
|
+
<xsd:sequence>
|
344
|
+
<xsd:element name="tracking-number" type="xsd:string" maxOccurs="unbounded" />
|
345
|
+
</xsd:sequence>
|
346
|
+
</xsd:complexType>
|
347
|
+
</xsd:element>
|
348
|
+
<xsd:element name="language-code" type="xsd:string" minOccurs="0" />
|
349
|
+
<xsd:element name="reference" type="xsd:string" minOccurs="0" />
|
350
|
+
</xsd:all>
|
351
|
+
</xsd:complexType>
|
352
|
+
</xsd:element>
|
353
|
+
</xsd:schema>
|
354
|
+
""")
|
355
|
+
|
356
|
+
XML_SCHEMA_TRACKING_RESPONSE_TEMPLATE = Template("""<?xml version="1.0"?>
|
357
|
+
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://{{id}}.com/ws/tracking" xmlns="http://{{id}}.com/ws/tracking" elementFormDefault="qualified">
|
358
|
+
<xsd:element name="tracking-response">
|
359
|
+
<xsd:complexType>
|
360
|
+
<xsd:sequence>
|
361
|
+
<xsd:element name="tracking-info" maxOccurs="unbounded">
|
362
|
+
<xsd:complexType>
|
363
|
+
<xsd:all>
|
364
|
+
<xsd:element name="tracking-number" type="xsd:string" />
|
365
|
+
<xsd:element name="status" type="xsd:string" />
|
366
|
+
<xsd:element name="status-details" type="xsd:string" minOccurs="0" />
|
367
|
+
<xsd:element name="estimated-delivery" type="xsd:date" minOccurs="0" />
|
368
|
+
<xsd:element name="events">
|
369
|
+
<xsd:complexType>
|
370
|
+
<xsd:sequence>
|
371
|
+
<xsd:element name="event" maxOccurs="unbounded">
|
372
|
+
<xsd:complexType>
|
373
|
+
<xsd:all>
|
374
|
+
<xsd:element name="date" type="xsd:date" />
|
375
|
+
<xsd:element name="time" type="xsd:time" />
|
376
|
+
<xsd:element name="code" type="xsd:string" />
|
377
|
+
<xsd:element name="description" type="xsd:string" />
|
378
|
+
<xsd:element name="location" type="xsd:string" minOccurs="0" />
|
379
|
+
</xsd:all>
|
380
|
+
</xsd:complexType>
|
381
|
+
</xsd:element>
|
382
|
+
</xsd:sequence>
|
383
|
+
</xsd:complexType>
|
384
|
+
</xsd:element>
|
385
|
+
</xsd:all>
|
386
|
+
</xsd:complexType>
|
387
|
+
</xsd:element>
|
388
|
+
</xsd:sequence>
|
389
|
+
</xsd:complexType>
|
390
|
+
</xsd:element>
|
391
|
+
</xsd:schema>
|
392
|
+
""")
|
393
|
+
|
394
|
+
JSON_SCHEMA_TRACKING_REQUEST_TEMPLATE = Template(
|
395
|
+
"""{
|
396
|
+
"trackingRequest": {
|
397
|
+
"trackingNumbers": [
|
398
|
+
"1Z999999999999999"
|
399
|
+
],
|
400
|
+
"languageCode": "en",
|
401
|
+
"reference": "ORDER123"
|
402
|
+
}
|
403
|
+
}
|
404
|
+
"""
|
405
|
+
)
|
406
|
+
|
407
|
+
JSON_SCHEMA_TRACKING_RESPONSE_TEMPLATE = Template(
|
408
|
+
"""{
|
409
|
+
"trackingResponse": {
|
410
|
+
"trackingInfo": [
|
411
|
+
{
|
412
|
+
"trackingNumber": "1Z999999999999999",
|
413
|
+
"status": "in_transit",
|
414
|
+
"statusDetails": "Package is in transit",
|
415
|
+
"estimatedDelivery": "2024-04-15",
|
416
|
+
"events": [
|
417
|
+
{
|
418
|
+
"date": "2024-04-12",
|
419
|
+
"time": "14:30:00",
|
420
|
+
"code": "PU",
|
421
|
+
"description": "Package picked up",
|
422
|
+
"location": "San Francisco, CA"
|
423
|
+
},
|
424
|
+
{
|
425
|
+
"date": "2024-04-13",
|
426
|
+
"time": "09:15:00",
|
427
|
+
"code": "IT",
|
428
|
+
"description": "In transit",
|
429
|
+
"location": "Los Angeles, CA"
|
430
|
+
}
|
431
|
+
]
|
432
|
+
}
|
433
|
+
]
|
434
|
+
}
|
435
|
+
}
|
436
|
+
"""
|
437
|
+
)
|
@@ -0,0 +1,165 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: karrio-cli
|
3
|
+
Version: 2025.5rc3
|
4
|
+
Summary: Command line interface for Karrio
|
5
|
+
Author-email: Karrio Team <hello@karrio.io>
|
6
|
+
License: MIT
|
7
|
+
Project-URL: Homepage, https://github.com/karrioapi/karrio
|
8
|
+
Project-URL: Bug Tracker, https://github.com/karrioapi/karrio/issues
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
12
|
+
Classifier: Operating System :: OS Independent
|
13
|
+
Requires-Python: >=3.11
|
14
|
+
Description-Content-Type: text/markdown
|
15
|
+
Requires-Dist: typer>=0.7.0
|
16
|
+
Requires-Dist: rich>=13.0.0
|
17
|
+
Requires-Dist: requests>=2.28.0
|
18
|
+
Requires-Dist: importlib-metadata>=4.12.0
|
19
|
+
Requires-Dist: jstruct>=0.1.0
|
20
|
+
Requires-Dist: generateDS
|
21
|
+
Requires-Dist: tabulate
|
22
|
+
Requires-Dist: Jinja2
|
23
|
+
Provides-Extra: dev
|
24
|
+
Requires-Dist: google-adk; extra == "dev"
|
25
|
+
Requires-Dist: python-dotenv; extra == "dev"
|
26
|
+
Requires-Dist: karrio; extra == "dev"
|
27
|
+
Requires-Dist: beautifulsoup4; extra == "dev"
|
28
|
+
Requires-Dist: pdfplumber; extra == "dev"
|
29
|
+
|
30
|
+
# Karrio CLI Tools
|
31
|
+
|
32
|
+
This folder contains CLI tools for the Karrio project.
|
33
|
+
|
34
|
+
## Codegen
|
35
|
+
|
36
|
+
The `codegen` command provides utilities for code generation, particularly for transforming JSON schemas into Python code using jstruct.
|
37
|
+
|
38
|
+
### Transform
|
39
|
+
|
40
|
+
The `transform` command converts Python code generated by quicktype (using dataclasses) into code that uses attrs and jstruct decorators.
|
41
|
+
|
42
|
+
```bash
|
43
|
+
# Transform from stdin to stdout
|
44
|
+
cat input.py | karrio codegen transform > output.py
|
45
|
+
|
46
|
+
# Transform from file to file
|
47
|
+
karrio codegen transform input.py output.py
|
48
|
+
|
49
|
+
# Transform from file to stdout
|
50
|
+
karrio codegen transform input.py
|
51
|
+
|
52
|
+
# Disable appending 'Type' to class names
|
53
|
+
karrio codegen transform input.py output.py --no-append-type-suffix
|
54
|
+
```
|
55
|
+
|
56
|
+
The transform command makes the following changes:
|
57
|
+
- Replaces `from dataclasses import dataclass` with explicit imports: `import attr`, `import jstruct`, `import typing`
|
58
|
+
- Removes any `from typing import ...` lines entirely
|
59
|
+
- Replaces `@dataclass` with `@attr.s(auto_attribs=True)`
|
60
|
+
- Appends 'Type' to all class names (unless they already end with 'Type') by default
|
61
|
+
- Replaces complex type annotations with jstruct equivalents
|
62
|
+
- Ensures there are no duplicate import statements
|
63
|
+
|
64
|
+
### Generate
|
65
|
+
|
66
|
+
The `generate` command generates Python code with jstruct from a JSON schema file using quicktype.
|
67
|
+
|
68
|
+
```bash
|
69
|
+
# Generate Python code with jstruct from a JSON schema
|
70
|
+
karrio codegen generate --src=schema.json --out=output.py
|
71
|
+
|
72
|
+
# Specify Python version
|
73
|
+
karrio codegen generate --src=schema.json --out=output.py --python-version=3.8
|
74
|
+
|
75
|
+
# Generate without --just-types
|
76
|
+
karrio codegen generate --src=schema.json --out=output.py --just-types=false
|
77
|
+
|
78
|
+
# Disable appending 'Type' to class names
|
79
|
+
karrio codegen generate --src=schema.json --out=output.py --no-append-type-suffix
|
80
|
+
```
|
81
|
+
|
82
|
+
### Create Tree
|
83
|
+
|
84
|
+
The `create-tree` command generates a Python code tree from a class definition. It's useful for visualizing the structure of complex nested objects and generating initialization code templates.
|
85
|
+
|
86
|
+
```bash
|
87
|
+
# Generate a tree for a class
|
88
|
+
karrio codegen create-tree --module=karrio.schemas.allied_express.label_request --class-name=LabelRequest
|
89
|
+
|
90
|
+
# Generate a tree with a module alias
|
91
|
+
karrio codegen create-tree --module=karrio.schemas.allied_express.label_request --class-name=LabelRequest --module-alias=allied
|
92
|
+
```
|
93
|
+
|
94
|
+
Example output:
|
95
|
+
```python
|
96
|
+
LabelRequestType(
|
97
|
+
bookedBy=None,
|
98
|
+
account=None,
|
99
|
+
instructions=None,
|
100
|
+
itemCount=None,
|
101
|
+
items=[
|
102
|
+
ItemType(
|
103
|
+
dangerous=None,
|
104
|
+
height=None,
|
105
|
+
itemCount=None,
|
106
|
+
length=None,
|
107
|
+
volume=None,
|
108
|
+
weight=None,
|
109
|
+
width=None,
|
110
|
+
)
|
111
|
+
],
|
112
|
+
jobStopsP=JobStopsType(
|
113
|
+
companyName=None,
|
114
|
+
contact=None,
|
115
|
+
emailAddress=None,
|
116
|
+
geographicAddress=GeographicAddressType(
|
117
|
+
address1=None,
|
118
|
+
address2=None,
|
119
|
+
country=None,
|
120
|
+
postCode=None,
|
121
|
+
state=None,
|
122
|
+
suburb=None,
|
123
|
+
),
|
124
|
+
phoneNumber=None,
|
125
|
+
),
|
126
|
+
jobStopsD=JobStopsType(...),
|
127
|
+
referenceNumbers=[],
|
128
|
+
serviceLevel=None,
|
129
|
+
volume=None,
|
130
|
+
weight=None,
|
131
|
+
)
|
132
|
+
```
|
133
|
+
|
134
|
+
## Migrating carrier connector generate scripts
|
135
|
+
|
136
|
+
To migrate carrier connector generate scripts to use the new codegen command, run:
|
137
|
+
|
138
|
+
```bash
|
139
|
+
python karrio/modules/cli/commands/migrate_generate_scripts.py /path/to/karrio/workspace
|
140
|
+
```
|
141
|
+
|
142
|
+
This will update all generate scripts in the carrier connectors to use the new karrio codegen command.
|
143
|
+
|
144
|
+
## JStruct Overview
|
145
|
+
|
146
|
+
JStruct is a Python library for nested object models that offers serialization and deserialization into Python dictionaries. It leverages the `attrs` library to define structs without boilerplate.
|
147
|
+
|
148
|
+
Here's an example of the transformed code:
|
149
|
+
|
150
|
+
```python
|
151
|
+
import attr
|
152
|
+
import jstruct
|
153
|
+
import typing
|
154
|
+
|
155
|
+
@attr.s(auto_attribs=True)
|
156
|
+
class PersonType:
|
157
|
+
first_name: typing.Optional[str] = None
|
158
|
+
last_name: typing.Optional[str] = None
|
159
|
+
|
160
|
+
@attr.s(auto_attribs=True)
|
161
|
+
class RoleModelsType:
|
162
|
+
scientists: typing.Optional[typing.List[PersonType]] = jstruct.JList[PersonType]
|
163
|
+
```
|
164
|
+
|
165
|
+
For more information, see the [JStruct README](https://github.com/karrioapi/jstruct/blob/main/README.md).
|
@@ -0,0 +1,68 @@
|
|
1
|
+
karrio_cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
karrio_cli/__main__.py,sha256=FETIfCIE1dYQHMsGojf22NXOueYYhe6rk4FOOVlYfIA,2045
|
3
|
+
karrio_cli/ai/README.md,sha256=amGxCCI5i7eZJ_4mXTirvmPZzNYa3fsFz3PhEHjc-4E,9751
|
4
|
+
karrio_cli/ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
+
karrio_cli/ai/commands.py,sha256=03YybqKVIZrlWa2LEfHecYnNvTOS3X1sQK4m951pacA,4061
|
6
|
+
karrio_cli/ai/karrio_ai/__init__.py,sha256=sQ2PmxLy-XcGjFgm14YyBUtEmIrZdDmHJmtypdOTnwI,28
|
7
|
+
karrio_cli/ai/karrio_ai/agent.py,sha256=LRSoSYvNHhEBzBPr3HTyeVU5c8kz6htz5lcOugHBcyc,37382
|
8
|
+
karrio_cli/ai/karrio_ai/enhanced_tools.py,sha256=zyk-rbR2b_c5GZh6komusmsYQddW6ksbuljYGPPfzkg,34779
|
9
|
+
karrio_cli/ai/karrio_ai/rag_system.py,sha256=ciD1AMiioBKDZg8w-_5keg3GKF17fyv0QNFPMMLDP3Q,19290
|
10
|
+
karrio_cli/ai/karrio_ai/architecture/INTEGRATION_AGENT_PROMPT.md,sha256=5ycvkLU_dbV_t6y2Ztg-OFUE1L9Z8kaKZaYOlfD9wlA,16212
|
11
|
+
karrio_cli/ai/karrio_ai/architecture/MAPPING_AGENT_PROMPT.md,sha256=DVJnEHsAXF1Xybmy90nUMQqlgUHLBqq6AoiYvTUv_es,11874
|
12
|
+
karrio_cli/ai/karrio_ai/architecture/REAL_WORLD_TESTING.md,sha256=SUV2i9l44lkQZyyCbAR6mRJnvRknIb6AHUMph0kfTYM,8387
|
13
|
+
karrio_cli/ai/karrio_ai/architecture/SCHEMA_AGENT_PROMPT.md,sha256=00_pupReY7gyRtn5eNdJNiN4-pmkbKnyJV8ayEQFq2g,5944
|
14
|
+
karrio_cli/ai/karrio_ai/architecture/TESTING_AGENT_PROMPT.md,sha256=O6VRBnfwi9kPUBBaDA-MqvoIbUKNO-JkKPymnP_UwjQ,15576
|
15
|
+
karrio_cli/ai/karrio_ai/architecture/TESTING_GUIDE.md,sha256=EuOTktH2N2zD3sB1S4VN7Wtfhoh4kBUmSQkkTCZJG6Q,7433
|
16
|
+
karrio_cli/ai/karrio_ai/tests/test_agent.py,sha256=RUEVQzbDJL9Yn-Gwz9BpCyTkpdNBFO2LWH9GPn1VFHA,11280
|
17
|
+
karrio_cli/ai/karrio_ai/tests/test_real_integration.py,sha256=UgjA2HAIYKNLEapKOPd5KDbqeyzzKoH_9jUSTzukl2c,14980
|
18
|
+
karrio_cli/ai/karrio_ai/tests/test_real_world_scenarios.py,sha256=RqtphbsiWRqLs-D5K_7UXvTGno5NEWelKwUEKuSv3rU,16135
|
19
|
+
karrio_cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
20
|
+
karrio_cli/commands/codegen.py,sha256=nFGpdUSYc9XMYc2oRV_nCP-7uPMgYnlRCOSdr05Kxu8,13908
|
21
|
+
karrio_cli/commands/login.py,sha256=Osxc93T8Fqea6YjLHZiGVK9mtMNBziqDyj1BEPpS2Uo,4143
|
22
|
+
karrio_cli/commands/plugins.py,sha256=7qWmSUWGfiy_8IorE5PjJk7QptWx9oMlo1amQqw_mWg,4802
|
23
|
+
karrio_cli/commands/sdk.py,sha256=rGEbn2akRqapjFUsduIMF4QwpwRk0VOoJM3GZpYdgUA,36856
|
24
|
+
karrio_cli/common/queries.py,sha256=eydEiU-9XoCRES25ZMEKCVWrtHuplTc3NtwBf1AMGy8,1652
|
25
|
+
karrio_cli/common/utils.py,sha256=h5B-Nzgqn2yqsfv1OUXyr0gjC6sv0QvrXQCJiplgdOo,10097
|
26
|
+
karrio_cli/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
27
|
+
karrio_cli/resources/carriers.py,sha256=ig1lnG_YzOtdf6pPMKrwka9ILuYXuDSLSQBM4J1sN5I,2517
|
28
|
+
karrio_cli/resources/connections.py,sha256=LFHsHXybZUfjpgfcu-5ikRQ7odPH4SR1TxhZknItS6g,6218
|
29
|
+
karrio_cli/resources/events.py,sha256=0nNlqnkmK05BZtENAMT6pOhg8yfAz2cYMbMllbKp71Q,4126
|
30
|
+
karrio_cli/resources/logs.py,sha256=w0q1MLW6DRWnkW6Us6OD3tDM-EDJXpFAKmChfArZGcY,3975
|
31
|
+
karrio_cli/resources/orders.py,sha256=WPyOUODhya-YfYr7mnJu4rZfSERsBj_t3j60AyWmNvw,4116
|
32
|
+
karrio_cli/resources/shipments.py,sha256=0sxP9IJzZoiW7qrBJ-Y4_j5ao1FU7s0vRHsj0PgE0R8,6428
|
33
|
+
karrio_cli/resources/trackers.py,sha256=fOiYShoELE8JD_pCGZrUn05kQCepzKvNmRgpUFdY4ao,7865
|
34
|
+
karrio_cli/templates/__init__.py,sha256=B1VuFlcYHlm7JYwYNAdDgSOuESP38fcFEK6gLN67ZQQ,383
|
35
|
+
karrio_cli/templates/address.py,sha256=D_br9H4OlSsaysjNb_nyEhH75V_YW4BdqKm5rqZRKqY,10667
|
36
|
+
karrio_cli/templates/docs.py,sha256=hYDZYAqJ1WXUtsMR1tX7Xs92DDoTWkcbv4RNJQaHH2I,2868
|
37
|
+
karrio_cli/templates/documents.py,sha256=8vJ-87zV2liCEkY9JOm_xW87hswTje51sZh_DgXooi8,14841
|
38
|
+
karrio_cli/templates/manifest.py,sha256=LKTNhCEufH-YLmqpsS8ByQp69KcKbp1fE5pknuPXYzo,14955
|
39
|
+
karrio_cli/templates/pickup.py,sha256=a2hYFcWwOFpZvXhgKBWOkB41pISa4EO97UUVwWGIucg,29365
|
40
|
+
karrio_cli/templates/rates.py,sha256=Aqje1UGrC-wJJeqqCCYIaTnmk3kXfyh_c8UAb1ZrhlU,22692
|
41
|
+
karrio_cli/templates/sdk.py,sha256=J8Bzpsc3uV-H6RdYesSQhzbBMEH6JYJAGzqSppkfzOE,38867
|
42
|
+
karrio_cli/templates/shipments.py,sha256=lXYR1t9Wc5TDZN5gNv7JQyjwrTJlggRJ3LibAyYW4uw,31308
|
43
|
+
karrio_cli/templates/tracking.py,sha256=E-hUiZTm5l5Nk9P4OGJz26CNprnbXC9LPeWRXYD7ygk,15512
|
44
|
+
karrio_cli/templates/__pycache__/__init__.cpython-311.pyc,sha256=qDu4BM3tNouqUngswf5rwXknzPl0C9eCELid1ZSrSLY,585
|
45
|
+
karrio_cli/templates/__pycache__/__init__.cpython-312.pyc,sha256=Cc_Oi4hNogcxkBgllpDd8f4eCs9VjU1RPcadf_VxrWo,574
|
46
|
+
karrio_cli/templates/__pycache__/address.cpython-311.pyc,sha256=FUdcVQPF5zi05wZL5LzBmloLxDS83-1lhgXHK4jV2dc,11076
|
47
|
+
karrio_cli/templates/__pycache__/address.cpython-312.pyc,sha256=q7QVt5B1wLOSZ-5-bJPymn346FIvY1R-TXrlsV96JSE,10979
|
48
|
+
karrio_cli/templates/__pycache__/docs.cpython-311.pyc,sha256=Lf1PdvaizHuts0PZZIfpI7azJwhh40Lo-G-7OsNF6Hw,3329
|
49
|
+
karrio_cli/templates/__pycache__/docs.cpython-312.pyc,sha256=y38X9lS_78Xm1Ueq1LPwicxMCHQE-4Cn2_Tebs-j1JE,3187
|
50
|
+
karrio_cli/templates/__pycache__/documents.cpython-311.pyc,sha256=gRjmeggtXNSYnZuqfdymH744zgfMSg-6F5E4yg1EYXY,15104
|
51
|
+
karrio_cli/templates/__pycache__/documents.cpython-312.pyc,sha256=_n1nuiM43CrVlnl7f72AAaUmc7mIFSk-WPUl3841SX0,14994
|
52
|
+
karrio_cli/templates/__pycache__/manifest.cpython-311.pyc,sha256=S9DMV4YTRRmGVIM5mCN1zkyeqNWaBku2VmnBtI5JYfc,15246
|
53
|
+
karrio_cli/templates/__pycache__/manifest.cpython-312.pyc,sha256=rh7abl1kDEKBcgGZktPJrBs5r3vHADe0jNxBxaI9q2o,15149
|
54
|
+
karrio_cli/templates/__pycache__/pickup.cpython-311.pyc,sha256=EafXZ1Mkwts362DpWhcN0dx57DLHtG_Ix47o4kJ-I2o,29992
|
55
|
+
karrio_cli/templates/__pycache__/pickup.cpython-312.pyc,sha256=_yw-DdiAxRdRHkdHIKqhvattQM2s0zJzNXW8DF5vC_g,29750
|
56
|
+
karrio_cli/templates/__pycache__/rates.cpython-311.pyc,sha256=HH1cvL-MNcgy8wHbXDOUF8G3isE-Ny8aClO58r9Nlew,23096
|
57
|
+
karrio_cli/templates/__pycache__/rates.cpython-312.pyc,sha256=gteFXtqp2YLte7Gtu3ivg2yRzGS7_Nt6K2JXnD1XU4Y,22998
|
58
|
+
karrio_cli/templates/__pycache__/sdk.cpython-311.pyc,sha256=iQ-IsWKuHqfUMp9Ar7jZUs_WB-Dt445lOMaGS2_J21U,39743
|
59
|
+
karrio_cli/templates/__pycache__/sdk.cpython-312.pyc,sha256=U05K8XTfrNkk5r_mmpFcDpkCss4dwg4IJuECLv74RvU,39434
|
60
|
+
karrio_cli/templates/__pycache__/shipments.cpython-311.pyc,sha256=TYumG54zRooTI-I47CqqdUkbN4EaO-ISSf6qlsB-O2I,31875
|
61
|
+
karrio_cli/templates/__pycache__/shipments.cpython-312.pyc,sha256=EyncH83RK4Nmt7HoBWM559hmz-54JbbVnqOxPmZrsrM,31699
|
62
|
+
karrio_cli/templates/__pycache__/tracking.cpython-311.pyc,sha256=QSznkeLaujXaGtwXrOAcA3REznPPfPgFaMFJ1b-h2RY,15915
|
63
|
+
karrio_cli/templates/__pycache__/tracking.cpython-312.pyc,sha256=xZfs_emE7hMOwvuDvcpLck2ndp_Q0KuCYLy5FUS3tpU,15818
|
64
|
+
karrio_cli-2025.5rc3.dist-info/METADATA,sha256=x50SAbSaBxZewlTlEgJz0wAVywvNoweyO0qkObpR9I4,5189
|
65
|
+
karrio_cli-2025.5rc3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
66
|
+
karrio_cli-2025.5rc3.dist-info/entry_points.txt,sha256=vlt_H7JoPE1KrgdsrLiyHI8c-VB3CKc0r5JG6iWXkeg,49
|
67
|
+
karrio_cli-2025.5rc3.dist-info/top_level.txt,sha256=Qgmy9qnJysxHRBnmw3pMmLtIJPwd3fbQWRugbsyi_C8,11
|
68
|
+
karrio_cli-2025.5rc3.dist-info/RECORD,,
|
@@ -0,0 +1 @@
|
|
1
|
+
karrio_cli
|