nextmv 0.35.0.dev1__py3-none-any.whl → 0.35.1__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/_serialization.py +3 -3
- nextmv/base_model.py +2 -2
- nextmv/cloud/acceptance_test.py +4 -5
- nextmv/cloud/application.py +116 -109
- nextmv/cloud/batch_experiment.py +17 -17
- nextmv/cloud/client.py +13 -13
- nextmv/cloud/ensemble.py +2 -3
- nextmv/cloud/input_set.py +7 -8
- nextmv/cloud/instance.py +3 -4
- nextmv/cloud/package.py +18 -12
- nextmv/cloud/scenario.py +6 -10
- nextmv/default_app/README.md +2 -2
- nextmv/input.py +38 -44
- nextmv/local/application.py +38 -38
- nextmv/local/executor.py +47 -17
- nextmv/local/runner.py +10 -10
- nextmv/manifest.py +69 -79
- nextmv/model.py +6 -6
- nextmv/options.py +12 -12
- nextmv/output.py +46 -61
- nextmv/polling.py +2 -2
- nextmv/run.py +58 -58
- {nextmv-0.35.0.dev1.dist-info → nextmv-0.35.1.dist-info}/METADATA +3 -4
- nextmv-0.35.1.dist-info/RECORD +49 -0
- nextmv/default_app/src/main.py +0 -37
- nextmv-0.35.0.dev1.dist-info/RECORD +0 -50
- {nextmv-0.35.0.dev1.dist-info → nextmv-0.35.1.dist-info}/WHEEL +0 -0
- {nextmv-0.35.0.dev1.dist-info → nextmv-0.35.1.dist-info}/licenses/LICENSE +0 -0
nextmv/local/application.py
CHANGED
|
@@ -17,7 +17,7 @@ import tempfile
|
|
|
17
17
|
import webbrowser
|
|
18
18
|
from dataclasses import dataclass
|
|
19
19
|
from datetime import datetime, timezone
|
|
20
|
-
from typing import Any
|
|
20
|
+
from typing import Any
|
|
21
21
|
|
|
22
22
|
from nextmv import cloud
|
|
23
23
|
from nextmv._serialization import deflated_serialize_json
|
|
@@ -92,9 +92,9 @@ class Application:
|
|
|
92
92
|
manifest.
|
|
93
93
|
"""
|
|
94
94
|
|
|
95
|
-
description:
|
|
95
|
+
description: str | None = None
|
|
96
96
|
"""Description of the application."""
|
|
97
|
-
manifest:
|
|
97
|
+
manifest: Manifest | None = None
|
|
98
98
|
"""
|
|
99
99
|
Manifest of the application. A manifest is a file named `app.yaml` that
|
|
100
100
|
must be present at the root of the application's `src` directory. If the
|
|
@@ -131,9 +131,9 @@ class Application:
|
|
|
131
131
|
@classmethod
|
|
132
132
|
def initialize(
|
|
133
133
|
cls,
|
|
134
|
-
src:
|
|
135
|
-
description:
|
|
136
|
-
destination:
|
|
134
|
+
src: str | None = None,
|
|
135
|
+
description: str | None = None,
|
|
136
|
+
destination: str | None = None,
|
|
137
137
|
) -> "Application":
|
|
138
138
|
"""
|
|
139
139
|
Initialize a sample Nextmv application, locally.
|
|
@@ -224,13 +224,13 @@ class Application:
|
|
|
224
224
|
|
|
225
225
|
def new_run(
|
|
226
226
|
self,
|
|
227
|
-
input:
|
|
228
|
-
name:
|
|
229
|
-
description:
|
|
230
|
-
options:
|
|
231
|
-
configuration:
|
|
232
|
-
json_configurations:
|
|
233
|
-
input_dir_path:
|
|
227
|
+
input: Input | dict[str, Any] | BaseModel | str = None,
|
|
228
|
+
name: str | None = None,
|
|
229
|
+
description: str | None = None,
|
|
230
|
+
options: Options | dict[str, str] | None = None,
|
|
231
|
+
configuration: RunConfiguration | dict[str, Any] | None = None,
|
|
232
|
+
json_configurations: dict[str, Any] | None = None,
|
|
233
|
+
input_dir_path: str | None = None,
|
|
234
234
|
) -> str:
|
|
235
235
|
"""
|
|
236
236
|
Run the application locally with the provided input.
|
|
@@ -361,15 +361,15 @@ class Application:
|
|
|
361
361
|
|
|
362
362
|
def new_run_with_result(
|
|
363
363
|
self,
|
|
364
|
-
input:
|
|
365
|
-
name:
|
|
366
|
-
description:
|
|
367
|
-
run_options:
|
|
364
|
+
input: Input | dict[str, Any] | BaseModel | str = None,
|
|
365
|
+
name: str | None = None,
|
|
366
|
+
description: str | None = None,
|
|
367
|
+
run_options: Options | dict[str, str] | None = None,
|
|
368
368
|
polling_options: PollingOptions = DEFAULT_POLLING_OPTIONS,
|
|
369
|
-
configuration:
|
|
370
|
-
json_configurations:
|
|
371
|
-
input_dir_path:
|
|
372
|
-
output_dir_path:
|
|
369
|
+
configuration: RunConfiguration | dict[str, Any] | None = None,
|
|
370
|
+
json_configurations: dict[str, Any] | None = None,
|
|
371
|
+
input_dir_path: str | None = None,
|
|
372
|
+
output_dir_path: str | None = ".",
|
|
373
373
|
) -> RunResult:
|
|
374
374
|
"""
|
|
375
375
|
Submit an input to start a new local run of the application and poll
|
|
@@ -594,7 +594,7 @@ class Application:
|
|
|
594
594
|
|
|
595
595
|
return info
|
|
596
596
|
|
|
597
|
-
def run_result(self, run_id: str, output_dir_path:
|
|
597
|
+
def run_result(self, run_id: str, output_dir_path: str | None = ".") -> RunResult:
|
|
598
598
|
"""
|
|
599
599
|
Get the local result of a run.
|
|
600
600
|
|
|
@@ -644,7 +644,7 @@ class Application:
|
|
|
644
644
|
self,
|
|
645
645
|
run_id: str,
|
|
646
646
|
polling_options: PollingOptions = DEFAULT_POLLING_OPTIONS,
|
|
647
|
-
output_dir_path:
|
|
647
|
+
output_dir_path: str | None = ".",
|
|
648
648
|
) -> RunResult:
|
|
649
649
|
"""
|
|
650
650
|
Get the result of a local run with polling.
|
|
@@ -761,9 +761,9 @@ class Application:
|
|
|
761
761
|
def sync( # noqa: C901
|
|
762
762
|
self,
|
|
763
763
|
target: cloud.Application,
|
|
764
|
-
run_ids:
|
|
765
|
-
instance_id:
|
|
766
|
-
verbose:
|
|
764
|
+
run_ids: list[str] | None = None,
|
|
765
|
+
instance_id: str | None = None,
|
|
766
|
+
verbose: bool | None = False,
|
|
767
767
|
) -> None:
|
|
768
768
|
"""
|
|
769
769
|
Sync the local application to a Nextmv Cloud application target.
|
|
@@ -867,7 +867,7 @@ class Application:
|
|
|
867
867
|
self,
|
|
868
868
|
run_id: str,
|
|
869
869
|
run_information: RunInformation,
|
|
870
|
-
output_dir_path:
|
|
870
|
+
output_dir_path: str | None = ".",
|
|
871
871
|
) -> RunResult:
|
|
872
872
|
"""
|
|
873
873
|
Get the result of a local run.
|
|
@@ -931,8 +931,8 @@ class Application:
|
|
|
931
931
|
|
|
932
932
|
def __validate_input_dir_path_and_configuration(
|
|
933
933
|
self,
|
|
934
|
-
input_dir_path:
|
|
935
|
-
configuration:
|
|
934
|
+
input_dir_path: str | None,
|
|
935
|
+
configuration: RunConfiguration | dict[str, Any] | None,
|
|
936
936
|
) -> RunConfiguration:
|
|
937
937
|
"""
|
|
938
938
|
Auxiliary function to validate the directory path and configuration.
|
|
@@ -984,8 +984,8 @@ class Application:
|
|
|
984
984
|
|
|
985
985
|
def __extract_input_data(
|
|
986
986
|
self,
|
|
987
|
-
input:
|
|
988
|
-
) ->
|
|
987
|
+
input: Input | dict[str, Any] | BaseModel | str = None,
|
|
988
|
+
) -> dict[str, Any] | str | None:
|
|
989
989
|
"""
|
|
990
990
|
Auxiliary function to extract the input data from the input, based on
|
|
991
991
|
its type.
|
|
@@ -1003,8 +1003,8 @@ class Application:
|
|
|
1003
1003
|
|
|
1004
1004
|
def __extract_options_dict(
|
|
1005
1005
|
self,
|
|
1006
|
-
options:
|
|
1007
|
-
json_configurations:
|
|
1006
|
+
options: Options | dict[str, str] | None = None,
|
|
1007
|
+
json_configurations: dict[str, Any] | None = None,
|
|
1008
1008
|
) -> dict[str, str]:
|
|
1009
1009
|
"""
|
|
1010
1010
|
Auxiliary function to extract the options that will be sent to the
|
|
@@ -1026,9 +1026,9 @@ class Application:
|
|
|
1026
1026
|
|
|
1027
1027
|
def __extract_run_config(
|
|
1028
1028
|
self,
|
|
1029
|
-
input:
|
|
1030
|
-
configuration:
|
|
1031
|
-
dir_path:
|
|
1029
|
+
input: Input | dict[str, Any] | BaseModel | str = None,
|
|
1030
|
+
configuration: RunConfiguration | dict[str, Any] | None = None,
|
|
1031
|
+
dir_path: str | None = None,
|
|
1032
1032
|
) -> dict[str, Any]:
|
|
1033
1033
|
"""
|
|
1034
1034
|
Auxiliary function to extract the run configuration that will be sent
|
|
@@ -1053,8 +1053,8 @@ class Application:
|
|
|
1053
1053
|
run_id: str,
|
|
1054
1054
|
runs_dir: str,
|
|
1055
1055
|
temp_dir: str,
|
|
1056
|
-
instance_id:
|
|
1057
|
-
verbose:
|
|
1056
|
+
instance_id: str | None = None,
|
|
1057
|
+
verbose: bool | None = False,
|
|
1058
1058
|
) -> bool:
|
|
1059
1059
|
"""
|
|
1060
1060
|
Syncs a local run to a Nextmv Cloud target application. Returns True if
|
nextmv/local/executor.py
CHANGED
|
@@ -43,7 +43,7 @@ import subprocess
|
|
|
43
43
|
import sys
|
|
44
44
|
import tempfile
|
|
45
45
|
from datetime import datetime, timezone
|
|
46
|
-
from typing import Any
|
|
46
|
+
from typing import Any
|
|
47
47
|
|
|
48
48
|
from nextmv.input import INPUTS_KEY, InputFormat, load
|
|
49
49
|
from nextmv.local.geojson_handler import handle_geojson_visual
|
|
@@ -56,7 +56,7 @@ from nextmv.local.local import (
|
|
|
56
56
|
calculate_files_size,
|
|
57
57
|
)
|
|
58
58
|
from nextmv.local.plotly_handler import handle_plotly_visual
|
|
59
|
-
from nextmv.manifest import Manifest
|
|
59
|
+
from nextmv.manifest import Manifest, ManifestType
|
|
60
60
|
from nextmv.output import ASSETS_KEY, OUTPUTS_KEY, SOLUTIONS_KEY, STATISTICS_KEY, Asset, OutputFormat, VisualSchema
|
|
61
61
|
from nextmv.status import StatusV2
|
|
62
62
|
|
|
@@ -87,9 +87,9 @@ def execute_run(
|
|
|
87
87
|
manifest_dict: dict[str, Any],
|
|
88
88
|
run_dir: str,
|
|
89
89
|
run_config: dict[str, Any],
|
|
90
|
-
inputs_dir_path:
|
|
91
|
-
options:
|
|
92
|
-
input_data:
|
|
90
|
+
inputs_dir_path: str | None = None,
|
|
91
|
+
options: dict[str, Any] | None = None,
|
|
92
|
+
input_data: dict[str, Any] | str | None = None,
|
|
93
93
|
) -> None:
|
|
94
94
|
"""
|
|
95
95
|
Executes the decision model run using a subprocess to call the entrypoint
|
|
@@ -152,7 +152,8 @@ def execute_run(
|
|
|
152
152
|
# Start a Python subprocess to execute the entrypoint. For now, we are
|
|
153
153
|
# supporting a Python-first experience, so we are not summoning
|
|
154
154
|
# applications that are not Python-based.
|
|
155
|
-
entrypoint = os.path.join(temp_src, manifest
|
|
155
|
+
entrypoint = os.path.join(temp_src, __determine_entrypoint(manifest))
|
|
156
|
+
cwd = __determine_cwd(manifest, default=temp_src)
|
|
156
157
|
args = [sys.executable, entrypoint] + options_args(options)
|
|
157
158
|
|
|
158
159
|
result = subprocess.run(
|
|
@@ -162,7 +163,7 @@ def execute_run(
|
|
|
162
163
|
text=True,
|
|
163
164
|
capture_output=True,
|
|
164
165
|
input=stdin_input,
|
|
165
|
-
cwd=
|
|
166
|
+
cwd=cwd,
|
|
166
167
|
)
|
|
167
168
|
|
|
168
169
|
process_run_output(
|
|
@@ -190,7 +191,7 @@ def execute_run(
|
|
|
190
191
|
f.truncate()
|
|
191
192
|
|
|
192
193
|
|
|
193
|
-
def options_args(options:
|
|
194
|
+
def options_args(options: dict[str, Any] | None = None) -> list[str]:
|
|
194
195
|
"""
|
|
195
196
|
Converts options dictionary to a list of command-line arguments.
|
|
196
197
|
|
|
@@ -218,8 +219,8 @@ def process_run_input(
|
|
|
218
219
|
temp_src: str,
|
|
219
220
|
run_format: str,
|
|
220
221
|
manifest: Manifest,
|
|
221
|
-
input_data:
|
|
222
|
-
inputs_dir_path:
|
|
222
|
+
input_data: dict[str, Any] | str | None = None,
|
|
223
|
+
inputs_dir_path: str | None = None,
|
|
223
224
|
) -> str:
|
|
224
225
|
"""
|
|
225
226
|
In the temp source, writes the run input according to the run format. If
|
|
@@ -465,7 +466,7 @@ def process_run_logs(
|
|
|
465
466
|
output_format: OutputFormat,
|
|
466
467
|
run_dir: str,
|
|
467
468
|
result: subprocess.CompletedProcess[str],
|
|
468
|
-
stdout_output:
|
|
469
|
+
stdout_output: str | dict[str, Any],
|
|
469
470
|
) -> None:
|
|
470
471
|
"""
|
|
471
472
|
Processes the logs of the run. Writes the logs to a logs directory.
|
|
@@ -502,7 +503,7 @@ def process_run_logs(
|
|
|
502
503
|
def process_run_statistics(
|
|
503
504
|
temp_run_outputs_dir: str,
|
|
504
505
|
outputs_dir: str,
|
|
505
|
-
stdout_output:
|
|
506
|
+
stdout_output: str | dict[str, Any],
|
|
506
507
|
temp_src: str,
|
|
507
508
|
manifest: Manifest,
|
|
508
509
|
) -> None:
|
|
@@ -563,7 +564,7 @@ def process_run_statistics(
|
|
|
563
564
|
def process_run_assets(
|
|
564
565
|
temp_run_outputs_dir: str,
|
|
565
566
|
outputs_dir: str,
|
|
566
|
-
stdout_output:
|
|
567
|
+
stdout_output: str | dict[str, Any],
|
|
567
568
|
temp_src: str,
|
|
568
569
|
manifest: Manifest,
|
|
569
570
|
) -> None:
|
|
@@ -627,7 +628,7 @@ def process_run_solutions(
|
|
|
627
628
|
temp_run_outputs_dir: str,
|
|
628
629
|
temp_src: str,
|
|
629
630
|
outputs_dir: str,
|
|
630
|
-
stdout_output:
|
|
631
|
+
stdout_output: str | dict[str, Any],
|
|
631
632
|
output_format: OutputFormat,
|
|
632
633
|
manifest: Manifest,
|
|
633
634
|
src: str,
|
|
@@ -756,7 +757,7 @@ def process_run_visuals(run_dir: str, outputs_dir: str) -> None:
|
|
|
756
757
|
# so we ignore it for now.
|
|
757
758
|
|
|
758
759
|
|
|
759
|
-
def resolve_stdout(result: subprocess.CompletedProcess[str]) ->
|
|
760
|
+
def resolve_stdout(result: subprocess.CompletedProcess[str]) -> str | dict[str, Any]:
|
|
760
761
|
"""
|
|
761
762
|
Resolves the stdout output of the subprocess run. If the stdout is valid
|
|
762
763
|
JSON, it returns the parsed dictionary. Otherwise, it returns the raw
|
|
@@ -838,8 +839,8 @@ def _ignore_patterns(dir_path: str, names: list[str]) -> list[str]:
|
|
|
838
839
|
def _copy_new_or_modified_files( # noqa: C901
|
|
839
840
|
runtime_dir: str,
|
|
840
841
|
dst_dir: str,
|
|
841
|
-
original_src_dir:
|
|
842
|
-
exclusion_dirs:
|
|
842
|
+
original_src_dir: str | None = None,
|
|
843
|
+
exclusion_dirs: list[str] | None = None,
|
|
843
844
|
) -> None:
|
|
844
845
|
"""
|
|
845
846
|
Copy only new or modified files from runtime directory to destination directory.
|
|
@@ -1006,5 +1007,34 @@ def _calculate_file_checksum(file_path: str) -> str:
|
|
|
1006
1007
|
return hash_md5.hexdigest()
|
|
1007
1008
|
|
|
1008
1009
|
|
|
1010
|
+
def __determine_entrypoint(manifest: Manifest) -> str:
|
|
1011
|
+
"""Returns the default entrypoint based on the runtime if not explicitly set."""
|
|
1012
|
+
if manifest.execution is not None and manifest.execution.entrypoint is not None:
|
|
1013
|
+
return manifest.execution.entrypoint
|
|
1014
|
+
|
|
1015
|
+
# Determine default entrypoint based on type
|
|
1016
|
+
if manifest.type == ManifestType.PYTHON:
|
|
1017
|
+
return "./main.py"
|
|
1018
|
+
elif manifest.type == ManifestType.GO:
|
|
1019
|
+
return "./main"
|
|
1020
|
+
elif manifest.type == ManifestType.JAVA:
|
|
1021
|
+
return "./main.jar"
|
|
1022
|
+
else:
|
|
1023
|
+
raise ValueError(
|
|
1024
|
+
f'entrypoint is not provided but the app type "{manifest.type}" could not '
|
|
1025
|
+
"be resolved to establish a default entrypoint"
|
|
1026
|
+
)
|
|
1027
|
+
|
|
1028
|
+
|
|
1029
|
+
def __determine_cwd(manifest: Manifest, default: str) -> str:
|
|
1030
|
+
"""
|
|
1031
|
+
Returns the working directory based on the manifest if set, otherwise the default.
|
|
1032
|
+
"""
|
|
1033
|
+
if manifest.execution is not None and manifest.execution.cwd is not None:
|
|
1034
|
+
return manifest.execution.cwd
|
|
1035
|
+
|
|
1036
|
+
return default
|
|
1037
|
+
|
|
1038
|
+
|
|
1009
1039
|
if __name__ == "__main__":
|
|
1010
1040
|
main()
|
nextmv/local/runner.py
CHANGED
|
@@ -20,7 +20,7 @@ import shutil
|
|
|
20
20
|
import subprocess
|
|
21
21
|
import sys
|
|
22
22
|
from datetime import datetime, timezone
|
|
23
|
-
from typing import Any
|
|
23
|
+
from typing import Any
|
|
24
24
|
|
|
25
25
|
from nextmv.input import INPUTS_KEY
|
|
26
26
|
from nextmv.local.local import DEFAULT_INPUT_JSON_FILE, NEXTMV_DIR, RUNS_KEY, calculate_files_size
|
|
@@ -34,11 +34,11 @@ def run(
|
|
|
34
34
|
src: str,
|
|
35
35
|
manifest: Manifest,
|
|
36
36
|
run_config: dict[str, Any],
|
|
37
|
-
name:
|
|
38
|
-
description:
|
|
39
|
-
input_data:
|
|
40
|
-
inputs_dir_path:
|
|
41
|
-
options:
|
|
37
|
+
name: str | None = None,
|
|
38
|
+
description: str | None = None,
|
|
39
|
+
input_data: dict[str, Any] | str | None = None,
|
|
40
|
+
inputs_dir_path: str | None = None,
|
|
41
|
+
options: dict[str, Any] | None = None,
|
|
42
42
|
) -> str:
|
|
43
43
|
"""
|
|
44
44
|
Execute a local run.
|
|
@@ -145,8 +145,8 @@ def new_run(
|
|
|
145
145
|
src: str,
|
|
146
146
|
run_id: str,
|
|
147
147
|
run_config: dict[str, Any],
|
|
148
|
-
name:
|
|
149
|
-
description:
|
|
148
|
+
name: str | None = None,
|
|
149
|
+
description: str | None = None,
|
|
150
150
|
) -> str:
|
|
151
151
|
"""
|
|
152
152
|
Initializes a new run.
|
|
@@ -223,8 +223,8 @@ def new_run(
|
|
|
223
223
|
def record_input(
|
|
224
224
|
run_dir: str,
|
|
225
225
|
run_id: str,
|
|
226
|
-
input_data:
|
|
227
|
-
inputs_dir_path:
|
|
226
|
+
input_data: dict[str, Any] | str | None = None,
|
|
227
|
+
inputs_dir_path: str | None = None,
|
|
228
228
|
) -> None:
|
|
229
229
|
"""
|
|
230
230
|
Writes the input to the appropriate location.
|