nextmv 0.39.0.dev1__py3-none-any.whl → 1.0.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/__entrypoint__.py +1 -2
- nextmv/__init__.py +2 -4
- nextmv/cli/CONTRIBUTING.md +583 -0
- nextmv/cli/cloud/__init__.py +49 -0
- nextmv/cli/cloud/acceptance/__init__.py +27 -0
- nextmv/cli/cloud/acceptance/create.py +391 -0
- nextmv/cli/cloud/acceptance/delete.py +64 -0
- nextmv/cli/cloud/acceptance/get.py +103 -0
- nextmv/cli/cloud/acceptance/list.py +62 -0
- nextmv/cli/cloud/acceptance/update.py +95 -0
- nextmv/cli/cloud/account/__init__.py +28 -0
- nextmv/cli/cloud/account/create.py +83 -0
- nextmv/cli/cloud/account/delete.py +59 -0
- nextmv/cli/cloud/account/get.py +66 -0
- nextmv/cli/cloud/account/update.py +70 -0
- nextmv/cli/cloud/app/__init__.py +35 -0
- nextmv/cli/cloud/app/create.py +140 -0
- nextmv/cli/cloud/app/delete.py +57 -0
- nextmv/cli/cloud/app/exists.py +44 -0
- nextmv/cli/cloud/app/get.py +66 -0
- nextmv/cli/cloud/app/list.py +61 -0
- nextmv/cli/cloud/app/push.py +432 -0
- nextmv/cli/cloud/app/update.py +124 -0
- nextmv/cli/cloud/batch/__init__.py +29 -0
- nextmv/cli/cloud/batch/create.py +452 -0
- nextmv/cli/cloud/batch/delete.py +64 -0
- nextmv/cli/cloud/batch/get.py +104 -0
- nextmv/cli/cloud/batch/list.py +63 -0
- nextmv/cli/cloud/batch/metadata.py +66 -0
- nextmv/cli/cloud/batch/update.py +95 -0
- nextmv/cli/cloud/data/__init__.py +26 -0
- nextmv/cli/cloud/data/upload.py +162 -0
- nextmv/cli/cloud/ensemble/__init__.py +33 -0
- nextmv/cli/cloud/ensemble/create.py +413 -0
- nextmv/cli/cloud/ensemble/delete.py +63 -0
- nextmv/cli/cloud/ensemble/get.py +65 -0
- nextmv/cli/cloud/ensemble/list.py +63 -0
- nextmv/cli/cloud/ensemble/update.py +103 -0
- nextmv/cli/cloud/input_set/__init__.py +32 -0
- nextmv/cli/cloud/input_set/create.py +168 -0
- nextmv/cli/cloud/input_set/delete.py +64 -0
- nextmv/cli/cloud/input_set/get.py +63 -0
- nextmv/cli/cloud/input_set/list.py +63 -0
- nextmv/cli/cloud/input_set/update.py +123 -0
- nextmv/cli/cloud/instance/__init__.py +35 -0
- nextmv/cli/cloud/instance/create.py +289 -0
- nextmv/cli/cloud/instance/delete.py +61 -0
- nextmv/cli/cloud/instance/exists.py +39 -0
- nextmv/cli/cloud/instance/get.py +62 -0
- nextmv/cli/cloud/instance/list.py +60 -0
- nextmv/cli/cloud/instance/update.py +216 -0
- nextmv/cli/cloud/managed_input/__init__.py +31 -0
- nextmv/cli/cloud/managed_input/create.py +144 -0
- nextmv/cli/cloud/managed_input/delete.py +64 -0
- nextmv/cli/cloud/managed_input/get.py +63 -0
- nextmv/cli/cloud/managed_input/list.py +60 -0
- nextmv/cli/cloud/managed_input/update.py +97 -0
- nextmv/cli/cloud/run/__init__.py +37 -0
- nextmv/cli/cloud/run/cancel.py +37 -0
- nextmv/cli/cloud/run/create.py +524 -0
- nextmv/cli/cloud/run/get.py +199 -0
- nextmv/cli/cloud/run/input.py +86 -0
- nextmv/cli/cloud/run/list.py +80 -0
- nextmv/cli/cloud/run/logs.py +166 -0
- nextmv/cli/cloud/run/metadata.py +67 -0
- nextmv/cli/cloud/run/track.py +500 -0
- nextmv/cli/cloud/scenario/__init__.py +29 -0
- nextmv/cli/cloud/scenario/create.py +451 -0
- nextmv/cli/cloud/scenario/delete.py +61 -0
- nextmv/cli/cloud/scenario/get.py +102 -0
- nextmv/cli/cloud/scenario/list.py +63 -0
- nextmv/cli/cloud/scenario/metadata.py +67 -0
- nextmv/cli/cloud/scenario/update.py +93 -0
- nextmv/cli/cloud/secrets/__init__.py +33 -0
- nextmv/cli/cloud/secrets/create.py +206 -0
- nextmv/cli/cloud/secrets/delete.py +63 -0
- nextmv/cli/cloud/secrets/get.py +66 -0
- nextmv/cli/cloud/secrets/list.py +60 -0
- nextmv/cli/cloud/secrets/update.py +144 -0
- nextmv/cli/cloud/shadow/__init__.py +33 -0
- nextmv/cli/cloud/shadow/create.py +184 -0
- nextmv/cli/cloud/shadow/delete.py +64 -0
- nextmv/cli/cloud/shadow/get.py +61 -0
- nextmv/cli/cloud/shadow/list.py +63 -0
- nextmv/cli/cloud/shadow/metadata.py +66 -0
- nextmv/cli/cloud/shadow/start.py +43 -0
- nextmv/cli/cloud/shadow/stop.py +53 -0
- nextmv/cli/cloud/shadow/update.py +96 -0
- nextmv/cli/cloud/switchback/__init__.py +33 -0
- nextmv/cli/cloud/switchback/create.py +151 -0
- nextmv/cli/cloud/switchback/delete.py +64 -0
- nextmv/cli/cloud/switchback/get.py +62 -0
- nextmv/cli/cloud/switchback/list.py +63 -0
- nextmv/cli/cloud/switchback/metadata.py +68 -0
- nextmv/cli/cloud/switchback/start.py +43 -0
- nextmv/cli/cloud/switchback/stop.py +53 -0
- nextmv/cli/cloud/switchback/update.py +96 -0
- nextmv/cli/cloud/upload/__init__.py +22 -0
- nextmv/cli/cloud/upload/create.py +39 -0
- nextmv/cli/cloud/version/__init__.py +33 -0
- nextmv/cli/cloud/version/create.py +96 -0
- nextmv/cli/cloud/version/delete.py +61 -0
- nextmv/cli/cloud/version/exists.py +39 -0
- nextmv/cli/cloud/version/get.py +62 -0
- nextmv/cli/cloud/version/list.py +60 -0
- nextmv/cli/cloud/version/update.py +92 -0
- nextmv/cli/community/__init__.py +24 -0
- nextmv/cli/community/clone.py +86 -0
- nextmv/cli/community/list.py +200 -0
- nextmv/cli/configuration/__init__.py +23 -0
- nextmv/cli/configuration/config.py +228 -0
- nextmv/cli/configuration/create.py +94 -0
- nextmv/cli/configuration/delete.py +67 -0
- nextmv/cli/configuration/list.py +77 -0
- nextmv/cli/confirm.py +34 -0
- nextmv/cli/main.py +161 -3
- nextmv/cli/message.py +170 -0
- nextmv/cli/options.py +220 -0
- nextmv/cli/version.py +22 -2
- nextmv/cloud/__init__.py +17 -38
- nextmv/cloud/acceptance_test.py +20 -83
- nextmv/cloud/account.py +269 -30
- nextmv/cloud/application/__init__.py +898 -0
- nextmv/cloud/application/_acceptance.py +424 -0
- nextmv/cloud/application/_batch_scenario.py +845 -0
- nextmv/cloud/application/_ensemble.py +251 -0
- nextmv/cloud/application/_input_set.py +263 -0
- nextmv/cloud/application/_instance.py +289 -0
- nextmv/cloud/application/_managed_input.py +227 -0
- nextmv/cloud/application/_run.py +1393 -0
- nextmv/cloud/application/_secrets.py +294 -0
- nextmv/cloud/application/_shadow.py +320 -0
- nextmv/cloud/application/_switchback.py +332 -0
- nextmv/cloud/application/_utils.py +54 -0
- nextmv/cloud/application/_version.py +304 -0
- nextmv/cloud/batch_experiment.py +6 -2
- nextmv/cloud/community.py +446 -0
- nextmv/cloud/instance.py +11 -1
- nextmv/cloud/integration.py +8 -5
- nextmv/cloud/package.py +50 -9
- nextmv/cloud/shadow.py +254 -0
- nextmv/cloud/switchback.py +228 -0
- nextmv/deprecated.py +5 -3
- nextmv/input.py +20 -88
- nextmv/local/application.py +3 -15
- nextmv/local/runner.py +1 -1
- nextmv/model.py +50 -11
- nextmv/options.py +11 -256
- nextmv/output.py +0 -62
- nextmv/polling.py +54 -16
- nextmv/run.py +84 -37
- nextmv/status.py +1 -51
- {nextmv-0.39.0.dev1.dist-info → nextmv-1.0.0.dist-info}/METADATA +37 -11
- nextmv-1.0.0.dist-info/RECORD +185 -0
- nextmv-1.0.0.dist-info/entry_points.txt +2 -0
- nextmv/cloud/application.py +0 -4204
- nextmv-0.39.0.dev1.dist-info/RECORD +0 -55
- nextmv-0.39.0.dev1.dist-info/entry_points.txt +0 -2
- {nextmv-0.39.0.dev1.dist-info → nextmv-1.0.0.dist-info}/WHEEL +0 -0
- {nextmv-0.39.0.dev1.dist-info → nextmv-1.0.0.dist-info}/licenses/LICENSE +0 -0
nextmv/cli/version.py
CHANGED
|
@@ -6,7 +6,7 @@ import typer
|
|
|
6
6
|
|
|
7
7
|
from nextmv.__about__ import __version__
|
|
8
8
|
|
|
9
|
-
#
|
|
9
|
+
# Set up subcommand application.
|
|
10
10
|
app = typer.Typer()
|
|
11
11
|
|
|
12
12
|
|
|
@@ -14,5 +14,25 @@ app = typer.Typer()
|
|
|
14
14
|
def version() -> None:
|
|
15
15
|
"""
|
|
16
16
|
Show the current version of the Nextmv CLI.
|
|
17
|
+
|
|
18
|
+
[bold][underline]Examples[/underline][/bold]
|
|
19
|
+
|
|
20
|
+
- Show the version.
|
|
21
|
+
$ [dim]nextmv version[/dim]
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
version_callback(True)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def version_callback(value: bool):
|
|
28
|
+
"""
|
|
29
|
+
Callback function to display the version.
|
|
30
|
+
|
|
31
|
+
Parameters
|
|
32
|
+
----------
|
|
33
|
+
value : bool
|
|
34
|
+
If True, print the version and exit.
|
|
17
35
|
"""
|
|
18
|
-
|
|
36
|
+
if value:
|
|
37
|
+
print(__version__)
|
|
38
|
+
raise typer.Exit()
|
nextmv/cloud/__init__.py
CHANGED
|
@@ -1,41 +1,5 @@
|
|
|
1
1
|
"""Functionality for interacting with the Nextmv Cloud."""
|
|
2
2
|
|
|
3
|
-
# These imports are kept for backwards compatibility but the preferred import path is
|
|
4
|
-
# from nextmv directly. These imports will be removed in a future release.
|
|
5
|
-
from nextmv.manifest import MANIFEST_FILE_NAME as MANIFEST_FILE_NAME
|
|
6
|
-
from nextmv.manifest import Manifest as Manifest
|
|
7
|
-
from nextmv.manifest import ManifestBuild as ManifestBuild
|
|
8
|
-
from nextmv.manifest import ManifestContent as ManifestContent
|
|
9
|
-
from nextmv.manifest import ManifestContentMultiFile as ManifestContentMultiFile
|
|
10
|
-
from nextmv.manifest import ManifestContentMultiFileInput as ManifestContentMultiFileInput
|
|
11
|
-
from nextmv.manifest import ManifestContentMultiFileOutput as ManifestContentMultiFileOutput
|
|
12
|
-
from nextmv.manifest import ManifestOption as ManifestOption
|
|
13
|
-
from nextmv.manifest import ManifestPython as ManifestPython
|
|
14
|
-
from nextmv.manifest import ManifestPythonModel as ManifestPythonModel
|
|
15
|
-
from nextmv.manifest import ManifestRuntime as ManifestRuntime
|
|
16
|
-
from nextmv.manifest import ManifestType as ManifestType
|
|
17
|
-
from nextmv.polling import PollingOptions as PollingOptions
|
|
18
|
-
from nextmv.run import ErrorLog as ErrorLog
|
|
19
|
-
from nextmv.run import ExternalRunResult as ExternalRunResult
|
|
20
|
-
from nextmv.run import Format as Format
|
|
21
|
-
from nextmv.run import FormatInput as FormatInput
|
|
22
|
-
from nextmv.run import FormatOutput as FormatOutput
|
|
23
|
-
from nextmv.run import Metadata as Metadata
|
|
24
|
-
from nextmv.run import RunConfiguration as RunConfiguration
|
|
25
|
-
from nextmv.run import RunInformation as RunInformation
|
|
26
|
-
from nextmv.run import RunLog as RunLog
|
|
27
|
-
from nextmv.run import RunQueuing as RunQueuing
|
|
28
|
-
from nextmv.run import RunResult as RunResult
|
|
29
|
-
from nextmv.run import RunType as RunType
|
|
30
|
-
from nextmv.run import RunTypeConfiguration as RunTypeConfiguration
|
|
31
|
-
from nextmv.run import TrackedRun as TrackedRun
|
|
32
|
-
from nextmv.run import TrackedRunStatus as TrackedRunStatus
|
|
33
|
-
from nextmv.run import run_duration as run_duration
|
|
34
|
-
from nextmv.safe import safe_id as safe_id
|
|
35
|
-
from nextmv.safe import safe_name_and_id as safe_name_and_id
|
|
36
|
-
from nextmv.status import Status as Status
|
|
37
|
-
from nextmv.status import StatusV2 as StatusV2
|
|
38
|
-
|
|
39
3
|
from .acceptance_test import AcceptanceTest as AcceptanceTest
|
|
40
4
|
from .acceptance_test import AcceptanceTestResults as AcceptanceTestResults
|
|
41
5
|
from .acceptance_test import Comparison as Comparison
|
|
@@ -51,12 +15,13 @@ from .acceptance_test import MetricToleranceType as MetricToleranceType
|
|
|
51
15
|
from .acceptance_test import MetricType as MetricType
|
|
52
16
|
from .acceptance_test import ResultStatistics as ResultStatistics
|
|
53
17
|
from .acceptance_test import StatisticType as StatisticType
|
|
54
|
-
from .acceptance_test import ToleranceType as ToleranceType
|
|
55
18
|
from .account import Account as Account
|
|
19
|
+
from .account import AccountMember as AccountMember
|
|
56
20
|
from .account import Queue as Queue
|
|
57
21
|
from .account import QueuedRun as QueuedRun
|
|
58
22
|
from .application import Application as Application
|
|
59
|
-
from .application import
|
|
23
|
+
from .application import ApplicationType as ApplicationType
|
|
24
|
+
from .application import list_applications as list_applications
|
|
60
25
|
from .assets import RunAsset as RunAsset
|
|
61
26
|
from .batch_experiment import BatchExperiment as BatchExperiment
|
|
62
27
|
from .batch_experiment import BatchExperimentInformation as BatchExperimentInformation
|
|
@@ -65,6 +30,9 @@ from .batch_experiment import BatchExperimentRun as BatchExperimentRun
|
|
|
65
30
|
from .batch_experiment import ExperimentStatus as ExperimentStatus
|
|
66
31
|
from .client import Client as Client
|
|
67
32
|
from .client import get_size as get_size
|
|
33
|
+
from .community import CommunityApp as CommunityApp
|
|
34
|
+
from .community import clone_community_app as clone_community_app
|
|
35
|
+
from .community import list_community_apps as list_community_apps
|
|
68
36
|
from .ensemble import EnsembleDefinition as EnsembleDefinition
|
|
69
37
|
from .ensemble import EvaluationRule as EvaluationRule
|
|
70
38
|
from .ensemble import RuleObjective as RuleObjective
|
|
@@ -87,6 +55,17 @@ from .secrets import Secret as Secret
|
|
|
87
55
|
from .secrets import SecretsCollection as SecretsCollection
|
|
88
56
|
from .secrets import SecretsCollectionSummary as SecretsCollectionSummary
|
|
89
57
|
from .secrets import SecretType as SecretType
|
|
58
|
+
from .shadow import ShadowTest as ShadowTest
|
|
59
|
+
from .shadow import ShadowTestMetadata as ShadowTestMetadata
|
|
60
|
+
from .shadow import StartEvents as StartEvents
|
|
61
|
+
from .shadow import StopIntent as StopIntent
|
|
62
|
+
from .shadow import TerminationEvents as TerminationEvents
|
|
63
|
+
from .shadow import TestComparison as TestComparison
|
|
64
|
+
from .switchback import SwitchbackPlan as SwitchbackPlan
|
|
65
|
+
from .switchback import SwitchbackPlanUnit as SwitchbackPlanUnit
|
|
66
|
+
from .switchback import SwitchbackTest as SwitchbackTest
|
|
67
|
+
from .switchback import SwitchbackTestMetadata as SwitchbackTestMetadata
|
|
68
|
+
from .switchback import TestComparisonSingle as TestComparisonSingle
|
|
90
69
|
from .url import DownloadURL as DownloadURL
|
|
91
70
|
from .url import UploadURL as UploadURL
|
|
92
71
|
from .version import Version as Version
|
nextmv/cloud/acceptance_test.py
CHANGED
|
@@ -13,7 +13,7 @@ StatisticType : Enum
|
|
|
13
13
|
Type of statistical process for collapsing multiple values of a metric.
|
|
14
14
|
Comparison : Enum
|
|
15
15
|
Comparison operators to use for comparing two metrics.
|
|
16
|
-
|
|
16
|
+
MetricToleranceType : Enum
|
|
17
17
|
Type of tolerance used for a metric.
|
|
18
18
|
ExperimentStatus : Enum
|
|
19
19
|
Status of an acceptance test experiment.
|
|
@@ -46,7 +46,6 @@ from enum import Enum
|
|
|
46
46
|
|
|
47
47
|
from nextmv.base_model import BaseModel
|
|
48
48
|
from nextmv.cloud.batch_experiment import ExperimentStatus
|
|
49
|
-
from nextmv.deprecated import deprecated
|
|
50
49
|
|
|
51
50
|
|
|
52
51
|
class MetricType(str, Enum):
|
|
@@ -212,69 +211,6 @@ class Comparison(str, Enum):
|
|
|
212
211
|
"""Not equal to metric type."""
|
|
213
212
|
|
|
214
213
|
|
|
215
|
-
class ToleranceType(str, Enum):
|
|
216
|
-
"""
|
|
217
|
-
!!! warning
|
|
218
|
-
`ToleranceType` is deprecated, use `MetricToleranceType` instead.
|
|
219
|
-
|
|
220
|
-
Type of tolerance used for a metric.
|
|
221
|
-
|
|
222
|
-
You can import the `ToleranceType` class directly from `cloud`:
|
|
223
|
-
|
|
224
|
-
```python
|
|
225
|
-
from nextmv.cloud import ToleranceType
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
This enumeration defines the different types of tolerances that can be used
|
|
229
|
-
when comparing metrics in acceptance tests.
|
|
230
|
-
|
|
231
|
-
Attributes
|
|
232
|
-
----------
|
|
233
|
-
undefined : str
|
|
234
|
-
Undefined tolerance type (empty string).
|
|
235
|
-
absolute : str
|
|
236
|
-
Absolute tolerance type, using a fixed value.
|
|
237
|
-
relative : str
|
|
238
|
-
Relative tolerance type, using a percentage.
|
|
239
|
-
|
|
240
|
-
Examples
|
|
241
|
-
--------
|
|
242
|
-
>>> from nextmv.cloud import ToleranceType
|
|
243
|
-
>>> tol_type = ToleranceType.absolute
|
|
244
|
-
>>> tol_type
|
|
245
|
-
<ToleranceType.absolute: 'absolute'>
|
|
246
|
-
"""
|
|
247
|
-
|
|
248
|
-
undefined = ""
|
|
249
|
-
"""ToleranceType is deprecated, please use MetricToleranceType instead.
|
|
250
|
-
Undefined tolerance type."""
|
|
251
|
-
absolute = "absolute"
|
|
252
|
-
"""ToleranceType is deprecated, please use MetricToleranceType instead.
|
|
253
|
-
Absolute tolerance type."""
|
|
254
|
-
relative = "relative"
|
|
255
|
-
"""ToleranceType is deprecated, please use MetricToleranceType instead.
|
|
256
|
-
Relative tolerance type."""
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
# Override __getattribute__ to emit deprecation warnings when enum values are accessed
|
|
260
|
-
_original_getattribute = ToleranceType.__class__.__getattribute__
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
def _deprecated_getattribute(cls, name: str):
|
|
264
|
-
# Only emit deprecation warning if this is specifically the ToleranceType class
|
|
265
|
-
if cls is ToleranceType and name in ("undefined", "absolute", "relative"):
|
|
266
|
-
deprecated(
|
|
267
|
-
f"ToleranceType.{name}",
|
|
268
|
-
"ToleranceType is deprecated and will be removed in a future version. "
|
|
269
|
-
"Please use MetricToleranceType instead",
|
|
270
|
-
)
|
|
271
|
-
|
|
272
|
-
return _original_getattribute(cls, name)
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
ToleranceType.__class__.__getattribute__ = _deprecated_getattribute
|
|
276
|
-
|
|
277
|
-
|
|
278
214
|
class MetricToleranceType(str, Enum):
|
|
279
215
|
"""
|
|
280
216
|
Type of tolerance used for a metric.
|
|
@@ -888,20 +824,20 @@ class AcceptanceTest(BaseModel):
|
|
|
888
824
|
Name of the acceptance test.
|
|
889
825
|
description : str
|
|
890
826
|
Description of the acceptance test.
|
|
891
|
-
|
|
827
|
+
created_at : datetime
|
|
828
|
+
Creation date of the acceptance test.
|
|
829
|
+
updated_at : datetime
|
|
830
|
+
Last update date of the acceptance test.
|
|
831
|
+
app_id : str, optional
|
|
892
832
|
ID of the app that owns the acceptance test.
|
|
893
|
-
experiment_id : str
|
|
833
|
+
experiment_id : str, optional
|
|
894
834
|
ID of the batch experiment underlying the acceptance test.
|
|
895
|
-
control : ComparisonInstance
|
|
835
|
+
control : ComparisonInstance, optional
|
|
896
836
|
Control instance of the acceptance test.
|
|
897
|
-
candidate : ComparisonInstance
|
|
837
|
+
candidate : ComparisonInstance, optional
|
|
898
838
|
Candidate instance of the acceptance test.
|
|
899
|
-
metrics : list[Metric]
|
|
839
|
+
metrics : list[Metric], optional
|
|
900
840
|
Metrics to evaluate in the acceptance test.
|
|
901
|
-
created_at : datetime
|
|
902
|
-
Creation date of the acceptance test.
|
|
903
|
-
updated_at : datetime
|
|
904
|
-
Last update date of the acceptance test.
|
|
905
841
|
status : ExperimentStatus, optional
|
|
906
842
|
Status of the acceptance test.
|
|
907
843
|
results : AcceptanceTestResults, optional
|
|
@@ -942,20 +878,21 @@ class AcceptanceTest(BaseModel):
|
|
|
942
878
|
"""Name of the acceptance test."""
|
|
943
879
|
description: str
|
|
944
880
|
"""Description of the acceptance test."""
|
|
945
|
-
|
|
881
|
+
created_at: datetime
|
|
882
|
+
"""Creation date of the acceptance test."""
|
|
883
|
+
updated_at: datetime
|
|
884
|
+
"""Last update date of the acceptance test."""
|
|
885
|
+
|
|
886
|
+
app_id: str | None = None
|
|
946
887
|
"""ID of the app that owns the acceptance test."""
|
|
947
|
-
experiment_id: str
|
|
888
|
+
experiment_id: str | None = None
|
|
948
889
|
"""ID of the batch experiment underlying in the acceptance test."""
|
|
949
|
-
control: ComparisonInstance
|
|
890
|
+
control: ComparisonInstance | None = None
|
|
950
891
|
"""Control instance of the acceptance test."""
|
|
951
|
-
candidate: ComparisonInstance
|
|
892
|
+
candidate: ComparisonInstance | None = None
|
|
952
893
|
"""Candidate instance of the acceptance test."""
|
|
953
|
-
metrics: list[Metric]
|
|
894
|
+
metrics: list[Metric] | None = None
|
|
954
895
|
"""Metrics of the acceptance test."""
|
|
955
|
-
created_at: datetime
|
|
956
|
-
"""Creation date of the acceptance test."""
|
|
957
|
-
updated_at: datetime
|
|
958
|
-
"""Last update date of the acceptance test."""
|
|
959
896
|
status: ExperimentStatus | None = ExperimentStatus.UNKNOWN
|
|
960
897
|
"""Status of the acceptance test."""
|
|
961
898
|
results: AcceptanceTestResults | None = None
|
nextmv/cloud/account.py
CHANGED
|
@@ -15,16 +15,18 @@ Account
|
|
|
15
15
|
The Nextmv Platform account with API access methods.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
from dataclasses import dataclass
|
|
19
18
|
from datetime import datetime
|
|
20
19
|
|
|
20
|
+
from pydantic import AliasChoices, Field
|
|
21
|
+
|
|
21
22
|
from nextmv.base_model import BaseModel
|
|
22
23
|
from nextmv.cloud.client import Client
|
|
23
|
-
from nextmv.status import
|
|
24
|
+
from nextmv.status import StatusV2
|
|
24
25
|
|
|
25
26
|
|
|
26
27
|
class QueuedRun(BaseModel):
|
|
27
|
-
"""
|
|
28
|
+
"""
|
|
29
|
+
A run that is pending to be executed in the account.
|
|
28
30
|
|
|
29
31
|
You can import the `QueuedRun` class directly from `cloud`:
|
|
30
32
|
|
|
@@ -55,8 +57,6 @@ class QueuedRun(BaseModel):
|
|
|
55
57
|
ID of the application version used for the run.
|
|
56
58
|
execution_class : str
|
|
57
59
|
Execution class used for the run.
|
|
58
|
-
status : Status
|
|
59
|
-
Deprecated: use status_v2.
|
|
60
60
|
status_v2 : StatusV2
|
|
61
61
|
Status of the run.
|
|
62
62
|
|
|
@@ -72,7 +72,6 @@ class QueuedRun(BaseModel):
|
|
|
72
72
|
... "application_instance_id": "appins-123456",
|
|
73
73
|
... "application_version_id": "appver-123456",
|
|
74
74
|
... "execution_class": "standard",
|
|
75
|
-
... "status": "RUNNING",
|
|
76
75
|
... "status_v2": "RUNNING"
|
|
77
76
|
... })
|
|
78
77
|
>>> print(queued_run.name)
|
|
@@ -97,14 +96,13 @@ class QueuedRun(BaseModel):
|
|
|
97
96
|
"""ID of the application version used for the run."""
|
|
98
97
|
execution_class: str
|
|
99
98
|
"""Execution class used for the run."""
|
|
100
|
-
status: Status
|
|
101
|
-
"""Deprecated: use status_v2."""
|
|
102
99
|
status_v2: StatusV2
|
|
103
100
|
"""Status of the run."""
|
|
104
101
|
|
|
105
102
|
|
|
106
103
|
class Queue(BaseModel):
|
|
107
|
-
"""
|
|
104
|
+
"""
|
|
105
|
+
A queue is a list of runs that are pending to be executed, or currently
|
|
108
106
|
being executed, in the account.
|
|
109
107
|
|
|
110
108
|
You can import the `Queue` class directly from `cloud`:
|
|
@@ -123,7 +121,9 @@ class Queue(BaseModel):
|
|
|
123
121
|
|
|
124
122
|
Examples
|
|
125
123
|
--------
|
|
126
|
-
>>>
|
|
124
|
+
>>> from nextmv.cloud import Client, Account
|
|
125
|
+
>>> client = Client(api_key="your-api-key")
|
|
126
|
+
>>> account = Account.get(client=client, account_id="your-account-id")
|
|
127
127
|
>>> queue = account.queue()
|
|
128
128
|
>>> print(f"Number of runs in queue: {len(queue.runs)}")
|
|
129
129
|
Number of runs in queue: 5
|
|
@@ -137,9 +137,54 @@ class Queue(BaseModel):
|
|
|
137
137
|
"""List of runs in the queue."""
|
|
138
138
|
|
|
139
139
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
140
|
+
class AccountMember(BaseModel):
|
|
141
|
+
"""
|
|
142
|
+
A member of a Nextmv Cloud account (organization).
|
|
143
|
+
|
|
144
|
+
You can import the `AccountMember` class directly from `cloud`:
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
from nextmv.cloud import AccountMember
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Represents an individual member of an organization in Nextmv Cloud,
|
|
151
|
+
including their role and invitation status.
|
|
152
|
+
|
|
153
|
+
Attributes
|
|
154
|
+
----------
|
|
155
|
+
email : str | None
|
|
156
|
+
Email of the account member.
|
|
157
|
+
role : str | None
|
|
158
|
+
Role of the account member.
|
|
159
|
+
pending_invite : bool | None
|
|
160
|
+
Whether the member has a pending invite.
|
|
161
|
+
|
|
162
|
+
Examples
|
|
163
|
+
--------
|
|
164
|
+
>>> member = AccountMember.from_dict({
|
|
165
|
+
... "email": "peter.rabbit@carrotexpress.com",
|
|
166
|
+
... "role": "admin",
|
|
167
|
+
... "pending_invite": False
|
|
168
|
+
... })
|
|
169
|
+
>>> print(f"{member.email} - {member.role}")
|
|
170
|
+
peter.rabbit@carrotexpress.com - admin
|
|
171
|
+
"""
|
|
172
|
+
|
|
173
|
+
email: str | None = None
|
|
174
|
+
"""Email of the account member."""
|
|
175
|
+
role: str | None = None
|
|
176
|
+
"""Role of the account member."""
|
|
177
|
+
pending_invite: bool | None = None
|
|
178
|
+
"""Whether the member has a pending invite."""
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
class Account(BaseModel):
|
|
182
|
+
"""
|
|
183
|
+
The Nextmv Cloud account (organization).
|
|
184
|
+
|
|
185
|
+
To handle managed accounts, SSO must be configured for your organization.
|
|
186
|
+
Please contact [Nextmv support](https://www.nextmv.io/contact) for
|
|
187
|
+
assistance.
|
|
143
188
|
|
|
144
189
|
You can import the `Account` class directly from `cloud`:
|
|
145
190
|
|
|
@@ -147,41 +192,191 @@ class Account:
|
|
|
147
192
|
from nextmv.cloud import Account
|
|
148
193
|
```
|
|
149
194
|
|
|
150
|
-
This class provides access to account-level operations in the Nextmv
|
|
195
|
+
This class provides access to account-level operations in the Nextmv Cloud,
|
|
151
196
|
such as retrieving the queue of runs.
|
|
152
197
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
client : Client
|
|
156
|
-
Client to use for interacting with the Nextmv Cloud API.
|
|
157
|
-
endpoint : str, optional
|
|
158
|
-
Base endpoint for the account, by default "v1/account"
|
|
198
|
+
Note: It is recommended to use `Account.get()` or `Account.new()`
|
|
199
|
+
instead of direct initialization to ensure proper setup.
|
|
159
200
|
|
|
160
|
-
|
|
201
|
+
Parameters
|
|
161
202
|
----------
|
|
162
203
|
client : Client
|
|
163
204
|
Client to use for interacting with the Nextmv Cloud API.
|
|
164
|
-
|
|
165
|
-
|
|
205
|
+
account_id : str, optional
|
|
206
|
+
ID of the account (organization).
|
|
207
|
+
name : str, optional
|
|
208
|
+
Name of the account (organization).
|
|
209
|
+
members : list[AccountMember], optional
|
|
210
|
+
List of members in the account (organization).
|
|
211
|
+
account_endpoint : str, default="v1/account"
|
|
212
|
+
Base endpoint for the account (SDK-specific).
|
|
213
|
+
organization_endpoint : str, default="v1/organization/{organization_id}"
|
|
214
|
+
Base endpoint for organization operations (SDK-specific).
|
|
166
215
|
|
|
167
216
|
Examples
|
|
168
217
|
--------
|
|
169
218
|
>>> from nextmv.cloud import Client, Account
|
|
170
219
|
>>> client = Client(api_key="your-api-key")
|
|
171
|
-
>>>
|
|
220
|
+
>>> # Retrieve an existing account
|
|
221
|
+
>>> account = Account.get(client=client, account_id="your-account-id")
|
|
222
|
+
>>> print(f"Account name: {account.name}")
|
|
223
|
+
Account name: Bunny Logistics
|
|
224
|
+
>>> # Create a new account
|
|
225
|
+
>>> new_account = Account.new(client=client, name="Hare Delivery Co", admins=["admin@example.com"])
|
|
226
|
+
>>> # Get the queue of runs
|
|
172
227
|
>>> queue = account.queue()
|
|
173
228
|
>>> print(f"Number of runs in queue: {len(queue.runs)}")
|
|
174
229
|
Number of runs in queue: 3
|
|
175
230
|
"""
|
|
176
231
|
|
|
177
|
-
|
|
232
|
+
# Actual API attributes of an account.
|
|
233
|
+
account_id: str | None = Field(
|
|
234
|
+
serialization_alias="id",
|
|
235
|
+
validation_alias=AliasChoices("id", "account_id"),
|
|
236
|
+
default=None,
|
|
237
|
+
)
|
|
238
|
+
"""ID of the account (organization)."""
|
|
239
|
+
name: str | None = None
|
|
240
|
+
"""Name of the account (organization)."""
|
|
241
|
+
members: list[AccountMember] | None = None
|
|
242
|
+
"""List of members in the account (organization)."""
|
|
243
|
+
|
|
244
|
+
# SDK-specific attributes for convenience when using methods.
|
|
245
|
+
client: Client = Field(exclude=True)
|
|
178
246
|
"""Client to use for interacting with the Nextmv Cloud API."""
|
|
179
|
-
|
|
180
|
-
endpoint: str = "v1/account"
|
|
247
|
+
account_endpoint: str = Field(exclude=True, default="v1/account")
|
|
181
248
|
"""Base endpoint for the account."""
|
|
249
|
+
organization_endpoint: str = Field(exclude=True, default="v1/organization/{organization_id}")
|
|
250
|
+
|
|
251
|
+
def model_post_init(self, __context) -> None:
|
|
252
|
+
"""
|
|
253
|
+
Initialize the organization_endpoint attribute.
|
|
254
|
+
|
|
255
|
+
This method is automatically called after class initialization to
|
|
256
|
+
format the organization_endpoint URL with the account ID.
|
|
257
|
+
"""
|
|
258
|
+
|
|
259
|
+
self.organization_endpoint = self.organization_endpoint.format(organization_id=self.account_id)
|
|
260
|
+
|
|
261
|
+
@classmethod
|
|
262
|
+
def get(cls, client: Client, account_id: str) -> "Account":
|
|
263
|
+
"""
|
|
264
|
+
Retrieve an account directly from Nextmv Cloud.
|
|
265
|
+
|
|
266
|
+
This function is useful if you want to populate an `Account` class
|
|
267
|
+
by fetching the attributes directly from Nextmv Cloud.
|
|
268
|
+
|
|
269
|
+
Parameters
|
|
270
|
+
----------
|
|
271
|
+
client : Client
|
|
272
|
+
Client to use for interacting with the Nextmv Cloud API.
|
|
273
|
+
account_id : str
|
|
274
|
+
ID of the account to retrieve.
|
|
275
|
+
|
|
276
|
+
Returns
|
|
277
|
+
-------
|
|
278
|
+
Account
|
|
279
|
+
The requested account.
|
|
280
|
+
|
|
281
|
+
Raises
|
|
282
|
+
------
|
|
283
|
+
requests.HTTPError
|
|
284
|
+
If the response status code is not 2xx.
|
|
285
|
+
|
|
286
|
+
Examples
|
|
287
|
+
--------
|
|
288
|
+
>>> from nextmv.cloud import Client, Account
|
|
289
|
+
>>> client = Client(api_key="your-api-key")
|
|
290
|
+
>>> account = Account.get(client=client, account_id="bunny-logistics")
|
|
291
|
+
>>> print(f"Account: {account.name}")
|
|
292
|
+
Account: Bunny Logistics
|
|
293
|
+
>>> print(f"Members: {len(account.members)}")
|
|
294
|
+
Members: 3
|
|
295
|
+
"""
|
|
296
|
+
|
|
297
|
+
response = client.request(
|
|
298
|
+
method="GET",
|
|
299
|
+
endpoint=f"v1/organization/{account_id}",
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
return cls.from_dict({"client": client} | response.json())
|
|
303
|
+
|
|
304
|
+
@classmethod
|
|
305
|
+
def new(
|
|
306
|
+
cls,
|
|
307
|
+
client: Client,
|
|
308
|
+
name: str,
|
|
309
|
+
admins: list[str],
|
|
310
|
+
) -> "Account":
|
|
311
|
+
"""
|
|
312
|
+
Create a new account (organization) directly in Nextmv Cloud.
|
|
313
|
+
|
|
314
|
+
To create managed accounts, SSO must be configured for your
|
|
315
|
+
organization. Please contact [Nextmv
|
|
316
|
+
support](https://www.nextmv.io/contact) for assistance.
|
|
317
|
+
|
|
318
|
+
Parameters
|
|
319
|
+
----------
|
|
320
|
+
client : Client
|
|
321
|
+
Client to use for interacting with the Nextmv Cloud API.
|
|
322
|
+
name : str
|
|
323
|
+
Name of the new account.
|
|
324
|
+
admins : list[str]
|
|
325
|
+
List of admin user emails for the new account.
|
|
326
|
+
|
|
327
|
+
Returns
|
|
328
|
+
-------
|
|
329
|
+
Account
|
|
330
|
+
The newly created account.
|
|
331
|
+
|
|
332
|
+
Examples
|
|
333
|
+
--------
|
|
334
|
+
>>> from nextmv.cloud import Client
|
|
335
|
+
>>> client = Client(api_key="your-api-key")
|
|
336
|
+
>>> account = Account.new(client=client, name="My New Account", admins=["admin@example.com"])
|
|
337
|
+
"""
|
|
338
|
+
|
|
339
|
+
if len(admins) == 0:
|
|
340
|
+
raise ValueError("at least one admin email must be provided to create an account")
|
|
341
|
+
|
|
342
|
+
payload = {
|
|
343
|
+
"name": name,
|
|
344
|
+
"admins": admins,
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
response = client.request(
|
|
348
|
+
method="POST",
|
|
349
|
+
endpoint="v1/organization",
|
|
350
|
+
payload=payload,
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
return cls.from_dict({"client": client} | response.json())
|
|
354
|
+
|
|
355
|
+
def delete(self) -> None:
|
|
356
|
+
"""
|
|
357
|
+
Delete the account.
|
|
358
|
+
|
|
359
|
+
Permanently removes the account (organization) from Nextmv Cloud. You
|
|
360
|
+
must have the administrator role on that account in order to delete it.
|
|
361
|
+
|
|
362
|
+
Raises
|
|
363
|
+
------
|
|
364
|
+
requests.HTTPError
|
|
365
|
+
If the response status code is not 2xx.
|
|
366
|
+
|
|
367
|
+
Examples
|
|
368
|
+
--------
|
|
369
|
+
>>> account.delete() # Permanently deletes the account
|
|
370
|
+
"""
|
|
371
|
+
|
|
372
|
+
_ = self.client.request(
|
|
373
|
+
method="DELETE",
|
|
374
|
+
endpoint=self.organization_endpoint,
|
|
375
|
+
)
|
|
182
376
|
|
|
183
377
|
def queue(self) -> Queue:
|
|
184
|
-
"""
|
|
378
|
+
"""
|
|
379
|
+
Get the queue of runs in the account.
|
|
185
380
|
|
|
186
381
|
Retrieves the current list of runs that are pending or being executed
|
|
187
382
|
in the Nextmv account.
|
|
@@ -198,7 +393,9 @@ class Account:
|
|
|
198
393
|
|
|
199
394
|
Examples
|
|
200
395
|
--------
|
|
201
|
-
>>>
|
|
396
|
+
>>> from nextmv.cloud import Client, Account
|
|
397
|
+
>>> client = Client(api_key="your-api-key")
|
|
398
|
+
>>> account = Account.get(client=client, account_id="your-account-id")
|
|
202
399
|
>>> queue = account.queue()
|
|
203
400
|
>>> for run in queue.runs:
|
|
204
401
|
... print(f"Run {run.id}: {run.name} - Status: {run.status_v2}")
|
|
@@ -207,7 +404,49 @@ class Account:
|
|
|
207
404
|
"""
|
|
208
405
|
response = self.client.request(
|
|
209
406
|
method="GET",
|
|
210
|
-
endpoint=self.
|
|
407
|
+
endpoint=self.account_endpoint + "/queue",
|
|
211
408
|
)
|
|
212
409
|
|
|
213
410
|
return Queue.from_dict(response.json())
|
|
411
|
+
|
|
412
|
+
def update(self, name: str) -> "Account":
|
|
413
|
+
"""
|
|
414
|
+
Update the account.
|
|
415
|
+
|
|
416
|
+
Parameters
|
|
417
|
+
----------
|
|
418
|
+
name : str
|
|
419
|
+
Name of the account.
|
|
420
|
+
|
|
421
|
+
Returns
|
|
422
|
+
-------
|
|
423
|
+
Account
|
|
424
|
+
The updated account.
|
|
425
|
+
|
|
426
|
+
Raises
|
|
427
|
+
------
|
|
428
|
+
requests.HTTPError
|
|
429
|
+
If the response status code is not 2xx.
|
|
430
|
+
|
|
431
|
+
Examples
|
|
432
|
+
--------
|
|
433
|
+
>>> from nextmv.cloud import Client, Account
|
|
434
|
+
>>> client = Client(api_key="your-api-key")
|
|
435
|
+
>>> account = Account.get(client=client, account_id="bunny-logistics")
|
|
436
|
+
>>> updated_account = account.update(name="Bunny Express Logistics")
|
|
437
|
+
>>> print(updated_account.name)
|
|
438
|
+
Bunny Express Logistics
|
|
439
|
+
"""
|
|
440
|
+
|
|
441
|
+
account = self.get(client=self.client, account_id=self.account_id)
|
|
442
|
+
account_dict = account.to_dict()
|
|
443
|
+
payload = account_dict.copy()
|
|
444
|
+
payload["name"] = name
|
|
445
|
+
|
|
446
|
+
response = self.client.request(
|
|
447
|
+
method="PUT",
|
|
448
|
+
endpoint=self.organization_endpoint,
|
|
449
|
+
payload=payload,
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
return Account.from_dict({"client": self.client} | response.json())
|