nextmv 0.28.3.dev0__py3-none-any.whl → 0.28.3.dev1__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.
nextmv/__about__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "v0.28.3.dev0"
1
+ __version__ = "v0.28.3.dev1"
@@ -66,7 +66,6 @@ from nextmv.logger import log
66
66
  from nextmv.model import Model, ModelConfiguration
67
67
  from nextmv.options import Options
68
68
  from nextmv.output import Output
69
- from nextmv.serialization import serialize_json
70
69
 
71
70
  # Maximum size of the run input/output in bytes. This constant defines the
72
71
  # maximum allowed size for run inputs and outputs. When the size exceeds this
@@ -1589,7 +1588,7 @@ class Application:
1589
1588
  if isinstance(v, str):
1590
1589
  options_dict[k] = v
1591
1590
  else:
1592
- options_dict[k] = serialize_json(v)
1591
+ options_dict[k] = json.dumps(v)
1593
1592
 
1594
1593
  payload = {}
1595
1594
  if upload_id_used:
@@ -2831,7 +2830,7 @@ class Application:
2831
2830
  """
2832
2831
 
2833
2832
  if isinstance(input, dict):
2834
- input = serialize_json(input)
2833
+ input = json.dumps(input)
2835
2834
 
2836
2835
  self.client.upload_to_presigned_url(
2837
2836
  url=upload_url.upload_url,
@@ -3175,7 +3174,7 @@ class Application:
3175
3174
  raise ValueError(f"Unknown scenario input type: {scenario.scenario_input.scenario_input_type}")
3176
3175
 
3177
3176
 
3178
- def poll(polling_options: PollingOptions, polling_func: Callable[[], tuple[Any, bool]]) -> Any:
3177
+ def poll(polling_options: PollingOptions, polling_func: Callable[[], tuple[Any, bool]]) -> Any: # noqa: C901
3179
3178
  """
3180
3179
  Poll a function until it succeeds or the polling strategy is exhausted.
3181
3180
 
@@ -3254,6 +3253,7 @@ def poll(polling_options: PollingOptions, polling_func: Callable[[], tuple[Any,
3254
3253
  stopped = False
3255
3254
 
3256
3255
  # Begin the polling process.
3256
+ max_reached = False
3257
3257
  for ix in range(polling_options.max_tries):
3258
3258
  # Check is we should stop polling according to the stop callback.
3259
3259
  if polling_options.stop is not None and polling_options.stop():
@@ -3280,12 +3280,24 @@ def poll(polling_options: PollingOptions, polling_func: Callable[[], tuple[Any,
3280
3280
  )
3281
3281
 
3282
3282
  # Calculate the delay.
3283
- delay = polling_options.delay # Base
3284
- delay += polling_options.backoff * (2**ix) # Add exponential backoff.
3285
- delay += random.uniform(0, polling_options.jitter) # Add jitter.
3283
+ delay = 0.0
3284
+ if max_reached:
3285
+ # If we already reached the maximum, we don't want to further calculate the
3286
+ # delay to avoid overflows.
3287
+ delay = polling_options.max_delay
3288
+ delay += random.uniform(0, polling_options.jitter) # Add jitter.
3289
+ else:
3290
+ delay = polling_options.delay # Base
3291
+ delay += polling_options.backoff * (2**ix) # Add exponential backoff.
3292
+ delay += random.uniform(0, polling_options.jitter) # Add jitter.
3293
+
3294
+ # We cannot exceed the max delay.
3295
+ if delay >= polling_options.max_delay:
3296
+ max_reached = True
3297
+ delay = polling_options.max_delay
3286
3298
 
3287
- # Sleep for the calculated delay. We cannot exceed the max delay.
3288
- sleep_duration = min(delay, polling_options.max_delay)
3299
+ # Sleep for the calculated delay.
3300
+ sleep_duration = delay
3289
3301
  if polling_options.verbose:
3290
3302
  log(f"polling | sleeping for duration: {sleep_duration}")
3291
3303
 
nextmv/cloud/client.py CHANGED
@@ -14,6 +14,7 @@ get_size(obj)
14
14
  Finds the size of an object in bytes.
15
15
  """
16
16
 
17
+ import json
17
18
  import os
18
19
  from dataclasses import dataclass, field
19
20
  from typing import IO, Any, Optional, Union
@@ -23,8 +24,6 @@ import requests
23
24
  import yaml
24
25
  from requests.adapters import HTTPAdapter, Retry
25
26
 
26
- from nextmv.serialization import serialize_json
27
-
28
27
  _MAX_LAMBDA_PAYLOAD_SIZE: int = 500 * 1024 * 1024
29
28
  """int: Maximum size of the payload handled by the Nextmv Cloud API.
30
29
 
@@ -294,11 +293,7 @@ class Client:
294
293
  if data is not None:
295
294
  kwargs["data"] = data
296
295
  if payload is not None:
297
- if isinstance(payload, (dict, list)):
298
- data = serialize_json(payload)
299
- kwargs["data"] = data
300
- else:
301
- raise ValueError("payload must be a dictionary or a list")
296
+ kwargs["json"] = payload
302
297
  if query_params is not None:
303
298
  kwargs["params"] = query_params
304
299
 
@@ -346,7 +341,7 @@ class Client:
346
341
 
347
342
  upload_data: Optional[str] = None
348
343
  if isinstance(data, dict):
349
- upload_data = serialize_json(data)
344
+ upload_data = json.dumps(data, separators=(",", ":"))
350
345
  elif isinstance(data, str):
351
346
  upload_data = data
352
347
  else:
@@ -441,7 +436,7 @@ def get_size(obj: Union[dict[str, Any], IO[bytes], str]) -> int:
441
436
  """
442
437
 
443
438
  if isinstance(obj, dict):
444
- obj_str = serialize_json(obj)
439
+ obj_str = json.dumps(obj, separators=(",", ":"))
445
440
  return len(obj_str.encode("utf-8"))
446
441
 
447
442
  elif hasattr(obj, "read"):
nextmv/cloud/run.py CHANGED
@@ -39,6 +39,7 @@ run_duration(start, end)
39
39
  Calculate the duration of a run in milliseconds.
40
40
  """
41
41
 
42
+ import json
42
43
  from dataclasses import dataclass
43
44
  from datetime import datetime
44
45
  from enum import Enum
@@ -50,7 +51,6 @@ from nextmv.base_model import BaseModel
50
51
  from nextmv.cloud.status import Status, StatusV2
51
52
  from nextmv.input import Input, InputFormat
52
53
  from nextmv.output import Output, OutputFormat
53
- from nextmv.serialization import serialize_json
54
54
 
55
55
 
56
56
  def run_duration(start: Union[datetime, float], end: Union[datetime, float]) -> int:
@@ -628,7 +628,7 @@ class TrackedRun:
628
628
  raise ValueError("Input.input_format must be JSON.")
629
629
  elif isinstance(self.input, dict):
630
630
  try:
631
- _ = serialize_json(self.input)
631
+ _ = json.dumps(self.input)
632
632
  except (TypeError, OverflowError) as e:
633
633
  raise ValueError("Input is dict[str, Any] but it is not JSON serializable") from e
634
634
 
@@ -637,7 +637,7 @@ class TrackedRun:
637
637
  raise ValueError("Output.output_format must be JSON.")
638
638
  elif isinstance(self.output, dict):
639
639
  try:
640
- _ = serialize_json(self.output)
640
+ _ = json.dumps(self.output)
641
641
  except (TypeError, OverflowError) as e:
642
642
  raise ValueError("Output is dict[str, Any] but it is not JSON serializable") from e
643
643
 
nextmv/input.py CHANGED
@@ -33,7 +33,6 @@ from typing import Any, Optional, Union
33
33
 
34
34
  from nextmv.deprecated import deprecated
35
35
  from nextmv.options import Options
36
- from nextmv.serialization import serialize_json
37
36
 
38
37
 
39
38
  class InputFormat(str, Enum):
@@ -140,7 +139,7 @@ class Input:
140
139
 
141
140
  if self.input_format == InputFormat.JSON:
142
141
  try:
143
- _ = serialize_json(self.data)
142
+ _ = json.dumps(self.data)
144
143
  except (TypeError, OverflowError) as e:
145
144
  raise ValueError(
146
145
  f"Input has input_format InputFormat.JSON and "
nextmv/output.py CHANGED
@@ -42,6 +42,8 @@ write
42
42
 
43
43
  import copy
44
44
  import csv
45
+ import datetime
46
+ import json
45
47
  import os
46
48
  import sys
47
49
  from dataclasses import dataclass
@@ -54,7 +56,6 @@ from nextmv.base_model import BaseModel
54
56
  from nextmv.deprecated import deprecated
55
57
  from nextmv.logger import reset_stdout
56
58
  from nextmv.options import Options
57
- from nextmv.serialization import serialize_json
58
59
 
59
60
 
60
61
  class RunStatistics(BaseModel):
@@ -643,7 +644,7 @@ class Output:
643
644
 
644
645
  if self.output_format == OutputFormat.JSON:
645
646
  try:
646
- _ = serialize_json(self.solution)
647
+ _ = json.dumps(self.solution, default=_custom_serial)
647
648
  except (TypeError, OverflowError) as e:
648
649
  raise ValueError(
649
650
  f"Output has output_format OutputFormat.JSON and "
@@ -721,6 +722,12 @@ class Output:
721
722
  and self.csv_configurations != {}
722
723
  ):
723
724
  output_dict["csv_configurations"] = self.csv_configurations
725
+ elif (
726
+ self.output_format == OutputFormat.JSON
727
+ and self.json_configurations is not None
728
+ and self.json_configurations != {}
729
+ ):
730
+ output_dict["json_configurations"] = self.json_configurations
724
731
 
725
732
  return output_dict
726
733
 
@@ -815,9 +822,19 @@ class LocalOutputWriter(OutputWriter):
815
822
  if hasattr(output, "json_configurations") and output.json_configurations is not None:
816
823
  json_configurations = output.json_configurations
817
824
 
818
- serialized = serialize_json(
825
+ indent, custom_serial = 2, _custom_serial
826
+ if "indent" in json_configurations:
827
+ indent = json_configurations["indent"]
828
+ del json_configurations["indent"]
829
+ if "default" in json_configurations:
830
+ custom_serial = json_configurations["default"]
831
+ del json_configurations["default"]
832
+
833
+ serialized = json.dumps(
819
834
  output_dict,
820
- json_configurations=json_configurations,
835
+ indent=indent,
836
+ default=custom_serial,
837
+ **json_configurations,
821
838
  )
822
839
 
823
840
  if path is None or path == "":
@@ -860,17 +877,13 @@ class LocalOutputWriter(OutputWriter):
860
877
  if not os.path.exists(dir_path):
861
878
  os.makedirs(dir_path)
862
879
 
863
- json_configurations = {}
864
- if hasattr(output, "json_configurations") and output.json_configurations is not None:
865
- json_configurations = output.json_configurations
866
-
867
- serialized = serialize_json(
880
+ serialized = json.dumps(
868
881
  {
869
882
  "options": output_dict.get("options", {}),
870
883
  "statistics": output_dict.get("statistics", {}),
871
884
  "assets": output_dict.get("assets", []),
872
885
  },
873
- json_configurations=json_configurations,
886
+ indent=2,
874
887
  )
875
888
  print(serialized, file=sys.stdout)
876
889
 
@@ -1105,3 +1118,32 @@ def write(
1105
1118
  """
1106
1119
 
1107
1120
  writer.write(output, path, skip_stdout_reset)
1121
+
1122
+
1123
+ def _custom_serial(obj: Any) -> str:
1124
+ """
1125
+ JSON serializer for objects not serializable by default json serializer.
1126
+
1127
+ This function provides custom serialization for datetime objects, converting
1128
+ them to ISO format strings.
1129
+
1130
+ Parameters
1131
+ ----------
1132
+ obj : Any
1133
+ The object to serialize.
1134
+
1135
+ Returns
1136
+ -------
1137
+ str
1138
+ The serialized representation of the object.
1139
+
1140
+ Raises
1141
+ ------
1142
+ TypeError
1143
+ If the object type is not supported for serialization.
1144
+ """
1145
+
1146
+ if isinstance(obj, (datetime.datetime | datetime.date)):
1147
+ return obj.isoformat()
1148
+
1149
+ raise TypeError(f"Type {type(obj)} not serializable")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nextmv
3
- Version: 0.28.3.dev0
3
+ Version: 0.28.3.dev1
4
4
  Summary: The all-purpose Python SDK for Nextmv
5
5
  Project-URL: Homepage, https://www.nextmv.io
6
6
  Project-URL: Documentation, https://www.nextmv.io/docs/python-sdks/nextmv/installation
@@ -1,31 +1,30 @@
1
- nextmv/__about__.py,sha256=5UvDgOpqeyt2cJW7GXHGUFo5DQevIOSEyedJAK3pbyY,29
1
+ nextmv/__about__.py,sha256=qR07ImJh4PgBmUcqUtoxk7xk8BzPgTn_tdkvhweOIMA,29
2
2
  nextmv/__entrypoint__.py,sha256=dA0iwwHtrq6Z9w9FxmxKLoBGLyhe7jWtUAU-Y3PEgHg,1094
3
3
  nextmv/__init__.py,sha256=3E3c3dk4hCR1IXDHZxFDDDK2NPEEO8utwdd9wZ0q6ys,1506
4
4
  nextmv/base_model.py,sha256=qmJ4AsYr9Yv01HQX_BERrn3229gyoZrYyP9tcyqNfeU,2311
5
5
  nextmv/deprecated.py,sha256=kEVfyQ-nT0v2ePXTNldjQG9uH5IlfQVy3L4tztIxwmU,1638
6
- nextmv/input.py,sha256=voThRVvzyMnNesq2TdHr8orFsXlybIcx9IUBVBMgVyc,21199
6
+ nextmv/input.py,sha256=PvSfWA0gv3djSNWkcuMj6Ux3tgXPCMNz17yvSuYx5Bs,21147
7
7
  nextmv/logger.py,sha256=kNIbu46MisrzYe4T0hNMpWfRTKKacDVvbtQcNys_c_E,2513
8
8
  nextmv/model.py,sha256=ebL_Ta25ptaLkP1_PmPlLM2yh6dzA2e7KRjSJ8RZcOU,14614
9
9
  nextmv/options.py,sha256=8hIlTnMMqL12z7GGrR-igVOQVtx4FLtlEqDktoPOxTg,33226
10
- nextmv/output.py,sha256=p4QBc5NEhvsmBhk4W-vr6SGfFK9a2S4IKuwBPr9a8mc,36168
11
- nextmv/serialization.py,sha256=j3Sh0jjexpXBqJXL5MixT8uh9Qmd4XIyem62iY1uEZA,1764
10
+ nextmv/output.py,sha256=7s0Io17I7VChQPfqakHj4F2vNV0CD-ANAbE4kqipOXM,37241
12
11
  nextmv/cloud/__init__.py,sha256=7BCh3z-XkbIcMvFHmbj2wA8OquIovjrAZL7O9kA9VZc,3868
13
12
  nextmv/cloud/acceptance_test.py,sha256=Bcfdmh2fkPeBx8FDCngeUo2fjV_LhsUdygnzDQCDbYY,26898
14
13
  nextmv/cloud/account.py,sha256=eukiYQha4U2fkIjg4SgdoawKE1kU5G7GPyDJVrn8hHA,6064
15
- nextmv/cloud/application.py,sha256=zkUP41vzNbDisvhZDaqAvNAvdX63R_EoY-Ebn_GLNiA,110312
14
+ nextmv/cloud/application.py,sha256=yx63cAA60F3PB1Mo0SeELQfzAEFPAoLnZqAUdphkdJA,110719
16
15
  nextmv/cloud/batch_experiment.py,sha256=rD3m-ioE1G8ADYN7afzr7zlq-3H22TNlj9RAh-_ZqIo,7270
17
- nextmv/cloud/client.py,sha256=EGEYZbyxk5qTBVnA-DNIcYGcG_QH8REQVMuWNE585OM,15893
16
+ nextmv/cloud/client.py,sha256=WxnIFZ4sx1yav5SVg9HCexfAqxdDABXkxuMVKjMauvg,15703
18
17
  nextmv/cloud/input_set.py,sha256=2dqmf5z-rZjTKwtBRvnUdfPfKv28It5uTCX0C70uP4Y,4242
19
18
  nextmv/cloud/instance.py,sha256=SS4tbp0LQMWDaeYpwcNxJei82oi_Hozv1t5i3QGjASY,4024
20
19
  nextmv/cloud/manifest.py,sha256=KLdaHIfyCsjVjE0PXqAoVy4mRH-0KWf1b7TcEICdaJU,30541
21
20
  nextmv/cloud/package.py,sha256=RcS8X3rMDyQVv0IWmTEDbmaoDs5nPWoIFBfUgSTuAtA,13028
22
- nextmv/cloud/run.py,sha256=qxgk3JBW8PBHLliAmc0iBa_yxb1F_mSGxqr9IwJ6j5E,19482
21
+ nextmv/cloud/run.py,sha256=inXHWiDS4tUDOp_whvDCBaLCljVr4Br_RnZfmEpU58k,19438
23
22
  nextmv/cloud/safe.py,sha256=idifvV8P_79Zo2hIC_qxqZt9LUmD5TLQ9ikKwRUvd34,2522
24
23
  nextmv/cloud/scenario.py,sha256=JRFTDiFBcrgud6wE2qDHUu5oO-Ur3zbPYhhB6ONCxTo,14263
25
24
  nextmv/cloud/secrets.py,sha256=fA5cX0jfTsPVZWV7433wzETGlXpWRLHGswuObx9e6FQ,6820
26
25
  nextmv/cloud/status.py,sha256=blvykRCTCTBkaqH88j4dzdQLhU2v1Ig62-_va98zw20,2789
27
26
  nextmv/cloud/version.py,sha256=5_S7_pWUVBFbvAArku20eK7S645GJcHtgE2OpXLdSzQ,5300
28
- nextmv-0.28.3.dev0.dist-info/METADATA,sha256=o1eYt_97rrtZ0CxJNsTXUN8r78BhuP6AIu1D01xvImU,15315
29
- nextmv-0.28.3.dev0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
30
- nextmv-0.28.3.dev0.dist-info/licenses/LICENSE,sha256=ZIbK-sSWA-OZprjNbmJAglYRtl5_K4l9UwAV3PGJAPc,11349
31
- nextmv-0.28.3.dev0.dist-info/RECORD,,
27
+ nextmv-0.28.3.dev1.dist-info/METADATA,sha256=sUhY7IQXYVFCWiilfkVtJCmPYC5lFBEemtm08Wc1BLE,15315
28
+ nextmv-0.28.3.dev1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
29
+ nextmv-0.28.3.dev1.dist-info/licenses/LICENSE,sha256=ZIbK-sSWA-OZprjNbmJAglYRtl5_K4l9UwAV3PGJAPc,11349
30
+ nextmv-0.28.3.dev1.dist-info/RECORD,,
nextmv/serialization.py DELETED
@@ -1,67 +0,0 @@
1
- import datetime
2
- import json
3
- from typing import Any, Union
4
-
5
-
6
- def serialize_json(
7
- obj: Union[dict, list],
8
- json_configurations: dict[str, Any] = None,
9
- ) -> str:
10
- """
11
- Serialize a Python object (dict or list) to a JSON string.
12
-
13
- Parameters
14
- ----------
15
- obj : Union[dict, list]
16
- The Python object to serialize.
17
- json_configurations : dict, optional
18
- Additional configurations for JSON serialization. This allows customization
19
- of the Python `json.dumps` function. You can specify parameters like `indent`
20
- for pretty printing or `default` for custom serialization functions.
21
-
22
- Returns
23
- -------
24
- str
25
- A JSON string representation of the object.
26
- """
27
-
28
- # Apply some default configuration if not provided
29
- json_configurations = json_configurations or {}
30
- if "default" not in json_configurations:
31
- json_configurations["default"] = _custom_serial
32
- if "separators" not in json_configurations:
33
- json_configurations["separators"] = (",", ":")
34
-
35
- return json.dumps(
36
- obj,
37
- **json_configurations,
38
- )
39
-
40
-
41
- def _custom_serial(obj: Any) -> str:
42
- """
43
- JSON serializer for objects not serializable by default json serializer.
44
-
45
- This function provides custom serialization for datetime objects, converting
46
- them to ISO format strings.
47
-
48
- Parameters
49
- ----------
50
- obj : Any
51
- The object to serialize.
52
-
53
- Returns
54
- -------
55
- str
56
- The serialized representation of the object.
57
-
58
- Raises
59
- ------
60
- TypeError
61
- If the object type is not supported for serialization.
62
- """
63
-
64
- if isinstance(obj, (datetime.datetime, datetime.date)):
65
- return obj.isoformat()
66
-
67
- raise TypeError(f"Type {type(obj)} not serializable")