nextmv 0.34.0.dev3__py3-none-any.whl → 0.34.1.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.34.0.dev3"
1
+ __version__ = "v0.34.1.dev1"
@@ -892,9 +892,6 @@ class Application:
892
892
  Auxiliary function to validate the directory path and configuration.
893
893
  """
894
894
 
895
- if input_dir_path is None or input_dir_path == "":
896
- return
897
-
898
895
  if configuration is None:
899
896
  if self.manifest.configuration is not None and self.manifest.configuration.content is not None:
900
897
  configuration = RunConfiguration(
@@ -904,18 +901,21 @@ class Application:
904
901
  ),
905
902
  ),
906
903
  )
907
- else:
908
- raise ValueError(
909
- "If `dir_path` is provided, either a `RunConfiguration` must also be provided or "
910
- "the application's manifest (app.yaml) must include the format under "
911
- "`configuration.content.format`.",
912
- )
913
-
914
- # Forcefully turn the configuration into a RunConfiguration object to
915
- # make it easier to deal with in the other functions.
916
- if isinstance(configuration, dict):
904
+ elif isinstance(configuration, dict):
905
+ # Forcefully turn the configuration into a RunConfiguration object to
906
+ # make it easier to deal with in the other functions.
917
907
  configuration = RunConfiguration.from_dict(configuration)
918
908
 
909
+ if input_dir_path is None or input_dir_path == "":
910
+ return configuration
911
+
912
+ if configuration is None:
913
+ raise ValueError(
914
+ "If `dir_path` is provided, either a `RunConfiguration` must also be provided or "
915
+ "the application's manifest (app.yaml) must include the format under "
916
+ "`configuration.content.format`.",
917
+ )
918
+
919
919
  config_format = configuration.format
920
920
  if config_format is None:
921
921
  raise ValueError(
nextmv/manifest.py CHANGED
@@ -11,6 +11,8 @@ ManifestType
11
11
  Enum for application types based on programming language.
12
12
  ManifestRuntime
13
13
  Enum for runtime environments where apps run on Nextmv.
14
+ ManifestPythonArch
15
+ Enum for target architecture for bundling Python apps.
14
16
  ManifestBuild
15
17
  Class for build-specific attributes in the manifest.
16
18
  ManifestPythonModel
@@ -38,6 +40,11 @@ ManifestConfiguration
38
40
  Manifest
39
41
  Main class representing an app manifest for Nextmv.
40
42
 
43
+ Functions
44
+ ---------
45
+ default_python_manifest
46
+ Creates a default Python manifest as a starting point for applications.
47
+
41
48
  Constants
42
49
  --------
43
50
  MANIFEST_FILE_NAME
@@ -331,7 +338,7 @@ class ManifestPython(BaseModel):
331
338
 
332
339
  Parameters
333
340
  ----------
334
- pip_requirements : Optional[str], default=None
341
+ pip_requirements : Optional[Union[str, list[str]]], default=None
335
342
  Path to a requirements.txt file containing (additional) Python
336
343
  dependencies that will be bundled with the app. Alternatively, you can provide a
337
344
  list of strings, each representing a package to install, e.g.,
@@ -358,10 +365,11 @@ class ManifestPython(BaseModel):
358
365
  default=None,
359
366
  )
360
367
  """
361
- Path to a requirements.txt file.
368
+ Path to a requirements.txt file or list of packages.
362
369
 
363
370
  Contains (additional) Python dependencies that will be bundled with the
364
- app.
371
+ app. Can be either a string path to a requirements.txt file or a list
372
+ of package specifications.
365
373
  """
366
374
  arch: Optional[ManifestPythonArch] = None
367
375
  """
@@ -383,6 +391,31 @@ class ManifestPython(BaseModel):
383
391
  @field_validator("version", mode="before")
384
392
  @classmethod
385
393
  def validate_version(cls, v: Optional[Union[str, float]]) -> Optional[str]:
394
+ """
395
+ Validate and convert the Python version field to a string.
396
+
397
+ This validator allows the version to be specified as either a float or string
398
+ in the manifest for convenience, but ensures it's stored internally as a string.
399
+
400
+ Parameters
401
+ ----------
402
+ v : Optional[Union[str, float]]
403
+ The version value to validate. Can be None, a string, or a float.
404
+
405
+ Returns
406
+ -------
407
+ Optional[str]
408
+ The version as a string, or None if the input was None.
409
+
410
+ Examples
411
+ --------
412
+ >>> ManifestPython.validate_version(3.11)
413
+ '3.11'
414
+ >>> ManifestPython.validate_version("3.11")
415
+ '3.11'
416
+ >>> ManifestPython.validate_version(None) is None
417
+ True
418
+ """
386
419
  # We allow the version to be a float in the manifest for convenience, but we want
387
420
  # to store it as a string internally.
388
421
  if v is None:
@@ -917,7 +950,23 @@ class ManifestContent(BaseModel):
917
950
  """Configuration for multi-file content format."""
918
951
 
919
952
  def model_post_init(self, __context) -> None:
920
- """Post-initialization to validate fields."""
953
+ """
954
+ Post-initialization validation to ensure format field contains valid values.
955
+
956
+ This method is automatically called by Pydantic after the model is initialized
957
+ to validate that the format field contains one of the acceptable values.
958
+
959
+ Parameters
960
+ ----------
961
+ __context : Any
962
+ Pydantic context (unused in this implementation).
963
+
964
+ Raises
965
+ ------
966
+ ValueError
967
+ If the format field contains an invalid value that is not one of the
968
+ acceptable formats (JSON, MULTI_FILE, or CSV_ARCHIVE).
969
+ """
921
970
  acceptable_formats = [InputFormat.JSON, InputFormat.MULTI_FILE, InputFormat.CSV_ARCHIVE]
922
971
  if self.format not in acceptable_formats:
923
972
  raise ValueError(f"Invalid format: {self.format}. Must be one of {acceptable_formats}.")
@@ -1084,6 +1133,26 @@ class Manifest(BaseModel):
1084
1133
  """
1085
1134
 
1086
1135
  def model_post_init(self, __context) -> None:
1136
+ """
1137
+ Post-initialization to set default entrypoint based on runtime if not specified.
1138
+
1139
+ This method is automatically called by Pydantic after the model is initialized.
1140
+ If no entrypoint is provided, it sets a default entrypoint based on the runtime:
1141
+ - Python runtimes (PYTHON, HEXALY, PYOMO, CUOPT): "./main.py"
1142
+ - DEFAULT runtime: "./main"
1143
+ - JAVA runtime: "./main.jar"
1144
+
1145
+ Parameters
1146
+ ----------
1147
+ __context : Any
1148
+ Pydantic context (unused in this implementation).
1149
+
1150
+ Raises
1151
+ ------
1152
+ ValueError
1153
+ If no entrypoint is provided and the runtime cannot be resolved to
1154
+ establish a default entrypoint.
1155
+ """
1087
1156
  if self.entrypoint is None:
1088
1157
  if self.runtime in (
1089
1158
  ManifestRuntime.PYTHON,
nextmv/run.py CHANGED
@@ -682,9 +682,10 @@ class Metadata(BaseModel):
682
682
  """Format of the input and output of the run."""
683
683
  status_v2: StatusV2
684
684
  """Status of the run."""
685
-
686
685
  status: Optional[Status] = None
687
686
  """Deprecated: use status_v2."""
687
+ statistics: Optional[dict[str, Any]] = None
688
+ """User defined statistics of the run."""
688
689
 
689
690
 
690
691
  class SyncedRun(BaseModel):
@@ -1560,9 +1561,9 @@ class TrackedRun:
1560
1561
 
1561
1562
  if isinstance(self.output, Output):
1562
1563
  try:
1563
- _ = serialize_json(self.output.data)
1564
+ _ = serialize_json(self.output.solution)
1564
1565
  except (TypeError, OverflowError) as e:
1565
- raise ValueError("Output.data is not JSON serializable") from e
1566
+ raise ValueError("`Output.solution` is not JSON serializable") from e
1566
1567
  elif isinstance(self.output, dict):
1567
1568
  try:
1568
1569
  _ = serialize_json(self.output)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nextmv
3
- Version: 0.34.0.dev3
3
+ Version: 0.34.1.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://nextmv-py.docs.nextmv.io/en/latest/nextmv/
@@ -1,4 +1,4 @@
1
- nextmv/__about__.py,sha256=DsLmieJeEYDa6llfj0-ywyjDq25tl2JnmYHkfnN9tbY,29
1
+ nextmv/__about__.py,sha256=ZGBbtMaJiSvvLAdMgJfmujCziIm_-DL6wE87sRVCj-I,29
2
2
  nextmv/__entrypoint__.py,sha256=dA0iwwHtrq6Z9w9FxmxKLoBGLyhe7jWtUAU-Y3PEgHg,1094
3
3
  nextmv/__init__.py,sha256=C2f8MteVvvOX1Wj-0GFjfUt-0RzCT0zpLpLI2yyZQw8,3796
4
4
  nextmv/_serialization.py,sha256=JlSl6BL0M2Esf7F89GsGIZ__Pp8RnFRNM0UxYhuuYU4,2853
@@ -6,12 +6,12 @@ nextmv/base_model.py,sha256=qmJ4AsYr9Yv01HQX_BERrn3229gyoZrYyP9tcyqNfeU,2311
6
6
  nextmv/deprecated.py,sha256=kEVfyQ-nT0v2ePXTNldjQG9uH5IlfQVy3L4tztIxwmU,1638
7
7
  nextmv/input.py,sha256=m9sVfO9ZL3F5i1l8amEtlWlbkekyUP4C3y9DduHWGFs,40211
8
8
  nextmv/logger.py,sha256=kNIbu46MisrzYe4T0hNMpWfRTKKacDVvbtQcNys_c_E,2513
9
- nextmv/manifest.py,sha256=N4Te82rKgcqzlXIpFGH-JX8JHDVW9sd7NoDvy9zZI6U,46859
9
+ nextmv/manifest.py,sha256=vo4GJk2yF6-6cA1M5YrynlXKqupH2vQE7HByph6ne4k,49256
10
10
  nextmv/model.py,sha256=vI3pSV3iTwjRPflar7nAg-6h98XRUyi9II5O2J06-Kc,15018
11
11
  nextmv/options.py,sha256=yPJu5lYMbV6YioMwAXv7ctpZUggLXKlZc9CqIbUFvE4,37895
12
12
  nextmv/output.py,sha256=HdvWYG3gIzwoXquulaEVI4LLchXJDjkbag0BkBPM0vQ,55128
13
13
  nextmv/polling.py,sha256=nfefvWI1smm-lIzaXE-4DMlojp6KXIvVi88XLJYUmo8,9724
14
- nextmv/run.py,sha256=8B9hh-jWJpoMSJiDmgmXaqvmzTicWCn75UTJu7Nf7Cs,52401
14
+ nextmv/run.py,sha256=DcVM67ot961RDeuP-jFqNj0Xq4uxXIap_hRNIdCAT_I,52504
15
15
  nextmv/safe.py,sha256=VAK4fGEurbLNji4Pg5Okga5XQSbI4aI9JJf95_68Z20,3867
16
16
  nextmv/status.py,sha256=SCDLhh2om3yeO5FxO0x-_RShQsZNXEpjHNdCGdb3VUI,2787
17
17
  nextmv/cloud/__init__.py,sha256=2wI72lhWq81BYv1OpS0OOTT5-3sivpX0H4z5ANPoLMc,5051
@@ -38,13 +38,13 @@ nextmv/default_app/src/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
38
38
  nextmv/default_app/src/main.py,sha256=WWeN_xl_mcPhICl3rSCvdEjRkFXGmAnej88FhS-fAmc,884
39
39
  nextmv/default_app/src/visuals.py,sha256=WYK_YBnLmYo3TpVev1CpoNCuW5R7hk9QIkeCmvMn1Fs,1014
40
40
  nextmv/local/__init__.py,sha256=6BsoqlK4dw6X11_uKzz9gBPfxKpdiol2FYO8R3X73SE,116
41
- nextmv/local/application.py,sha256=ZANcQFa8x-hBeCAQmFRAVZcEUXRqnGOPYqmJLV5GdaE,46982
41
+ nextmv/local/application.py,sha256=yJDlbQB_mh29Y541Mt6a6zyT3XutdtzjqSd0mlOeteo,47002
42
42
  nextmv/local/executor.py,sha256=7rxVkpyZ4GyTH7hjJX7rdM0hCo7_fSqX4EiA8YHZpC8,36624
43
43
  nextmv/local/geojson_handler.py,sha256=7FavJdkUonop-yskjis0x3qFGB8A5wZyoBUblw-bVhw,12540
44
44
  nextmv/local/local.py,sha256=cp56UpI8h19Ob6Jvb_Ni0ceXH5Vv3ET_iPTDe6ftq3Y,2617
45
45
  nextmv/local/plotly_handler.py,sha256=bLb50e3AkVr_W-F6S7lXfeRdN60mG2jk3UElNmhoMWU,1930
46
46
  nextmv/local/runner.py,sha256=hwkITHrQG_J9TzxufnaP1mjLWG-iSsNQD66UFZY4pp4,8602
47
- nextmv-0.34.0.dev3.dist-info/METADATA,sha256=6K9eoJKvAufPITu_j0f0dlfMIMUNSKu0KEUcS_OJhk8,16013
48
- nextmv-0.34.0.dev3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
49
- nextmv-0.34.0.dev3.dist-info/licenses/LICENSE,sha256=ZIbK-sSWA-OZprjNbmJAglYRtl5_K4l9UwAV3PGJAPc,11349
50
- nextmv-0.34.0.dev3.dist-info/RECORD,,
47
+ nextmv-0.34.1.dev1.dist-info/METADATA,sha256=YvwqMKKdytHQm9fZ4XqHwUZhMeXyzrUCBHScAwGo5tI,16013
48
+ nextmv-0.34.1.dev1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
49
+ nextmv-0.34.1.dev1.dist-info/licenses/LICENSE,sha256=ZIbK-sSWA-OZprjNbmJAglYRtl5_K4l9UwAV3PGJAPc,11349
50
+ nextmv-0.34.1.dev1.dist-info/RECORD,,