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.
Files changed (68) hide show
  1. karrio_cli/__init__.py +0 -0
  2. karrio_cli/__main__.py +105 -0
  3. karrio_cli/ai/README.md +335 -0
  4. karrio_cli/ai/__init__.py +0 -0
  5. karrio_cli/ai/commands.py +102 -0
  6. karrio_cli/ai/karrio_ai/__init__.py +1 -0
  7. karrio_cli/ai/karrio_ai/agent.py +972 -0
  8. karrio_cli/ai/karrio_ai/architecture/INTEGRATION_AGENT_PROMPT.md +497 -0
  9. karrio_cli/ai/karrio_ai/architecture/MAPPING_AGENT_PROMPT.md +355 -0
  10. karrio_cli/ai/karrio_ai/architecture/REAL_WORLD_TESTING.md +305 -0
  11. karrio_cli/ai/karrio_ai/architecture/SCHEMA_AGENT_PROMPT.md +183 -0
  12. karrio_cli/ai/karrio_ai/architecture/TESTING_AGENT_PROMPT.md +448 -0
  13. karrio_cli/ai/karrio_ai/architecture/TESTING_GUIDE.md +271 -0
  14. karrio_cli/ai/karrio_ai/enhanced_tools.py +943 -0
  15. karrio_cli/ai/karrio_ai/rag_system.py +503 -0
  16. karrio_cli/ai/karrio_ai/tests/test_agent.py +350 -0
  17. karrio_cli/ai/karrio_ai/tests/test_real_integration.py +360 -0
  18. karrio_cli/ai/karrio_ai/tests/test_real_world_scenarios.py +513 -0
  19. karrio_cli/commands/__init__.py +0 -0
  20. karrio_cli/commands/codegen.py +336 -0
  21. karrio_cli/commands/login.py +139 -0
  22. karrio_cli/commands/plugins.py +168 -0
  23. karrio_cli/commands/sdk.py +870 -0
  24. karrio_cli/common/queries.py +101 -0
  25. karrio_cli/common/utils.py +368 -0
  26. karrio_cli/resources/__init__.py +0 -0
  27. karrio_cli/resources/carriers.py +91 -0
  28. karrio_cli/resources/connections.py +207 -0
  29. karrio_cli/resources/events.py +151 -0
  30. karrio_cli/resources/logs.py +151 -0
  31. karrio_cli/resources/orders.py +144 -0
  32. karrio_cli/resources/shipments.py +210 -0
  33. karrio_cli/resources/trackers.py +287 -0
  34. karrio_cli/templates/__init__.py +9 -0
  35. karrio_cli/templates/__pycache__/__init__.cpython-311.pyc +0 -0
  36. karrio_cli/templates/__pycache__/__init__.cpython-312.pyc +0 -0
  37. karrio_cli/templates/__pycache__/address.cpython-311.pyc +0 -0
  38. karrio_cli/templates/__pycache__/address.cpython-312.pyc +0 -0
  39. karrio_cli/templates/__pycache__/docs.cpython-311.pyc +0 -0
  40. karrio_cli/templates/__pycache__/docs.cpython-312.pyc +0 -0
  41. karrio_cli/templates/__pycache__/documents.cpython-311.pyc +0 -0
  42. karrio_cli/templates/__pycache__/documents.cpython-312.pyc +0 -0
  43. karrio_cli/templates/__pycache__/manifest.cpython-311.pyc +0 -0
  44. karrio_cli/templates/__pycache__/manifest.cpython-312.pyc +0 -0
  45. karrio_cli/templates/__pycache__/pickup.cpython-311.pyc +0 -0
  46. karrio_cli/templates/__pycache__/pickup.cpython-312.pyc +0 -0
  47. karrio_cli/templates/__pycache__/rates.cpython-311.pyc +0 -0
  48. karrio_cli/templates/__pycache__/rates.cpython-312.pyc +0 -0
  49. karrio_cli/templates/__pycache__/sdk.cpython-311.pyc +0 -0
  50. karrio_cli/templates/__pycache__/sdk.cpython-312.pyc +0 -0
  51. karrio_cli/templates/__pycache__/shipments.cpython-311.pyc +0 -0
  52. karrio_cli/templates/__pycache__/shipments.cpython-312.pyc +0 -0
  53. karrio_cli/templates/__pycache__/tracking.cpython-311.pyc +0 -0
  54. karrio_cli/templates/__pycache__/tracking.cpython-312.pyc +0 -0
  55. karrio_cli/templates/address.py +308 -0
  56. karrio_cli/templates/docs.py +150 -0
  57. karrio_cli/templates/documents.py +428 -0
  58. karrio_cli/templates/manifest.py +396 -0
  59. karrio_cli/templates/pickup.py +839 -0
  60. karrio_cli/templates/rates.py +638 -0
  61. karrio_cli/templates/sdk.py +947 -0
  62. karrio_cli/templates/shipments.py +892 -0
  63. karrio_cli/templates/tracking.py +437 -0
  64. karrio_cli-2025.5rc3.dist-info/METADATA +165 -0
  65. karrio_cli-2025.5rc3.dist-info/RECORD +68 -0
  66. karrio_cli-2025.5rc3.dist-info/WHEEL +5 -0
  67. karrio_cli-2025.5rc3.dist-info/entry_points.txt +2 -0
  68. 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,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ kcli = karrio_cli.__main__:app
@@ -0,0 +1 @@
1
+ karrio_cli