nextmv 0.28.2__py3-none-any.whl → 0.28.3__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.2"
1
+ __version__ = "v0.28.3"
@@ -0,0 +1,96 @@
1
+ import datetime
2
+ import json
3
+ from typing import Any, Union
4
+
5
+
6
+ def deflated_serialize_json(obj: Union[dict, list], json_configurations: dict[str, Any] = None) -> str:
7
+ """
8
+ Serialize a Python object (dict or list) to a JSON string with default configuration for a deflated format.
9
+
10
+ Parameters
11
+ ----------
12
+ obj : Union[dict, list]
13
+ The Python object to serialize.
14
+ json_configurations : dict, optional
15
+ Additional configurations for JSON serialization. This allows customization
16
+ of the Python `json.dumps` function. You can specify parameters like `indent`
17
+ for pretty printing or `default` for custom serialization functions.
18
+
19
+ Returns
20
+ -------
21
+ str
22
+ A JSON string representation of the object.
23
+ """
24
+
25
+ # Apply a default configuration if not provided targeting a deflated format
26
+ json_configurations = json_configurations or {}
27
+ if "default" not in json_configurations:
28
+ json_configurations["default"] = _custom_serial
29
+ if "separators" not in json_configurations:
30
+ json_configurations["separators"] = (",", ":")
31
+
32
+ return json.dumps(
33
+ obj,
34
+ **json_configurations,
35
+ )
36
+
37
+
38
+ def serialize_json(obj: Union[dict, list], json_configurations: dict[str, Any] = None) -> str:
39
+ """
40
+ Serialize a Python object (dict or list) to a JSON string.
41
+
42
+ Parameters
43
+ ----------
44
+ obj : Union[dict, list]
45
+ The Python object to serialize.
46
+ json_configurations : dict, optional
47
+ Additional configurations for JSON serialization. This allows customization
48
+ of the Python `json.dumps` function. You can specify parameters like `indent`
49
+ for pretty printing or `default` for custom serialization functions.
50
+
51
+ Returns
52
+ -------
53
+ str
54
+ A JSON string representation of the object.
55
+ """
56
+
57
+ # Apply some default configuration if not provided
58
+ json_configurations = json_configurations or {}
59
+ if "default" not in json_configurations:
60
+ json_configurations["default"] = _custom_serial
61
+ if "indent" not in json_configurations:
62
+ json_configurations["indent"] = 2
63
+
64
+ return json.dumps(
65
+ obj,
66
+ **json_configurations,
67
+ )
68
+
69
+
70
+ def _custom_serial(obj: Any) -> str:
71
+ """
72
+ JSON serializer for objects not serializable by default json serializer.
73
+
74
+ This function provides custom serialization for datetime objects, converting
75
+ them to ISO format strings.
76
+
77
+ Parameters
78
+ ----------
79
+ obj : Any
80
+ The object to serialize.
81
+
82
+ Returns
83
+ -------
84
+ str
85
+ The serialized representation of the object.
86
+
87
+ Raises
88
+ ------
89
+ TypeError
90
+ If the object type is not supported for serialization.
91
+ """
92
+
93
+ if isinstance(obj, (datetime.datetime, datetime.date)):
94
+ return obj.isoformat()
95
+
96
+ raise TypeError(f"Type {type(obj)} not serializable")
@@ -33,6 +33,7 @@ from typing import Any, Optional, Union
33
33
 
34
34
  import requests
35
35
 
36
+ from nextmv._serialization import deflated_serialize_json
36
37
  from nextmv.base_model import BaseModel
37
38
  from nextmv.cloud import package
38
39
  from nextmv.cloud.acceptance_test import AcceptanceTest, ExperimentStatus, Metric
@@ -184,10 +185,12 @@ class PollingOptions:
184
185
  """
185
186
  max_delay: float = 20
186
187
  """Maximum delay to use between polls, in seconds."""
187
- max_duration: float = 300
188
- """Maximum duration of the polling strategy, in seconds."""
189
- max_tries: int = 100
190
- """Maximum number of tries to use."""
188
+ max_duration: float = -1
189
+ """
190
+ Maximum duration of the polling strategy, in seconds. A negative value means no limit.
191
+ """
192
+ max_tries: int = -1
193
+ """Maximum number of tries to use. A negative value means no limit."""
191
194
  jitter: float = 1
192
195
  """
193
196
  Jitter to use for the polling strategy. A uniform distribution is sampled
@@ -1490,6 +1493,7 @@ class Application:
1490
1493
  configuration: Optional[Union[RunConfiguration, dict[str, Any]]] = None,
1491
1494
  batch_experiment_id: Optional[str] = None,
1492
1495
  external_result: Optional[Union[ExternalRunResult, dict[str, Any]]] = None,
1496
+ json_configurations: Optional[dict[str, Any]] = None,
1493
1497
  ) -> str:
1494
1498
  """
1495
1499
  Submit an input to start a new run of the application. Returns the
@@ -1538,6 +1542,9 @@ class Application:
1538
1542
  configuration. This is used when the run is an external run. We
1539
1543
  suggest that instead of specifying this parameter, you use the
1540
1544
  `track_run` method of the class.
1545
+ json_configurations: Optional[dict[str, Any]]
1546
+ Optional configurations for JSON serialization. This is used to
1547
+ customize the serialization before data is sent.
1541
1548
 
1542
1549
  Returns
1543
1550
  ----------
@@ -1588,7 +1595,7 @@ class Application:
1588
1595
  if isinstance(v, str):
1589
1596
  options_dict[k] = v
1590
1597
  else:
1591
- options_dict[k] = json.dumps(v)
1598
+ options_dict[k] = deflated_serialize_json(v, json_configurations=json_configurations)
1592
1599
 
1593
1600
  payload = {}
1594
1601
  if upload_id_used:
@@ -1626,6 +1633,7 @@ class Application:
1626
1633
  endpoint=f"{self.endpoint}/runs",
1627
1634
  payload=payload,
1628
1635
  query_params=query_params,
1636
+ json_configurations=json_configurations,
1629
1637
  )
1630
1638
 
1631
1639
  return response.json()["run_id"]
@@ -2791,6 +2799,7 @@ class Application:
2791
2799
  self,
2792
2800
  input: Union[dict[str, Any], str],
2793
2801
  upload_url: UploadURL,
2802
+ json_configurations: Optional[dict[str, Any]] = None,
2794
2803
  ) -> None:
2795
2804
  """
2796
2805
  Upload large input data to the provided upload URL.
@@ -2806,6 +2815,9 @@ class Application:
2806
2815
  converted to JSON, or a pre-formatted JSON string.
2807
2816
  upload_url : UploadURL
2808
2817
  Upload URL object containing the pre-signed URL to use for uploading.
2818
+ json_configurations : Optional[dict[str, Any]], default=None
2819
+ Optional configurations for JSON serialization. If provided, these
2820
+ configurations will be used when serializing the data via `json.dumps`.
2809
2821
 
2810
2822
  Returns
2811
2823
  -------
@@ -2830,7 +2842,7 @@ class Application:
2830
2842
  """
2831
2843
 
2832
2844
  if isinstance(input, dict):
2833
- input = json.dumps(input)
2845
+ input = deflated_serialize_json(input, json_configurations=json_configurations)
2834
2846
 
2835
2847
  self.client.upload_to_presigned_url(
2836
2848
  url=upload_url.upload_url,
@@ -3174,7 +3186,11 @@ class Application:
3174
3186
  raise ValueError(f"Unknown scenario input type: {scenario.scenario_input.scenario_input_type}")
3175
3187
 
3176
3188
 
3177
- def poll(polling_options: PollingOptions, polling_func: Callable[[], tuple[Any, bool]]) -> Any:
3189
+ def poll( # noqa: C901
3190
+ polling_options: PollingOptions,
3191
+ polling_func: Callable[[], tuple[Any, bool]],
3192
+ __sleep_func: Callable[[float], None] = time.sleep,
3193
+ ) -> Any:
3178
3194
  """
3179
3195
  Poll a function until it succeeds or the polling strategy is exhausted.
3180
3196
 
@@ -3247,13 +3263,20 @@ def poll(polling_options: PollingOptions, polling_func: Callable[[], tuple[Any,
3247
3263
  if polling_options.verbose:
3248
3264
  log(f"polling | sleeping for initial delay: {polling_options.initial_delay}")
3249
3265
 
3250
- time.sleep(polling_options.initial_delay)
3266
+ __sleep_func(polling_options.initial_delay)
3251
3267
 
3252
3268
  start_time = time.time()
3253
3269
  stopped = False
3254
3270
 
3255
3271
  # Begin the polling process.
3256
- for ix in range(polling_options.max_tries):
3272
+ max_reached = False
3273
+ ix = 0
3274
+ while True:
3275
+ # Check if we reached the maximum number of tries. Break if so.
3276
+ if ix >= polling_options.max_tries and polling_options.max_tries >= 0:
3277
+ break
3278
+ ix += 1
3279
+
3257
3280
  # Check is we should stop polling according to the stop callback.
3258
3281
  if polling_options.stop is not None and polling_options.stop():
3259
3282
  stopped = True
@@ -3273,22 +3296,33 @@ def poll(polling_options: PollingOptions, polling_func: Callable[[], tuple[Any,
3273
3296
  if polling_options.verbose:
3274
3297
  log(f"polling | elapsed time: {passed}")
3275
3298
 
3276
- if passed >= polling_options.max_duration:
3299
+ if passed >= polling_options.max_duration and polling_options.max_duration >= 0:
3277
3300
  raise TimeoutError(
3278
3301
  f"polling did not succeed after {passed} seconds, exceeds max duration: {polling_options.max_duration}",
3279
3302
  )
3280
3303
 
3281
3304
  # Calculate the delay.
3282
- delay = polling_options.delay # Base
3283
- delay += polling_options.backoff * (2**ix) # Add exponential backoff.
3284
- delay += random.uniform(0, polling_options.jitter) # Add jitter.
3305
+ if max_reached:
3306
+ # If we already reached the maximum, we don't want to further calculate the
3307
+ # delay to avoid overflows.
3308
+ delay = polling_options.max_delay
3309
+ delay += random.uniform(0, polling_options.jitter) # Add jitter.
3310
+ else:
3311
+ delay = polling_options.delay # Base
3312
+ delay += polling_options.backoff * (2**ix) # Add exponential backoff.
3313
+ delay += random.uniform(0, polling_options.jitter) # Add jitter.
3314
+
3315
+ # We cannot exceed the max delay.
3316
+ if delay >= polling_options.max_delay:
3317
+ max_reached = True
3318
+ delay = polling_options.max_delay
3285
3319
 
3286
- # Sleep for the calculated delay. We cannot exceed the max delay.
3287
- sleep_duration = min(delay, polling_options.max_delay)
3320
+ # Sleep for the calculated delay.
3321
+ sleep_duration = delay
3288
3322
  if polling_options.verbose:
3289
3323
  log(f"polling | sleeping for duration: {sleep_duration}")
3290
3324
 
3291
- time.sleep(sleep_duration)
3325
+ __sleep_func(sleep_duration)
3292
3326
 
3293
3327
  if stopped:
3294
3328
  log("polling | stop condition met, stopping polling")
nextmv/cloud/client.py CHANGED
@@ -14,7 +14,6 @@ get_size(obj)
14
14
  Finds the size of an object in bytes.
15
15
  """
16
16
 
17
- import json
18
17
  import os
19
18
  from dataclasses import dataclass, field
20
19
  from typing import IO, Any, Optional, Union
@@ -24,6 +23,8 @@ import requests
24
23
  import yaml
25
24
  from requests.adapters import HTTPAdapter, Retry
26
25
 
26
+ from nextmv._serialization import deflated_serialize_json
27
+
27
28
  _MAX_LAMBDA_PAYLOAD_SIZE: int = 500 * 1024 * 1024
28
29
  """int: Maximum size of the payload handled by the Nextmv Cloud API.
29
30
 
@@ -199,6 +200,7 @@ class Client:
199
200
  headers: Optional[dict[str, str]] = None,
200
201
  payload: Optional[dict[str, Any]] = None,
201
202
  query_params: Optional[dict[str, Any]] = None,
203
+ json_configurations: Optional[dict[str, Any]] = None,
202
204
  ) -> requests.Response:
203
205
  """
204
206
  Makes a request to the Nextmv Cloud API.
@@ -221,6 +223,11 @@ class Client:
221
223
  provided.
222
224
  query_params : dict[str, Any], optional
223
225
  Query parameters to append to the request URL.
226
+ json_configurations : dict[str, Any], optional
227
+ Additional configurations for JSON serialization. This allows
228
+ customization of the Python `json.dumps` function, such as
229
+ specifying `indent` for pretty printing or `default` for custom
230
+ serialization functions.
224
231
 
225
232
  Returns
226
233
  -------
@@ -261,16 +268,19 @@ class Client:
261
268
  if payload is not None and data is not None:
262
269
  raise ValueError("cannot use both data and payload")
263
270
 
264
- if payload is not None and get_size(payload) > _MAX_LAMBDA_PAYLOAD_SIZE:
271
+ if (
272
+ payload is not None
273
+ and get_size(payload, json_configurations=json_configurations) > _MAX_LAMBDA_PAYLOAD_SIZE
274
+ ):
265
275
  raise ValueError(
266
- f"payload size of {get_size(payload)} bytes exceeds the maximum "
267
- f"allowed size of {_MAX_LAMBDA_PAYLOAD_SIZE} bytes"
276
+ f"payload size of {get_size(payload, json_configurations=json_configurations)} bytes exceeds "
277
+ + f"the maximum allowed size of {_MAX_LAMBDA_PAYLOAD_SIZE} bytes"
268
278
  )
269
279
 
270
- if data is not None and get_size(data) > _MAX_LAMBDA_PAYLOAD_SIZE:
280
+ if data is not None and get_size(data, json_configurations=json_configurations) > _MAX_LAMBDA_PAYLOAD_SIZE:
271
281
  raise ValueError(
272
- f"data size of {get_size(data)} bytes exceeds the maximum "
273
- f"allowed size of {_MAX_LAMBDA_PAYLOAD_SIZE} bytes"
282
+ f"data size of {get_size(data, json_configurations=json_configurations)} bytes exceeds "
283
+ + f"the maximum allowed size of {_MAX_LAMBDA_PAYLOAD_SIZE} bytes"
274
284
  )
275
285
 
276
286
  session = requests.Session()
@@ -293,7 +303,11 @@ class Client:
293
303
  if data is not None:
294
304
  kwargs["data"] = data
295
305
  if payload is not None:
296
- kwargs["json"] = payload
306
+ if isinstance(payload, (dict, list)):
307
+ data = deflated_serialize_json(payload, json_configurations=json_configurations)
308
+ kwargs["data"] = data
309
+ else:
310
+ raise ValueError("payload must be a dictionary or a list")
297
311
  if query_params is not None:
298
312
  kwargs["params"] = query_params
299
313
 
@@ -308,7 +322,9 @@ class Client:
308
322
 
309
323
  return response
310
324
 
311
- def upload_to_presigned_url(self, data: Union[dict[str, Any], str], url: str) -> None:
325
+ def upload_to_presigned_url(
326
+ self, data: Union[dict[str, Any], str], url: str, json_configurations: Optional[dict[str, Any]] = None
327
+ ) -> None:
312
328
  """
313
329
  Uploads data to a presigned URL.
314
330
 
@@ -323,6 +339,11 @@ class Client:
323
339
  as is.
324
340
  url : str
325
341
  The presigned URL to which the data will be uploaded.
342
+ json_configurations : dict[str, Any], optional
343
+ Additional configurations for JSON serialization. This allows
344
+ customization of the Python `json.dumps` function, such as
345
+ specifying `indent` for pretty printing or `default` for custom
346
+ serialization functions.
326
347
 
327
348
  Raises
328
349
  ------
@@ -341,7 +362,7 @@ class Client:
341
362
 
342
363
  upload_data: Optional[str] = None
343
364
  if isinstance(data, dict):
344
- upload_data = json.dumps(data, separators=(",", ":"))
365
+ upload_data = deflated_serialize_json(data, json_configurations=json_configurations)
345
366
  elif isinstance(data, str):
346
367
  upload_data = data
347
368
  else:
@@ -393,7 +414,7 @@ class Client:
393
414
  }
394
415
 
395
416
 
396
- def get_size(obj: Union[dict[str, Any], IO[bytes], str]) -> int:
417
+ def get_size(obj: Union[dict[str, Any], IO[bytes], str], json_configurations: Optional[dict[str, Any]] = None) -> int:
397
418
  """
398
419
  Finds the size of an object in bytes.
399
420
 
@@ -407,6 +428,11 @@ def get_size(obj: Union[dict[str, Any], IO[bytes], str]) -> int:
407
428
  - If a dict, it's converted to a JSON string.
408
429
  - If a file-like object (e.g., opened file), its size is read.
409
430
  - If a string, its UTF-8 encoded byte length is calculated.
431
+ json_configurations : dict[str, Any], optional
432
+ Additional configurations for JSON serialization. This allows
433
+ customization of the Python `json.dumps` function, such as specifying
434
+ `indent` for pretty printing or `default` for custom serialization
435
+ functions.
410
436
 
411
437
  Returns
412
438
  -------
@@ -436,7 +462,7 @@ def get_size(obj: Union[dict[str, Any], IO[bytes], str]) -> int:
436
462
  """
437
463
 
438
464
  if isinstance(obj, dict):
439
- obj_str = json.dumps(obj, separators=(",", ":"))
465
+ obj_str = deflated_serialize_json(obj, json_configurations=json_configurations)
440
466
  return len(obj_str.encode("utf-8"))
441
467
 
442
468
  elif hasattr(obj, "read"):
nextmv/cloud/run.py CHANGED
@@ -39,7 +39,6 @@ run_duration(start, end)
39
39
  Calculate the duration of a run in milliseconds.
40
40
  """
41
41
 
42
- import json
43
42
  from dataclasses import dataclass
44
43
  from datetime import datetime
45
44
  from enum import Enum
@@ -47,6 +46,7 @@ from typing import Any, Optional, Union
47
46
 
48
47
  from pydantic import AliasChoices, Field
49
48
 
49
+ from nextmv._serialization import serialize_json
50
50
  from nextmv.base_model import BaseModel
51
51
  from nextmv.cloud.status import Status, StatusV2
52
52
  from nextmv.input import Input, InputFormat
@@ -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
- _ = json.dumps(self.input)
631
+ _ = serialize_json(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
- _ = json.dumps(self.output)
640
+ _ = serialize_json(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
@@ -31,6 +31,7 @@ from dataclasses import dataclass
31
31
  from enum import Enum
32
32
  from typing import Any, Optional, Union
33
33
 
34
+ from nextmv._serialization import serialize_json
34
35
  from nextmv.deprecated import deprecated
35
36
  from nextmv.options import Options
36
37
 
@@ -139,7 +140,7 @@ class Input:
139
140
 
140
141
  if self.input_format == InputFormat.JSON:
141
142
  try:
142
- _ = json.dumps(self.data)
143
+ _ = serialize_json(self.data)
143
144
  except (TypeError, OverflowError) as e:
144
145
  raise ValueError(
145
146
  f"Input has input_format InputFormat.JSON and "
nextmv/output.py CHANGED
@@ -42,8 +42,6 @@ write
42
42
 
43
43
  import copy
44
44
  import csv
45
- import datetime
46
- import json
47
45
  import os
48
46
  import sys
49
47
  from dataclasses import dataclass
@@ -52,6 +50,7 @@ from typing import Any, Optional, Union
52
50
 
53
51
  from pydantic import AliasChoices, Field
54
52
 
53
+ from nextmv._serialization import serialize_json
55
54
  from nextmv.base_model import BaseModel
56
55
  from nextmv.deprecated import deprecated
57
56
  from nextmv.logger import reset_stdout
@@ -644,7 +643,7 @@ class Output:
644
643
 
645
644
  if self.output_format == OutputFormat.JSON:
646
645
  try:
647
- _ = json.dumps(self.solution, default=_custom_serial)
646
+ _ = serialize_json(self.solution)
648
647
  except (TypeError, OverflowError) as e:
649
648
  raise ValueError(
650
649
  f"Output has output_format OutputFormat.JSON and "
@@ -722,12 +721,6 @@ class Output:
722
721
  and self.csv_configurations != {}
723
722
  ):
724
723
  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
731
724
 
732
725
  return output_dict
733
726
 
@@ -822,19 +815,9 @@ class LocalOutputWriter(OutputWriter):
822
815
  if hasattr(output, "json_configurations") and output.json_configurations is not None:
823
816
  json_configurations = output.json_configurations
824
817
 
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(
818
+ serialized = serialize_json(
834
819
  output_dict,
835
- indent=indent,
836
- default=custom_serial,
837
- **json_configurations,
820
+ json_configurations=json_configurations,
838
821
  )
839
822
 
840
823
  if path is None or path == "":
@@ -877,13 +860,17 @@ class LocalOutputWriter(OutputWriter):
877
860
  if not os.path.exists(dir_path):
878
861
  os.makedirs(dir_path)
879
862
 
880
- serialized = json.dumps(
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(
881
868
  {
882
869
  "options": output_dict.get("options", {}),
883
870
  "statistics": output_dict.get("statistics", {}),
884
871
  "assets": output_dict.get("assets", []),
885
872
  },
886
- indent=2,
873
+ json_configurations=json_configurations,
887
874
  )
888
875
  print(serialized, file=sys.stdout)
889
876
 
@@ -1118,32 +1105,3 @@ def write(
1118
1105
  """
1119
1106
 
1120
1107
  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.2
3
+ Version: 0.28.3
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,30 +1,31 @@
1
- nextmv/__about__.py,sha256=OvqMjd7c71S8Psw9qFPqf0MJB6HAZ-JPZ4GnoCdn6SE,24
1
+ nextmv/__about__.py,sha256=KeNJEWNIu2f2CgksmFkebdssYW1RtZ62pr8Qi92VkVY,24
2
2
  nextmv/__entrypoint__.py,sha256=dA0iwwHtrq6Z9w9FxmxKLoBGLyhe7jWtUAU-Y3PEgHg,1094
3
3
  nextmv/__init__.py,sha256=3E3c3dk4hCR1IXDHZxFDDDK2NPEEO8utwdd9wZ0q6ys,1506
4
+ nextmv/_serialization.py,sha256=JlSl6BL0M2Esf7F89GsGIZ__Pp8RnFRNM0UxYhuuYU4,2853
4
5
  nextmv/base_model.py,sha256=qmJ4AsYr9Yv01HQX_BERrn3229gyoZrYyP9tcyqNfeU,2311
5
6
  nextmv/deprecated.py,sha256=kEVfyQ-nT0v2ePXTNldjQG9uH5IlfQVy3L4tztIxwmU,1638
6
- nextmv/input.py,sha256=PvSfWA0gv3djSNWkcuMj6Ux3tgXPCMNz17yvSuYx5Bs,21147
7
+ nextmv/input.py,sha256=AsOhaw4kjq692BsBBVE4v8JwOHrNbl5dbdnHyHjChd0,21200
7
8
  nextmv/logger.py,sha256=kNIbu46MisrzYe4T0hNMpWfRTKKacDVvbtQcNys_c_E,2513
8
9
  nextmv/model.py,sha256=ebL_Ta25ptaLkP1_PmPlLM2yh6dzA2e7KRjSJ8RZcOU,14614
9
10
  nextmv/options.py,sha256=8hIlTnMMqL12z7GGrR-igVOQVtx4FLtlEqDktoPOxTg,33226
10
- nextmv/output.py,sha256=7s0Io17I7VChQPfqakHj4F2vNV0CD-ANAbE4kqipOXM,37241
11
+ nextmv/output.py,sha256=bC_N_BSVOiIO3Tilmu-pWhsfoVPHz612oXCWLpVUS_8,36169
11
12
  nextmv/cloud/__init__.py,sha256=7BCh3z-XkbIcMvFHmbj2wA8OquIovjrAZL7O9kA9VZc,3868
12
13
  nextmv/cloud/acceptance_test.py,sha256=Bcfdmh2fkPeBx8FDCngeUo2fjV_LhsUdygnzDQCDbYY,26898
13
14
  nextmv/cloud/account.py,sha256=eukiYQha4U2fkIjg4SgdoawKE1kU5G7GPyDJVrn8hHA,6064
14
- nextmv/cloud/application.py,sha256=Wo4kHRfC2M1bZuv4FzuKLPo1-HJWKEUz38CK931jgUw,110256
15
+ nextmv/cloud/application.py,sha256=2DeJE21GXQhxp-aQsJktIOIZR5YzzQco9zBb_ZF8jm4,111813
15
16
  nextmv/cloud/batch_experiment.py,sha256=rD3m-ioE1G8ADYN7afzr7zlq-3H22TNlj9RAh-_ZqIo,7270
16
- nextmv/cloud/client.py,sha256=WxnIFZ4sx1yav5SVg9HCexfAqxdDABXkxuMVKjMauvg,15703
17
+ nextmv/cloud/client.py,sha256=YKrJMNx4d-NEtUZ2nUKS46QHldUdVkexJ7CmzbFLFS4,17360
17
18
  nextmv/cloud/input_set.py,sha256=2dqmf5z-rZjTKwtBRvnUdfPfKv28It5uTCX0C70uP4Y,4242
18
19
  nextmv/cloud/instance.py,sha256=SS4tbp0LQMWDaeYpwcNxJei82oi_Hozv1t5i3QGjASY,4024
19
20
  nextmv/cloud/manifest.py,sha256=KLdaHIfyCsjVjE0PXqAoVy4mRH-0KWf1b7TcEICdaJU,30541
20
21
  nextmv/cloud/package.py,sha256=RcS8X3rMDyQVv0IWmTEDbmaoDs5nPWoIFBfUgSTuAtA,13028
21
- nextmv/cloud/run.py,sha256=inXHWiDS4tUDOp_whvDCBaLCljVr4Br_RnZfmEpU58k,19438
22
+ nextmv/cloud/run.py,sha256=zRPYeceNiuBMEcu-XZ2TUESn982HAUWGrwC2t13zHMg,19483
22
23
  nextmv/cloud/safe.py,sha256=idifvV8P_79Zo2hIC_qxqZt9LUmD5TLQ9ikKwRUvd34,2522
23
24
  nextmv/cloud/scenario.py,sha256=JRFTDiFBcrgud6wE2qDHUu5oO-Ur3zbPYhhB6ONCxTo,14263
24
25
  nextmv/cloud/secrets.py,sha256=fA5cX0jfTsPVZWV7433wzETGlXpWRLHGswuObx9e6FQ,6820
25
26
  nextmv/cloud/status.py,sha256=blvykRCTCTBkaqH88j4dzdQLhU2v1Ig62-_va98zw20,2789
26
27
  nextmv/cloud/version.py,sha256=5_S7_pWUVBFbvAArku20eK7S645GJcHtgE2OpXLdSzQ,5300
27
- nextmv-0.28.2.dist-info/METADATA,sha256=6qQJh41B_pXGlYilPWKLnN6L3562DlhoLN8g5d_TTGU,15310
28
- nextmv-0.28.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
29
- nextmv-0.28.2.dist-info/licenses/LICENSE,sha256=ZIbK-sSWA-OZprjNbmJAglYRtl5_K4l9UwAV3PGJAPc,11349
30
- nextmv-0.28.2.dist-info/RECORD,,
28
+ nextmv-0.28.3.dist-info/METADATA,sha256=8Aoig9CZzsrTFjxY_I9PAEcSvJae45l3wypqQOW22pY,15310
29
+ nextmv-0.28.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
30
+ nextmv-0.28.3.dist-info/licenses/LICENSE,sha256=ZIbK-sSWA-OZprjNbmJAglYRtl5_K4l9UwAV3PGJAPc,11349
31
+ nextmv-0.28.3.dist-info/RECORD,,