nextmv 1.0.0__py3-none-any.whl → 1.0.0.dev0__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/__entrypoint__.py +2 -1
- nextmv/__init__.py +4 -0
- nextmv/cli/CONTRIBUTING.md +40 -112
- nextmv/cli/cloud/__init__.py +0 -4
- nextmv/cli/cloud/acceptance/create.py +22 -20
- nextmv/cli/cloud/acceptance/delete.py +12 -8
- nextmv/cli/cloud/acceptance/get.py +10 -9
- nextmv/cli/cloud/acceptance/list.py +3 -3
- nextmv/cli/cloud/acceptance/update.py +6 -6
- nextmv/cli/cloud/account/__init__.py +3 -3
- nextmv/cli/cloud/account/create.py +11 -11
- nextmv/cli/cloud/account/delete.py +8 -7
- nextmv/cli/cloud/account/get.py +3 -3
- nextmv/cli/cloud/account/update.py +5 -5
- nextmv/cli/cloud/app/create.py +26 -25
- nextmv/cli/cloud/app/delete.py +7 -6
- nextmv/cli/cloud/app/exists.py +2 -2
- nextmv/cli/cloud/app/get.py +2 -2
- nextmv/cli/cloud/app/list.py +3 -3
- nextmv/cli/cloud/app/push.py +54 -349
- nextmv/cli/cloud/app/update.py +12 -12
- nextmv/cli/cloud/batch/create.py +28 -26
- nextmv/cli/cloud/batch/delete.py +10 -6
- nextmv/cli/cloud/batch/get.py +9 -9
- nextmv/cli/cloud/batch/list.py +3 -3
- nextmv/cli/cloud/batch/metadata.py +4 -4
- nextmv/cli/cloud/batch/update.py +6 -6
- nextmv/cli/cloud/data/__init__.py +1 -1
- nextmv/cli/cloud/data/upload.py +15 -15
- nextmv/cli/cloud/ensemble/__init__.py +0 -2
- nextmv/cli/cloud/ensemble/create.py +22 -21
- nextmv/cli/cloud/ensemble/delete.py +10 -6
- nextmv/cli/cloud/ensemble/get.py +4 -4
- nextmv/cli/cloud/ensemble/update.py +9 -9
- nextmv/cli/cloud/input_set/__init__.py +0 -2
- nextmv/cli/cloud/input_set/create.py +22 -22
- nextmv/cli/cloud/input_set/get.py +3 -3
- nextmv/cli/cloud/input_set/list.py +3 -3
- nextmv/cli/cloud/input_set/update.py +24 -24
- nextmv/cli/cloud/instance/create.py +15 -14
- nextmv/cli/cloud/instance/delete.py +7 -6
- nextmv/cli/cloud/instance/exists.py +2 -2
- nextmv/cli/cloud/instance/get.py +2 -2
- nextmv/cli/cloud/instance/list.py +3 -3
- nextmv/cli/cloud/instance/update.py +14 -14
- nextmv/cli/cloud/managed_input/create.py +16 -14
- nextmv/cli/cloud/managed_input/delete.py +8 -7
- nextmv/cli/cloud/managed_input/get.py +3 -3
- nextmv/cli/cloud/managed_input/list.py +3 -3
- nextmv/cli/cloud/managed_input/update.py +9 -9
- nextmv/cli/cloud/run/cancel.py +2 -2
- nextmv/cli/cloud/run/create.py +40 -34
- nextmv/cli/cloud/run/get.py +8 -8
- nextmv/cli/cloud/run/input.py +4 -4
- nextmv/cli/cloud/run/list.py +6 -6
- nextmv/cli/cloud/run/logs.py +10 -9
- nextmv/cli/cloud/run/metadata.py +4 -4
- nextmv/cli/cloud/run/track.py +33 -32
- nextmv/cli/cloud/scenario/create.py +21 -21
- nextmv/cli/cloud/scenario/delete.py +10 -6
- nextmv/cli/cloud/scenario/get.py +9 -9
- nextmv/cli/cloud/scenario/list.py +3 -3
- nextmv/cli/cloud/scenario/metadata.py +4 -4
- nextmv/cli/cloud/scenario/update.py +6 -6
- nextmv/cli/cloud/secrets/create.py +17 -17
- nextmv/cli/cloud/secrets/delete.py +10 -6
- nextmv/cli/cloud/secrets/get.py +4 -4
- nextmv/cli/cloud/secrets/list.py +3 -3
- nextmv/cli/cloud/secrets/update.py +20 -17
- nextmv/cli/cloud/upload/create.py +2 -2
- nextmv/cli/cloud/version/create.py +10 -9
- nextmv/cli/cloud/version/delete.py +7 -6
- nextmv/cli/cloud/version/exists.py +2 -2
- nextmv/cli/cloud/version/get.py +2 -2
- nextmv/cli/cloud/version/list.py +3 -3
- nextmv/cli/cloud/version/update.py +8 -8
- nextmv/cli/community/__init__.py +1 -1
- nextmv/cli/community/clone.py +204 -20
- nextmv/cli/community/list.py +125 -60
- nextmv/cli/configuration/config.py +10 -43
- nextmv/cli/configuration/create.py +7 -7
- nextmv/cli/configuration/delete.py +8 -8
- nextmv/cli/configuration/list.py +3 -3
- nextmv/cli/main.py +36 -26
- nextmv/cli/message.py +54 -71
- nextmv/cli/options.py +0 -28
- nextmv/cli/version.py +1 -1
- nextmv/cloud/__init__.py +38 -14
- nextmv/cloud/acceptance_test.py +65 -1
- nextmv/cloud/account.py +6 -1
- nextmv/cloud/application/__init__.py +75 -18
- nextmv/cloud/application/_acceptance.py +8 -13
- nextmv/cloud/application/_batch_scenario.py +19 -4
- nextmv/cloud/application/_input_set.py +6 -42
- nextmv/cloud/application/_instance.py +3 -3
- nextmv/cloud/application/_managed_input.py +2 -2
- nextmv/cloud/application/_version.py +3 -4
- nextmv/cloud/batch_experiment.py +1 -3
- nextmv/cloud/integration.py +4 -7
- nextmv/deprecated.py +3 -5
- nextmv/input.py +52 -0
- nextmv/local/runner.py +1 -1
- nextmv/model.py +11 -50
- nextmv/options.py +256 -11
- nextmv/output.py +62 -0
- nextmv/run.py +10 -1
- nextmv/status.py +51 -1
- {nextmv-1.0.0.dist-info → nextmv-1.0.0.dev0.dist-info}/METADATA +4 -5
- nextmv-1.0.0.dev0.dist-info/RECORD +158 -0
- nextmv/cli/cloud/ensemble/list.py +0 -63
- nextmv/cli/cloud/input_set/delete.py +0 -64
- nextmv/cli/cloud/shadow/__init__.py +0 -33
- nextmv/cli/cloud/shadow/create.py +0 -184
- nextmv/cli/cloud/shadow/delete.py +0 -64
- nextmv/cli/cloud/shadow/get.py +0 -61
- nextmv/cli/cloud/shadow/list.py +0 -63
- nextmv/cli/cloud/shadow/metadata.py +0 -66
- nextmv/cli/cloud/shadow/start.py +0 -43
- nextmv/cli/cloud/shadow/stop.py +0 -53
- nextmv/cli/cloud/shadow/update.py +0 -96
- nextmv/cli/cloud/switchback/__init__.py +0 -33
- nextmv/cli/cloud/switchback/create.py +0 -151
- nextmv/cli/cloud/switchback/delete.py +0 -64
- nextmv/cli/cloud/switchback/get.py +0 -62
- nextmv/cli/cloud/switchback/list.py +0 -63
- nextmv/cli/cloud/switchback/metadata.py +0 -68
- nextmv/cli/cloud/switchback/start.py +0 -43
- nextmv/cli/cloud/switchback/stop.py +0 -53
- nextmv/cli/cloud/switchback/update.py +0 -96
- nextmv/cli/confirm.py +0 -34
- nextmv/cloud/application/_shadow.py +0 -320
- nextmv/cloud/application/_switchback.py +0 -332
- nextmv/cloud/community.py +0 -446
- nextmv/cloud/shadow.py +0 -254
- nextmv/cloud/switchback.py +0 -228
- nextmv-1.0.0.dist-info/RECORD +0 -185
- nextmv-1.0.0.dist-info/entry_points.txt +0 -2
- {nextmv-1.0.0.dist-info → nextmv-1.0.0.dev0.dist-info}/WHEEL +0 -0
- {nextmv-1.0.0.dist-info → nextmv-1.0.0.dev0.dist-info}/licenses/LICENSE +0 -0
|
@@ -21,7 +21,7 @@ list_application
|
|
|
21
21
|
import json
|
|
22
22
|
import shutil
|
|
23
23
|
import sys
|
|
24
|
-
from datetime import datetime
|
|
24
|
+
from datetime import datetime, timezone
|
|
25
25
|
from enum import Enum
|
|
26
26
|
from typing import Any
|
|
27
27
|
|
|
@@ -41,8 +41,6 @@ from nextmv.cloud.application._instance import ApplicationInstanceMixin
|
|
|
41
41
|
from nextmv.cloud.application._managed_input import ApplicationManagedInputMixin
|
|
42
42
|
from nextmv.cloud.application._run import ApplicationRunMixin
|
|
43
43
|
from nextmv.cloud.application._secrets import ApplicationSecretsMixin
|
|
44
|
-
from nextmv.cloud.application._shadow import ApplicationShadowMixin
|
|
45
|
-
from nextmv.cloud.application._switchback import ApplicationSwitchbackMixin
|
|
46
44
|
from nextmv.cloud.application._utils import _is_not_exist_error
|
|
47
45
|
from nextmv.cloud.application._version import ApplicationVersionMixin
|
|
48
46
|
from nextmv.cloud.client import Client
|
|
@@ -102,8 +100,6 @@ class Application(
|
|
|
102
100
|
ApplicationVersionMixin,
|
|
103
101
|
ApplicationInputSetMixin,
|
|
104
102
|
ApplicationManagedInputMixin,
|
|
105
|
-
ApplicationShadowMixin,
|
|
106
|
-
ApplicationSwitchbackMixin,
|
|
107
103
|
):
|
|
108
104
|
"""
|
|
109
105
|
A published decision model that can be executed.
|
|
@@ -250,7 +246,7 @@ class Application(
|
|
|
250
246
|
def new(
|
|
251
247
|
cls,
|
|
252
248
|
client: Client,
|
|
253
|
-
name: str
|
|
249
|
+
name: str,
|
|
254
250
|
id: str | None = None,
|
|
255
251
|
description: str | None = None,
|
|
256
252
|
is_workflow: bool | None = None,
|
|
@@ -268,13 +264,13 @@ class Application(
|
|
|
268
264
|
----------
|
|
269
265
|
client : Client
|
|
270
266
|
Client to use for interacting with the Nextmv Cloud API.
|
|
271
|
-
name : str
|
|
272
|
-
Name of the application.
|
|
273
|
-
id : str
|
|
267
|
+
name : str
|
|
268
|
+
Name of the application.
|
|
269
|
+
id : str, optional
|
|
274
270
|
ID of the application. Will be generated if not provided.
|
|
275
|
-
description : str
|
|
271
|
+
description : str, optional
|
|
276
272
|
Description of the application.
|
|
277
|
-
is_workflow : bool
|
|
273
|
+
is_workflow : bool, optional
|
|
278
274
|
Whether the application is a Decision Workflow.
|
|
279
275
|
exist_ok : bool, default=False
|
|
280
276
|
If True and an application with the same ID already exists,
|
|
@@ -296,10 +292,7 @@ class Application(
|
|
|
296
292
|
>>> app = Application.new(client=client, name="My New App", id="my-app")
|
|
297
293
|
"""
|
|
298
294
|
|
|
299
|
-
if
|
|
300
|
-
raise ValueError("If exist_ok is True, id must be provided")
|
|
301
|
-
|
|
302
|
-
if id is None or id == "":
|
|
295
|
+
if id is None:
|
|
303
296
|
id = safe_id("app")
|
|
304
297
|
|
|
305
298
|
if exist_ok and cls.exists(client=client, id=id):
|
|
@@ -310,9 +303,6 @@ class Application(
|
|
|
310
303
|
|
|
311
304
|
return cls.from_dict({"client": client} | response.json())
|
|
312
305
|
|
|
313
|
-
if name is None or name == "":
|
|
314
|
-
name = id
|
|
315
|
-
|
|
316
306
|
payload = {
|
|
317
307
|
"name": name,
|
|
318
308
|
"id": id,
|
|
@@ -405,6 +395,10 @@ class Application(
|
|
|
405
395
|
model: Model | None = None,
|
|
406
396
|
model_configuration: ModelConfiguration | None = None,
|
|
407
397
|
rich_print: bool = False,
|
|
398
|
+
no_version: bool = False,
|
|
399
|
+
version_id: str | None = None,
|
|
400
|
+
version_name: str | None = None,
|
|
401
|
+
version_description: str | None = None,
|
|
408
402
|
) -> None:
|
|
409
403
|
"""
|
|
410
404
|
Push an app to Nextmv Cloud.
|
|
@@ -422,6 +416,15 @@ class Application(
|
|
|
422
416
|
`nextmv.Model`. The model is encoded, some dependencies and
|
|
423
417
|
accompanying files are packaged, and the app is pushed to Nextmv Cloud.
|
|
424
418
|
|
|
419
|
+
The default behavior of this function is to create a new application
|
|
420
|
+
version _after_ the app has been pushed. You can set the `no_version`
|
|
421
|
+
argument to `True` to skip this step. The `version_id`, `version_name`,
|
|
422
|
+
and `version_description` arguments can be used to customize the version
|
|
423
|
+
that is created. If the `version_id` is not specified, a randomly
|
|
424
|
+
generated ID will be used. If the `version_name` is not specified, a
|
|
425
|
+
generic name with a timestamp will be used. Lastly, if no description is
|
|
426
|
+
specified, then a generic description will also be used.
|
|
427
|
+
|
|
425
428
|
Parameters
|
|
426
429
|
----------
|
|
427
430
|
manifest : Optional[Manifest], default=None
|
|
@@ -440,6 +443,21 @@ class Application(
|
|
|
440
443
|
with `model`.
|
|
441
444
|
rich_print : bool, default=False
|
|
442
445
|
Whether to use rich printing when verbose output is enabled.
|
|
446
|
+
no_version : bool, default=False
|
|
447
|
+
If True, do not create a new version after pushing the app.
|
|
448
|
+
version_id : Optional[str], default=None
|
|
449
|
+
ID of the version to create after pushing the app. If None, a unique
|
|
450
|
+
ID will be generated.
|
|
451
|
+
version_name : Optional[str], default=None
|
|
452
|
+
Name of the version to create after pushing the app. If None, a name
|
|
453
|
+
with a timestamp will be generated.
|
|
454
|
+
version_description : Optional[str], default=None
|
|
455
|
+
Description of the version to create after pushing the app. If None, a
|
|
456
|
+
generic description with a timestamp will be generated.
|
|
457
|
+
|
|
458
|
+
Returns
|
|
459
|
+
-------
|
|
460
|
+
None
|
|
443
461
|
|
|
444
462
|
Raises
|
|
445
463
|
------
|
|
@@ -543,6 +561,45 @@ class Application(
|
|
|
543
561
|
except OSError as e:
|
|
544
562
|
raise Exception(f"error deleting output directory: {e}") from e
|
|
545
563
|
|
|
564
|
+
if no_version:
|
|
565
|
+
if verbose:
|
|
566
|
+
if rich_print:
|
|
567
|
+
rich.print(
|
|
568
|
+
f":white_check_mark: Push completed for Nextmv application [magenta]{self.id}[/magenta] "
|
|
569
|
+
"without creating a new version.",
|
|
570
|
+
file=sys.stderr,
|
|
571
|
+
)
|
|
572
|
+
else:
|
|
573
|
+
log("✅ Push completed without creating a new version for Nextmv application.")
|
|
574
|
+
|
|
575
|
+
return
|
|
576
|
+
|
|
577
|
+
now = datetime.now(timezone.utc)
|
|
578
|
+
if version_id is None:
|
|
579
|
+
version_id = safe_id(prefix="version") + f"-{now.strftime('%Y%m%d-%H%M%S')}"
|
|
580
|
+
if version_name is None:
|
|
581
|
+
version_name = f"Version {version_id}"
|
|
582
|
+
if version_description is None:
|
|
583
|
+
version_description = f"Version created automatically from push at {now.strftime('%Y-%m-%dT%H:%M:%SZ')}"
|
|
584
|
+
|
|
585
|
+
version = self.new_version(
|
|
586
|
+
id=version_id,
|
|
587
|
+
name=version_name,
|
|
588
|
+
description=version_description,
|
|
589
|
+
)
|
|
590
|
+
version_dict = version.to_dict()
|
|
591
|
+
|
|
592
|
+
if verbose:
|
|
593
|
+
if rich_print:
|
|
594
|
+
rich.print(
|
|
595
|
+
f":white_check_mark: Automatically created new version [magenta]{version.id}[/magenta].",
|
|
596
|
+
file=sys.stderr,
|
|
597
|
+
)
|
|
598
|
+
rich.print_json(data=version_dict)
|
|
599
|
+
else:
|
|
600
|
+
log(f'✅ Automatically created new version "{version.id}".')
|
|
601
|
+
log(json.dumps(version_dict, indent=2))
|
|
602
|
+
|
|
546
603
|
def update(
|
|
547
604
|
self,
|
|
548
605
|
name: str | None = None,
|
|
@@ -9,7 +9,6 @@ import requests
|
|
|
9
9
|
from nextmv.cloud.acceptance_test import AcceptanceTest, Metric
|
|
10
10
|
from nextmv.cloud.batch_experiment import BatchExperimentRun, ExperimentStatus
|
|
11
11
|
from nextmv.polling import DEFAULT_POLLING_OPTIONS, PollingOptions, poll
|
|
12
|
-
from nextmv.safe import safe_id
|
|
13
12
|
|
|
14
13
|
if TYPE_CHECKING:
|
|
15
14
|
from . import Application
|
|
@@ -164,8 +163,8 @@ class ApplicationAcceptanceMixin:
|
|
|
164
163
|
self: "Application",
|
|
165
164
|
candidate_instance_id: str,
|
|
166
165
|
baseline_instance_id: str,
|
|
166
|
+
id: str,
|
|
167
167
|
metrics: list[Metric | dict[str, Any]],
|
|
168
|
-
id: str | None = None,
|
|
169
168
|
name: str | None = None,
|
|
170
169
|
input_set_id: str | None = None,
|
|
171
170
|
description: str | None = None,
|
|
@@ -186,8 +185,8 @@ class ApplicationAcceptanceMixin:
|
|
|
186
185
|
ID of the candidate instance.
|
|
187
186
|
baseline_instance_id : str
|
|
188
187
|
ID of the baseline instance.
|
|
189
|
-
id : str
|
|
190
|
-
ID of the acceptance test.
|
|
188
|
+
id : str
|
|
189
|
+
ID of the acceptance test.
|
|
191
190
|
metrics : list[Union[Metric, dict[str, Any]]]
|
|
192
191
|
List of metrics to use for the acceptance test.
|
|
193
192
|
name : Optional[str], default=None
|
|
@@ -211,11 +210,6 @@ class ApplicationAcceptanceMixin:
|
|
|
211
210
|
If the batch experiment ID does not match the acceptance test ID.
|
|
212
211
|
"""
|
|
213
212
|
|
|
214
|
-
# Generate ID if not provided
|
|
215
|
-
if id is None or id == "":
|
|
216
|
-
id = safe_id("acceptance")
|
|
217
|
-
|
|
218
|
-
# Use ID as name if name not provided
|
|
219
213
|
if name is None or name == "":
|
|
220
214
|
name = id
|
|
221
215
|
|
|
@@ -271,10 +265,11 @@ class ApplicationAcceptanceMixin:
|
|
|
271
265
|
"metrics": payload_metrics,
|
|
272
266
|
"experiment_id": batch_experiment_id,
|
|
273
267
|
"name": name,
|
|
274
|
-
"id": id,
|
|
275
268
|
}
|
|
276
269
|
if description is not None:
|
|
277
270
|
payload["description"] = description
|
|
271
|
+
if id is not None:
|
|
272
|
+
payload["id"] = id
|
|
278
273
|
|
|
279
274
|
response = self.client.request(
|
|
280
275
|
method="POST",
|
|
@@ -288,8 +283,8 @@ class ApplicationAcceptanceMixin:
|
|
|
288
283
|
self: "Application",
|
|
289
284
|
candidate_instance_id: str,
|
|
290
285
|
baseline_instance_id: str,
|
|
286
|
+
id: str,
|
|
291
287
|
metrics: list[Metric | dict[str, Any]],
|
|
292
|
-
id: str | None = None,
|
|
293
288
|
name: str | None = None,
|
|
294
289
|
input_set_id: str | None = None,
|
|
295
290
|
description: str | None = None,
|
|
@@ -307,8 +302,8 @@ class ApplicationAcceptanceMixin:
|
|
|
307
302
|
ID of the candidate instance.
|
|
308
303
|
baseline_instance_id : str
|
|
309
304
|
ID of the baseline instance.
|
|
310
|
-
id : str
|
|
311
|
-
ID of the acceptance test.
|
|
305
|
+
id : str
|
|
306
|
+
ID of the acceptance test.
|
|
312
307
|
metrics : list[Union[Metric, dict[str, Any]]]
|
|
313
308
|
List of metrics to use for the acceptance test.
|
|
314
309
|
name : Optional[str], default=None
|
|
@@ -10,6 +10,7 @@ from nextmv.cloud.batch_experiment import (
|
|
|
10
10
|
BatchExperimentMetadata,
|
|
11
11
|
BatchExperimentRun,
|
|
12
12
|
ExperimentStatus,
|
|
13
|
+
to_runs,
|
|
13
14
|
)
|
|
14
15
|
from nextmv.cloud.input_set import InputSet, ManagedInput
|
|
15
16
|
from nextmv.cloud.scenario import Scenario, ScenarioInputType, _option_sets, _scenarios_by_id
|
|
@@ -257,6 +258,7 @@ class ApplicationBatchMixin:
|
|
|
257
258
|
self: "Application",
|
|
258
259
|
name: str | None = None,
|
|
259
260
|
input_set_id: str | None = None,
|
|
261
|
+
instance_ids: list[str] | None = None,
|
|
260
262
|
description: str | None = None,
|
|
261
263
|
id: str | None = None,
|
|
262
264
|
option_sets: dict[str, dict[str, str]] | None = None,
|
|
@@ -272,6 +274,9 @@ class ApplicationBatchMixin:
|
|
|
272
274
|
Name of the batch experiment. If not provided, the ID will be used as the name.
|
|
273
275
|
input_set_id: str | None
|
|
274
276
|
ID of the input set to use for the batch experiment.
|
|
277
|
+
instance_ids: list[str]
|
|
278
|
+
This argument is deprecated, use `runs` instead.
|
|
279
|
+
List of instance IDs to use for the batch experiment.
|
|
275
280
|
description: Optional[str]
|
|
276
281
|
Optional description of the batch experiment.
|
|
277
282
|
id: Optional[str]
|
|
@@ -299,11 +304,11 @@ class ApplicationBatchMixin:
|
|
|
299
304
|
"""
|
|
300
305
|
|
|
301
306
|
# Generate ID if not provided
|
|
302
|
-
if id is None
|
|
307
|
+
if id is None:
|
|
303
308
|
id = safe_id("batch")
|
|
304
309
|
|
|
305
310
|
# Use ID as name if name not provided
|
|
306
|
-
if name is None
|
|
311
|
+
if name is None:
|
|
307
312
|
name = id
|
|
308
313
|
|
|
309
314
|
payload = {
|
|
@@ -312,6 +317,11 @@ class ApplicationBatchMixin:
|
|
|
312
317
|
}
|
|
313
318
|
if input_set_id is not None:
|
|
314
319
|
payload["input_set_id"] = input_set_id
|
|
320
|
+
if instance_ids is not None:
|
|
321
|
+
input_set = self.input_set(input_set_id)
|
|
322
|
+
runs = to_runs(instance_ids, input_set)
|
|
323
|
+
payload_runs = [run.to_dict() for run in runs]
|
|
324
|
+
payload["runs"] = payload_runs
|
|
315
325
|
if description is not None:
|
|
316
326
|
payload["description"] = description
|
|
317
327
|
if option_sets is not None:
|
|
@@ -336,6 +346,7 @@ class ApplicationBatchMixin:
|
|
|
336
346
|
self: "Application",
|
|
337
347
|
name: str | None = None,
|
|
338
348
|
input_set_id: str | None = None,
|
|
349
|
+
instance_ids: list[str] | None = None,
|
|
339
350
|
description: str | None = None,
|
|
340
351
|
id: str | None = None,
|
|
341
352
|
option_sets: dict[str, dict[str, str]] | None = None,
|
|
@@ -357,6 +368,9 @@ class ApplicationBatchMixin:
|
|
|
357
368
|
Name of the batch experiment. If not provided, the ID will be used as the name.
|
|
358
369
|
input_set_id: str
|
|
359
370
|
ID of the input set to use for the batch experiment.
|
|
371
|
+
instance_ids: list[str]
|
|
372
|
+
List of instance IDs to use for the batch experiment. This argument
|
|
373
|
+
is deprecated, use `runs` instead.
|
|
360
374
|
description: Optional[str]
|
|
361
375
|
Optional description of the batch experiment.
|
|
362
376
|
id: Optional[str]
|
|
@@ -388,6 +402,7 @@ class ApplicationBatchMixin:
|
|
|
388
402
|
batch_id = self.new_batch_experiment(
|
|
389
403
|
name=name,
|
|
390
404
|
input_set_id=input_set_id,
|
|
405
|
+
instance_ids=instance_ids,
|
|
391
406
|
description=description,
|
|
392
407
|
id=id,
|
|
393
408
|
option_sets=option_sets,
|
|
@@ -466,11 +481,11 @@ class ApplicationBatchMixin:
|
|
|
466
481
|
raise ValueError("At least one scenario must be provided")
|
|
467
482
|
|
|
468
483
|
# Generate ID if not provided
|
|
469
|
-
if id is None
|
|
484
|
+
if id is None:
|
|
470
485
|
id = safe_id("scenario")
|
|
471
486
|
|
|
472
487
|
# Use ID as name if name not provided
|
|
473
|
-
if name is None
|
|
488
|
+
if name is None:
|
|
474
489
|
name = id
|
|
475
490
|
|
|
476
491
|
scenarios_by_id = _scenarios_by_id(scenarios)
|
|
@@ -6,7 +6,6 @@ from datetime import datetime
|
|
|
6
6
|
from typing import TYPE_CHECKING
|
|
7
7
|
|
|
8
8
|
from nextmv.cloud.input_set import InputSet, ManagedInput
|
|
9
|
-
from nextmv.safe import safe_id
|
|
10
9
|
|
|
11
10
|
if TYPE_CHECKING:
|
|
12
11
|
from . import Application
|
|
@@ -17,32 +16,6 @@ class ApplicationInputSetMixin:
|
|
|
17
16
|
Mixin class for managing app input sets within an application.
|
|
18
17
|
"""
|
|
19
18
|
|
|
20
|
-
def delete_input_set(self: "Application", input_set_id: str) -> None:
|
|
21
|
-
"""
|
|
22
|
-
Delete an input set.
|
|
23
|
-
|
|
24
|
-
Deletes an input set along with all the associated information.
|
|
25
|
-
|
|
26
|
-
Parameters
|
|
27
|
-
----------
|
|
28
|
-
input_set_id : str
|
|
29
|
-
ID of the input set to delete.
|
|
30
|
-
|
|
31
|
-
Raises
|
|
32
|
-
------
|
|
33
|
-
requests.HTTPError
|
|
34
|
-
If the response status code is not 2xx.
|
|
35
|
-
|
|
36
|
-
Examples
|
|
37
|
-
--------
|
|
38
|
-
>>> app.delete_input_set("input-set-123")
|
|
39
|
-
"""
|
|
40
|
-
|
|
41
|
-
_ = self.client.request(
|
|
42
|
-
method="DELETE",
|
|
43
|
-
endpoint=f"{self.experiments_endpoint}/inputsets/{input_set_id}",
|
|
44
|
-
)
|
|
45
|
-
|
|
46
19
|
def input_set(self: "Application", input_set_id: str) -> InputSet:
|
|
47
20
|
"""
|
|
48
21
|
Get an input set.
|
|
@@ -108,8 +81,8 @@ class ApplicationInputSetMixin:
|
|
|
108
81
|
|
|
109
82
|
def new_input_set(
|
|
110
83
|
self: "Application",
|
|
111
|
-
id: str
|
|
112
|
-
name: str
|
|
84
|
+
id: str,
|
|
85
|
+
name: str,
|
|
113
86
|
description: str | None = None,
|
|
114
87
|
end_time: datetime | None = None,
|
|
115
88
|
instance_id: str | None = None,
|
|
@@ -134,11 +107,10 @@ class ApplicationInputSetMixin:
|
|
|
134
107
|
|
|
135
108
|
Parameters
|
|
136
109
|
----------
|
|
137
|
-
id: str
|
|
138
|
-
ID of the input set
|
|
139
|
-
name: str
|
|
140
|
-
Name of the input set.
|
|
141
|
-
the name.
|
|
110
|
+
id: str
|
|
111
|
+
ID of the input set
|
|
112
|
+
name: str
|
|
113
|
+
Name of the input set.
|
|
142
114
|
description: Optional[str]
|
|
143
115
|
Optional description of the input set.
|
|
144
116
|
end_time: Optional[datetime]
|
|
@@ -173,14 +145,6 @@ class ApplicationInputSetMixin:
|
|
|
173
145
|
If the response status code is not 2xx.
|
|
174
146
|
"""
|
|
175
147
|
|
|
176
|
-
# Generate ID if not provided
|
|
177
|
-
if id is None or id == "":
|
|
178
|
-
id = safe_id("input-set")
|
|
179
|
-
|
|
180
|
-
# Use ID as name if name not provided
|
|
181
|
-
if name is None or name == "":
|
|
182
|
-
name = id
|
|
183
|
-
|
|
184
148
|
payload = {
|
|
185
149
|
"id": id,
|
|
186
150
|
"name": name,
|
|
@@ -194,15 +194,15 @@ class ApplicationInstanceMixin:
|
|
|
194
194
|
'Production Instance'
|
|
195
195
|
"""
|
|
196
196
|
|
|
197
|
-
if exist_ok and
|
|
197
|
+
if exist_ok and id is None:
|
|
198
198
|
raise ValueError("If exist_ok is True, id must be provided")
|
|
199
199
|
|
|
200
200
|
if exist_ok and self.instance_exists(instance_id=id):
|
|
201
201
|
return self.instance(instance_id=id)
|
|
202
202
|
|
|
203
|
-
if id is None
|
|
203
|
+
if id is None:
|
|
204
204
|
id = safe_id(prefix="instance")
|
|
205
|
-
if name is None
|
|
205
|
+
if name is None:
|
|
206
206
|
name = id
|
|
207
207
|
|
|
208
208
|
payload = {
|
|
@@ -147,9 +147,9 @@ class ApplicationManagedInputMixin:
|
|
|
147
147
|
if upload_id is None and run_id is None:
|
|
148
148
|
raise ValueError("Either upload_id or run_id must be specified")
|
|
149
149
|
|
|
150
|
-
if id is None
|
|
150
|
+
if id is None:
|
|
151
151
|
id = safe_id(prefix="managed-input")
|
|
152
|
-
if name is None
|
|
152
|
+
if name is None:
|
|
153
153
|
name = id
|
|
154
154
|
|
|
155
155
|
payload = {
|
|
@@ -132,16 +132,15 @@ class ApplicationVersionMixin:
|
|
|
132
132
|
... )
|
|
133
133
|
"""
|
|
134
134
|
|
|
135
|
-
if exist_ok and
|
|
135
|
+
if exist_ok and id is None:
|
|
136
136
|
raise ValueError("If exist_ok is True, id must be provided")
|
|
137
137
|
|
|
138
138
|
if exist_ok and self.version_exists(version_id=id):
|
|
139
139
|
return self.version(version_id=id)
|
|
140
140
|
|
|
141
|
-
if id is None
|
|
141
|
+
if id is None:
|
|
142
142
|
id = safe_id(prefix="version")
|
|
143
|
-
|
|
144
|
-
if name is None or name == "":
|
|
143
|
+
if name is None:
|
|
145
144
|
name = id
|
|
146
145
|
|
|
147
146
|
payload = {
|
nextmv/cloud/batch_experiment.py
CHANGED
|
@@ -30,9 +30,7 @@ class ExperimentStatus(str, Enum):
|
|
|
30
30
|
|
|
31
31
|
You can import the `ExperimentStatus` class directly from `cloud`:
|
|
32
32
|
|
|
33
|
-
```python
|
|
34
|
-
from nextmv.cloud import ExperimentStatus
|
|
35
|
-
```
|
|
33
|
+
```python from nextmv.cloud import ExperimentStatus ```
|
|
36
34
|
|
|
37
35
|
This enum represents the comprehensive set of possible states for an
|
|
38
36
|
experiment in Nextmv Cloud.
|
nextmv/cloud/integration.py
CHANGED
|
@@ -225,12 +225,12 @@ class Integration(BaseModel):
|
|
|
225
225
|
def new( # noqa: C901
|
|
226
226
|
cls,
|
|
227
227
|
client: Client,
|
|
228
|
+
name: str,
|
|
228
229
|
integration_type: IntegrationType | str,
|
|
229
230
|
exec_types: list[ManifestType | str],
|
|
230
231
|
provider: IntegrationProvider | str,
|
|
231
232
|
provider_config: dict[str, Any],
|
|
232
233
|
integration_id: str | None = None,
|
|
233
|
-
name: str | None = None,
|
|
234
234
|
description: str | None = None,
|
|
235
235
|
is_global: bool = False,
|
|
236
236
|
application_ids: list[str] | None = None,
|
|
@@ -243,6 +243,8 @@ class Integration(BaseModel):
|
|
|
243
243
|
----------
|
|
244
244
|
client : Client
|
|
245
245
|
Client to use for interacting with the Nextmv Cloud API.
|
|
246
|
+
name : str
|
|
247
|
+
The name of the integration.
|
|
246
248
|
integration_type : IntegrationType | str
|
|
247
249
|
The type of the integration. Please refer to the `IntegrationType`
|
|
248
250
|
enum for possible values.
|
|
@@ -257,9 +259,6 @@ class Integration(BaseModel):
|
|
|
257
259
|
integration_id : str, optional
|
|
258
260
|
The unique identifier of the integration. If not provided,
|
|
259
261
|
it will be generated automatically.
|
|
260
|
-
name : str | None, optional
|
|
261
|
-
The name of the integration. If not provided, the integration ID
|
|
262
|
-
will be used as the name.
|
|
263
262
|
description : str, optional
|
|
264
263
|
An optional description of the integration.
|
|
265
264
|
is_global : bool, optional, default=False
|
|
@@ -303,10 +302,8 @@ class Integration(BaseModel):
|
|
|
303
302
|
elif not is_global and application_ids is None:
|
|
304
303
|
raise ValueError("A non-global integration must have specific application IDs.")
|
|
305
304
|
|
|
306
|
-
if integration_id is None
|
|
305
|
+
if integration_id is None:
|
|
307
306
|
integration_id = safe_id("integration")
|
|
308
|
-
if name is None or name == "":
|
|
309
|
-
name = integration_id
|
|
310
307
|
|
|
311
308
|
if exist_ok:
|
|
312
309
|
try:
|
nextmv/deprecated.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Utilities for handling deprecated functionality within the Nextmv Python SDK.
|
|
1
|
+
"""Utilities for handling deprecated functionality within the Nextmv Python SDK.
|
|
3
2
|
|
|
4
3
|
This module provides tools to mark functions, methods, or features as deprecated,
|
|
5
4
|
emitting appropriate warnings to users. These warnings inform users that the
|
|
@@ -14,8 +13,7 @@ import warnings
|
|
|
14
13
|
|
|
15
14
|
|
|
16
15
|
def deprecated(name: str, reason: str) -> None:
|
|
17
|
-
"""
|
|
18
|
-
Mark functionality as deprecated with a warning message.
|
|
16
|
+
"""Mark functionality as deprecated with a warning message.
|
|
19
17
|
|
|
20
18
|
This function emits a DeprecationWarning when called, indicating that
|
|
21
19
|
the functionality will be removed in a future release.
|
|
@@ -42,7 +40,7 @@ def deprecated(name: str, reason: str) -> None:
|
|
|
42
40
|
|
|
43
41
|
warnings.simplefilter("always", DeprecationWarning)
|
|
44
42
|
warnings.warn(
|
|
45
|
-
f"{name}: {reason}. This functionality will be removed in
|
|
43
|
+
f"{name}: {reason}. This functionality will be removed in a future release",
|
|
46
44
|
category=DeprecationWarning,
|
|
47
45
|
stacklevel=2,
|
|
48
46
|
)
|
nextmv/input.py
CHANGED
|
@@ -38,6 +38,7 @@ from enum import Enum
|
|
|
38
38
|
from typing import Any
|
|
39
39
|
|
|
40
40
|
from nextmv._serialization import serialize_json
|
|
41
|
+
from nextmv.deprecated import deprecated
|
|
41
42
|
from nextmv.options import Options
|
|
42
43
|
|
|
43
44
|
INPUTS_KEY = "inputs"
|
|
@@ -940,6 +941,57 @@ class LocalInputLoader(InputLoader):
|
|
|
940
941
|
return data
|
|
941
942
|
|
|
942
943
|
|
|
944
|
+
def load_local(
|
|
945
|
+
input_format: InputFormat | None = InputFormat.JSON,
|
|
946
|
+
options: Options | None = None,
|
|
947
|
+
path: str | None = None,
|
|
948
|
+
csv_configurations: dict[str, Any] | None = None,
|
|
949
|
+
) -> Input:
|
|
950
|
+
"""
|
|
951
|
+
!!! warning
|
|
952
|
+
`load_local` is deprecated, use `load` instead.
|
|
953
|
+
|
|
954
|
+
Load input data from local sources.
|
|
955
|
+
|
|
956
|
+
This is a convenience function for instantiating a `LocalInputLoader`
|
|
957
|
+
and calling its `load` method.
|
|
958
|
+
|
|
959
|
+
Parameters
|
|
960
|
+
----------
|
|
961
|
+
input_format : InputFormat, optional
|
|
962
|
+
Format of the input data. Default is `InputFormat.JSON`.
|
|
963
|
+
options : Options, optional
|
|
964
|
+
Options for loading the input data.
|
|
965
|
+
path : str, optional
|
|
966
|
+
Path to the input data.
|
|
967
|
+
csv_configurations : dict[str, Any], optional
|
|
968
|
+
Configurations for loading CSV files. Custom kwargs for
|
|
969
|
+
Python's `csv.DictReader`.
|
|
970
|
+
|
|
971
|
+
Returns
|
|
972
|
+
-------
|
|
973
|
+
Input
|
|
974
|
+
The loaded input data in an Input object.
|
|
975
|
+
|
|
976
|
+
Raises
|
|
977
|
+
------
|
|
978
|
+
ValueError
|
|
979
|
+
If the path is invalid or data format is incorrect.
|
|
980
|
+
|
|
981
|
+
See Also
|
|
982
|
+
--------
|
|
983
|
+
load : The recommended function to use instead.
|
|
984
|
+
"""
|
|
985
|
+
|
|
986
|
+
deprecated(
|
|
987
|
+
name="load_local",
|
|
988
|
+
reason="`load_local` is deprecated, use `load` instead",
|
|
989
|
+
)
|
|
990
|
+
|
|
991
|
+
loader = LocalInputLoader()
|
|
992
|
+
return loader.load(input_format, options, path, csv_configurations)
|
|
993
|
+
|
|
994
|
+
|
|
943
995
|
_LOCAL_INPUT_LOADER = LocalInputLoader()
|
|
944
996
|
"""Default instance of LocalInputLoader used by the load function."""
|
|
945
997
|
|
nextmv/local/runner.py
CHANGED
|
@@ -204,7 +204,7 @@ def new_run(
|
|
|
204
204
|
if description is None:
|
|
205
205
|
description = f"Local run created at {created_at.isoformat().replace('+00:00', 'Z')}"
|
|
206
206
|
|
|
207
|
-
if name is None
|
|
207
|
+
if name is None:
|
|
208
208
|
name = f"local run {run_id}"
|
|
209
209
|
|
|
210
210
|
information = RunInformation(
|