nextmv 0.27.0__py3-none-any.whl → 0.28.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/__about__.py +1 -1
- nextmv/__init__.py +1 -0
- nextmv/base_model.py +52 -7
- nextmv/cloud/__init__.py +3 -0
- nextmv/cloud/acceptance_test.py +711 -20
- nextmv/cloud/account.py +152 -7
- nextmv/cloud/application.py +1213 -382
- nextmv/cloud/batch_experiment.py +133 -21
- nextmv/cloud/client.py +240 -46
- nextmv/cloud/input_set.py +96 -3
- nextmv/cloud/instance.py +89 -3
- nextmv/cloud/manifest.py +507 -131
- nextmv/cloud/package.py +2 -2
- nextmv/cloud/run.py +372 -41
- nextmv/cloud/safe.py +7 -7
- nextmv/cloud/scenario.py +205 -20
- nextmv/cloud/secrets.py +179 -6
- nextmv/cloud/status.py +95 -2
- nextmv/cloud/version.py +132 -4
- nextmv/deprecated.py +36 -2
- nextmv/input.py +298 -80
- nextmv/logger.py +71 -7
- nextmv/model.py +223 -56
- nextmv/options.py +281 -66
- nextmv/output.py +552 -159
- {nextmv-0.27.0.dist-info → nextmv-0.28.0.dist-info}/METADATA +1 -1
- nextmv-0.28.0.dist-info/RECORD +30 -0
- nextmv-0.27.0.dist-info/RECORD +0 -30
- {nextmv-0.27.0.dist-info → nextmv-0.28.0.dist-info}/WHEEL +0 -0
- {nextmv-0.27.0.dist-info → nextmv-0.28.0.dist-info}/licenses/LICENSE +0 -0
nextmv/cloud/manifest.py
CHANGED
|
@@ -1,4 +1,35 @@
|
|
|
1
|
-
"""Module with the logic for handling an app manifest.
|
|
1
|
+
"""Module with the logic for handling an app manifest.
|
|
2
|
+
|
|
3
|
+
This module provides classes and functions for managing Nextmv app manifests.
|
|
4
|
+
Manifest files (app.yaml) define how an application is built, run, and deployed
|
|
5
|
+
on the Nextmv Cloud platform.
|
|
6
|
+
|
|
7
|
+
Classes
|
|
8
|
+
-------
|
|
9
|
+
ManifestType
|
|
10
|
+
Enum for application types based on programming language.
|
|
11
|
+
ManifestRuntime
|
|
12
|
+
Enum for runtime environments where apps run on Nextmv Cloud.
|
|
13
|
+
ManifestBuild
|
|
14
|
+
Class for build-specific attributes in the manifest.
|
|
15
|
+
ManifestPythonModel
|
|
16
|
+
Class for model-specific instructions for Python apps.
|
|
17
|
+
ManifestPython
|
|
18
|
+
Class for Python-specific instructions in the manifest.
|
|
19
|
+
ManifestOption
|
|
20
|
+
Class representing an option for the decision model in the manifest.
|
|
21
|
+
ManifestOptions
|
|
22
|
+
Class containing a list of options for the decision model.
|
|
23
|
+
ManifestConfiguration
|
|
24
|
+
Class for configuration settings for the decision model.
|
|
25
|
+
Manifest
|
|
26
|
+
Main class representing an app manifest for Nextmv Cloud.
|
|
27
|
+
|
|
28
|
+
Constants
|
|
29
|
+
--------
|
|
30
|
+
FILE_NAME
|
|
31
|
+
Name of the app manifest file.
|
|
32
|
+
"""
|
|
2
33
|
|
|
3
34
|
import os
|
|
4
35
|
from enum import Enum
|
|
@@ -11,23 +42,53 @@ from nextmv.base_model import BaseModel
|
|
|
11
42
|
from nextmv.model import _REQUIREMENTS_FILE, ModelConfiguration
|
|
12
43
|
from nextmv.options import Option, Options
|
|
13
44
|
|
|
14
|
-
|
|
15
|
-
"""Name of the app manifest file.
|
|
45
|
+
MANIFEST_FILE_NAME = "app.yaml"
|
|
46
|
+
"""Name of the app manifest file.
|
|
47
|
+
|
|
48
|
+
This constant defines the standard filename for Nextmv app manifest files.
|
|
49
|
+
|
|
50
|
+
You can import the `FILE_NAME` constant directly from `cloud`:
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
from nextmv.cloud import FILE_NAME
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Notes
|
|
57
|
+
-----
|
|
58
|
+
All Nextmv applications must include an app.yaml file for proper deployment.
|
|
59
|
+
"""
|
|
16
60
|
|
|
17
61
|
|
|
18
62
|
class ManifestType(str, Enum):
|
|
19
63
|
"""
|
|
20
|
-
Type of application in the manifest, based on the programming
|
|
21
|
-
|
|
64
|
+
Type of application in the manifest, based on the programming language.
|
|
65
|
+
|
|
66
|
+
You can import the `ManifestType` class directly from `cloud`:
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from nextmv.cloud import ManifestType
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
This enum defines the supported programming languages for applications
|
|
73
|
+
that can be deployed on Nextmv Cloud.
|
|
22
74
|
|
|
23
75
|
Attributes
|
|
24
76
|
----------
|
|
25
|
-
PYTHON: str
|
|
26
|
-
Python format
|
|
27
|
-
GO: str
|
|
28
|
-
Go format
|
|
29
|
-
JAVA: str
|
|
30
|
-
Java format
|
|
77
|
+
PYTHON : str
|
|
78
|
+
Python format, used for Python applications.
|
|
79
|
+
GO : str
|
|
80
|
+
Go format, used for Go applications.
|
|
81
|
+
JAVA : str
|
|
82
|
+
Java format, used for Java applications.
|
|
83
|
+
|
|
84
|
+
Examples
|
|
85
|
+
--------
|
|
86
|
+
>>> from nextmv.cloud import ManifestType
|
|
87
|
+
>>> manifest_type = ManifestType.PYTHON
|
|
88
|
+
>>> manifest_type
|
|
89
|
+
<ManifestType.PYTHON: 'python'>
|
|
90
|
+
>>> str(manifest_type)
|
|
91
|
+
'python'
|
|
31
92
|
"""
|
|
32
93
|
|
|
33
94
|
PYTHON = "python"
|
|
@@ -42,19 +103,37 @@ class ManifestRuntime(str, Enum):
|
|
|
42
103
|
"""
|
|
43
104
|
Runtime (environment) where the app will be run on Nextmv Cloud.
|
|
44
105
|
|
|
106
|
+
You can import the `ManifestRuntime` class directly from `cloud`:
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
from nextmv.cloud import ManifestRuntime
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
This enum defines the supported runtime environments for applications
|
|
113
|
+
that can be deployed on Nextmv Cloud.
|
|
114
|
+
|
|
45
115
|
Attributes
|
|
46
116
|
----------
|
|
47
|
-
DEFAULT: str
|
|
117
|
+
DEFAULT : str
|
|
48
118
|
This runtime is used to run compiled applications such as Go binaries.
|
|
49
|
-
PYTHON: str
|
|
119
|
+
PYTHON : str
|
|
50
120
|
This runtime is used as the basis for all other Python runtimes and
|
|
51
121
|
Python applications.
|
|
52
|
-
JAVA: str
|
|
122
|
+
JAVA : str
|
|
53
123
|
This runtime is used to run Java applications.
|
|
54
|
-
PYOMO: str
|
|
124
|
+
PYOMO : str
|
|
55
125
|
This runtime provisions Python packages to run Pyomo applications.
|
|
56
|
-
HEXALY: str
|
|
126
|
+
HEXALY : str
|
|
57
127
|
This runtime provisions Python packages to run Hexaly applications.
|
|
128
|
+
|
|
129
|
+
Examples
|
|
130
|
+
--------
|
|
131
|
+
>>> from nextmv.cloud import ManifestRuntime
|
|
132
|
+
>>> runtime = ManifestRuntime.PYTHON
|
|
133
|
+
>>> runtime
|
|
134
|
+
<ManifestRuntime.PYTHON: 'ghcr.io/nextmv-io/runtime/python:3.11'>
|
|
135
|
+
>>> str(runtime)
|
|
136
|
+
'ghcr.io/nextmv-io/runtime/python:3.11'
|
|
58
137
|
"""
|
|
59
138
|
|
|
60
139
|
DEFAULT = "ghcr.io/nextmv-io/runtime/default:latest"
|
|
@@ -79,29 +158,45 @@ class ManifestBuild(BaseModel):
|
|
|
79
158
|
"""
|
|
80
159
|
Build-specific attributes.
|
|
81
160
|
|
|
82
|
-
|
|
161
|
+
You can import the `ManifestBuild` class directly from `cloud`:
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
from nextmv.cloud import ManifestBuild
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Parameters
|
|
83
168
|
----------
|
|
84
|
-
command: Optional[str]
|
|
169
|
+
command : Optional[str], default=None
|
|
85
170
|
The command to run to build the app. This command will be executed
|
|
86
171
|
without a shell, i.e., directly. The command must exit with a status of
|
|
87
172
|
0 to continue the push process of the app to Nextmv Cloud. This command
|
|
88
173
|
is executed prior to the pre-push command.
|
|
89
|
-
environment: Optional[dict[str, Any]]
|
|
174
|
+
environment : Optional[dict[str, Any]], default=None
|
|
90
175
|
Environment variables to set when running the build command given as
|
|
91
176
|
key-value pairs.
|
|
177
|
+
|
|
178
|
+
Examples
|
|
179
|
+
--------
|
|
180
|
+
>>> from nextmv.cloud import ManifestBuild
|
|
181
|
+
>>> build_config = ManifestBuild(
|
|
182
|
+
... command="make build",
|
|
183
|
+
... environment={"DEBUG": "true"}
|
|
184
|
+
... )
|
|
185
|
+
>>> build_config.command
|
|
186
|
+
'make build'
|
|
92
187
|
"""
|
|
93
188
|
|
|
94
189
|
command: Optional[str] = None
|
|
95
|
-
"""
|
|
96
|
-
|
|
97
|
-
a shell, i.e., directly. The command
|
|
98
|
-
continue the push process of the app to
|
|
99
|
-
executed prior to the pre-push command.
|
|
190
|
+
"""The command to run to build the app.
|
|
191
|
+
|
|
192
|
+
This command will be executed without a shell, i.e., directly. The command
|
|
193
|
+
must exit with a status of 0 to continue the push process of the app to
|
|
194
|
+
Nextmv Cloud. This command is executed prior to the pre-push command.
|
|
100
195
|
"""
|
|
101
196
|
environment: Optional[dict[str, Any]] = None
|
|
102
|
-
"""
|
|
103
|
-
|
|
104
|
-
key-value pairs.
|
|
197
|
+
"""Environment variables to set when running the build command.
|
|
198
|
+
|
|
199
|
+
Given as key-value pairs.
|
|
105
200
|
"""
|
|
106
201
|
|
|
107
202
|
def environment_to_dict(self) -> dict[str, str]:
|
|
@@ -111,8 +206,18 @@ class ManifestBuild(BaseModel):
|
|
|
111
206
|
Returns
|
|
112
207
|
-------
|
|
113
208
|
dict[str, str]
|
|
114
|
-
The environment variables as a dictionary.
|
|
115
|
-
|
|
209
|
+
The environment variables as a dictionary of string key-value pairs.
|
|
210
|
+
Returns an empty dictionary if no environment variables are set.
|
|
211
|
+
|
|
212
|
+
Examples
|
|
213
|
+
--------
|
|
214
|
+
>>> from nextmv.cloud import ManifestBuild
|
|
215
|
+
>>> build_config = ManifestBuild(environment={"COUNT": 1, "NAME": "test"})
|
|
216
|
+
>>> build_config.environment_to_dict()
|
|
217
|
+
{'COUNT': '1', 'NAME': 'test'}
|
|
218
|
+
>>> build_config_empty = ManifestBuild()
|
|
219
|
+
>>> build_config_empty.environment_to_dict()
|
|
220
|
+
{}
|
|
116
221
|
"""
|
|
117
222
|
|
|
118
223
|
if self.environment is None:
|
|
@@ -125,15 +230,31 @@ class ManifestPythonModel(BaseModel):
|
|
|
125
230
|
"""
|
|
126
231
|
Model-specific instructions for a Python app.
|
|
127
232
|
|
|
128
|
-
|
|
233
|
+
You can import the `ManifestPythonModel` class directly from `cloud`:
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
from nextmv.cloud import ManifestPythonModel
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Parameters
|
|
129
240
|
----------
|
|
130
|
-
name: str
|
|
241
|
+
name : str
|
|
131
242
|
The name of the decision model.
|
|
132
|
-
options: Optional[list[dict[str, Any]]]
|
|
243
|
+
options : Optional[list[dict[str, Any]]], default=None
|
|
133
244
|
Options for the decision model. This is a data representation of the
|
|
134
245
|
`nextmv.Options` class. It consists of a list of dicts. Each dict
|
|
135
246
|
represents the `nextmv.Option` class. It is used to be able to
|
|
136
247
|
reconstruct an Options object from data when loading a decision model.
|
|
248
|
+
|
|
249
|
+
Examples
|
|
250
|
+
--------
|
|
251
|
+
>>> from nextmv.cloud import ManifestPythonModel
|
|
252
|
+
>>> python_model_config = ManifestPythonModel(
|
|
253
|
+
... name="routing_model",
|
|
254
|
+
... options=[{"name": "max_vehicles", "type": "int", "default": 10}]
|
|
255
|
+
... )
|
|
256
|
+
>>> python_model_config.name
|
|
257
|
+
'routing_model'
|
|
137
258
|
"""
|
|
138
259
|
|
|
139
260
|
name: str
|
|
@@ -151,14 +272,31 @@ class ManifestPython(BaseModel):
|
|
|
151
272
|
"""
|
|
152
273
|
Python-specific instructions.
|
|
153
274
|
|
|
154
|
-
|
|
275
|
+
You can import the `ManifestPython` class directly from `cloud`:
|
|
276
|
+
|
|
277
|
+
```python
|
|
278
|
+
from nextmv.cloud import ManifestPython
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Parameters
|
|
155
282
|
----------
|
|
156
|
-
pip_requirements: Optional[str]
|
|
283
|
+
pip_requirements : Optional[str], default=None
|
|
157
284
|
Path to a requirements.txt file containing (additional) Python
|
|
158
285
|
dependencies that will be bundled with the app.
|
|
159
|
-
|
|
160
|
-
|
|
286
|
+
Aliases: `pip-requirements`.
|
|
287
|
+
model : Optional[ManifestPythonModel], default=None
|
|
288
|
+
Information about an encoded decision model as handled via mlflow. This
|
|
161
289
|
information is used to load the decision model from the app bundle.
|
|
290
|
+
|
|
291
|
+
Examples
|
|
292
|
+
--------
|
|
293
|
+
>>> from nextmv.cloud import ManifestPython, ManifestPythonModel
|
|
294
|
+
>>> python_config = ManifestPython(
|
|
295
|
+
... pip_requirements="requirements.txt",
|
|
296
|
+
... model=ManifestPythonModel(name="my_model")
|
|
297
|
+
... )
|
|
298
|
+
>>> python_config.pip_requirements
|
|
299
|
+
'requirements.txt'
|
|
162
300
|
"""
|
|
163
301
|
|
|
164
302
|
pip_requirements: Optional[str] = Field(
|
|
@@ -166,14 +304,16 @@ class ManifestPython(BaseModel):
|
|
|
166
304
|
validation_alias=AliasChoices("pip-requirements", "pip_requirements"),
|
|
167
305
|
default=None,
|
|
168
306
|
)
|
|
169
|
-
"""
|
|
170
|
-
|
|
171
|
-
dependencies that will be bundled with the
|
|
307
|
+
"""Path to a requirements.txt file.
|
|
308
|
+
|
|
309
|
+
Contains (additional) Python dependencies that will be bundled with the
|
|
310
|
+
app.
|
|
172
311
|
"""
|
|
173
312
|
model: Optional[ManifestPythonModel] = None
|
|
174
|
-
"""
|
|
175
|
-
|
|
176
|
-
information is used to load the decision model
|
|
313
|
+
"""Information about an encoded decision model.
|
|
314
|
+
|
|
315
|
+
As handled via mlflow. This information is used to load the decision model
|
|
316
|
+
from the app bundle.
|
|
177
317
|
"""
|
|
178
318
|
|
|
179
319
|
|
|
@@ -181,19 +321,44 @@ class ManifestOption(BaseModel):
|
|
|
181
321
|
"""
|
|
182
322
|
An option for the decision model that is recorded in the manifest.
|
|
183
323
|
|
|
184
|
-
|
|
324
|
+
You can import the `ManifestOption` class directly from `cloud`:
|
|
325
|
+
|
|
326
|
+
```python
|
|
327
|
+
from nextmv.cloud import ManifestOption
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
Parameters
|
|
185
331
|
----------
|
|
186
|
-
name: str
|
|
332
|
+
name : str
|
|
187
333
|
The name of the option.
|
|
188
|
-
option_type: str
|
|
334
|
+
option_type : str
|
|
189
335
|
The type of the option. This is a string representation of the
|
|
190
|
-
`nextmv.Option` class.
|
|
191
|
-
|
|
336
|
+
`nextmv.Option` class (e.g., "string", "int", "bool", "float").
|
|
337
|
+
Aliases: `type`.
|
|
338
|
+
default : Optional[Any], default=None
|
|
192
339
|
The default value of the option.
|
|
193
|
-
description: Optional[str]
|
|
340
|
+
description : Optional[str], default=""
|
|
194
341
|
The description of the option.
|
|
195
|
-
required: bool
|
|
342
|
+
required : bool, default=False
|
|
196
343
|
Whether the option is required or not.
|
|
344
|
+
additional_attributes : Optional[dict[str, Any]], default=None
|
|
345
|
+
Optional additional attributes for the option. The Nextmv Cloud may
|
|
346
|
+
perform validation on these attributes. For example, the maximum
|
|
347
|
+
length of a string or the maximum value of an integer. These
|
|
348
|
+
additional attributes will be shown in the help message of the
|
|
349
|
+
`Options`.
|
|
350
|
+
|
|
351
|
+
Examples
|
|
352
|
+
--------
|
|
353
|
+
>>> from nextmv.cloud import ManifestOption
|
|
354
|
+
>>> option = ManifestOption(
|
|
355
|
+
... name="solve.duration",
|
|
356
|
+
... option_type="string",
|
|
357
|
+
... default="30s",
|
|
358
|
+
... description="Maximum duration for the solver."
|
|
359
|
+
... )
|
|
360
|
+
>>> option.name
|
|
361
|
+
'solve.duration'
|
|
197
362
|
"""
|
|
198
363
|
|
|
199
364
|
name: str
|
|
@@ -202,7 +367,7 @@ class ManifestOption(BaseModel):
|
|
|
202
367
|
serialization_alias="type",
|
|
203
368
|
validation_alias=AliasChoices("type", "option_type"),
|
|
204
369
|
)
|
|
205
|
-
"""The type of the option"""
|
|
370
|
+
"""The type of the option (e.g., "string", "int", "bool", "float)."""
|
|
206
371
|
|
|
207
372
|
default: Optional[Any] = None
|
|
208
373
|
"""The default value of the option"""
|
|
@@ -211,11 +376,11 @@ class ManifestOption(BaseModel):
|
|
|
211
376
|
required: bool = False
|
|
212
377
|
"""Whether the option is required or not"""
|
|
213
378
|
additional_attributes: Optional[dict[str, Any]] = None
|
|
214
|
-
"""
|
|
215
|
-
|
|
216
|
-
perform validation on these attributes. For example,
|
|
217
|
-
a string or the maximum value of an integer. These
|
|
218
|
-
will be shown in the help message of the `Options`.
|
|
379
|
+
"""Optional additional attributes for the option.
|
|
380
|
+
|
|
381
|
+
The Nextmv Cloud may perform validation on these attributes. For example,
|
|
382
|
+
the maximum length of a string or the maximum value of an integer. These
|
|
383
|
+
additional attributes will be shown in the help message of the `Options`.
|
|
219
384
|
"""
|
|
220
385
|
|
|
221
386
|
@classmethod
|
|
@@ -225,13 +390,29 @@ class ManifestOption(BaseModel):
|
|
|
225
390
|
|
|
226
391
|
Parameters
|
|
227
392
|
----------
|
|
228
|
-
option: Option
|
|
393
|
+
option : nextmv.options.Option
|
|
229
394
|
The option to convert.
|
|
230
395
|
|
|
231
396
|
Returns
|
|
232
397
|
-------
|
|
233
398
|
ManifestOption
|
|
234
399
|
The converted option.
|
|
400
|
+
|
|
401
|
+
Raises
|
|
402
|
+
------
|
|
403
|
+
ValueError
|
|
404
|
+
If the `option.option_type` is unknown.
|
|
405
|
+
|
|
406
|
+
Examples
|
|
407
|
+
--------
|
|
408
|
+
>>> from nextmv.options import Option
|
|
409
|
+
>>> from nextmv.cloud import ManifestOption
|
|
410
|
+
>>> sdk_option = Option(name="max_stops", option_type=int, default=100)
|
|
411
|
+
>>> manifest_opt = ManifestOption.from_option(sdk_option)
|
|
412
|
+
>>> manifest_opt.name
|
|
413
|
+
'max_stops'
|
|
414
|
+
>>> manifest_opt.option_type
|
|
415
|
+
'int'
|
|
235
416
|
"""
|
|
236
417
|
option_type = option.option_type
|
|
237
418
|
if option_type is str:
|
|
@@ -260,8 +441,23 @@ class ManifestOption(BaseModel):
|
|
|
260
441
|
|
|
261
442
|
Returns
|
|
262
443
|
-------
|
|
263
|
-
Option
|
|
444
|
+
nextmv.options.Option
|
|
264
445
|
The converted option.
|
|
446
|
+
|
|
447
|
+
Raises
|
|
448
|
+
------
|
|
449
|
+
ValueError
|
|
450
|
+
If the `self.option_type` is unknown.
|
|
451
|
+
|
|
452
|
+
Examples
|
|
453
|
+
--------
|
|
454
|
+
>>> from nextmv.cloud import ManifestOption
|
|
455
|
+
>>> manifest_opt = ManifestOption(name="max_stops", option_type="int", default=100)
|
|
456
|
+
>>> sdk_option = manifest_opt.to_option()
|
|
457
|
+
>>> sdk_option.name
|
|
458
|
+
'max_stops'
|
|
459
|
+
>>> sdk_option.option_type
|
|
460
|
+
<class 'int'>
|
|
265
461
|
"""
|
|
266
462
|
|
|
267
463
|
option_type_string = self.option_type
|
|
@@ -290,21 +486,42 @@ class ManifestOptions(BaseModel):
|
|
|
290
486
|
"""
|
|
291
487
|
Options for the decision model.
|
|
292
488
|
|
|
293
|
-
|
|
489
|
+
You can import the `ManifestOptions` class directly from `cloud`:
|
|
490
|
+
|
|
491
|
+
```python
|
|
492
|
+
from nextmv.cloud import ManifestOptions
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
Parameters
|
|
294
496
|
----------
|
|
295
|
-
strict: bool
|
|
497
|
+
strict : Optional[bool], default=False
|
|
296
498
|
If strict is set to `True`, only the listed options will be allowed.
|
|
297
|
-
items: list[ManifestOption]
|
|
298
|
-
|
|
499
|
+
items : Optional[list[ManifestOption]], default=None
|
|
500
|
+
The actual list of options for the decision model. An option
|
|
299
501
|
is a parameter that configures the decision model.
|
|
502
|
+
|
|
503
|
+
Examples
|
|
504
|
+
--------
|
|
505
|
+
>>> from nextmv.cloud import ManifestOptions, ManifestOption
|
|
506
|
+
>>> options_config = ManifestOptions(
|
|
507
|
+
... strict=True,
|
|
508
|
+
... items=[
|
|
509
|
+
... ManifestOption(name="timeout", option_type="int", default=60),
|
|
510
|
+
... ManifestOption(name="vehicle_capacity", option_type="float", default=100.0)
|
|
511
|
+
... ]
|
|
512
|
+
... )
|
|
513
|
+
>>> options_config.strict
|
|
514
|
+
True
|
|
515
|
+
>>> len(options_config.items)
|
|
516
|
+
2
|
|
300
517
|
"""
|
|
301
518
|
|
|
302
519
|
strict: Optional[bool] = False
|
|
303
520
|
"""If strict is set to `True`, only the listed options will be allowed."""
|
|
304
521
|
items: Optional[list[ManifestOption]] = None
|
|
305
|
-
"""
|
|
306
|
-
|
|
307
|
-
parameter that configures the decision model.
|
|
522
|
+
"""The actual list of options for the decision model.
|
|
523
|
+
|
|
524
|
+
An option is a parameter that configures the decision model.
|
|
308
525
|
"""
|
|
309
526
|
|
|
310
527
|
|
|
@@ -312,11 +529,27 @@ class ManifestConfiguration(BaseModel):
|
|
|
312
529
|
"""
|
|
313
530
|
Configuration for the decision model.
|
|
314
531
|
|
|
315
|
-
|
|
532
|
+
You can import the `ManifestConfiguration` class directly from `cloud`:
|
|
533
|
+
|
|
534
|
+
```python
|
|
535
|
+
from nextmv.cloud import ManifestConfiguration
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
Parameters
|
|
316
539
|
----------
|
|
317
|
-
options: ManifestOptions
|
|
318
|
-
|
|
319
|
-
|
|
540
|
+
options : ManifestOptions
|
|
541
|
+
Options for the decision model.
|
|
542
|
+
|
|
543
|
+
Examples
|
|
544
|
+
--------
|
|
545
|
+
>>> from nextmv.cloud import ManifestConfiguration, ManifestOptions, ManifestOption
|
|
546
|
+
>>> model_config = ManifestConfiguration(
|
|
547
|
+
... options=ManifestOptions(
|
|
548
|
+
... items=[ManifestOption(name="debug_mode", option_type="bool", default=False)]
|
|
549
|
+
... )
|
|
550
|
+
... )
|
|
551
|
+
>>> model_config.options.items[0].name
|
|
552
|
+
'debug_mode'
|
|
320
553
|
"""
|
|
321
554
|
|
|
322
555
|
options: ManifestOptions
|
|
@@ -325,6 +558,14 @@ class ManifestConfiguration(BaseModel):
|
|
|
325
558
|
|
|
326
559
|
class Manifest(BaseModel):
|
|
327
560
|
"""
|
|
561
|
+
Represents an app manifest (`app.yaml`) for Nextmv Cloud.
|
|
562
|
+
|
|
563
|
+
You can import the `Manifest` class directly from `cloud`:
|
|
564
|
+
|
|
565
|
+
```python
|
|
566
|
+
from nextmv.cloud import Manifest
|
|
567
|
+
```
|
|
568
|
+
|
|
328
569
|
An application that runs on the Nextmv Platform must contain a file named
|
|
329
570
|
`app.yaml` which is known as the app manifest. This file is used to specify
|
|
330
571
|
the execution environment for the app.
|
|
@@ -332,77 +573,95 @@ class Manifest(BaseModel):
|
|
|
332
573
|
This class represents the app manifest and allows you to load it from a
|
|
333
574
|
file or create it programmatically.
|
|
334
575
|
|
|
335
|
-
|
|
576
|
+
Parameters
|
|
336
577
|
----------
|
|
337
|
-
files: list[str]
|
|
338
|
-
|
|
339
|
-
runtime: ManifestRuntime
|
|
340
|
-
|
|
341
|
-
in which the app runs.
|
|
342
|
-
type: ManifestType
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
578
|
+
files : list[str]
|
|
579
|
+
The files to include (or exclude) in the app. This is mandatory.
|
|
580
|
+
runtime : ManifestRuntime, default=ManifestRuntime.PYTHON
|
|
581
|
+
The runtime to use for the app, it provides the environment
|
|
582
|
+
in which the app runs. This is mandatory.
|
|
583
|
+
type : ManifestType, default=ManifestType.PYTHON
|
|
584
|
+
Type of application, based on the programming language. This is
|
|
585
|
+
mandatory.
|
|
586
|
+
build : Optional[ManifestBuild], default=None
|
|
587
|
+
Build-specific attributes. The `build.command` to run to build
|
|
346
588
|
the app. This command will be executed without a shell, i.e., directly.
|
|
347
589
|
The command must exit with a status of 0 to continue the push process of
|
|
348
590
|
the app to Nextmv Cloud. This command is executed prior to the pre-push
|
|
349
|
-
command. The build.environment is used to set environment variables when
|
|
591
|
+
command. The `build.environment` is used to set environment variables when
|
|
350
592
|
running the build command given as key-value pairs.
|
|
351
|
-
pre_push: Optional[str]
|
|
352
|
-
|
|
593
|
+
pre_push : Optional[str], default=None
|
|
594
|
+
A command to run before the app is pushed to the Nextmv Cloud.
|
|
353
595
|
This command can be used to compile a binary, run tests or similar tasks.
|
|
354
596
|
One difference with what is specified under build, is that the command
|
|
355
|
-
will be executed via
|
|
356
|
-
|
|
357
|
-
|
|
597
|
+
will be executed via the shell (i.e., `bash -c` on Linux & macOS or
|
|
598
|
+
`cmd /c` on Windows). The command must exit with a status of 0 to
|
|
599
|
+
continue the push process. This command is executed just before the app
|
|
600
|
+
gets bundled and pushed (after the build command).
|
|
601
|
+
Aliases: `pre-push`.
|
|
602
|
+
python : Optional[ManifestPython], default=None
|
|
603
|
+
Only for Python apps. Contains further Python-specific
|
|
358
604
|
attributes.
|
|
359
|
-
configuration: Optional[ManifestConfiguration]
|
|
360
|
-
|
|
605
|
+
configuration : Optional[ManifestConfiguration], default=None
|
|
606
|
+
A list of options for the decision model. An option is a
|
|
361
607
|
parameter that configures the decision model.
|
|
608
|
+
|
|
609
|
+
Examples
|
|
610
|
+
--------
|
|
611
|
+
>>> from nextmv.cloud import Manifest, ManifestRuntime, ManifestType
|
|
612
|
+
>>> manifest = Manifest(
|
|
613
|
+
... files=["main.py", "model_logic/"],
|
|
614
|
+
... runtime=ManifestRuntime.PYTHON,
|
|
615
|
+
... type=ManifestType.PYTHON,
|
|
616
|
+
... )
|
|
617
|
+
>>> manifest.files
|
|
618
|
+
['main.py', 'model_logic/']
|
|
362
619
|
"""
|
|
363
620
|
|
|
364
621
|
files: list[str]
|
|
365
|
-
"""
|
|
622
|
+
"""The files to include (or exclude) in the app. This is mandatory."""
|
|
366
623
|
|
|
367
624
|
runtime: ManifestRuntime = ManifestRuntime.PYTHON
|
|
368
|
-
"""
|
|
369
|
-
|
|
370
|
-
which the app runs.
|
|
625
|
+
"""The runtime to use for the app.
|
|
626
|
+
|
|
627
|
+
It provides the environment in which the app runs. This is mandatory.
|
|
371
628
|
"""
|
|
372
629
|
type: ManifestType = ManifestType.PYTHON
|
|
373
|
-
"""
|
|
630
|
+
"""Type of application, based on the programming language. This is mandatory."""
|
|
374
631
|
build: Optional[ManifestBuild] = None
|
|
375
|
-
"""
|
|
376
|
-
|
|
377
|
-
app. This command will be executed
|
|
378
|
-
command must exit with a status of 0
|
|
379
|
-
app to Nextmv Cloud. This command is
|
|
380
|
-
command. The build.environment is used to
|
|
381
|
-
running the build command given as key-value
|
|
632
|
+
"""Build-specific attributes.
|
|
633
|
+
|
|
634
|
+
The `build.command` to run to build the app. This command will be executed
|
|
635
|
+
without a shell, i.e., directly. The command must exit with a status of 0
|
|
636
|
+
to continue the push process of the app to Nextmv Cloud. This command is
|
|
637
|
+
executed prior to the pre-push command. The `build.environment` is used to
|
|
638
|
+
set environment variables when running the build command given as key-value
|
|
639
|
+
pairs.
|
|
382
640
|
"""
|
|
383
641
|
pre_push: Optional[str] = Field(
|
|
384
642
|
serialization_alias="pre-push",
|
|
385
643
|
validation_alias=AliasChoices("pre-push", "pre_push"),
|
|
386
644
|
default=None,
|
|
387
645
|
)
|
|
388
|
-
"""
|
|
389
|
-
|
|
646
|
+
"""A command to run before the app is pushed to the Nextmv Cloud.
|
|
647
|
+
|
|
390
648
|
This command can be used to compile a binary, run tests or similar tasks.
|
|
391
649
|
One difference with what is specified under build, is that the command will
|
|
392
|
-
be executed via the shell (i.e., bash -c on Linux & macOS or cmd /c on
|
|
650
|
+
be executed via the shell (i.e., `bash -c` on Linux & macOS or `cmd /c` on
|
|
393
651
|
Windows). The command must exit with a status of 0 to continue the push
|
|
394
652
|
process. This command is executed just before the app gets bundled and
|
|
395
653
|
pushed (after the build command).
|
|
396
654
|
"""
|
|
397
655
|
python: Optional[ManifestPython] = None
|
|
398
|
-
"""
|
|
399
|
-
|
|
400
|
-
attributes.
|
|
656
|
+
"""Python-specific attributes.
|
|
657
|
+
|
|
658
|
+
Only for Python apps. Contains further Python-specific attributes.
|
|
401
659
|
"""
|
|
402
660
|
configuration: Optional[ManifestConfiguration] = None
|
|
403
|
-
"""
|
|
404
|
-
|
|
405
|
-
|
|
661
|
+
"""Configuration for the decision model.
|
|
662
|
+
|
|
663
|
+
A list of options for the decision model. An option is a parameter that
|
|
664
|
+
configures the decision model.
|
|
406
665
|
"""
|
|
407
666
|
|
|
408
667
|
@classmethod
|
|
@@ -410,19 +669,44 @@ class Manifest(BaseModel):
|
|
|
410
669
|
"""
|
|
411
670
|
Load a manifest from a YAML file.
|
|
412
671
|
|
|
672
|
+
The YAML file is expected to be named `app.yaml` and located in the
|
|
673
|
+
specified directory.
|
|
674
|
+
|
|
413
675
|
Parameters
|
|
414
676
|
----------
|
|
415
|
-
dirpath: str
|
|
416
|
-
Path to the directory containing the app.yaml file.
|
|
677
|
+
dirpath : str
|
|
678
|
+
Path to the directory containing the `app.yaml` file.
|
|
417
679
|
|
|
418
680
|
Returns
|
|
419
681
|
-------
|
|
420
682
|
Manifest
|
|
421
683
|
The loaded manifest.
|
|
422
684
|
|
|
685
|
+
Raises
|
|
686
|
+
------
|
|
687
|
+
FileNotFoundError
|
|
688
|
+
If the `app.yaml` file is not found in `dirpath`.
|
|
689
|
+
yaml.YAMLError
|
|
690
|
+
If there is an error parsing the YAML file.
|
|
691
|
+
|
|
692
|
+
Examples
|
|
693
|
+
--------
|
|
694
|
+
Assuming an `app.yaml` file exists in `./my_app_dir`:
|
|
695
|
+
|
|
696
|
+
```yaml
|
|
697
|
+
# ./my_app_dir/app.yaml
|
|
698
|
+
files:
|
|
699
|
+
- main.py
|
|
700
|
+
runtime: ghcr.io/nextmv-io/runtime/python:3.11
|
|
701
|
+
type: python
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
>>> from nextmv.cloud import Manifest
|
|
705
|
+
>>> # manifest = Manifest.from_yaml("./my_app_dir") # This would be run
|
|
706
|
+
>>> # assert manifest.type == "python"
|
|
423
707
|
"""
|
|
424
708
|
|
|
425
|
-
with open(os.path.join(dirpath,
|
|
709
|
+
with open(os.path.join(dirpath, MANIFEST_FILE_NAME)) as file:
|
|
426
710
|
raw_manifest = yaml.safe_load(file)
|
|
427
711
|
|
|
428
712
|
return cls.from_dict(raw_manifest)
|
|
@@ -431,27 +715,63 @@ class Manifest(BaseModel):
|
|
|
431
715
|
"""
|
|
432
716
|
Write the manifest to a YAML file.
|
|
433
717
|
|
|
718
|
+
The manifest will be written to a file named `app.yaml` in the
|
|
719
|
+
specified directory.
|
|
720
|
+
|
|
434
721
|
Parameters
|
|
435
722
|
----------
|
|
436
|
-
dirpath: str
|
|
437
|
-
Path to the directory where the app.yaml file will be written.
|
|
438
|
-
|
|
723
|
+
dirpath : str
|
|
724
|
+
Path to the directory where the `app.yaml` file will be written.
|
|
725
|
+
|
|
726
|
+
Raises
|
|
727
|
+
------
|
|
728
|
+
IOError
|
|
729
|
+
If there is an error writing the file.
|
|
730
|
+
yaml.YAMLError
|
|
731
|
+
If there is an error serializing the manifest to YAML.
|
|
732
|
+
|
|
733
|
+
Examples
|
|
734
|
+
--------
|
|
735
|
+
>>> from nextmv.cloud import Manifest
|
|
736
|
+
>>> manifest = Manifest(files=["solver.py"], type="python")
|
|
737
|
+
>>> # manifest.to_yaml("./output_dir") # This would create ./output_dir/app.yaml
|
|
439
738
|
"""
|
|
440
739
|
|
|
441
|
-
with open(os.path.join(dirpath,
|
|
740
|
+
with open(os.path.join(dirpath, MANIFEST_FILE_NAME), "w") as file:
|
|
442
741
|
yaml.dump(self.to_dict(), file)
|
|
443
742
|
|
|
444
743
|
def extract_options(self) -> Optional[Options]:
|
|
445
744
|
"""
|
|
446
|
-
Convert the manifest options to a `nextmv.Options` object.
|
|
447
|
-
|
|
448
|
-
|
|
745
|
+
Convert the manifest options to a `nextmv.Options` object.
|
|
746
|
+
|
|
747
|
+
If the manifest does not have valid options defined in
|
|
748
|
+
`.configuration.options.items`, this method returns `None`.
|
|
449
749
|
|
|
450
750
|
Returns
|
|
451
751
|
-------
|
|
452
|
-
Optional[Options]
|
|
752
|
+
Optional[nextmv.options.Options]
|
|
453
753
|
The options extracted from the manifest. If no options are found,
|
|
454
754
|
`None` is returned.
|
|
755
|
+
|
|
756
|
+
Examples
|
|
757
|
+
--------
|
|
758
|
+
>>> from nextmv.cloud import Manifest, ManifestConfiguration, ManifestOptions, ManifestOption
|
|
759
|
+
>>> manifest = Manifest(
|
|
760
|
+
... files=["main.py"],
|
|
761
|
+
... configuration=ManifestConfiguration(
|
|
762
|
+
... options=ManifestOptions(
|
|
763
|
+
... items=[
|
|
764
|
+
... ManifestOption(name="duration", option_type="string", default="10s")
|
|
765
|
+
... ]
|
|
766
|
+
... )
|
|
767
|
+
... )
|
|
768
|
+
... )
|
|
769
|
+
>>> sdk_options = manifest.extract_options()
|
|
770
|
+
>>> sdk_options.get_option("duration").default
|
|
771
|
+
'10s'
|
|
772
|
+
>>> empty_manifest = Manifest(files=["main.py"])
|
|
773
|
+
>>> empty_manifest.extract_options() is None
|
|
774
|
+
True
|
|
455
775
|
"""
|
|
456
776
|
|
|
457
777
|
if self.configuration is None or self.configuration.options is None or self.configuration.options.items is None:
|
|
@@ -462,23 +782,52 @@ class Manifest(BaseModel):
|
|
|
462
782
|
return Options(*options)
|
|
463
783
|
|
|
464
784
|
@classmethod
|
|
465
|
-
def from_model_configuration(
|
|
785
|
+
def from_model_configuration(
|
|
786
|
+
cls,
|
|
787
|
+
model_configuration: ModelConfiguration,
|
|
788
|
+
) -> "Manifest":
|
|
466
789
|
"""
|
|
467
|
-
Create a Python manifest from a
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
`nextmv.Model
|
|
471
|
-
|
|
790
|
+
Create a Python manifest from a `nextmv.model.ModelConfiguration`.
|
|
791
|
+
|
|
792
|
+
Note that the `ModelConfiguration` is almost always used in
|
|
793
|
+
conjunction with the `nextmv.Model` class. If you are not
|
|
794
|
+
implementing an instance of `nextmv.Model`, consider using the
|
|
795
|
+
`from_options` method instead to initialize the manifest with the
|
|
796
|
+
options of the model.
|
|
797
|
+
|
|
798
|
+
The resulting manifest will have:
|
|
799
|
+
|
|
800
|
+
- `files` set to `["main.py", f"{model_configuration.name}/**"]`
|
|
801
|
+
- `runtime` set to `ManifestRuntime.PYTHON`
|
|
802
|
+
- `type` set to `ManifestType.PYTHON`
|
|
803
|
+
- `python.pip_requirements` set to the default requirements file name.
|
|
804
|
+
- `python.model.name` set to `model_configuration.name`.
|
|
805
|
+
- `python.model.options` populated from `model_configuration.options`.
|
|
806
|
+
- `configuration.options` populated from `model_configuration.options`.
|
|
472
807
|
|
|
473
808
|
Parameters
|
|
474
809
|
----------
|
|
475
|
-
model_configuration: ModelConfiguration
|
|
810
|
+
model_configuration : nextmv.model.ModelConfiguration
|
|
476
811
|
The model configuration.
|
|
477
812
|
|
|
478
813
|
Returns
|
|
479
814
|
-------
|
|
480
815
|
Manifest
|
|
481
816
|
The Python manifest.
|
|
817
|
+
|
|
818
|
+
Examples
|
|
819
|
+
--------
|
|
820
|
+
>>> from nextmv.model import ModelConfiguration, Options, Option
|
|
821
|
+
>>> from nextmv.cloud import Manifest
|
|
822
|
+
>>> opts = Options(Option(name="vehicle_count", option_type=int, default=5))
|
|
823
|
+
>>> mc = ModelConfiguration(name="vehicle_router", options=opts)
|
|
824
|
+
>>> manifest = Manifest.from_model_configuration(mc)
|
|
825
|
+
>>> manifest.python.model.name
|
|
826
|
+
'vehicle_router'
|
|
827
|
+
>>> manifest.files
|
|
828
|
+
['main.py', 'vehicle_router/**']
|
|
829
|
+
>>> manifest.configuration.options.items[0].name
|
|
830
|
+
'vehicle_count'
|
|
482
831
|
"""
|
|
483
832
|
|
|
484
833
|
manifest_python_dict = {
|
|
@@ -512,21 +861,48 @@ class Manifest(BaseModel):
|
|
|
512
861
|
@classmethod
|
|
513
862
|
def from_options(cls, options: Options) -> "Manifest":
|
|
514
863
|
"""
|
|
515
|
-
Create a basic Python manifest from `Options`.
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
864
|
+
Create a basic Python manifest from `nextmv.options.Options`.
|
|
865
|
+
|
|
866
|
+
If you have more files than just a `main.py`, make sure you modify
|
|
867
|
+
the `.files` attribute of the resulting manifest. This method assumes
|
|
868
|
+
that requirements are specified in a `requirements.txt` file. You may
|
|
869
|
+
also specify a different requirements file once you instantiate the
|
|
870
|
+
manifest.
|
|
871
|
+
|
|
872
|
+
The resulting manifest will have:
|
|
873
|
+
- `files` set to `["main.py"]`
|
|
874
|
+
- `runtime` set to `ManifestRuntime.PYTHON`
|
|
875
|
+
- `type` set to `ManifestType.PYTHON`
|
|
876
|
+
- `python.pip_requirements` set to `"requirements.txt"`.
|
|
877
|
+
- `configuration.options` populated from the provided `options`.
|
|
520
878
|
|
|
521
879
|
Parameters
|
|
522
880
|
----------
|
|
523
|
-
options: Options
|
|
881
|
+
options : nextmv.options.Options
|
|
524
882
|
The options to include in the manifest.
|
|
525
883
|
|
|
526
884
|
Returns
|
|
527
885
|
-------
|
|
528
886
|
Manifest
|
|
529
887
|
The manifest with the given options.
|
|
888
|
+
|
|
889
|
+
Examples
|
|
890
|
+
--------
|
|
891
|
+
>>> from nextmv.options import Options, Option
|
|
892
|
+
>>> from nextmv.cloud import Manifest
|
|
893
|
+
>>> opts = Options(
|
|
894
|
+
... Option(name="max_runtime", option_type=str, default="60s"),
|
|
895
|
+
... Option(name="use_heuristic", option_type=bool, default=True)
|
|
896
|
+
... )
|
|
897
|
+
>>> manifest = Manifest.from_options(opts)
|
|
898
|
+
>>> manifest.files
|
|
899
|
+
['main.py']
|
|
900
|
+
>>> manifest.python.pip_requirements
|
|
901
|
+
'requirements.txt'
|
|
902
|
+
>>> len(manifest.configuration.options.items)
|
|
903
|
+
2
|
|
904
|
+
>>> manifest.configuration.options.items[0].name
|
|
905
|
+
'max_runtime'
|
|
530
906
|
"""
|
|
531
907
|
|
|
532
908
|
manifest = cls(
|