nextmv 0.35.0.dev1__py3-none-any.whl → 0.36.0__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/manifest.py CHANGED
@@ -53,7 +53,7 @@ MANIFEST_FILE_NAME
53
53
 
54
54
  import os
55
55
  from enum import Enum
56
- from typing import Any, Optional, Union
56
+ from typing import Any
57
57
 
58
58
  import yaml
59
59
  from pydantic import AliasChoices, Field, field_validator
@@ -158,25 +158,17 @@ class ManifestRuntime(str, Enum):
158
158
  """
159
159
 
160
160
  DEFAULT = "ghcr.io/nextmv-io/runtime/default:latest"
161
- """This runtime is used to run compiled applications such as Go binaries."""
161
+ """A runtime used to run compiled applications such as Go binaries."""
162
162
  PYTHON = "ghcr.io/nextmv-io/runtime/python:3.11"
163
- """
164
- This runtime is used as the basis for all other Python runtimes and Python
165
- applications.
166
- """
163
+ """A runtime used to run standard Python applications."""
167
164
  JAVA = "ghcr.io/nextmv-io/runtime/java:latest"
168
- """This runtime is used to run Java applications."""
165
+ """A runtime used to run Java applications."""
169
166
  PYOMO = "ghcr.io/nextmv-io/runtime/pyomo:latest"
170
- """This runtime provisions Python packages to run Pyomo applications."""
171
- HEXALY = "ghcr.io/nextmv-io/runtime/hexaly:latest"
172
- """
173
- Based on the python runtime, it provisions (pre-installs) the Hexaly solver
174
- to run Python applications.
175
- """
167
+ """A runtime provisioning Python packages to run Pyomo applications."""
176
168
  CUOPT = "ghcr.io/nextmv-io/runtime/cuopt:latest"
177
- """
178
- A runtime providing the NVIDIA cuOpt solver.
179
- """
169
+ """A runtime providing the NVIDIA cuOpt solver."""
170
+ GAMSPY = "ghcr.io/nextmv-io/runtime/gamspy:latest"
171
+ """A runtime provisioning the GAMS Python API and supported solvers."""
180
172
 
181
173
 
182
174
  class ManifestPythonArch(str, Enum):
@@ -244,14 +236,14 @@ class ManifestBuild(BaseModel):
244
236
  'make build'
245
237
  """
246
238
 
247
- command: Optional[str] = None
239
+ command: str | None = None
248
240
  """The command to run to build the app.
249
241
 
250
242
  This command will be executed without a shell, i.e., directly. The command
251
243
  must exit with a status of 0 to continue the push process of the app to
252
244
  Nextmv Cloud. This command is executed prior to the pre-push command.
253
245
  """
254
- environment: Optional[dict[str, Any]] = None
246
+ environment: dict[str, Any] | None = None
255
247
  """Environment variables to set when running the build command.
256
248
 
257
249
  Given as key-value pairs.
@@ -317,7 +309,7 @@ class ManifestPythonModel(BaseModel):
317
309
 
318
310
  name: str
319
311
  """The name of the decision model."""
320
- options: Optional[list[dict[str, Any]]] = None
312
+ options: list[dict[str, Any]] | None = None
321
313
  """
322
314
  Options for the decision model. This is a data representation of the
323
315
  `nextmv.Options` class. It consists of a list of dicts. Each dict
@@ -359,7 +351,7 @@ class ManifestPython(BaseModel):
359
351
  'requirements.txt'
360
352
  """
361
353
 
362
- pip_requirements: Optional[Union[str, list[str]]] = Field(
354
+ pip_requirements: str | list[str] | None = Field(
363
355
  serialization_alias="pip-requirements",
364
356
  validation_alias=AliasChoices("pip-requirements", "pip_requirements"),
365
357
  default=None,
@@ -371,16 +363,16 @@ class ManifestPython(BaseModel):
371
363
  app. Can be either a string path to a requirements.txt file or a list
372
364
  of package specifications.
373
365
  """
374
- arch: Optional[ManifestPythonArch] = None
366
+ arch: ManifestPythonArch | None = None
375
367
  """
376
368
  The architecture this model is meant to run on. One of "arm64" or "amd64". Uses
377
369
  "arm64" if not specified.
378
370
  """
379
- version: Optional[Union[str, float]] = None
371
+ version: str | float | None = None
380
372
  """
381
373
  The Python version this model is meant to run with. Uses "3.11" if not specified.
382
374
  """
383
- model: Optional[ManifestPythonModel] = None
375
+ model: ManifestPythonModel | None = None
384
376
  """
385
377
  Information about an encoded decision model.
386
378
 
@@ -390,7 +382,7 @@ class ManifestPython(BaseModel):
390
382
 
391
383
  @field_validator("version", mode="before")
392
384
  @classmethod
393
- def validate_version(cls, v: Optional[Union[str, float]]) -> Optional[str]:
385
+ def validate_version(cls, v: str | float | None) -> str | None:
394
386
  """
395
387
  Validate and convert the Python version field to a string.
396
388
 
@@ -461,11 +453,11 @@ class ManifestOptionUI(BaseModel):
461
453
  'input'
462
454
  """
463
455
 
464
- control_type: Optional[str] = None
456
+ control_type: str | None = None
465
457
  """The type of control to use for the option in the Nextmv Cloud UI."""
466
- hidden_from: Optional[list[str]] = None
458
+ hidden_from: list[str] | None = None
467
459
  """A list of team roles for which this option will be hidden in the UI."""
468
- display_name: Optional[str] = None
460
+ display_name: str | None = None
469
461
  """An optional display name for the option. This is useful for making
470
462
  the option more user-friendly in the UI.
471
463
  """
@@ -529,15 +521,15 @@ class ManifestOption(BaseModel):
529
521
  )
530
522
  """The type of the option (e.g., "string", "int", "bool", "float)."""
531
523
 
532
- default: Optional[Any] = None
524
+ default: Any | None = None
533
525
  """The default value of the option"""
534
- description: Optional[str] = ""
526
+ description: str | None = ""
535
527
  """The description of the option"""
536
528
  required: bool = False
537
529
  """Whether the option is required or not"""
538
- additional_attributes: Optional[dict[str, Any]] = None
530
+ additional_attributes: dict[str, Any] | None = None
539
531
  """Optional additional attributes for the option."""
540
- ui: Optional[ManifestOptionUI] = None
532
+ ui: ManifestOptionUI | None = None
541
533
  """Optional UI attributes for the option."""
542
534
 
543
535
  @classmethod
@@ -727,16 +719,16 @@ class ManifestOptions(BaseModel):
727
719
  2
728
720
  """
729
721
 
730
- strict: Optional[bool] = False
722
+ strict: bool | None = False
731
723
  """If strict is set to `True`, only the listed options will be allowed."""
732
- validation: Optional[ManifestValidation] = None
724
+ validation: ManifestValidation | None = None
733
725
  """Optional validation rules for all options."""
734
- items: Optional[list[ManifestOption]] = None
726
+ items: list[ManifestOption] | None = None
735
727
  """The actual list of options for the decision model.
736
728
 
737
729
  An option is a parameter that configures the decision model.
738
730
  """
739
- format: Optional[list[str]] = None
731
+ format: list[str] | None = None
740
732
  """A list of strings that define how options are transformed into command line arguments.
741
733
 
742
734
  Use `{{name}}` to refer to the option name and `{{value}}` to refer to the option value.
@@ -749,7 +741,7 @@ class ManifestOptions(BaseModel):
749
741
  cls,
750
742
  options: Options,
751
743
  validation: OptionsEnforcement = None,
752
- format: Optional[list[str]] = None,
744
+ format: list[str] | None = None,
753
745
  ) -> "ManifestOptions":
754
746
  """
755
747
  Create a `ManifestOptions` from a `nextmv.Options`.
@@ -853,11 +845,11 @@ class ManifestContentMultiFileOutput(BaseModel):
853
845
  'my-outputs/statistics.json'
854
846
  """
855
847
 
856
- statistics: Optional[str] = ""
848
+ statistics: str | None = ""
857
849
  """The path to the statistics file."""
858
- assets: Optional[str] = ""
850
+ assets: str | None = ""
859
851
  """The path to the assets file."""
860
- solutions: Optional[str] = ""
852
+ solutions: str | None = ""
861
853
  """The path to the solutions directory."""
862
854
 
863
855
 
@@ -942,7 +934,7 @@ class ManifestContent(BaseModel):
942
934
  The format of the content. Can only be `InputFormat.JSON`,
943
935
  `InputFormat.MULTI_FILE`, or `InputFormat.CSV_ARCHIVE`.
944
936
  """
945
- multi_file: Optional[ManifestContentMultiFile] = Field(
937
+ multi_file: ManifestContentMultiFile | None = Field(
946
938
  serialization_alias="multi-file",
947
939
  validation_alias=AliasChoices("multi-file", "multi_file"),
948
940
  default=None,
@@ -1001,12 +993,46 @@ class ManifestConfiguration(BaseModel):
1001
993
  'debug_mode'
1002
994
  """
1003
995
 
1004
- options: Optional[ManifestOptions] = None
996
+ options: ManifestOptions | None = None
1005
997
  """Options for the decision model."""
1006
- content: Optional[ManifestContent] = None
998
+ content: ManifestContent | None = None
1007
999
  """Content configuration for specifying how the app input/output is handled."""
1008
1000
 
1009
1001
 
1002
+ class ManifestExecution(BaseModel):
1003
+ """
1004
+ Execution configuration for the decision model.
1005
+
1006
+ You can import the `ManifestExecution` class directly from `nextmv`:
1007
+
1008
+ ```python
1009
+ from nextmv import ManifestExecution
1010
+ ```
1011
+
1012
+ Parameters
1013
+ ----------
1014
+ entrypoint : Optional[str], default=None
1015
+ The entrypoint for the decision model, e.g.: `./app.py`.
1016
+ cwd : Optional[str], default=None
1017
+ The working directory to set when running the app, e.g.: `./src/`.
1018
+
1019
+ Examples
1020
+ --------
1021
+ >>> from nextmv import ManifestExecution
1022
+ >>> exec_config = ManifestExecution(
1023
+ ... entrypoint="./app.py",
1024
+ ... cwd="./src/"
1025
+ ... )
1026
+ >>> exec_config.entrypoint
1027
+ './app.py'
1028
+ """
1029
+
1030
+ entrypoint: str | None = None
1031
+ """The entrypoint for the decision model, e.g.: `./app.py`."""
1032
+ cwd: str | None = None
1033
+ """The working directory to set when running the app, e.g.: `./src/`."""
1034
+
1035
+
1010
1036
  class Manifest(BaseModel):
1011
1037
  """
1012
1038
  Represents an app manifest (`app.yaml`) for Nextmv Cloud.
@@ -1084,7 +1110,7 @@ class Manifest(BaseModel):
1084
1110
  The runtime to use for the app. It provides the environment in which the
1085
1111
  app runs. This is mandatory.
1086
1112
  """
1087
- python: Optional[ManifestPython] = None
1113
+ python: ManifestPython | None = None
1088
1114
  """
1089
1115
  Python-specific attributes. Only for Python apps. Contains further
1090
1116
  Python-specific attributes.
@@ -1093,12 +1119,12 @@ class Manifest(BaseModel):
1093
1119
  default_factory=list,
1094
1120
  )
1095
1121
  """The files to include (or exclude) in the app. This is mandatory."""
1096
- configuration: Optional[ManifestConfiguration] = None
1122
+ configuration: ManifestConfiguration | None = None
1097
1123
  """
1098
1124
  Configuration for the decision model. A list of options for the decision
1099
1125
  model. An option is a parameter that configures the decision model.
1100
1126
  """
1101
- build: Optional[ManifestBuild] = None
1127
+ build: ManifestBuild | None = None
1102
1128
  """
1103
1129
  Build-specific attributes.
1104
1130
 
@@ -1109,7 +1135,7 @@ class Manifest(BaseModel):
1109
1135
  set environment variables when running the build command given as key-value
1110
1136
  pairs.
1111
1137
  """
1112
- pre_push: Optional[str] = Field(
1138
+ pre_push: str | None = Field(
1113
1139
  serialization_alias="pre-push",
1114
1140
  validation_alias=AliasChoices("pre-push", "pre_push"),
1115
1141
  default=None,
@@ -1124,55 +1150,12 @@ class Manifest(BaseModel):
1124
1150
  process. This command is executed just before the app gets bundled and
1125
1151
  pushed (after the build command).
1126
1152
  """
1127
- entrypoint: Optional[str] = None
1153
+ execution: ManifestExecution | None = None
1128
1154
  """
1129
- Optional entrypoint for the decision model. When not specified, the
1130
- following default entrypoints are used, according to the `.runtime`:
1131
-
1132
- - `ManifestRuntime.PYTHON`, `ManifestRuntime.HEXALY`, `ManifestRuntime.PYOMO`: `./main.py`
1133
- - `ManifestRuntime.DEFAULT`: `./main`
1134
- - Java: `./main.jar`
1155
+ Optional execution configuration for the decision model. Allows configuration of
1156
+ entrypoint and more.
1135
1157
  """
1136
1158
 
1137
- def model_post_init(self, __context) -> None:
1138
- """
1139
- Post-initialization to set default entrypoint based on runtime if not specified.
1140
-
1141
- This method is automatically called by Pydantic after the model is initialized.
1142
- If no entrypoint is provided, it sets a default entrypoint based on the runtime:
1143
- - Python runtimes (PYTHON, HEXALY, PYOMO, CUOPT): "./main.py"
1144
- - DEFAULT runtime: "./main"
1145
- - JAVA runtime: "./main.jar"
1146
-
1147
- Parameters
1148
- ----------
1149
- __context : Any
1150
- Pydantic context (unused in this implementation).
1151
-
1152
- Raises
1153
- ------
1154
- ValueError
1155
- If no entrypoint is provided and the runtime cannot be resolved to
1156
- establish a default entrypoint.
1157
- """
1158
- if self.entrypoint is None:
1159
- if self.runtime in (
1160
- ManifestRuntime.PYTHON,
1161
- ManifestRuntime.HEXALY,
1162
- ManifestRuntime.PYOMO,
1163
- ManifestRuntime.CUOPT,
1164
- ):
1165
- self.entrypoint = "./main.py"
1166
- elif self.runtime == ManifestRuntime.DEFAULT:
1167
- self.entrypoint = "./main"
1168
- elif self.runtime == ManifestRuntime.JAVA:
1169
- self.entrypoint = "./main.jar"
1170
- else:
1171
- raise ValueError(
1172
- f'entrypoint is not provided but the runtime "{self.runtime}" could not '
1173
- "be resolved to establish a default entrypoint"
1174
- )
1175
-
1176
1159
  @classmethod
1177
1160
  def from_yaml(cls, dirpath: str) -> "Manifest":
1178
1161
  """
@@ -1256,7 +1239,7 @@ class Manifest(BaseModel):
1256
1239
  width=120,
1257
1240
  )
1258
1241
 
1259
- def extract_options(self, should_parse: bool = True) -> Optional[Options]:
1242
+ def extract_options(self, should_parse: bool = True) -> Options | None:
1260
1243
  """
1261
1244
  Convert the manifest options to a `nextmv.Options` object.
1262
1245
 
@@ -1477,6 +1460,5 @@ def default_python_manifest() -> Manifest:
1477
1460
  type=ManifestType.PYTHON,
1478
1461
  python=ManifestPython(pip_requirements="requirements.txt"),
1479
1462
  )
1480
- m.entrypoint = None # TODO: change this when we are ready for the entrypoint.
1481
1463
 
1482
1464
  return m
nextmv/model.py CHANGED
@@ -20,7 +20,7 @@ import os
20
20
  import shutil
21
21
  import warnings
22
22
  from dataclasses import dataclass
23
- from typing import Any, Optional
23
+ from typing import Any
24
24
 
25
25
  from nextmv.input import Input
26
26
  from nextmv.logger import log
@@ -152,11 +152,11 @@ class ModelConfiguration:
152
152
 
153
153
  name: str
154
154
  """The name of the decision model."""
155
- requirements: Optional[list[str]] = None
155
+ requirements: list[str] | None = None
156
156
  """A list of Python dependencies that the decision model requires."""
157
- options: Optional[Options] = None
157
+ options: Options | None = None
158
158
  """Options that the decision model requires."""
159
- options_enforcement: Optional[OptionsEnforcement] = None
159
+ options_enforcement: OptionsEnforcement | None = None
160
160
  """Enforcement of options for the model."""
161
161
 
162
162
 
@@ -308,7 +308,7 @@ class Model:
308
308
  self,
309
309
  context,
310
310
  model_input,
311
- params: Optional[dict[str, Any]] = None,
311
+ params: dict[str, Any] | None = None,
312
312
  ) -> Any:
313
313
  """
314
314
  MLflow-compliant prediction method that calls the Nextmv model's solve method.
@@ -376,7 +376,7 @@ class Model:
376
376
 
377
377
  def _cleanup_python_model(
378
378
  model_dir: str,
379
- model_configuration: Optional[ModelConfiguration] = None,
379
+ model_configuration: ModelConfiguration | None = None,
380
380
  verbose: bool = False,
381
381
  ) -> None:
382
382
  """
nextmv/options.py CHANGED
@@ -21,7 +21,7 @@ import copy
21
21
  import json
22
22
  import os
23
23
  from dataclasses import dataclass
24
- from typing import Any, Optional, Union
24
+ from typing import Any
25
25
 
26
26
  from nextmv.base_model import BaseModel
27
27
  from nextmv.deprecated import deprecated
@@ -74,17 +74,17 @@ class Parameter:
74
74
  param_type: type
75
75
  """The type of the parameter."""
76
76
 
77
- default: Optional[Any] = None
77
+ default: Any | None = None
78
78
  """The default value of the parameter. Even though this is optional, it is
79
79
  recommended to provide a default value for all parameters."""
80
- description: Optional[str] = None
80
+ description: str | None = None
81
81
  """An optional description of the parameter. This is useful for generating
82
82
  help messages for the configuration."""
83
83
  required: bool = False
84
84
  """Whether the parameter is required. If a parameter is required, it will
85
85
  be an error to not provide a value for it, either trough a command-line
86
86
  argument, an environment variable or a default value."""
87
- choices: list[Optional[Any]] = None
87
+ choices: list[Any | None] = None
88
88
  """Limits values to a specific set of choices."""
89
89
 
90
90
  def __post_init__(self):
@@ -246,12 +246,12 @@ class Option:
246
246
  option_type: type
247
247
  """The type of the option."""
248
248
 
249
- default: Optional[Any] = None
249
+ default: Any | None = None
250
250
  """
251
251
  The default value of the option. Even though this is optional, it is
252
252
  recommended to provide a default value for all options.
253
253
  """
254
- description: Optional[str] = None
254
+ description: str | None = None
255
255
  """
256
256
  An optional description of the option. This is useful for generating help
257
257
  messages for the `Options`.
@@ -262,16 +262,16 @@ class Option:
262
262
  error to not provide a value for it, either trough a command-line argument,
263
263
  an environment variable or a default value.
264
264
  """
265
- choices: Optional[list[Any]] = None
265
+ choices: list[Any] | None = None
266
266
  """Limits values to a specific set of choices."""
267
- additional_attributes: Optional[dict[str, Any]] = None
267
+ additional_attributes: dict[str, Any] | None = None
268
268
  """
269
269
  Optional additional attributes for the option. The Nextmv Cloud may
270
270
  perform validation on these attributes. For example, the maximum length of
271
271
  a string or the maximum value of an integer. These additional attributes
272
272
  will be shown in the help message of the `Options`.
273
273
  """
274
- control_type: Optional[str] = None
274
+ control_type: str | None = None
275
275
  """
276
276
  The type of control to use for the option in the Nextmv Cloud UI. This is
277
277
  useful for defining how the option should be presented in the Nextmv
@@ -281,13 +281,13 @@ class Option:
281
281
  the option. This will be validated by the Nextmv Cloud, and availability
282
282
  is based on options_type.
283
283
  """
284
- hidden_from: Optional[list[str]] = None
284
+ hidden_from: list[str] | None = None
285
285
  """
286
286
  A list of team roles for which this option will be hidden in the UI. For
287
287
  example, if you want to hide an option from the "operator" role, you can
288
288
  pass `hidden_from=["operator"]`.
289
289
  """
290
- display_name: Optional[str] = None
290
+ display_name: str | None = None
291
291
  """
292
292
  An optional display name for the option. This is useful for making
293
293
  the option more user-friendly in the UI.
@@ -1032,7 +1032,7 @@ class Options:
1032
1032
  return False
1033
1033
 
1034
1034
  @staticmethod
1035
- def _option_type(option: Union[Option, Parameter]) -> type:
1035
+ def _option_type(option: Option | Parameter) -> type:
1036
1036
  """
1037
1037
  Get the type of an option.
1038
1038