karrio 2023.3.4__py3-none-any.whl → 2023.4.4__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/api/interface.py CHANGED
@@ -81,6 +81,27 @@ def check_operation(gateway: gateway.Gateway, request: str, **kwargs):
81
81
  return True, None
82
82
 
83
83
 
84
+ def filter_rates(rates: typing.List[models.RateDetails], gateway: gateway.Gateway):
85
+ """Filter rates by gateway
86
+
87
+ Args:
88
+ rates (List[models.Rate]): the rates to filter
89
+ gateways (List[gateway.Gateway]): the gateways to filter by
90
+
91
+ Returns:
92
+ List[models.Rate]: the filtered rates
93
+ """
94
+ restricted_services = (
95
+ gateway.settings.connection_config.shipping_services.state or []
96
+ )
97
+
98
+ return [
99
+ rate
100
+ for rate in rates
101
+ if (not any(restricted_services) or rate.service in restricted_services)
102
+ ]
103
+
104
+
84
105
  @attr.s(auto_attribs=True)
85
106
  class IDeserialize:
86
107
  """A lazy deserializer type class"""
@@ -290,7 +311,29 @@ class Rating:
290
311
 
291
312
  def flatten(*args):
292
313
  responses = [p.parse() for p in deserializable_collection]
293
- flattened_rates = sum((r for r, _ in responses if r is not None), [])
314
+ flattened_rates = sum(
315
+ (
316
+ (
317
+ (lambda gateway: filter_rates(rates, gateway))(
318
+ # find the gateway that matches the carrier_id of the rates
319
+ next(
320
+ (
321
+ g
322
+ for g in gateways
323
+ if (
324
+ g.settings.carrier_id == rates[0].carrier_id
325
+ )
326
+ )
327
+ )
328
+ )
329
+ if len(rates) > 0
330
+ else rates
331
+ )
332
+ for rates, _ in responses
333
+ if rates is not None
334
+ ),
335
+ [],
336
+ )
294
337
  messages = sum((m for _, m in responses), [])
295
338
  return flattened_rates, messages
296
339
 
karrio/core/metadata.py CHANGED
@@ -23,10 +23,11 @@ class Metadata:
23
23
  Settings: Type[Settings]
24
24
 
25
25
  # Data Units
26
- services: Optional[Type[Enum]] = None
27
26
  options: Optional[Type[Enum]] = None
27
+ services: Optional[Type[Enum]] = None
28
28
  package_presets: Optional[Type[Enum]] = None
29
29
  packaging_types: Optional[Type[Enum]] = None
30
+ connection_configs: Optional[Type[Enum]] = None
30
31
  service_levels: Optional[List[ServiceLevel]] = None
31
32
 
32
33
  id: Optional[str] = None
karrio/core/models.py CHANGED
@@ -4,14 +4,6 @@ from typing import List, Dict, Any, Union
4
4
  from jstruct import JList, JStruct, REQUIRED
5
5
 
6
6
 
7
- @attr.s(auto_attribs=True)
8
- class AddressExtra:
9
- street_name: str = None
10
- street_type: str = None
11
- suburb: str = None
12
- suite: str = None
13
-
14
-
15
7
  @attr.s(auto_attribs=True)
16
8
  class Address:
17
9
  """shipping party (contact and address) data type."""
@@ -35,8 +27,6 @@ class Address:
35
27
  federal_tax_id: str = None
36
28
  state_tax_id: str = None
37
29
 
38
- extra: AddressExtra = JStruct[AddressExtra]
39
-
40
30
 
41
31
  @attr.s(auto_attribs=True)
42
32
  class Commodity:
@@ -304,12 +294,13 @@ class TrackingInfo:
304
294
  shipment_service: str = None
305
295
  shipment_origin_country: str = None
306
296
  shipment_origin_postal_code: str = None
307
- shipment_destication_country: str = None
297
+ shipment_destination_country: str = None
308
298
  shipment_destination_postal_code: str = None
309
299
  shipping_date: str = None
310
300
  signed_by: str = None
311
301
  source: str = None
312
302
 
303
+
313
304
  @attr.s(auto_attribs=True)
314
305
  class TrackingDetails:
315
306
  """Karrio unified tracking details data type."""
@@ -330,6 +321,9 @@ class Documents:
330
321
  """Karrio unified shipment details data type."""
331
322
 
332
323
  label: str
324
+ zpl_label: str = None
325
+ pdf_label: str = None
326
+
333
327
  invoice: str = None
334
328
 
335
329
 
karrio/core/settings.py CHANGED
@@ -1,26 +1,35 @@
1
1
  """Karrio Settings abstract class definition"""
2
2
 
3
+ import abc
3
4
  import attr
4
- from typing import Optional
5
- from abc import ABC
5
+ import typing
6
6
 
7
7
 
8
8
  @attr.s(auto_attribs=True)
9
- class Settings(ABC):
10
- """
11
- Unified API carrier Connection settings (Interface)
12
- """
9
+ class Settings(abc.ABC):
10
+ """Unified API carrier Connection settings (Interface)"""
13
11
 
14
12
  carrier_id: str
15
- id: str = None
16
- test_mode: bool = False
17
13
  account_country_code: str = None
14
+ test_mode: bool = False
18
15
  metadata: dict = {}
16
+ config: dict = {}
17
+ id: str = None
18
+
19
+ @property
20
+ def carrier_name(self) -> typing.Optional[str]:
21
+ return None
19
22
 
20
23
  @property
21
- def server_url(self) -> Optional[str]:
24
+ def server_url(self) -> typing.Optional[str]:
22
25
  return None
23
26
 
24
27
  @property
25
- def carrier_name(self) -> Optional[str]:
28
+ def tracking_url(self) -> typing.Optional[str]:
26
29
  return None
30
+
31
+ @property
32
+ def connection_config(self):
33
+ import karrio.lib as lib
34
+
35
+ return lib.to_connection_config(self.config or {})
karrio/core/units.py CHANGED
@@ -139,6 +139,11 @@ class MeasurementOptionsType(typing.NamedTuple):
139
139
  min_lb: typing.Optional[float] = None
140
140
  min_kg: typing.Optional[float] = None
141
141
  min_oz: typing.Optional[float] = None
142
+ max_in: typing.Optional[float] = None
143
+ max_cm: typing.Optional[float] = None
144
+ max_lb: typing.Optional[float] = None
145
+ max_kg: typing.Optional[float] = None
146
+ max_oz: typing.Optional[float] = None
142
147
  quant: typing.Optional[float] = None
143
148
 
144
149
 
@@ -428,6 +433,10 @@ class Products(typing.Iterable[Product]):
428
433
  def quantity(self):
429
434
  return sum((item.quantity for item in self._items), 0)
430
435
 
436
+ @property
437
+ def value_amount(self):
438
+ return sum((item.value_amount or 0.0 for item in self._items), 0.0)
439
+
431
440
 
432
441
  class Package:
433
442
  """The parcel common processing helper"""
@@ -830,11 +839,13 @@ class ShippingOption(utils.Enum):
830
839
  currency = utils.OptionEnum("currency")
831
840
  insurance = utils.OptionEnum("insurance", float)
832
841
  cash_on_delivery = utils.OptionEnum("COD", float)
842
+ shipment_note = utils.OptionEnum("shipment_note")
833
843
  shipment_date = utils.OptionEnum("shipment_date")
834
844
  dangerous_good = utils.OptionEnum("dangerous_good", bool)
835
845
  declared_value = utils.OptionEnum("declared_value", float)
836
846
  paperless_trade = utils.OptionEnum("paperless_trade", bool)
837
847
  hold_at_location = utils.OptionEnum("hold_at_location", bool)
848
+ sms_notification = utils.OptionEnum("email_notification", bool)
838
849
  email_notification = utils.OptionEnum("email_notification", bool)
839
850
  email_notification_to = utils.OptionEnum("email_notification_to")
840
851
  signature_confirmation = utils.OptionEnum("signature_confirmation", bool)
@@ -875,6 +886,10 @@ class ShippingOptions(Options):
875
886
 
876
887
  return ShippingOption.email_notification.value(True)
877
888
 
889
+ @property
890
+ def sms_notification(self) -> utils.OptionEnum:
891
+ return self[ShippingOption.sms_notification.name]
892
+
878
893
  @property
879
894
  def email_notification_to(self) -> utils.OptionEnum:
880
895
  return self[ShippingOption.email_notification_to.name]
@@ -903,6 +918,10 @@ class ShippingOptions(Options):
903
918
  def doc_references(self) -> utils.OptionEnum:
904
919
  return self[ShippingOption.doc_references.name]
905
920
 
921
+ @property
922
+ def shipment_note(self) -> utils.OptionEnum:
923
+ return self[ShippingOption.shipment_note.name]
924
+
906
925
 
907
926
  class CustomsOption(utils.Enum):
908
927
  """common shipment customs identifiers"""
@@ -994,6 +1013,43 @@ class DocumentUploadOption(utils.Enum):
994
1013
  destination_country_code = utils.OptionEnum("destination_country_code")
995
1014
 
996
1015
 
1016
+ class ConnectionConfigOption(utils.Enum):
1017
+ """common shipment document upload options"""
1018
+
1019
+ label_type = utils.OptionEnum("label_type")
1020
+ language_code = utils.OptionEnum("language_code")
1021
+ default_currency = utils.OptionEnum("default_currency")
1022
+ shipping_options = utils.OptionEnum("shipping_options", list)
1023
+ shipping_services = utils.OptionEnum("shipping_services", list)
1024
+
1025
+
1026
+ class ConnectionConfigOptions(Options):
1027
+ """The options common processing helper"""
1028
+
1029
+ def __init__(self, *args, **kwargs):
1030
+ super().__init__(*args, **kwargs, base_option_type=ConnectionConfigOption)
1031
+
1032
+ @property
1033
+ def label_type(self) -> utils.OptionEnum:
1034
+ return self[ConnectionConfigOption.label_type.name]
1035
+
1036
+ @property
1037
+ def language_code(self) -> utils.OptionEnum:
1038
+ return self[ConnectionConfigOption.language_code.name]
1039
+
1040
+ @property
1041
+ def default_currency(self) -> utils.OptionEnum:
1042
+ return self[ConnectionConfigOption.default_currency.name]
1043
+
1044
+ @property
1045
+ def shipping_options(self) -> utils.OptionEnum:
1046
+ return self[ConnectionConfigOption.shipping_options.name]
1047
+
1048
+ @property
1049
+ def shipping_services(self) -> utils.OptionEnum:
1050
+ return self[ConnectionConfigOption.shipping_services.name]
1051
+
1052
+
997
1053
  class Services:
998
1054
  """The services common processing helper"""
999
1055
 
@@ -1050,6 +1106,9 @@ class ComputedAddress(models.Address):
1050
1106
  self.address = address
1051
1107
 
1052
1108
  def __getattr__(self, item):
1109
+ if item == "street_number":
1110
+ return self._compute_street_number()
1111
+
1053
1112
  if hasattr(self.address, item):
1054
1113
  return getattr(self.address, item)
1055
1114
 
@@ -1067,6 +1126,33 @@ class ComputedAddress(models.Address):
1067
1126
  def address_lines(self) -> str:
1068
1127
  return self._compute_address_line(join=False)
1069
1128
 
1129
+ @property
1130
+ def street(self) -> typing.Optional[str]:
1131
+ return typing.cast(
1132
+ str,
1133
+ utils.SF.concat_str(
1134
+ self.street_number,
1135
+ self.street_name,
1136
+ join=True,
1137
+ ),
1138
+ )
1139
+
1140
+ @property
1141
+ def street_name(self) -> typing.Optional[str]:
1142
+ """The address line 1 without the street number"""
1143
+ return typing.cast(
1144
+ str,
1145
+ utils.SF.concat_str(
1146
+ *[
1147
+ _
1148
+ for _ in self.address.address_line1.split(" ")
1149
+ if _ != self.street_number
1150
+ ],
1151
+ join=True,
1152
+ ),
1153
+ )
1154
+ return self.address.address_line1.replace(self.street_number, "").strip()
1155
+
1070
1156
  @property
1071
1157
  def tax_id(self) -> typing.Optional[str]:
1072
1158
  return self.address.federal_tax_id or self.address.state_tax_id
@@ -1092,50 +1178,43 @@ class ComputedAddress(models.Address):
1092
1178
  def has_tax_info(self) -> bool:
1093
1179
  return any([self.address.federal_tax_id, self.address.state_tax_id])
1094
1180
 
1095
- @property
1096
- def suite(self) -> typing.Optional[str]:
1097
- return getattr(self.address.extra, "suite", None)
1098
-
1099
1181
  @property
1100
1182
  def contact(self) -> typing.Optional[str]:
1101
1183
  return getattr(self.address, "person_name", None) or getattr(
1102
1184
  self.address, "company_name", None
1103
1185
  )
1104
1186
 
1105
- @property
1106
- def street_name(self) -> typing.Optional[str]:
1107
- return getattr(self.address.extra, "street_name", None)
1108
-
1109
- @property
1110
- def street_type(self) -> typing.Optional[str]:
1111
- return getattr(self.address.extra, "street_type", None)
1112
-
1113
1187
  def _compute_address_line(self, join: bool = True) -> typing.Optional[str]:
1114
1188
  if any(
1115
1189
  [
1116
- self.address.street_number,
1117
- self.address.address_line1,
1118
- self.address.address_line2,
1190
+ self.street_number,
1191
+ self.street_name,
1192
+ self.address_line2,
1119
1193
  ]
1120
1194
  ):
1121
1195
  return utils.SF.concat_str(
1122
- self.address.street_number,
1123
- self.address.address_line1,
1124
- self.address.address_line2,
1196
+ self.street_number,
1197
+ self.street_name,
1198
+ self.address_line2,
1125
1199
  join=join,
1126
1200
  ) # type:ignore
1127
1201
 
1128
- if self.address.extra is not None:
1129
- return utils.SF.concat_str(
1130
- self.address.extra.suite,
1131
- self.address.street_number,
1132
- self.address.extra.street_name,
1133
- self.address.extra.street_type,
1134
- join=True,
1135
- ) # type:ignore
1136
-
1137
1202
  return None
1138
1203
 
1204
+ def _compute_street_number(self):
1205
+ _value = getattr(self.address, "street_number", None)
1206
+
1207
+ if _value is None:
1208
+ words = self.address.address_line1.split(" ")
1209
+
1210
+ if any(_.isdigit() for _ in words[0]):
1211
+ return words[0]
1212
+
1213
+ if any(_.isdigit() for _ in words[-1]):
1214
+ return words[-1]
1215
+
1216
+ return _value
1217
+
1139
1218
 
1140
1219
  class ComputedDocumentFile(models.DocumentFile):
1141
1220
  def __init__(self, document: typing.Optional[models.DocumentFile]):
@@ -44,17 +44,28 @@ def to_buffer(encoded_file: str, **kwargs) -> io.BytesIO:
44
44
  return buffer
45
45
 
46
46
 
47
- def image_to_pdf(image_str: str, rotate: int = None) -> str:
47
+ def image_to_pdf(image_str: str, rotate: int = None, resize: dict = None) -> str:
48
48
  buffer = to_buffer(image_str)
49
49
  _image = Image.open(buffer)
50
+
50
51
  image = (
51
- _image.rotate(rotate, Image.NEAREST, expand = True)
52
+ _image.rotate(rotate, Image.NEAREST, expand=True)
52
53
  if rotate is not None
53
54
  else _image
54
55
  )
55
56
 
57
+ if resize is not None:
58
+ img = image.copy()
59
+ wpercent = resize["width"] / float(img.size[0])
60
+ hsize = int((float(img.size[1]) * float(wpercent)))
61
+ image = img.resize((resize["width"], hsize), Image.Resampling.LANCZOS)
62
+
63
+ if resize is not None:
64
+ img = image.copy()
65
+ image = img.resize((resize["width"], resize["height"]), Image.ANTIALIAS)
66
+
56
67
  new_buffer = io.BytesIO()
57
- image.save(new_buffer, format="PDF")
68
+ image.save(new_buffer, format="PDF", dpi=(300, 300))
58
69
 
59
70
  return base64.b64encode(new_buffer.getvalue()).decode("utf-8")
60
71
 
@@ -116,11 +127,26 @@ def bundle_base64(base64_strings: List[str], format: str = "PDF") -> str:
116
127
  return base64.b64encode(result.getvalue()).decode("utf-8")
117
128
 
118
129
 
130
+ def zpl_to_pdf(zpl_str: str, width: int, height: int, dpmm: int = 12) -> str:
131
+ """Return a PDF base64 string from a ZPL string."""
132
+ import karrio.lib as lib
133
+
134
+ data = lib.to_json(dict(file=base64.b64decode(zpl_str).decode("utf-8")))
135
+ doc = request(
136
+ url=f"http://api.labelary.com/v1/printers/{dpmm}dpmm/labels/{width}x{height}/",
137
+ data=data,
138
+ headers={"Accept": "application/pdf"},
139
+ decoder=lambda b: base64.encodebytes(b).decode("utf-8"),
140
+ )
141
+
142
+ return doc
143
+
144
+
119
145
  def decode_bytes(byte):
120
146
  return (
121
- failsafe(lambda: byte.decode("utf-8")) or
122
- failsafe(lambda: byte.decode("ISO-8859-1")) or
123
- byte.decode("utf-8")
147
+ failsafe(lambda: byte.decode("utf-8"))
148
+ or failsafe(lambda: byte.decode("ISO-8859-1"))
149
+ or byte.decode("utf-8")
124
150
  )
125
151
 
126
152
 
@@ -1,22 +1,22 @@
1
1
  import attr
2
+ import typing
2
3
  import logging
3
- from typing import Any, Callable, Generic, TypeVar
4
4
 
5
5
  from karrio.core.utils.helpers import identity
6
6
 
7
7
  logger = logging.getLogger(__name__)
8
8
 
9
9
  XML_str = str
10
- T = TypeVar("T")
10
+ T = typing.TypeVar("T")
11
11
 
12
12
 
13
13
  @attr.s(auto_attribs=True)
14
- class Serializable(Generic[T]):
15
- value: T
16
- _serializer: Callable[[T], Any] = identity
14
+ class Serializable(typing.Generic[T]):
15
+ value: typing.Any
16
+ _serializer: typing.Callable[[typing.Any], T] = identity
17
17
  _ctx: dict = {}
18
18
 
19
- def serialize(self) -> Any:
19
+ def serialize(self) -> T:
20
20
  serialized_value = self._serializer(self.value)
21
21
  logger.debug(serialized_value)
22
22
  return serialized_value
@@ -27,12 +27,12 @@ class Serializable(Generic[T]):
27
27
 
28
28
 
29
29
  @attr.s(auto_attribs=True)
30
- class Deserializable(Generic[T]):
31
- value: T
32
- _deserializer: Callable[[T], Any] = identity
30
+ class Deserializable(typing.Generic[T]):
31
+ value: typing.Any
32
+ _deserializer: typing.Callable[[typing.Any], T] = identity
33
33
  _ctx: dict = {}
34
34
 
35
- def deserialize(self) -> Any:
35
+ def deserialize(self) -> T:
36
36
  logger.debug(self.value)
37
37
  return self._deserializer(self.value)
38
38
 
karrio/lib.py CHANGED
@@ -368,7 +368,11 @@ def to_shipping_options(
368
368
  if initializer is not None:
369
369
  return initializer(options, **kwargs)
370
370
 
371
- return units.ShippingOptions(options)
371
+ return units.ShippingOptions(
372
+ options,
373
+ option_type=kwargs.get("option_type"),
374
+ items_filter=kwargs.get("items_filter"),
375
+ )
372
376
 
373
377
 
374
378
  def to_services(
@@ -422,6 +426,16 @@ def to_upload_options(
422
426
  )
423
427
 
424
428
 
429
+ def to_connection_config(
430
+ options: dict,
431
+ option_type: typing.Optional[typing.Type[utils.Enum]] = None,
432
+ ) -> units.ConnectionConfigOptions:
433
+ return units.ConnectionConfigOptions(
434
+ options,
435
+ option_type=option_type,
436
+ )
437
+
438
+
425
439
  # -----------------------------------------------------------
426
440
  # Address utility functions.
427
441
  # -----------------------------------------------------------
@@ -577,8 +591,9 @@ def request(
577
591
  def image_to_pdf(
578
592
  image_str: str,
579
593
  rotate: int = None,
594
+ resize: dict = None,
580
595
  ) -> str:
581
- return utils.image_to_pdf(image_str, rotate=rotate)
596
+ return utils.image_to_pdf(image_str, rotate=rotate, resize=resize)
582
597
 
583
598
 
584
599
  def bundle_pdfs(
@@ -599,6 +614,16 @@ def bundle_zpls(
599
614
  return utils.bundle_zpls(base64_strings)
600
615
 
601
616
 
617
+ def zpl_to_pdf(
618
+ zpl_str: str,
619
+ width: int,
620
+ height: int,
621
+ dpmm: int = 12,
622
+ ) -> str:
623
+ """Return a PDF base64 string from a ZPL string."""
624
+ return utils.zpl_to_pdf(zpl_str, width, height, dpmm=dpmm)
625
+
626
+
602
627
  def bundle_base64(
603
628
  base64_strings: typing.List[str],
604
629
  format: str = "PDF",
karrio/references.py CHANGED
@@ -78,6 +78,11 @@ def collect_references() -> dict:
78
78
  for key, mapper in PROVIDERS_DATA.items()
79
79
  if mapper.get("options") is not None
80
80
  }
81
+ connection_configs = {
82
+ key: {c.name: dict(code=c.value.code) for c in list(mapper["connection_configs"])} # type: ignore
83
+ for key, mapper in PROVIDERS_DATA.items()
84
+ if mapper.get("connection_configs") is not None
85
+ }
81
86
 
82
87
  REFERENCES = {
83
88
  "countries": {c.name: c.value for c in list(units.Country)},
@@ -103,6 +108,7 @@ def collect_references() -> dict:
103
108
  },
104
109
  "services": services,
105
110
  "options": options,
111
+ "connection_configs": connection_configs,
106
112
  "carrier_capabilities": {
107
113
  key: detect_capabilities(detect_proxy_methods(mapper["Proxy"]))
108
114
  for key, mapper in PROVIDERS_DATA.items()
@@ -21,7 +21,7 @@ class RatingMixinProxy:
21
21
  )
22
22
 
23
23
  def get_rates(
24
- self, request: utils.Serializable[models.RateRequest]
24
+ self, request: utils.Serializable
25
25
  ) -> utils.Deserializable[typing.List[typing.Tuple[str, PackageRates]]]:
26
26
  _request = request.serialize()
27
27
 
@@ -144,12 +144,10 @@ def get_available_rates(
144
144
  for zone in service.zones or []:
145
145
  # Check Location inclusion
146
146
  _cover_supported_cities = (
147
- zone.cities is not None
148
- and recipient.city in zone.cities
147
+ zone.cities is not None and recipient.city in zone.cities
149
148
  ) or not any(zone.cities or [])
150
149
  _cover_supported_countries = (
151
- zone.cities is not None
152
- and recipient.country_code in zone.country_codes
150
+ zone.cities is not None and recipient.country_code in zone.country_codes
153
151
  ) or not any(zone.country_codes or [])
154
152
 
155
153
  # Check if weight and dimensions fit restrictions
@@ -14,7 +14,7 @@ class ShippingMixinProxy:
14
14
  settings: ShippingMixinSettings
15
15
 
16
16
  def create_shipment(
17
- self, request: lib.Serializable[ShipmentRequest]
17
+ self, request: lib.Serializable
18
18
  ) -> lib.Deserializable[
19
19
  typing.Tuple[typing.List[typing.Tuple[str, ServiceLabel]], typing.List[Message]]
20
20
  ]:
@@ -3,15 +3,18 @@ import karrio.lib as lib
3
3
  import karrio.core.models as models
4
4
  import karrio.universal.providers.rating.utils as utils
5
5
 
6
+ ResponseType = typing.List[typing.Tuple[str, utils.PackageRates]]
7
+
6
8
 
7
9
  def parse_rate_response(
8
- responses: typing.List[typing.Tuple[str, utils.PackageRates]], _
10
+ _response: lib.Deserializable[ResponseType], _
9
11
  ) -> typing.Tuple[typing.List[models.RateDetails], typing.List[models.Message]]:
12
+ responses = _response.deserialize()
10
13
  package_rates: typing.List[typing.Tuple[str, typing.List[models.RateDetails]]] = []
11
14
  messages: typing.List[models.Message] = []
12
15
 
13
- for _ref, _response in responses:
14
- _rates, _messages = _response
16
+ for _ref, _res in responses:
17
+ _rates, _messages = _res
15
18
  messages += _messages
16
19
  package_rates += [(_ref, _rates)]
17
20
 
@@ -20,7 +23,5 @@ def parse_rate_response(
20
23
  return rates, messages
21
24
 
22
25
 
23
- def rate_request(
24
- payload: models.RateRequest, _
25
- ) -> lib.Serializable[models.RateRequest]:
26
+ def rate_request(payload: models.RateRequest, _) -> lib.Serializable:
26
27
  return lib.Serializable(payload)
@@ -9,13 +9,14 @@ from karrio.core.models import (
9
9
  from karrio.universal.providers.shipping.utils import ShippingMixinSettings
10
10
  from karrio.core.models import ServiceLabel
11
11
  from karrio.core.utils.transformer import to_multi_piece_shipment
12
+ import karrio.lib as lib
12
13
 
13
14
 
14
15
  def parse_shipment_response(
15
- response: Tuple[List[Tuple[str, ServiceLabel]], List[Message]],
16
+ _response: lib.Deserializable[Tuple[List[Tuple[str, ServiceLabel]], List[Message]]],
16
17
  settings: ShippingMixinSettings,
17
18
  ) -> Tuple[ShipmentDetails, List[Message]]:
18
- service_labels, errors = response
19
+ service_labels, errors = _response.deserialize()
19
20
  shipment = to_multi_piece_shipment(
20
21
  [
21
22
  (package_ref, _extract_details(service_label, settings))
@@ -40,5 +41,5 @@ def _extract_details(
40
41
  )
41
42
 
42
43
 
43
- def shipment_request(payload: ShipmentRequest, _) -> Serializable[ShipmentRequest]:
44
+ def shipment_request(payload: ShipmentRequest, _) -> Serializable:
44
45
  return Serializable(payload)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: karrio
3
- Version: 2023.3.4
3
+ Version: 2023.4.4
4
4
  Summary: Multi-carrier shipping API integration with python
5
5
  Home-page: https://github.com/karrioapi/karrio
6
6
  Author: karrio
@@ -1,6 +1,6 @@
1
1
  karrio/__init__.py,sha256=MGaZGiMfGOpYY5gTQaOT-FgpyAmRoBio8dfXl1IcRWA,3149
2
- karrio/lib.py,sha256=yx-UwnCef4jhhSkYVZVjgTmY0LUnWNLlR9Kl50r9V-o,17459
3
- karrio/references.py,sha256=0z-b2U2Z8ghhvC-hH6XpMhiVKrGcizyq5FTD4G1XsRg,4673
2
+ karrio/lib.py,sha256=jeFbDvSONXTG5cd6Sw-7FyskKzWfrDcYKlIt1L9rFq8,18075
3
+ karrio/references.py,sha256=Re-PHb3QyhFkqCGTuKyQjIFxpa30b9vaRqA5TVjwr1E,4969
4
4
  karrio/addons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  karrio/addons/label.py,sha256=WwC1o97Ztyj3kRNTlAkHmYh4It7dC7l8bsC3fc-5yMA,10316
6
6
  karrio/addons/renderer.py,sha256=tLO1ZWrYExBOyLVv29v-1FWtASrevZlG2OCgQFf8lqk,7016
@@ -8,25 +8,25 @@ karrio/addons/fonts/Oswald-Regular.ttf,sha256=JkY5cy9a34D6weSp7z8OtY5Yta6tB4UAh2
8
8
  karrio/addons/fonts/Oswald-SemiBold.ttf,sha256=s4enQAb3fl-rF7yrZAHO8P99AVqUjiJ3DS873v-lidA,91700
9
9
  karrio/api/__init__.py,sha256=fJbOJLRIdrVlUi2BM-JtagKdm05ADc9naRMtx6rZ0V4,127
10
10
  karrio/api/gateway.py,sha256=9E30taInhrN7-VGeZz3NKcbKEwhy7h9grB_nZ8dlkQM,4955
11
- karrio/api/interface.py,sha256=hsk4ekSEOq-jyqukVPkPPcV_Sw6ZewbaugEWZ2ETS0k,14594
11
+ karrio/api/interface.py,sha256=9vt5IZO0bZBYpeyFrxHe1XVLbR75gygdPowAY6DoJnE,16054
12
12
  karrio/api/mapper.py,sha256=OjLH2b6_NRcVNnJDb3hZypY6FfHuTHiMlAJgYnWpkzM,13472
13
13
  karrio/api/proxy.py,sha256=Mx5tpcL0L_02lIZ84AvnEfroVu5Qi22iz7AVueX4YjI,6320
14
14
  karrio/core/__init__.py,sha256=BboTt3huAYrsqcTcaq1lFX5O4uKiIi2cpWEXp68ItMo,71
15
15
  karrio/core/errors.py,sha256=iMwiwCwK0eiYzk5KJ9Qu86JMWpymw1zDCvmqY67ghSw,3006
16
- karrio/core/metadata.py,sha256=kJUov6vdVZVrNaRF-J0RP4Papb8hZifAVY97TxcYQO0,1029
17
- karrio/core/models.py,sha256=M7o--xOHsDWlkQgcnBuGQeIiFfUxlJH_PTWEb7PKMS4,11098
18
- karrio/core/settings.py,sha256=mjL6vtKZnjK7ITcmkxvmOZHshHc7LDuhseF5wAojt_4,518
19
- karrio/core/units.py,sha256=TNkub7bMrsrIy1dVn-FrH1bYkNGqtcifaVKsactesw8,55580
16
+ karrio/core/metadata.py,sha256=vs4doqUjxDSRbDulbdBeTAyFUIZ8MdjsRP74YjtdNEY,1081
17
+ karrio/core/models.py,sha256=wkqD4M7cCDFJmdpI3shDvxX4M9mFirL6K3yHUl0GIbM,10953
18
+ karrio/core/settings.py,sha256=1d-w-U5nODMxsbmR0B4CdgggvYCzsgtSipP7GUWmFkI,753
19
+ karrio/core/units.py,sha256=PyHjHEdge6fY-xZph9_NUQdbExROoyIpUSdRT8MgKIs,58015
20
20
  karrio/core/utils/__init__.py,sha256=NPxAugvQ4lhWOngITOagexXrsTQqlJQ0gyaXc9iBivg,739
21
21
  karrio/core/utils/caching.py,sha256=zx0R1XAWPuA0q2hz5xUw0-OLZhHd7haS41uO_Prg8Ng,1734
22
22
  karrio/core/utils/datetime.py,sha256=aFMqLB_AdRGM0By2TO8mYce-UlqExf_J2s2eLNtDClY,2311
23
23
  karrio/core/utils/dict.py,sha256=fUsyMwRduh3qJ6D6Vf4LUVcljEqDHJVn8Av9x4rUadg,2312
24
24
  karrio/core/utils/enum.py,sha256=qCrqP49wXyypfQ7rw4kFGjJ6rawptOxq_RPwqaz09dk,4420
25
- karrio/core/utils/helpers.py,sha256=wqrMYUX2_JpQbXBd0eLnmE1R3I0qKDbGJ2EoR0Wv4wc,7593
25
+ karrio/core/utils/helpers.py,sha256=I3oMOPl4oeOyR8qQLlt1jVL59-uxnE8dBoWlfuqP658,8518
26
26
  karrio/core/utils/log.py,sha256=G0JqUqNiS7JwkFMurtHtbxa42miAs28dPfNZZdlZid4,434
27
27
  karrio/core/utils/number.py,sha256=z455Zbx5V92Ofo8PEaC_UEfmVEwnb-nq7fIoSeApz4o,1176
28
28
  karrio/core/utils/pipeline.py,sha256=6wXdsUGW7ZVqhpsEzreBnS6dHSCU5XgClOaBgKfJyh8,1253
29
- karrio/core/utils/serializable.py,sha256=0dAy0wWnzur4HE0WS9vB9BWB4GNE3WndeR4Q8K5NPtw,890
29
+ karrio/core/utils/serializable.py,sha256=iaeiVeiCqnpIhX0danUPfsixVWcYkhb3NkYlfQaFuJA,916
30
30
  karrio/core/utils/soap.py,sha256=g8AzymGypJris0liiK-zwsjeoCPlIJ8r25WSBlSHqqs,5274
31
31
  karrio/core/utils/string.py,sha256=l2CL4rn7Tls26oH_IgAsiQh80grG39Tj4NKY4CtcCsU,762
32
32
  karrio/core/utils/tracing.py,sha256=84dmmpEPs_iBC3JaFv4f9vbC0VgR6KW4HZEYIrdt084,1462
@@ -36,16 +36,16 @@ karrio/mappers/__init__.py,sha256=i5qDwqYoTmFscV1rwxIOo19JiRzyfTWJd9Jx0qEvUmo,12
36
36
  karrio/providers/__init__.py,sha256=02HsiVGylnZLoB_OE-7kJTvF500-CpOe-WWkOkqRUno,131
37
37
  karrio/universal/__init__.py,sha256=bpT73UG7mZL_JjEqMwbYx6q69jA8J5Jcoul1LcDokhA,81
38
38
  karrio/universal/mappers/__init__.py,sha256=bpT73UG7mZL_JjEqMwbYx6q69jA8J5Jcoul1LcDokhA,81
39
- karrio/universal/mappers/rating_proxy.py,sha256=j3NQ4HZWfhX1FEZokSEEcoHbo66ixrZqklmhQGzMb0c,10686
40
- karrio/universal/mappers/shipping_proxy.py,sha256=DaUJD_6djKezfm9wz4zg3ZF24zCFMM7J8z9onXDiUc0,1952
39
+ karrio/universal/mappers/rating_proxy.py,sha256=la0cAsbhuXzSFYdzi8tJalC4kT79FvZu_N99VMGTktU,10634
40
+ karrio/universal/mappers/shipping_proxy.py,sha256=-hEXZ0R3-Ps6MSRAGpE_IlWsa0gKr6xJjIz4NuoeXQ8,1935
41
41
  karrio/universal/providers/__init__.py,sha256=bpT73UG7mZL_JjEqMwbYx6q69jA8J5Jcoul1LcDokhA,81
42
42
  karrio/universal/providers/rating/__init__.py,sha256=3f8u1FS7OF9OZUGauBSt4B1ad0dmqIsmFaG3pWu7Sck,139
43
- karrio/universal/providers/rating/rate.py,sha256=sXH3uIs_1H1herLKMMKARGINUXCoBvYF41ZeV6FxWlI,808
43
+ karrio/universal/providers/rating/rate.py,sha256=5M79YhIX-XMnm44kezFEoY5vE9d-WWjGAaBnE7MOmJI,861
44
44
  karrio/universal/providers/rating/utils.py,sha256=WVyJWdxCdKM1YlhTHVFxEMyac0FKIGHEkYXWEgJUzYA,558
45
45
  karrio/universal/providers/shipping/__init__.py,sha256=JRcfJWSeDSjO2g2fRnLgBurBXn01nVpdi21ShxLpG34,188
46
- karrio/universal/providers/shipping/shipment.py,sha256=FwpIAaRMLhwINNRGSRTCcSB0xmPS2yGGbGHNAf4O8Cg,1468
46
+ karrio/universal/providers/shipping/shipment.py,sha256=t7PO4uSzD1ZL3q3UZWHAPD3UUZUKXReQvED8mVKUe1A,1512
47
47
  karrio/universal/providers/shipping/utils.py,sha256=1LuO31RMhpUls6-h5xhWkfky4G7tdWmGKmRhLkj-e98,593
48
- karrio-2023.3.4.dist-info/METADATA,sha256=K-ximGrFsQtHCJ6kvK9hWefXw4uluhHLB2KDXvF6jsE,4705
49
- karrio-2023.3.4.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
50
- karrio-2023.3.4.dist-info/top_level.txt,sha256=mfkVZXzNuVRmA7NRlck_Ub-C8Zgtqxbx3gX1Rq_W-i0,7
51
- karrio-2023.3.4.dist-info/RECORD,,
48
+ karrio-2023.4.4.dist-info/METADATA,sha256=dRozbMtKfDyrdjkZtVUAHMOyE4vbgM3M-dzUyicgKJo,4705
49
+ karrio-2023.4.4.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
50
+ karrio-2023.4.4.dist-info/top_level.txt,sha256=mfkVZXzNuVRmA7NRlck_Ub-C8Zgtqxbx3gX1Rq_W-i0,7
51
+ karrio-2023.4.4.dist-info/RECORD,,