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,308 @@
1
+ from jinja2 import Template
2
+
3
+ PROVIDER_ADDRESS_TEMPLATE = Template(
4
+ '''"""Karrio {{name}} address validation API implementation."""
5
+
6
+ # IMPLEMENTATION INSTRUCTIONS:
7
+ # 1. Uncomment the imports when the schema types are generated
8
+ # 2. Import the specific request and response types you need
9
+ # 3. Create a request instance with the appropriate request type
10
+ # 4. Extract address validation details from the response
11
+ #
12
+ # NOTE: JSON schema types are generated with "Type" suffix (e.g., AddressValidationRequestType),
13
+ # while XML schema types don't have this suffix (e.g., AddressValidationRequest).
14
+
15
+ import karrio.schemas.{{id}}.address_validation_request as {{id}}_req
16
+ import karrio.schemas.{{id}}.address_validation_response as {{id}}_res
17
+
18
+ import typing
19
+ import karrio.lib as lib
20
+ import karrio.core.units as units
21
+ import karrio.core.models as models
22
+ import karrio.providers.{{id}}.error as error
23
+ import karrio.providers.{{id}}.utils as provider_utils
24
+ import karrio.providers.{{id}}.units as provider_units
25
+
26
+
27
+ def parse_address_validation_response(
28
+ _response: lib.Deserializable[{% if is_xml_api %}lib.Element{% else %}dict{% endif %}],
29
+ settings: provider_utils.Settings,
30
+ ) -> typing.Tuple[models.AddressValidationDetails, typing.List[models.Message]]:
31
+ response = _response.deserialize()
32
+ messages = error.parse_error_response(response, settings)
33
+
34
+ validation_details = models.AddressValidationDetails(
35
+ carrier_id=settings.carrier_id,
36
+ carrier_name=settings.carrier_name,
37
+ success=True,
38
+ )
39
+
40
+ return validation_details, messages
41
+
42
+
43
+ def address_validation_request(
44
+ payload: models.AddressValidationRequest,
45
+ settings: provider_utils.Settings,
46
+ ) -> lib.Serializable:
47
+ """
48
+ Create an address validation request for the carrier API
49
+
50
+ payload: The standardized AddressValidationRequest from karrio
51
+ settings: The carrier connection settings
52
+
53
+ Returns a Serializable object that can be sent to the carrier API
54
+ """
55
+ # Extract the address from payload
56
+ address = lib.to_address(payload.address)
57
+
58
+ {% if is_xml_api %}
59
+ # For XML API request
60
+ request = {{id}}_req.AddressValidationRequest(
61
+ street=address.address_line1,
62
+ city_name=address.city,
63
+ postcode=address.postal_code,
64
+ country_code=address.country_code,
65
+ province_code=address.state_code,
66
+ )
67
+ {% else %}
68
+ # For JSON API request - Using camelCase attribute names to match schema definition
69
+ request = {{id}}_req.AddressValidationRequestType(
70
+ streetAddress=address.address_line1,
71
+ cityLocality=address.city,
72
+ postalCode=address.postal_code,
73
+ countryCode=address.country_code,
74
+ stateProvince=address.state_code,
75
+ )
76
+ {% endif %}
77
+
78
+ return lib.Serializable(request, {% if is_xml_api %}lib.to_xml{% else %}lib.to_dict{% endif %})
79
+ '''
80
+ )
81
+
82
+ JSON_SCHEMA_ADDRESS_VALIDATION_REQUEST_TEMPLATE = Template('''
83
+ {
84
+ "streetAddress": "123 Main St",
85
+ "cityLocality": "City Name",
86
+ "postalCode": "12345",
87
+ "countryCode": "US",
88
+ "stateProvince": "CA"
89
+ }
90
+ ''')
91
+
92
+ JSON_SCHEMA_ADDRESS_VALIDATION_RESPONSE_TEMPLATE = Template('''
93
+ {
94
+ "isValid": true,
95
+ "normalizedAddress": {
96
+ "streetAddress": "123 Main St",
97
+ "cityLocality": "City Name",
98
+ "postalCode": "12345",
99
+ "countryCode": "US",
100
+ "stateProvince": "CA"
101
+ },
102
+ "validationMessages": [
103
+ {
104
+ "message": "Address is valid",
105
+ "code": "SUCCESS"
106
+ }
107
+ ]
108
+ }
109
+ ''')
110
+
111
+ XML_SCHEMA_ADDRESS_VALIDATION_REQUEST_TEMPLATE = Template('''<?xml version="1.0"?>
112
+ <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://{{id}}.com/ws/address" xmlns="http://{{id}}.com/ws/address" elementFormDefault="qualified">
113
+ <xsd:element name="address-validation-request">
114
+ <xsd:complexType>
115
+ <xsd:sequence>
116
+ <xsd:element name="street" type="xsd:string" />
117
+ <xsd:element name="city_name" type="xsd:string" />
118
+ <xsd:element name="postcode" type="xsd:string" />
119
+ <xsd:element name="country_code" type="xsd:string" />
120
+ <xsd:element name="province_code" type="xsd:string" minOccurs="0" />
121
+ </xsd:sequence>
122
+ </xsd:complexType>
123
+ </xsd:element>
124
+ </xsd:schema>
125
+ ''')
126
+
127
+ XML_SCHEMA_ADDRESS_VALIDATION_RESPONSE_TEMPLATE = Template('''<?xml version="1.0"?>
128
+ <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://{{id}}.com/ws/address" xmlns="http://{{id}}.com/ws/address" elementFormDefault="qualified">
129
+ <xsd:element name="address-validation-response">
130
+ <xsd:complexType>
131
+ <xsd:sequence>
132
+ <xsd:element name="valid_address" type="xsd:string" />
133
+ <xsd:element name="normalized_address" minOccurs="0">
134
+ <xsd:complexType>
135
+ <xsd:sequence>
136
+ <xsd:element name="street" type="xsd:string" />
137
+ <xsd:element name="city_name" type="xsd:string" />
138
+ <xsd:element name="postcode" type="xsd:string" />
139
+ <xsd:element name="country_code" type="xsd:string" />
140
+ <xsd:element name="province_code" type="xsd:string" minOccurs="0" />
141
+ </xsd:sequence>
142
+ </xsd:complexType>
143
+ </xsd:element>
144
+ <xsd:element name="validation_messages" minOccurs="0">
145
+ <xsd:complexType>
146
+ <xsd:sequence>
147
+ <xsd:element name="message" maxOccurs="unbounded">
148
+ <xsd:complexType>
149
+ <xsd:sequence>
150
+ <xsd:element name="text" type="xsd:string" />
151
+ <xsd:element name="code" type="xsd:string" />
152
+ </xsd:sequence>
153
+ </xsd:complexType>
154
+ </xsd:element>
155
+ </xsd:sequence>
156
+ </xsd:complexType>
157
+ </xsd:element>
158
+ </xsd:sequence>
159
+ </xsd:complexType>
160
+ </xsd:element>
161
+ </xsd:schema>
162
+ ''')
163
+
164
+ TEST_ADDRESS_TEMPLATE = Template('''"""{{name}} carrier address validation tests."""
165
+
166
+ import unittest
167
+ from unittest.mock import patch, ANY
168
+ from .fixture import gateway
169
+ import logging
170
+ import karrio.sdk as karrio
171
+ import karrio.lib as lib
172
+ import karrio.core.models as models
173
+
174
+ logger = logging.getLogger(__name__)
175
+
176
+ class Test{{compact_name}}Address(unittest.TestCase):
177
+ def setUp(self):
178
+ self.maxDiff = None
179
+ self.AddressValidationRequest = models.AddressValidationRequest(**AddressValidationPayload)
180
+
181
+ def test_create_address_validation_request(self):
182
+ request = gateway.mapper.create_address_validation_request(self.AddressValidationRequest)
183
+ self.assertEqual(lib.to_dict(request.serialize()), AddressValidationRequest)
184
+
185
+ def test_validate_address(self):
186
+ with patch("karrio.mappers.{{id}}.proxy.lib.request") as mock:
187
+ mock.return_value = {% if is_xml_api %}"<r></r>"{% else %}"{}"{% endif %}
188
+ karrio.Address.validate(self.AddressValidationRequest).from_(gateway)
189
+ self.assertEqual(
190
+ mock.call_args[1]["url"],
191
+ f"{gateway.settings.server_url}/address/validate"
192
+ )
193
+
194
+ def test_parse_address_validation_response(self):
195
+ with patch("karrio.mappers.{{id}}.proxy.lib.request") as mock:
196
+ mock.return_value = AddressValidationResponse
197
+ parsed_response = (
198
+ karrio.Address.validate(self.AddressValidationRequest)
199
+ .from_(gateway)
200
+ .parse()
201
+ )
202
+ self.assertListEqual(lib.to_dict(parsed_response), ParsedAddressValidationResponse)
203
+
204
+ def test_parse_error_response(self):
205
+ with patch("karrio.mappers.{{id}}.proxy.lib.request") as mock:
206
+ mock.return_value = ErrorResponse
207
+ parsed_response = (
208
+ karrio.Address.validate(self.AddressValidationRequest)
209
+ .from_(gateway)
210
+ .parse()
211
+ )
212
+ self.assertListEqual(lib.to_dict(parsed_response), ParsedErrorResponse)
213
+
214
+
215
+ if __name__ == "__main__":
216
+ unittest.main()
217
+
218
+
219
+ AddressValidationPayload = {
220
+ "address": {
221
+ "address_line1": "123 Main St",
222
+ "city": "City Name",
223
+ "postal_code": "12345",
224
+ "country_code": "US",
225
+ "state_code": "CA",
226
+ }
227
+ }
228
+
229
+ AddressValidationRequest = {% if is_xml_api %}"""<?xml version="1.0"?>
230
+ <address-validation-request>
231
+ <street>123 Main St</street>
232
+ <city_name>City Name</city_name>
233
+ <postcode>12345</postcode>
234
+ <country_code>US</country_code>
235
+ <province_code>CA</province_code>
236
+ </address-validation-request>"""{% else %}{
237
+ "streetAddress": "123 Main St",
238
+ "cityLocality": "City Name",
239
+ "postalCode": "12345",
240
+ "countryCode": "US",
241
+ "stateProvince": "CA"
242
+ }{% endif %}
243
+
244
+ AddressValidationResponse = {% if is_xml_api %}"""<?xml version="1.0"?>
245
+ <address-validation-response>
246
+ <valid_address>true</valid_address>
247
+ <normalized_address>
248
+ <street>123 MAIN ST</street>
249
+ <city_name>CITY NAME</city_name>
250
+ <postcode>12345</postcode>
251
+ <country_code>US</country_code>
252
+ <province_code>CA</province_code>
253
+ </normalized_address>
254
+ </address-validation-response>"""{% else %}"""{
255
+ "isValid": true,
256
+ "normalizedAddress": {
257
+ "streetAddress": "123 MAIN ST",
258
+ "cityLocality": "CITY NAME",
259
+ "postalCode": "12345",
260
+ "countryCode": "US",
261
+ "stateProvince": "CA"
262
+ },
263
+ "validationMessages": [
264
+ {
265
+ "message": "Address is valid",
266
+ "code": "SUCCESS"
267
+ }
268
+ ]
269
+ }"""{% endif %}
270
+
271
+ ErrorResponse = {% if is_xml_api %}"""<?xml version="1.0"?>
272
+ <error-response>
273
+ <e>
274
+ <code>address_error</code>
275
+ <message>Unable to validate address</message>
276
+ <details>Invalid address information provided</details>
277
+ </e>
278
+ </error-response>"""{% else %}"""{
279
+ "error": {
280
+ "code": "address_error",
281
+ "message": "Unable to validate address",
282
+ "details": "Invalid address information provided"
283
+ }
284
+ }"""{% endif %}
285
+
286
+ ParsedAddressValidationResponse = [
287
+ {
288
+ "carrier_id": "{{id}}",
289
+ "carrier_name": "{{id}}",
290
+ "success": True
291
+ },
292
+ []
293
+ ]
294
+
295
+ ParsedErrorResponse = [
296
+ None,
297
+ [
298
+ {
299
+ "carrier_id": "{{id}}",
300
+ "carrier_name": "{{id}}",
301
+ "code": "address_error",
302
+ "message": "Unable to validate address",
303
+ "details": {
304
+ "details": "Invalid address information provided"
305
+ }
306
+ }
307
+ ]
308
+ ]''')
@@ -0,0 +1,150 @@
1
+ from jinja2 import Template
2
+
3
+
4
+ EMPTY_FILE_TEMPLATE = Template("")
5
+
6
+
7
+ MODELS_TEMPLATE = Template(
8
+ """
9
+ {% for name, cls in classes.items() %}
10
+ #### {{ name }}
11
+
12
+ | Name | Type | Description
13
+ | --- | --- | --- |
14
+ {% for prop in cls.__attrs_attrs__ %}| `{{ prop.name }}` | {{ prop.type }} | {{ '**required**' if str(prop.default) == 'NOTHING' else '' }}
15
+ {% endfor %}
16
+ {% endfor %}
17
+ """
18
+ )
19
+
20
+ SETTINGS_TEMPLATE = Template(
21
+ """
22
+ {% for k, val in settings.items() %}
23
+ #### {{ val['label'] }} Settings `[carrier_name = {{k}}]`
24
+
25
+ | Name | Type | Description
26
+ | --- | --- | --- |
27
+ {% for prop in val['Settings'].__attrs_attrs__ %}| `{{ prop.name }}` | {{ prop.type }} | {{ '**required**' if str(prop.default) == 'NOTHING' else '' }}
28
+ {% endfor %}
29
+ {% endfor %}
30
+ """
31
+ )
32
+
33
+ SERVICES_TEMPLATE = Template(
34
+ """
35
+ {% for key, value in service_mappers.items() %}
36
+ #### {{ mappers[key]["label"] }}
37
+
38
+ | Code | Identifier
39
+ | --- | ---
40
+ {% for code, name in value.items() %}| `{{ code }}` | {{ name }}
41
+ {% endfor %}
42
+ {% endfor %}
43
+ """
44
+ )
45
+
46
+ SHIPMENT_OPTIONS_TEMPLATE = Template(
47
+ """
48
+ {% for key, value in option_mappers.items() %}
49
+ #### {{ mappers[key]["label"] }}
50
+
51
+ | Code | Identifier | Description
52
+ | --- | --- | ---
53
+ {% for code, spec in value.items() %}| `{{ code }}` | {{ spec.get('key') }} | {{ spec.get('type') }}
54
+ {% endfor %}
55
+ {% endfor %}
56
+ """
57
+ )
58
+
59
+ PACKAGING_TYPES_TEMPLATE = Template(
60
+ """
61
+ {% for key, value in packaging_mappers.items() %}
62
+ #### {{ mappers[key]["label"] }}
63
+
64
+ | Code | Identifier
65
+ | --- | ---
66
+ {% for code, name in value.items() %}| `{{ code }}` | {{ name }}
67
+ {% endfor %}
68
+ {% endfor %}
69
+ """
70
+ )
71
+
72
+ SHIPMENT_PRESETS_TEMPLATE = Template(
73
+ """
74
+ {% for key, value in preset_mappers.items() %}
75
+ #### {{ mappers[key]["label"] }}
76
+
77
+ | Code | Dimensions | Note
78
+ | --- | --- | ---
79
+ {% for code, dim in value.items() %}{{ format_dimension(code, dim) }}
80
+ {% endfor %}
81
+ {% endfor %}
82
+ """
83
+ )
84
+
85
+ UTILS_TOOLS_TEMPLATE = Template(
86
+ """
87
+ {% for tool, import in utils %}
88
+ - `{{ tool.__name__ }}`
89
+
90
+ Usage:
91
+ ```python
92
+ {{ import }}
93
+ ```
94
+
95
+ ```text
96
+ {{ doc(tool) }}
97
+ ```
98
+
99
+ {% endfor %}
100
+ """
101
+ )
102
+
103
+ COUNTRY_INFO_TEMPLATES = Template(
104
+ """
105
+ ## Countries
106
+
107
+ | Code | Name
108
+ | --- | ---
109
+ {% for code, name in countries.items() %}| `{{ code }}` | {{ name }}
110
+ {% endfor %}
111
+
112
+ ## States and Provinces
113
+
114
+ {% for country, states in country_states.items() %}
115
+
116
+ ### {{ countries[country] }}
117
+
118
+ | Code | Name
119
+ | --- | ---
120
+ {% for code, name in states.items() %}| `{{ code }}` | {{ name }}
121
+ {% endfor %}
122
+ {% endfor %}
123
+
124
+ ## Currencies
125
+
126
+ | Code | Name
127
+ | --- | ---
128
+ {% for code, name in currencies.items() %}| `{{ code }}` | {{ name }}
129
+ {% endfor %}
130
+ """
131
+ )
132
+
133
+ UNITS_TEMPLATES = Template(
134
+ """
135
+ ## WEIGHT UNITS
136
+
137
+ | Code | Identifier
138
+ | --- | ---
139
+ {% for code, name in weight_units.items() %}| `{{ code }}` | {{ name }}
140
+ {% endfor %}
141
+
142
+ ## DIMENSION UNITS
143
+
144
+ | Code | Identifier
145
+ | --- | ---
146
+ {% for code, name in dimension_units.items() %}| `{{ code }}` | {{ name }}
147
+ {% endfor %}
148
+
149
+ """
150
+ )