nextmv 0.33.0.dev0__py3-none-any.whl → 0.34.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 +3 -0
- nextmv/cloud/acceptance_test.py +16 -6
- nextmv/cloud/application.py +51 -79
- nextmv/cloud/package.py +62 -24
- nextmv/local/application.py +114 -70
- nextmv/local/executor.py +419 -66
- nextmv/local/local.py +1 -1
- nextmv/manifest.py +192 -23
- nextmv/run.py +175 -13
- {nextmv-0.33.0.dev0.dist-info → nextmv-0.34.0.dist-info}/METADATA +1 -1
- {nextmv-0.33.0.dev0.dist-info → nextmv-0.34.0.dist-info}/RECORD +14 -14
- {nextmv-0.33.0.dev0.dist-info → nextmv-0.34.0.dist-info}/WHEEL +0 -0
- {nextmv-0.33.0.dev0.dist-info → nextmv-0.34.0.dist-info}/licenses/LICENSE +0 -0
nextmv/local/local.py
CHANGED
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
|
|
@@ -49,7 +56,7 @@ from enum import Enum
|
|
|
49
56
|
from typing import Any, Optional, Union
|
|
50
57
|
|
|
51
58
|
import yaml
|
|
52
|
-
from pydantic import AliasChoices, Field
|
|
59
|
+
from pydantic import AliasChoices, Field, field_validator
|
|
53
60
|
|
|
54
61
|
from nextmv.base_model import BaseModel
|
|
55
62
|
from nextmv.input import InputFormat
|
|
@@ -166,6 +173,43 @@ class ManifestRuntime(str, Enum):
|
|
|
166
173
|
Based on the python runtime, it provisions (pre-installs) the Hexaly solver
|
|
167
174
|
to run Python applications.
|
|
168
175
|
"""
|
|
176
|
+
CUOPT = "ghcr.io/nextmv-io/runtime/cuopt:latest"
|
|
177
|
+
"""
|
|
178
|
+
A runtime providing the NVIDIA cuOpt solver.
|
|
179
|
+
"""
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class ManifestPythonArch(str, Enum):
|
|
183
|
+
"""
|
|
184
|
+
Target architecture for bundling Python apps.
|
|
185
|
+
|
|
186
|
+
You can import the `ManifestPythonArch` class directly from `nextmv`:
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
from nextmv import ManifestPythonArch
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Attributes
|
|
193
|
+
----------
|
|
194
|
+
ARM64 : str
|
|
195
|
+
ARM 64-bit architecture.
|
|
196
|
+
AMD64 : str
|
|
197
|
+
AMD 64-bit architecture.
|
|
198
|
+
|
|
199
|
+
Examples
|
|
200
|
+
--------
|
|
201
|
+
>>> from nextmv import ManifestPythonArch
|
|
202
|
+
>>> arch = ManifestPythonArch.ARM64
|
|
203
|
+
>>> arch
|
|
204
|
+
<ManifestPythonArch.ARM64: 'arm64'>
|
|
205
|
+
>>> str(arch)
|
|
206
|
+
'arm64'
|
|
207
|
+
"""
|
|
208
|
+
|
|
209
|
+
ARM64 = "arm64"
|
|
210
|
+
"""ARM 64-bit architecture."""
|
|
211
|
+
AMD64 = "amd64"
|
|
212
|
+
"""AMD 64-bit architecture."""
|
|
169
213
|
|
|
170
214
|
|
|
171
215
|
class ManifestBuild(BaseModel):
|
|
@@ -294,7 +338,7 @@ class ManifestPython(BaseModel):
|
|
|
294
338
|
|
|
295
339
|
Parameters
|
|
296
340
|
----------
|
|
297
|
-
pip_requirements : Optional[str], default=None
|
|
341
|
+
pip_requirements : Optional[Union[str, list[str]]], default=None
|
|
298
342
|
Path to a requirements.txt file containing (additional) Python
|
|
299
343
|
dependencies that will be bundled with the app. Alternatively, you can provide a
|
|
300
344
|
list of strings, each representing a package to install, e.g.,
|
|
@@ -320,18 +364,66 @@ class ManifestPython(BaseModel):
|
|
|
320
364
|
validation_alias=AliasChoices("pip-requirements", "pip_requirements"),
|
|
321
365
|
default=None,
|
|
322
366
|
)
|
|
323
|
-
"""
|
|
367
|
+
"""
|
|
368
|
+
Path to a requirements.txt file or list of packages.
|
|
324
369
|
|
|
325
370
|
Contains (additional) Python dependencies that will be bundled with the
|
|
326
|
-
app.
|
|
371
|
+
app. Can be either a string path to a requirements.txt file or a list
|
|
372
|
+
of package specifications.
|
|
373
|
+
"""
|
|
374
|
+
arch: Optional[ManifestPythonArch] = None
|
|
375
|
+
"""
|
|
376
|
+
The architecture this model is meant to run on. One of "arm64" or "amd64". Uses
|
|
377
|
+
"arm64" if not specified.
|
|
378
|
+
"""
|
|
379
|
+
version: Optional[Union[str, float]] = None
|
|
380
|
+
"""
|
|
381
|
+
The Python version this model is meant to run with. Uses "3.11" if not specified.
|
|
327
382
|
"""
|
|
328
383
|
model: Optional[ManifestPythonModel] = None
|
|
329
|
-
"""
|
|
384
|
+
"""
|
|
385
|
+
Information about an encoded decision model.
|
|
330
386
|
|
|
331
387
|
As handled via mlflow. This information is used to load the decision model
|
|
332
388
|
from the app bundle.
|
|
333
389
|
"""
|
|
334
390
|
|
|
391
|
+
@field_validator("version", mode="before")
|
|
392
|
+
@classmethod
|
|
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
|
+
"""
|
|
419
|
+
# We allow the version to be a float in the manifest for convenience, but we want
|
|
420
|
+
# to store it as a string internally.
|
|
421
|
+
if v is None:
|
|
422
|
+
return None
|
|
423
|
+
if isinstance(v, float):
|
|
424
|
+
return str(v)
|
|
425
|
+
return v
|
|
426
|
+
|
|
335
427
|
|
|
336
428
|
class ManifestOptionUI(BaseModel):
|
|
337
429
|
"""
|
|
@@ -858,7 +950,23 @@ class ManifestContent(BaseModel):
|
|
|
858
950
|
"""Configuration for multi-file content format."""
|
|
859
951
|
|
|
860
952
|
def model_post_init(self, __context) -> None:
|
|
861
|
-
"""
|
|
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
|
+
"""
|
|
862
970
|
acceptable_formats = [InputFormat.JSON, InputFormat.MULTI_FILE, InputFormat.CSV_ARCHIVE]
|
|
863
971
|
if self.format not in acceptable_formats:
|
|
864
972
|
raise ValueError(f"Invalid format: {self.format}. Must be one of {acceptable_formats}.")
|
|
@@ -965,17 +1073,28 @@ class Manifest(BaseModel):
|
|
|
965
1073
|
['main.py', 'model_logic/']
|
|
966
1074
|
"""
|
|
967
1075
|
|
|
968
|
-
|
|
969
|
-
"""
|
|
970
|
-
|
|
1076
|
+
type: ManifestType = ManifestType.PYTHON
|
|
1077
|
+
"""
|
|
1078
|
+
Type of application, based on the programming language. This is mandatory.
|
|
1079
|
+
"""
|
|
971
1080
|
runtime: ManifestRuntime = ManifestRuntime.PYTHON
|
|
972
1081
|
"""
|
|
973
1082
|
The runtime to use for the app. It provides the environment in which the
|
|
974
1083
|
app runs. This is mandatory.
|
|
975
1084
|
"""
|
|
976
|
-
|
|
1085
|
+
python: Optional[ManifestPython] = None
|
|
977
1086
|
"""
|
|
978
|
-
|
|
1087
|
+
Python-specific attributes. Only for Python apps. Contains further
|
|
1088
|
+
Python-specific attributes.
|
|
1089
|
+
"""
|
|
1090
|
+
files: list[str] = Field(
|
|
1091
|
+
default_factory=list,
|
|
1092
|
+
)
|
|
1093
|
+
"""The files to include (or exclude) in the app. This is mandatory."""
|
|
1094
|
+
configuration: Optional[ManifestConfiguration] = None
|
|
1095
|
+
"""
|
|
1096
|
+
Configuration for the decision model. A list of options for the decision
|
|
1097
|
+
model. An option is a parameter that configures the decision model.
|
|
979
1098
|
"""
|
|
980
1099
|
build: Optional[ManifestBuild] = None
|
|
981
1100
|
"""
|
|
@@ -1003,16 +1122,6 @@ class Manifest(BaseModel):
|
|
|
1003
1122
|
process. This command is executed just before the app gets bundled and
|
|
1004
1123
|
pushed (after the build command).
|
|
1005
1124
|
"""
|
|
1006
|
-
python: Optional[ManifestPython] = None
|
|
1007
|
-
"""
|
|
1008
|
-
Python-specific attributes. Only for Python apps. Contains further
|
|
1009
|
-
Python-specific attributes.
|
|
1010
|
-
"""
|
|
1011
|
-
configuration: Optional[ManifestConfiguration] = None
|
|
1012
|
-
"""
|
|
1013
|
-
Configuration for the decision model. A list of options for the decision
|
|
1014
|
-
model. An option is a parameter that configures the decision model.
|
|
1015
|
-
"""
|
|
1016
1125
|
entrypoint: Optional[str] = None
|
|
1017
1126
|
"""
|
|
1018
1127
|
Optional entrypoint for the decision model. When not specified, the
|
|
@@ -1024,8 +1133,33 @@ class Manifest(BaseModel):
|
|
|
1024
1133
|
"""
|
|
1025
1134
|
|
|
1026
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
|
+
"""
|
|
1027
1156
|
if self.entrypoint is None:
|
|
1028
|
-
if self.runtime in (
|
|
1157
|
+
if self.runtime in (
|
|
1158
|
+
ManifestRuntime.PYTHON,
|
|
1159
|
+
ManifestRuntime.HEXALY,
|
|
1160
|
+
ManifestRuntime.PYOMO,
|
|
1161
|
+
ManifestRuntime.CUOPT,
|
|
1162
|
+
):
|
|
1029
1163
|
self.entrypoint = "./main.py"
|
|
1030
1164
|
elif self.runtime == ManifestRuntime.DEFAULT:
|
|
1031
1165
|
self.entrypoint = "./main"
|
|
@@ -1111,7 +1245,14 @@ class Manifest(BaseModel):
|
|
|
1111
1245
|
"""
|
|
1112
1246
|
|
|
1113
1247
|
with open(os.path.join(dirpath, MANIFEST_FILE_NAME), "w") as file:
|
|
1114
|
-
yaml.dump(
|
|
1248
|
+
yaml.dump(
|
|
1249
|
+
self.to_dict(),
|
|
1250
|
+
file,
|
|
1251
|
+
sort_keys=False,
|
|
1252
|
+
default_flow_style=False,
|
|
1253
|
+
indent=2,
|
|
1254
|
+
width=120,
|
|
1255
|
+
)
|
|
1115
1256
|
|
|
1116
1257
|
def extract_options(self) -> Optional[Options]:
|
|
1117
1258
|
"""
|
|
@@ -1293,3 +1434,31 @@ class Manifest(BaseModel):
|
|
|
1293
1434
|
)
|
|
1294
1435
|
|
|
1295
1436
|
return manifest
|
|
1437
|
+
|
|
1438
|
+
|
|
1439
|
+
def default_python_manifest() -> Manifest:
|
|
1440
|
+
"""
|
|
1441
|
+
Creates a default Python manifest as a starting point for applications
|
|
1442
|
+
being executed on the Nextmv Platform.
|
|
1443
|
+
|
|
1444
|
+
You can import the `default_python_manifest` function directly from `nextmv`:
|
|
1445
|
+
|
|
1446
|
+
```python
|
|
1447
|
+
from nextmv import default_python_manifest
|
|
1448
|
+
```
|
|
1449
|
+
|
|
1450
|
+
Returns
|
|
1451
|
+
-------
|
|
1452
|
+
Manifest
|
|
1453
|
+
A default Python manifest with common settings.
|
|
1454
|
+
"""
|
|
1455
|
+
|
|
1456
|
+
m = Manifest(
|
|
1457
|
+
files=["main.py"],
|
|
1458
|
+
runtime=ManifestRuntime.PYTHON,
|
|
1459
|
+
type=ManifestType.PYTHON,
|
|
1460
|
+
python=ManifestPython(pip_requirements="requirements.txt"),
|
|
1461
|
+
)
|
|
1462
|
+
m.entrypoint = None # TODO: change this when we are ready for the entrypoint.
|
|
1463
|
+
|
|
1464
|
+
return m
|
nextmv/run.py
CHANGED
|
@@ -52,7 +52,7 @@ from pydantic import AliasChoices, Field, field_validator
|
|
|
52
52
|
from nextmv._serialization import serialize_json
|
|
53
53
|
from nextmv.base_model import BaseModel
|
|
54
54
|
from nextmv.input import Input, InputFormat
|
|
55
|
-
from nextmv.output import Output, OutputFormat
|
|
55
|
+
from nextmv.output import Asset, Output, OutputFormat, Statistics
|
|
56
56
|
from nextmv.status import Status, StatusV2
|
|
57
57
|
|
|
58
58
|
|
|
@@ -687,6 +687,56 @@ class Metadata(BaseModel):
|
|
|
687
687
|
"""Deprecated: use status_v2."""
|
|
688
688
|
|
|
689
689
|
|
|
690
|
+
class SyncedRun(BaseModel):
|
|
691
|
+
"""
|
|
692
|
+
Information about a run that has been synced to a remote application.
|
|
693
|
+
|
|
694
|
+
You can import the `SyncedRun` class directly from `nextmv`:
|
|
695
|
+
|
|
696
|
+
```python
|
|
697
|
+
from nextmv import SyncedRun
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
Parameters
|
|
701
|
+
----------
|
|
702
|
+
run_id : str
|
|
703
|
+
ID of the synced remote run. When the `Application.sync` method is
|
|
704
|
+
used, this field marks the association between the local run (`id`) and
|
|
705
|
+
the remote run (`synced_run.id`).
|
|
706
|
+
synced_at : datetime
|
|
707
|
+
Timestamp when the run was synced with the remote run.
|
|
708
|
+
app_id : str
|
|
709
|
+
The ID of the remote application that the local run was synced to.
|
|
710
|
+
instance_id : Optional[str], optional
|
|
711
|
+
The instance of the remote application that the local run was synced
|
|
712
|
+
to. This field is optional and may be None. If it is not specified, it
|
|
713
|
+
indicates that the run was synced against the default instance of the
|
|
714
|
+
app. Defaults to None.
|
|
715
|
+
"""
|
|
716
|
+
|
|
717
|
+
run_id: str
|
|
718
|
+
"""
|
|
719
|
+
ID of the synced remote run. When the `Application.sync` method is used,
|
|
720
|
+
this field marks the association between the local run (`id`) and the
|
|
721
|
+
remote run (`synced_run.id`)
|
|
722
|
+
"""
|
|
723
|
+
synced_at: datetime
|
|
724
|
+
"""
|
|
725
|
+
Timestamp when the run was synced with the remote run.
|
|
726
|
+
"""
|
|
727
|
+
app_id: str
|
|
728
|
+
"""
|
|
729
|
+
The ID of the remote application that the local run was synced to.
|
|
730
|
+
"""
|
|
731
|
+
|
|
732
|
+
instance_id: Optional[str] = None
|
|
733
|
+
"""
|
|
734
|
+
The instance of the remote application that the local run was synced to.
|
|
735
|
+
This field is optional and may be None. If it is not specified, it
|
|
736
|
+
indicates that the run was synced against the default instance of the app.
|
|
737
|
+
"""
|
|
738
|
+
|
|
739
|
+
|
|
690
740
|
class RunInformation(BaseModel):
|
|
691
741
|
"""
|
|
692
742
|
Information of a run.
|
|
@@ -727,19 +777,18 @@ class RunInformation(BaseModel):
|
|
|
727
777
|
"""
|
|
728
778
|
URL to the run in the Nextmv console.
|
|
729
779
|
"""
|
|
730
|
-
|
|
731
|
-
"""
|
|
732
|
-
ID of the synced remote run, if applicable. When the `Application.sync`
|
|
733
|
-
method is used, this field marks the association between the local run
|
|
734
|
-
(`id`) and the remote run (`synced_run_id`). This field is None if the run
|
|
735
|
-
was not created using `Application.sync` or if the run has not been synced
|
|
736
|
-
yet.
|
|
780
|
+
synced_runs: Optional[list[SyncedRun]] = None
|
|
737
781
|
"""
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
None if the run was not created using `Application.sync` or if the
|
|
742
|
-
has not been synced yet.
|
|
782
|
+
List of synced runs associated with this run, if applicable. When the
|
|
783
|
+
`Application.sync` method is used, this field contains the associations
|
|
784
|
+
between the local run (`id`) and the remote runs (`synced_run.id`). This
|
|
785
|
+
field is None if the run was not created using `Application.sync` or if the
|
|
786
|
+
run has not been synced yet. It is possible to sync a single local run to
|
|
787
|
+
multiple remote runs. A remote run is identified by its application ID and
|
|
788
|
+
instance (if applicable). A local run cannot be synced to a remote run if
|
|
789
|
+
it is already present, this is, if there exists a record in the list with
|
|
790
|
+
the same application ID and instance. If there is not a repeated remote
|
|
791
|
+
run, a new record is added to the list.
|
|
743
792
|
"""
|
|
744
793
|
|
|
745
794
|
def to_run(self) -> Run:
|
|
@@ -817,6 +866,83 @@ class RunInformation(BaseModel):
|
|
|
817
866
|
input_set_id=None,
|
|
818
867
|
)
|
|
819
868
|
|
|
869
|
+
def add_synced_run(self, synced_run: SyncedRun) -> bool:
|
|
870
|
+
"""
|
|
871
|
+
Add a synced run to the RunInformation.
|
|
872
|
+
|
|
873
|
+
This method adds a `SyncedRun` instance to the list of synced runs
|
|
874
|
+
associated with this `RunInformation`. If the list is None, it
|
|
875
|
+
initializes it first. If the run has already been synced, then it is
|
|
876
|
+
not added to the list. A run is already synced if there exists a record
|
|
877
|
+
in the list with the same application ID. This method returns True if
|
|
878
|
+
the synced run was added, and False otherwise.
|
|
879
|
+
|
|
880
|
+
Parameters
|
|
881
|
+
----------
|
|
882
|
+
synced_run : SyncedRun
|
|
883
|
+
The SyncedRun instance to add.
|
|
884
|
+
|
|
885
|
+
Returns
|
|
886
|
+
-------
|
|
887
|
+
bool
|
|
888
|
+
True if the synced run was added, False if it was already present.
|
|
889
|
+
"""
|
|
890
|
+
|
|
891
|
+
if self.synced_runs is None:
|
|
892
|
+
self.synced_runs = [synced_run]
|
|
893
|
+
|
|
894
|
+
return True
|
|
895
|
+
|
|
896
|
+
if synced_run.instance_id is None:
|
|
897
|
+
for existing_run in self.synced_runs:
|
|
898
|
+
if existing_run.app_id == synced_run.app_id:
|
|
899
|
+
return False
|
|
900
|
+
else:
|
|
901
|
+
for existing_run in self.synced_runs:
|
|
902
|
+
if existing_run.app_id == synced_run.app_id and existing_run.instance_id == synced_run.instance_id:
|
|
903
|
+
return False
|
|
904
|
+
|
|
905
|
+
self.synced_runs.append(synced_run)
|
|
906
|
+
|
|
907
|
+
return True
|
|
908
|
+
|
|
909
|
+
def is_synced(self, app_id: str, instance_id: Optional[str] = None) -> tuple[SyncedRun, bool]:
|
|
910
|
+
"""
|
|
911
|
+
Check if the run has been synced to a specific application and instance.
|
|
912
|
+
|
|
913
|
+
This method checks if there exists a `SyncedRun` in the list of synced
|
|
914
|
+
runs that matches the given application ID and optional instance ID.
|
|
915
|
+
|
|
916
|
+
Parameters
|
|
917
|
+
----------
|
|
918
|
+
app_id : str
|
|
919
|
+
The application ID to check.
|
|
920
|
+
instance_id : Optional[str], optional
|
|
921
|
+
The instance ID to check. If None, only the application ID is
|
|
922
|
+
considered. Defaults to None.
|
|
923
|
+
|
|
924
|
+
Returns
|
|
925
|
+
-------
|
|
926
|
+
tuple[SyncedRun, bool]
|
|
927
|
+
A tuple containing the SyncedRun instance if found, and a boolean
|
|
928
|
+
indicating whether the run has been synced to the specified
|
|
929
|
+
application and instance.
|
|
930
|
+
"""
|
|
931
|
+
|
|
932
|
+
if self.synced_runs is None:
|
|
933
|
+
return None, False
|
|
934
|
+
|
|
935
|
+
if instance_id is None:
|
|
936
|
+
for existing_run in self.synced_runs:
|
|
937
|
+
if existing_run.app_id == app_id:
|
|
938
|
+
return existing_run, True
|
|
939
|
+
else:
|
|
940
|
+
for existing_run in self.synced_runs:
|
|
941
|
+
if existing_run.app_id == app_id and existing_run.instance_id == instance_id:
|
|
942
|
+
return existing_run, True
|
|
943
|
+
|
|
944
|
+
return None, False
|
|
945
|
+
|
|
820
946
|
|
|
821
947
|
class ErrorLog(BaseModel):
|
|
822
948
|
"""
|
|
@@ -1154,6 +1280,16 @@ class ExternalRunResult(BaseModel):
|
|
|
1154
1280
|
"""Error message of the run."""
|
|
1155
1281
|
execution_duration: Optional[int] = None
|
|
1156
1282
|
"""Duration of the run, in milliseconds."""
|
|
1283
|
+
statistics_upload_id: Optional[str] = None
|
|
1284
|
+
"""
|
|
1285
|
+
ID of the statistics upload. Use this field when working with `CSV_ARCHIVE`
|
|
1286
|
+
or `MULTI_FILE` output formats.
|
|
1287
|
+
"""
|
|
1288
|
+
assets_upload_id: Optional[str] = None
|
|
1289
|
+
"""
|
|
1290
|
+
ID of the assets upload. Use this field when working with `CSV_ARCHIVE`
|
|
1291
|
+
or `MULTI_FILE` output formats.
|
|
1292
|
+
"""
|
|
1157
1293
|
|
|
1158
1294
|
def __post_init_post_parse__(self):
|
|
1159
1295
|
"""
|
|
@@ -1265,6 +1401,18 @@ class TrackedRun:
|
|
|
1265
1401
|
when working with `CSV_ARCHIVE` or `MULTI_FILE`. If both `output` and
|
|
1266
1402
|
`output_dir_path` are specified, the `output` is ignored, and the files
|
|
1267
1403
|
are saved in the directory instead. Defaults to None.
|
|
1404
|
+
statistics : Statistics or dict[str, Any], optional
|
|
1405
|
+
Statistics of the run being tracked. Only use this field if you want to
|
|
1406
|
+
track statistics for `CSV_ARCHIVE` or `MULTI_FILE` output formats. If you
|
|
1407
|
+
are working with `JSON` or `TEXT` output formats, this field will be
|
|
1408
|
+
ignored, as the statistics are extracted directly from the `output`.
|
|
1409
|
+
This field is optional. Defaults to None.
|
|
1410
|
+
assets : list[Asset or dict[str, Any]], optional
|
|
1411
|
+
Assets associated with the run being tracked. Only use this field if you
|
|
1412
|
+
want to track assets for `CSV_ARCHIVE` or `MULTI_FILE` output formats.
|
|
1413
|
+
If you are working with `JSON` or `TEXT` output formats, this field will
|
|
1414
|
+
be ignored, as the assets are extracted directly from the `output`.
|
|
1415
|
+
This field is optional. Defaults to None.
|
|
1268
1416
|
|
|
1269
1417
|
Examples
|
|
1270
1418
|
--------
|
|
@@ -1365,6 +1513,20 @@ class TrackedRun:
|
|
|
1365
1513
|
`output_dir_path` are specified, the `output` is ignored, and the files
|
|
1366
1514
|
are saved in the directory instead.
|
|
1367
1515
|
"""
|
|
1516
|
+
statistics: Optional[Union[Statistics, dict[str, Any]]] = None
|
|
1517
|
+
"""
|
|
1518
|
+
Statistics of the run being tracked. Only use this field if you want to
|
|
1519
|
+
track statistics for `CSV_ARCHIVE` or `MULTI_FILE` output formats. If you
|
|
1520
|
+
are working with `JSON` or `TEXT` output formats, this field will be
|
|
1521
|
+
ignored, as the statistics are extracted directly from the `output`.
|
|
1522
|
+
"""
|
|
1523
|
+
assets: Optional[list[Union[Asset, dict[str, Any]]]] = None
|
|
1524
|
+
"""
|
|
1525
|
+
Assets associated with the run being tracked. Only use this field if you
|
|
1526
|
+
want to track assets for `CSV_ARCHIVE` or `MULTI_FILE` output formats.
|
|
1527
|
+
If you are working with `JSON` or `TEXT` output formats, this field will
|
|
1528
|
+
be ignored, as the assets are extracted directly from the `output`.
|
|
1529
|
+
"""
|
|
1368
1530
|
|
|
1369
1531
|
def __post_init__(self): # noqa: C901
|
|
1370
1532
|
"""
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
nextmv/__about__.py,sha256=
|
|
1
|
+
nextmv/__about__.py,sha256=R6JmJlUTOJ25ql5gmHiwKZDMDym2RLkSYwWgTeG9wAQ,24
|
|
2
2
|
nextmv/__entrypoint__.py,sha256=dA0iwwHtrq6Z9w9FxmxKLoBGLyhe7jWtUAU-Y3PEgHg,1094
|
|
3
|
-
nextmv/__init__.py,sha256=
|
|
3
|
+
nextmv/__init__.py,sha256=C2f8MteVvvOX1Wj-0GFjfUt-0RzCT0zpLpLI2yyZQw8,3796
|
|
4
4
|
nextmv/_serialization.py,sha256=JlSl6BL0M2Esf7F89GsGIZ__Pp8RnFRNM0UxYhuuYU4,2853
|
|
5
5
|
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=
|
|
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=
|
|
14
|
+
nextmv/run.py,sha256=8B9hh-jWJpoMSJiDmgmXaqvmzTicWCn75UTJu7Nf7Cs,52401
|
|
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
|
|
18
|
-
nextmv/cloud/acceptance_test.py,sha256=
|
|
18
|
+
nextmv/cloud/acceptance_test.py,sha256=ZEzCMrfJF-nUFr1nEr4IDgcoyavPhnanjFuPBJ79tAk,27731
|
|
19
19
|
nextmv/cloud/account.py,sha256=jIdGNyI3l3dVh2PuriAwAOrEuWRM150WgzxcBMVBNRw,6058
|
|
20
|
-
nextmv/cloud/application.py,sha256=
|
|
20
|
+
nextmv/cloud/application.py,sha256=oUpw6I1r4u9Cn0pnlylWlm23hPgZKsg_vnBXbqTtU-w,139693
|
|
21
21
|
nextmv/cloud/batch_experiment.py,sha256=13ciRpgBabMMTyazfdfEAymD3rTPrTAAorECsANxxuA,10397
|
|
22
22
|
nextmv/cloud/client.py,sha256=E0DiUb377jvEnpXlRnfT1PGCI0Jm0lTUoX5VqeU91lk,18165
|
|
23
23
|
nextmv/cloud/ensemble.py,sha256=glrRgyRFcEH12fNUhEl1FOo6xOTDEaF478dxfX0wj2Y,8604
|
|
24
24
|
nextmv/cloud/input_set.py,sha256=NkzA6_hwgD-YwoirzwvZrObIoBTfurry7Os3jo4DyXc,4236
|
|
25
25
|
nextmv/cloud/instance.py,sha256=SS4tbp0LQMWDaeYpwcNxJei82oi_Hozv1t5i3QGjASY,4024
|
|
26
|
-
nextmv/cloud/package.py,sha256=
|
|
26
|
+
nextmv/cloud/package.py,sha256=Xmt-daAeN9QJKpquV28IiZa2eYCX0P3wSS564JHvrtY,14495
|
|
27
27
|
nextmv/cloud/scenario.py,sha256=JRFTDiFBcrgud6wE2qDHUu5oO-Ur3zbPYhhB6ONCxTo,14263
|
|
28
28
|
nextmv/cloud/secrets.py,sha256=fA5cX0jfTsPVZWV7433wzETGlXpWRLHGswuObx9e6FQ,6820
|
|
29
29
|
nextmv/cloud/url.py,sha256=Fz70ywkWdCLmP21ZBmJwZi5kDbjpmsX_VlwVF_xQeHg,1836
|
|
@@ -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=
|
|
42
|
-
nextmv/local/executor.py,sha256=
|
|
41
|
+
nextmv/local/application.py,sha256=yJDlbQB_mh29Y541Mt6a6zyT3XutdtzjqSd0mlOeteo,47002
|
|
42
|
+
nextmv/local/executor.py,sha256=7rxVkpyZ4GyTH7hjJX7rdM0hCo7_fSqX4EiA8YHZpC8,36624
|
|
43
43
|
nextmv/local/geojson_handler.py,sha256=7FavJdkUonop-yskjis0x3qFGB8A5wZyoBUblw-bVhw,12540
|
|
44
|
-
nextmv/local/local.py,sha256=
|
|
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.
|
|
48
|
-
nextmv-0.
|
|
49
|
-
nextmv-0.
|
|
50
|
-
nextmv-0.
|
|
47
|
+
nextmv-0.34.0.dist-info/METADATA,sha256=xaYGEjnGpH8t_ULjbHULvcEVtvMXNQ6B5Wx41tone0o,16008
|
|
48
|
+
nextmv-0.34.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
49
|
+
nextmv-0.34.0.dist-info/licenses/LICENSE,sha256=ZIbK-sSWA-OZprjNbmJAglYRtl5_K4l9UwAV3PGJAPc,11349
|
|
50
|
+
nextmv-0.34.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|