nextmv 0.28.3.dev0__py3-none-any.whl → 0.28.3.dev2__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.dev2"
@@ -3,12 +3,9 @@ import json
3
3
  from typing import Any, Union
4
4
 
5
5
 
6
- def serialize_json(
7
- obj: Union[dict, list],
8
- json_configurations: dict[str, Any] = None,
9
- ) -> str:
6
+ def deflated_serialize_json(obj: Union[dict, list], json_configurations: dict[str, Any] = None) -> str:
10
7
  """
11
- Serialize a Python object (dict or list) to a JSON string.
8
+ Serialize a Python object (dict or list) to a JSON string with default configuration for a deflated format.
12
9
 
13
10
  Parameters
14
11
  ----------
@@ -25,7 +22,7 @@ def serialize_json(
25
22
  A JSON string representation of the object.
26
23
  """
27
24
 
28
- # Apply some default configuration if not provided
25
+ # Apply a default configuration if not provided targeting a deflated format
29
26
  json_configurations = json_configurations or {}
30
27
  if "default" not in json_configurations:
31
28
  json_configurations["default"] = _custom_serial
@@ -38,6 +35,38 @@ def serialize_json(
38
35
  )
39
36
 
40
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
+
41
70
  def _custom_serial(obj: Any) -> str:
42
71
  """
43
72
  JSON serializer for objects not serializable by default json serializer.
@@ -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
@@ -66,7 +67,6 @@ from nextmv.logger import log
66
67
  from nextmv.model import Model, ModelConfiguration
67
68
  from nextmv.options import Options
68
69
  from nextmv.output import Output
69
- from nextmv.serialization import serialize_json
70
70
 
71
71
  # Maximum size of the run input/output in bytes. This constant defines the
72
72
  # maximum allowed size for run inputs and outputs. When the size exceeds this
@@ -185,10 +185,12 @@ class PollingOptions:
185
185
  """
186
186
  max_delay: float = 20
187
187
  """Maximum delay to use between polls, in seconds."""
188
- max_duration: float = 300
189
- """Maximum duration of the polling strategy, in seconds."""
190
- max_tries: int = 100
191
- """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."""
192
194
  jitter: float = 1
193
195
  """
194
196
  Jitter to use for the polling strategy. A uniform distribution is sampled
@@ -1491,6 +1493,7 @@ class Application:
1491
1493
  configuration: Optional[Union[RunConfiguration, dict[str, Any]]] = None,
1492
1494
  batch_experiment_id: Optional[str] = None,
1493
1495
  external_result: Optional[Union[ExternalRunResult, dict[str, Any]]] = None,
1496
+ json_configurations: Optional[dict[str, Any]] = None,
1494
1497
  ) -> str:
1495
1498
  """
1496
1499
  Submit an input to start a new run of the application. Returns the
@@ -1539,6 +1542,9 @@ class Application:
1539
1542
  configuration. This is used when the run is an external run. We
1540
1543
  suggest that instead of specifying this parameter, you use the
1541
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.
1542
1548
 
1543
1549
  Returns
1544
1550
  ----------
@@ -1589,7 +1595,7 @@ class Application:
1589
1595
  if isinstance(v, str):
1590
1596
  options_dict[k] = v
1591
1597
  else:
1592
- options_dict[k] = serialize_json(v)
1598
+ options_dict[k] = deflated_serialize_json(v, json_configurations=json_configurations)
1593
1599
 
1594
1600
  payload = {}
1595
1601
  if upload_id_used:
@@ -1627,6 +1633,7 @@ class Application:
1627
1633
  endpoint=f"{self.endpoint}/runs",
1628
1634
  payload=payload,
1629
1635
  query_params=query_params,
1636
+ json_configurations=json_configurations,
1630
1637
  )
1631
1638
 
1632
1639
  return response.json()["run_id"]
@@ -2792,6 +2799,7 @@ class Application:
2792
2799
  self,
2793
2800
  input: Union[dict[str, Any], str],
2794
2801
  upload_url: UploadURL,
2802
+ json_configurations: Optional[dict[str, Any]] = None,
2795
2803
  ) -> None:
2796
2804
  """
2797
2805
  Upload large input data to the provided upload URL.
@@ -2807,6 +2815,9 @@ class Application:
2807
2815
  converted to JSON, or a pre-formatted JSON string.
2808
2816
  upload_url : UploadURL
2809
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`.
2810
2821
 
2811
2822
  Returns
2812
2823
  -------
@@ -2831,7 +2842,7 @@ class Application:
2831
2842
  """
2832
2843
 
2833
2844
  if isinstance(input, dict):
2834
- input = serialize_json(input)
2845
+ input = deflated_serialize_json(input, json_configurations=json_configurations)
2835
2846
 
2836
2847
  self.client.upload_to_presigned_url(
2837
2848
  url=upload_url.upload_url,
@@ -3175,7 +3186,11 @@ class Application:
3175
3186
  raise ValueError(f"Unknown scenario input type: {scenario.scenario_input.scenario_input_type}")
3176
3187
 
3177
3188
 
3178
- 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:
3179
3194
  """
3180
3195
  Poll a function until it succeeds or the polling strategy is exhausted.
3181
3196
 
@@ -3248,13 +3263,20 @@ def poll(polling_options: PollingOptions, polling_func: Callable[[], tuple[Any,
3248
3263
  if polling_options.verbose:
3249
3264
  log(f"polling | sleeping for initial delay: {polling_options.initial_delay}")
3250
3265
 
3251
- time.sleep(polling_options.initial_delay)
3266
+ __sleep_func(polling_options.initial_delay)
3252
3267
 
3253
3268
  start_time = time.time()
3254
3269
  stopped = False
3255
3270
 
3256
3271
  # Begin the polling process.
3257
- 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
+
3258
3280
  # Check is we should stop polling according to the stop callback.
3259
3281
  if polling_options.stop is not None and polling_options.stop():
3260
3282
  stopped = True
@@ -3274,22 +3296,33 @@ def poll(polling_options: PollingOptions, polling_func: Callable[[], tuple[Any,
3274
3296
  if polling_options.verbose:
3275
3297
  log(f"polling | elapsed time: {passed}")
3276
3298
 
3277
- if passed >= polling_options.max_duration:
3299
+ if passed >= polling_options.max_duration and polling_options.max_duration >= 0:
3278
3300
  raise TimeoutError(
3279
3301
  f"polling did not succeed after {passed} seconds, exceeds max duration: {polling_options.max_duration}",
3280
3302
  )
3281
3303
 
3282
3304
  # 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.
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
3286
3319
 
3287
- # Sleep for the calculated delay. We cannot exceed the max delay.
3288
- sleep_duration = min(delay, polling_options.max_delay)
3320
+ # Sleep for the calculated delay.
3321
+ sleep_duration = delay
3289
3322
  if polling_options.verbose:
3290
3323
  log(f"polling | sleeping for duration: {sleep_duration}")
3291
3324
 
3292
- time.sleep(sleep_duration)
3325
+ __sleep_func(sleep_duration)
3293
3326
 
3294
3327
  if stopped:
3295
3328
  log("polling | stop condition met, stopping polling")
nextmv/cloud/client.py CHANGED
@@ -23,7 +23,7 @@ import requests
23
23
  import yaml
24
24
  from requests.adapters import HTTPAdapter, Retry
25
25
 
26
- from nextmv.serialization import serialize_json
26
+ from nextmv._serialization import deflated_serialize_json
27
27
 
28
28
  _MAX_LAMBDA_PAYLOAD_SIZE: int = 500 * 1024 * 1024
29
29
  """int: Maximum size of the payload handled by the Nextmv Cloud API.
@@ -200,6 +200,7 @@ class Client:
200
200
  headers: Optional[dict[str, str]] = None,
201
201
  payload: Optional[dict[str, Any]] = None,
202
202
  query_params: Optional[dict[str, Any]] = None,
203
+ json_configurations: Optional[dict[str, Any]] = None,
203
204
  ) -> requests.Response:
204
205
  """
205
206
  Makes a request to the Nextmv Cloud API.
@@ -222,6 +223,11 @@ class Client:
222
223
  provided.
223
224
  query_params : dict[str, Any], optional
224
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.
225
231
 
226
232
  Returns
227
233
  -------
@@ -262,16 +268,19 @@ class Client:
262
268
  if payload is not None and data is not None:
263
269
  raise ValueError("cannot use both data and payload")
264
270
 
265
- 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
+ ):
266
275
  raise ValueError(
267
- f"payload size of {get_size(payload)} bytes exceeds the maximum "
268
- 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"
269
278
  )
270
279
 
271
- 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:
272
281
  raise ValueError(
273
- f"data size of {get_size(data)} bytes exceeds the maximum "
274
- 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"
275
284
  )
276
285
 
277
286
  session = requests.Session()
@@ -295,7 +304,7 @@ class Client:
295
304
  kwargs["data"] = data
296
305
  if payload is not None:
297
306
  if isinstance(payload, (dict, list)):
298
- data = serialize_json(payload)
307
+ data = deflated_serialize_json(payload, json_configurations=json_configurations)
299
308
  kwargs["data"] = data
300
309
  else:
301
310
  raise ValueError("payload must be a dictionary or a list")
@@ -313,7 +322,9 @@ class Client:
313
322
 
314
323
  return response
315
324
 
316
- 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:
317
328
  """
318
329
  Uploads data to a presigned URL.
319
330
 
@@ -328,6 +339,11 @@ class Client:
328
339
  as is.
329
340
  url : str
330
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.
331
347
 
332
348
  Raises
333
349
  ------
@@ -346,7 +362,7 @@ class Client:
346
362
 
347
363
  upload_data: Optional[str] = None
348
364
  if isinstance(data, dict):
349
- upload_data = serialize_json(data)
365
+ upload_data = deflated_serialize_json(data, json_configurations=json_configurations)
350
366
  elif isinstance(data, str):
351
367
  upload_data = data
352
368
  else:
@@ -398,7 +414,7 @@ class Client:
398
414
  }
399
415
 
400
416
 
401
- 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:
402
418
  """
403
419
  Finds the size of an object in bytes.
404
420
 
@@ -412,6 +428,11 @@ def get_size(obj: Union[dict[str, Any], IO[bytes], str]) -> int:
412
428
  - If a dict, it's converted to a JSON string.
413
429
  - If a file-like object (e.g., opened file), its size is read.
414
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.
415
436
 
416
437
  Returns
417
438
  -------
@@ -441,7 +462,7 @@ def get_size(obj: Union[dict[str, Any], IO[bytes], str]) -> int:
441
462
  """
442
463
 
443
464
  if isinstance(obj, dict):
444
- obj_str = serialize_json(obj)
465
+ obj_str = deflated_serialize_json(obj, json_configurations=json_configurations)
445
466
  return len(obj_str.encode("utf-8"))
446
467
 
447
468
  elif hasattr(obj, "read"):
nextmv/cloud/run.py CHANGED
@@ -46,11 +46,11 @@ from typing import Any, Optional, Union
46
46
 
47
47
  from pydantic import AliasChoices, Field
48
48
 
49
+ from nextmv._serialization import serialize_json
49
50
  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:
nextmv/input.py CHANGED
@@ -31,9 +31,9 @@ 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
- from nextmv.serialization import serialize_json
37
37
 
38
38
 
39
39
  class InputFormat(str, Enum):
nextmv/output.py CHANGED
@@ -50,11 +50,11 @@ from typing import Any, Optional, Union
50
50
 
51
51
  from pydantic import AliasChoices, Field
52
52
 
53
+ from nextmv._serialization import serialize_json
53
54
  from nextmv.base_model import BaseModel
54
55
  from nextmv.deprecated import deprecated
55
56
  from nextmv.logger import reset_stdout
56
57
  from nextmv.options import Options
57
- from nextmv.serialization import serialize_json
58
58
 
59
59
 
60
60
  class RunStatistics(BaseModel):
@@ -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.dev2
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,31 @@
1
- nextmv/__about__.py,sha256=5UvDgOpqeyt2cJW7GXHGUFo5DQevIOSEyedJAK3pbyY,29
1
+ nextmv/__about__.py,sha256=Wu8L-DqfNRj4H8AIqpDfmAljXF11zU1pllQgoZvuvpo,29
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=voThRVvzyMnNesq2TdHr8orFsXlybIcx9IUBVBMgVyc,21199
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=p4QBc5NEhvsmBhk4W-vr6SGfFK9a2S4IKuwBPr9a8mc,36168
11
- nextmv/serialization.py,sha256=j3Sh0jjexpXBqJXL5MixT8uh9Qmd4XIyem62iY1uEZA,1764
11
+ nextmv/output.py,sha256=bC_N_BSVOiIO3Tilmu-pWhsfoVPHz612oXCWLpVUS_8,36169
12
12
  nextmv/cloud/__init__.py,sha256=7BCh3z-XkbIcMvFHmbj2wA8OquIovjrAZL7O9kA9VZc,3868
13
13
  nextmv/cloud/acceptance_test.py,sha256=Bcfdmh2fkPeBx8FDCngeUo2fjV_LhsUdygnzDQCDbYY,26898
14
14
  nextmv/cloud/account.py,sha256=eukiYQha4U2fkIjg4SgdoawKE1kU5G7GPyDJVrn8hHA,6064
15
- nextmv/cloud/application.py,sha256=zkUP41vzNbDisvhZDaqAvNAvdX63R_EoY-Ebn_GLNiA,110312
15
+ nextmv/cloud/application.py,sha256=2DeJE21GXQhxp-aQsJktIOIZR5YzzQco9zBb_ZF8jm4,111813
16
16
  nextmv/cloud/batch_experiment.py,sha256=rD3m-ioE1G8ADYN7afzr7zlq-3H22TNlj9RAh-_ZqIo,7270
17
- nextmv/cloud/client.py,sha256=EGEYZbyxk5qTBVnA-DNIcYGcG_QH8REQVMuWNE585OM,15893
17
+ nextmv/cloud/client.py,sha256=YKrJMNx4d-NEtUZ2nUKS46QHldUdVkexJ7CmzbFLFS4,17360
18
18
  nextmv/cloud/input_set.py,sha256=2dqmf5z-rZjTKwtBRvnUdfPfKv28It5uTCX0C70uP4Y,4242
19
19
  nextmv/cloud/instance.py,sha256=SS4tbp0LQMWDaeYpwcNxJei82oi_Hozv1t5i3QGjASY,4024
20
20
  nextmv/cloud/manifest.py,sha256=KLdaHIfyCsjVjE0PXqAoVy4mRH-0KWf1b7TcEICdaJU,30541
21
21
  nextmv/cloud/package.py,sha256=RcS8X3rMDyQVv0IWmTEDbmaoDs5nPWoIFBfUgSTuAtA,13028
22
- nextmv/cloud/run.py,sha256=qxgk3JBW8PBHLliAmc0iBa_yxb1F_mSGxqr9IwJ6j5E,19482
22
+ nextmv/cloud/run.py,sha256=zRPYeceNiuBMEcu-XZ2TUESn982HAUWGrwC2t13zHMg,19483
23
23
  nextmv/cloud/safe.py,sha256=idifvV8P_79Zo2hIC_qxqZt9LUmD5TLQ9ikKwRUvd34,2522
24
24
  nextmv/cloud/scenario.py,sha256=JRFTDiFBcrgud6wE2qDHUu5oO-Ur3zbPYhhB6ONCxTo,14263
25
25
  nextmv/cloud/secrets.py,sha256=fA5cX0jfTsPVZWV7433wzETGlXpWRLHGswuObx9e6FQ,6820
26
26
  nextmv/cloud/status.py,sha256=blvykRCTCTBkaqH88j4dzdQLhU2v1Ig62-_va98zw20,2789
27
27
  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,,
28
+ nextmv-0.28.3.dev2.dist-info/METADATA,sha256=MBfOdi7SutcZfEm0lXKtyAt9ElmvULx-jhu8emz4qw8,15315
29
+ nextmv-0.28.3.dev2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
30
+ nextmv-0.28.3.dev2.dist-info/licenses/LICENSE,sha256=ZIbK-sSWA-OZprjNbmJAglYRtl5_K4l9UwAV3PGJAPc,11349
31
+ nextmv-0.28.3.dev2.dist-info/RECORD,,