nextmv 0.32.0__tar.gz → 0.33.0__tar.gz
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-0.32.0 → nextmv-0.33.0}/PKG-INFO +1 -1
- nextmv-0.33.0/nextmv/__about__.py +1 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/__init__.py +1 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/cloud/__init__.py +7 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/cloud/acceptance_test.py +69 -5
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/cloud/application.py +257 -95
- nextmv-0.33.0/nextmv/cloud/ensemble.py +248 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/cloud/package.py +62 -24
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/local/executor.py +2 -1
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/manifest.py +61 -2
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/local/test_executor.py +2 -1
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/test_manifest.py +5 -0
- nextmv-0.32.0/nextmv/__about__.py +0 -1
- {nextmv-0.32.0 → nextmv-0.33.0}/.gitignore +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/LICENSE +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/README.md +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/__entrypoint__.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/_serialization.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/base_model.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/cloud/account.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/cloud/batch_experiment.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/cloud/client.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/cloud/input_set.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/cloud/instance.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/cloud/scenario.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/cloud/secrets.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/cloud/url.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/cloud/version.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/default_app/.gitignore +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/default_app/README.md +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/default_app/app.yaml +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/default_app/input.json +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/default_app/main.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/default_app/requirements.txt +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/default_app/src/__init__.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/default_app/src/main.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/default_app/src/visuals.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/deprecated.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/input.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/local/__init__.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/local/application.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/local/geojson_handler.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/local/local.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/local/plotly_handler.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/local/runner.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/logger.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/model.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/options.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/output.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/polling.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/run.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/safe.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/nextmv/status.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/pyproject.toml +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/__init__.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/cloud/__init__.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/cloud/app.yaml +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/cloud/test_client.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/cloud/test_package.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/cloud/test_scenario.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/local/__init__.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/local/test_application.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/local/test_runner.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/scripts/__init__.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/scripts/options1.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/scripts/options2.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/scripts/options3.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/scripts/options4.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/scripts/options5.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/scripts/options6.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/scripts/options7.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/scripts/options_deprecated.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/test_base_model.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/test_entrypoint/__init__.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/test_entrypoint/test_entrypoint.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/test_input.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/test_inputs/test_data.csv +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/test_inputs/test_data.json +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/test_inputs/test_data.txt +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/test_logger.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/test_model.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/test_options.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/test_output.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/test_polling.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/test_run.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/test_safe.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/test_serialization.py +0 -0
- {nextmv-0.32.0 → nextmv-0.33.0}/tests/test_version.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "v0.33.0"
|
|
@@ -21,6 +21,7 @@ from .manifest import Manifest as Manifest
|
|
|
21
21
|
from .manifest import ManifestBuild as ManifestBuild
|
|
22
22
|
from .manifest import ManifestOption as ManifestOption
|
|
23
23
|
from .manifest import ManifestPython as ManifestPython
|
|
24
|
+
from .manifest import ManifestPythonArch as ManifestPythonArch
|
|
24
25
|
from .manifest import ManifestPythonModel as ManifestPythonModel
|
|
25
26
|
from .manifest import ManifestRuntime as ManifestRuntime
|
|
26
27
|
from .manifest import ManifestType as ManifestType
|
|
@@ -47,6 +47,7 @@ from .acceptance_test import MetricParams as MetricParams
|
|
|
47
47
|
from .acceptance_test import MetricResult as MetricResult
|
|
48
48
|
from .acceptance_test import MetricStatistics as MetricStatistics
|
|
49
49
|
from .acceptance_test import MetricTolerance as MetricTolerance
|
|
50
|
+
from .acceptance_test import MetricToleranceType as MetricToleranceType
|
|
50
51
|
from .acceptance_test import MetricType as MetricType
|
|
51
52
|
from .acceptance_test import ResultStatistics as ResultStatistics
|
|
52
53
|
from .acceptance_test import StatisticType as StatisticType
|
|
@@ -63,6 +64,12 @@ from .batch_experiment import BatchExperimentRun as BatchExperimentRun
|
|
|
63
64
|
from .batch_experiment import ExperimentStatus as ExperimentStatus
|
|
64
65
|
from .client import Client as Client
|
|
65
66
|
from .client import get_size as get_size
|
|
67
|
+
from .ensemble import EnsembleDefinition as EnsembleDefinition
|
|
68
|
+
from .ensemble import EvaluationRule as EvaluationRule
|
|
69
|
+
from .ensemble import RuleObjective as RuleObjective
|
|
70
|
+
from .ensemble import RuleTolerance as RuleTolerance
|
|
71
|
+
from .ensemble import RuleToleranceType as RuleToleranceType
|
|
72
|
+
from .ensemble import RunGroup as RunGroup
|
|
66
73
|
from .input_set import InputSet as InputSet
|
|
67
74
|
from .input_set import ManagedInput as ManagedInput
|
|
68
75
|
from .instance import Instance as Instance
|
|
@@ -47,6 +47,7 @@ from typing import Optional
|
|
|
47
47
|
|
|
48
48
|
from nextmv.base_model import BaseModel
|
|
49
49
|
from nextmv.cloud.batch_experiment import ExperimentStatus
|
|
50
|
+
from nextmv.deprecated import deprecated
|
|
50
51
|
|
|
51
52
|
|
|
52
53
|
class MetricType(str, Enum):
|
|
@@ -214,6 +215,9 @@ class Comparison(str, Enum):
|
|
|
214
215
|
|
|
215
216
|
class ToleranceType(str, Enum):
|
|
216
217
|
"""
|
|
218
|
+
!!! warning
|
|
219
|
+
`ToleranceType` is deprecated, use `MetricToleranceType` instead.
|
|
220
|
+
|
|
217
221
|
Type of tolerance used for a metric.
|
|
218
222
|
|
|
219
223
|
You can import the `ToleranceType` class directly from `cloud`:
|
|
@@ -242,6 +246,66 @@ class ToleranceType(str, Enum):
|
|
|
242
246
|
<ToleranceType.absolute: 'absolute'>
|
|
243
247
|
"""
|
|
244
248
|
|
|
249
|
+
undefined = ""
|
|
250
|
+
"""ToleranceType is deprecated, please use MetricToleranceType instead.
|
|
251
|
+
Undefined tolerance type."""
|
|
252
|
+
absolute = "absolute"
|
|
253
|
+
"""ToleranceType is deprecated, please use MetricToleranceType instead.
|
|
254
|
+
Absolute tolerance type."""
|
|
255
|
+
relative = "relative"
|
|
256
|
+
"""ToleranceType is deprecated, please use MetricToleranceType instead.
|
|
257
|
+
Relative tolerance type."""
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
# Override __getattribute__ to emit deprecation warnings when enum values are accessed
|
|
261
|
+
_original_getattribute = ToleranceType.__class__.__getattribute__
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def _deprecated_getattribute(cls, name: str):
|
|
265
|
+
# Only emit deprecation warning if this is specifically the ToleranceType class
|
|
266
|
+
if cls is ToleranceType and name in ("undefined", "absolute", "relative"):
|
|
267
|
+
deprecated(
|
|
268
|
+
f"ToleranceType.{name}",
|
|
269
|
+
"ToleranceType is deprecated and will be removed in a future version. "
|
|
270
|
+
"Please use MetricToleranceType instead",
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
return _original_getattribute(cls, name)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
ToleranceType.__class__.__getattribute__ = _deprecated_getattribute
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
class MetricToleranceType(str, Enum):
|
|
280
|
+
"""
|
|
281
|
+
Type of tolerance used for a metric.
|
|
282
|
+
|
|
283
|
+
You can import the `MetricToleranceType` class directly from `cloud`:
|
|
284
|
+
|
|
285
|
+
```python
|
|
286
|
+
from nextmv.cloud import MetricToleranceType
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
This enumeration defines the different types of tolerances that can be used
|
|
290
|
+
when comparing metrics in acceptance tests.
|
|
291
|
+
|
|
292
|
+
Attributes
|
|
293
|
+
----------
|
|
294
|
+
undefined : str
|
|
295
|
+
Undefined tolerance type (empty string).
|
|
296
|
+
absolute : str
|
|
297
|
+
Absolute tolerance type, using a fixed value.
|
|
298
|
+
relative : str
|
|
299
|
+
Relative tolerance type, using a percentage.
|
|
300
|
+
|
|
301
|
+
Examples
|
|
302
|
+
--------
|
|
303
|
+
>>> from nextmv.cloud import MetricToleranceType
|
|
304
|
+
>>> tol_type = MetricToleranceType.absolute
|
|
305
|
+
>>> tol_type
|
|
306
|
+
<MetricToleranceType.absolute: 'absolute'>
|
|
307
|
+
"""
|
|
308
|
+
|
|
245
309
|
undefined = ""
|
|
246
310
|
"""Undefined tolerance type."""
|
|
247
311
|
absolute = "absolute"
|
|
@@ -265,22 +329,22 @@ class MetricTolerance(BaseModel):
|
|
|
265
329
|
|
|
266
330
|
Attributes
|
|
267
331
|
----------
|
|
268
|
-
type :
|
|
332
|
+
type : MetricToleranceType
|
|
269
333
|
Type of tolerance (absolute or relative).
|
|
270
334
|
value : float
|
|
271
335
|
Value of the tolerance.
|
|
272
336
|
|
|
273
337
|
Examples
|
|
274
338
|
--------
|
|
275
|
-
>>> from nextmv.cloud import MetricTolerance,
|
|
276
|
-
>>> tolerance = MetricTolerance(type=
|
|
339
|
+
>>> from nextmv.cloud import MetricTolerance, MetricToleranceType
|
|
340
|
+
>>> tolerance = MetricTolerance(type=MetricToleranceType.absolute, value=0.1)
|
|
277
341
|
>>> tolerance.type
|
|
278
|
-
<
|
|
342
|
+
<MetricToleranceType.absolute: 'absolute'>
|
|
279
343
|
>>> tolerance.value
|
|
280
344
|
0.1
|
|
281
345
|
"""
|
|
282
346
|
|
|
283
|
-
type:
|
|
347
|
+
type: MetricToleranceType
|
|
284
348
|
"""Type of tolerance."""
|
|
285
349
|
value: float
|
|
286
350
|
"""Value of the tolerance."""
|
|
@@ -46,6 +46,7 @@ from nextmv.cloud.batch_experiment import (
|
|
|
46
46
|
to_runs,
|
|
47
47
|
)
|
|
48
48
|
from nextmv.cloud.client import Client, get_size
|
|
49
|
+
from nextmv.cloud.ensemble import EnsembleDefinition, EvaluationRule, RunGroup
|
|
49
50
|
from nextmv.cloud.input_set import InputSet, ManagedInput
|
|
50
51
|
from nextmv.cloud.instance import Instance, InstanceConfiguration
|
|
51
52
|
from nextmv.cloud.scenario import Scenario, ScenarioInputType, _option_sets, _scenarios_by_id
|
|
@@ -129,6 +130,8 @@ class Application:
|
|
|
129
130
|
"""Base endpoint for the application."""
|
|
130
131
|
experiments_endpoint: str = "{base}/experiments"
|
|
131
132
|
"""Base endpoint for the experiments in the application."""
|
|
133
|
+
ensembles_endpoint: str = "{base}/ensembles"
|
|
134
|
+
"""Base endpoint for managing the ensemble definitions in the application"""
|
|
132
135
|
|
|
133
136
|
def __post_init__(self):
|
|
134
137
|
"""Initialize the endpoint and experiments_endpoint attributes.
|
|
@@ -138,6 +141,7 @@ class Application:
|
|
|
138
141
|
"""
|
|
139
142
|
self.endpoint = self.endpoint.format(id=self.id)
|
|
140
143
|
self.experiments_endpoint = self.experiments_endpoint.format(base=self.endpoint)
|
|
144
|
+
self.ensembles_endpoint = self.ensembles_endpoint.format(base=self.endpoint)
|
|
141
145
|
|
|
142
146
|
@classmethod
|
|
143
147
|
def new(
|
|
@@ -515,6 +519,30 @@ class Application:
|
|
|
515
519
|
endpoint=f"{self.experiments_endpoint}/batch/{batch_id}",
|
|
516
520
|
)
|
|
517
521
|
|
|
522
|
+
def delete_ensemble_definition(self, ensemble_definition_id: str) -> None:
|
|
523
|
+
"""
|
|
524
|
+
Delete an ensemble definition.
|
|
525
|
+
|
|
526
|
+
Parameters
|
|
527
|
+
----------
|
|
528
|
+
ensemble_definition_id : str
|
|
529
|
+
ID of the ensemble definition to delete.
|
|
530
|
+
|
|
531
|
+
Raises
|
|
532
|
+
------
|
|
533
|
+
requests.HTTPError
|
|
534
|
+
If the response status code is not 2xx.
|
|
535
|
+
|
|
536
|
+
Examples
|
|
537
|
+
--------
|
|
538
|
+
>>> app.delete_ensemble_definition("development-ensemble-definition")
|
|
539
|
+
"""
|
|
540
|
+
|
|
541
|
+
_ = self.client.request(
|
|
542
|
+
method="DELETE",
|
|
543
|
+
endpoint=f"{self.ensembles_endpoint}/{ensemble_definition_id}",
|
|
544
|
+
)
|
|
545
|
+
|
|
518
546
|
def delete_scenario_test(self, scenario_test_id: str) -> None:
|
|
519
547
|
"""
|
|
520
548
|
Delete a scenario test.
|
|
@@ -563,6 +591,39 @@ class Application:
|
|
|
563
591
|
endpoint=f"{self.endpoint}/secrets/{secrets_collection_id}",
|
|
564
592
|
)
|
|
565
593
|
|
|
594
|
+
def ensemble_definition(self, ensemble_definition_id: str) -> EnsembleDefinition:
|
|
595
|
+
"""
|
|
596
|
+
Get an ensemble definition.
|
|
597
|
+
|
|
598
|
+
Parameters
|
|
599
|
+
----------
|
|
600
|
+
ensemble_definition_id : str
|
|
601
|
+
ID of the ensemble definition to retrieve.
|
|
602
|
+
|
|
603
|
+
Returns
|
|
604
|
+
-------
|
|
605
|
+
EnsembleDefintion
|
|
606
|
+
The requested ensemble definition details.
|
|
607
|
+
|
|
608
|
+
Raises
|
|
609
|
+
------
|
|
610
|
+
requests.HTTPError
|
|
611
|
+
If the response status code is not 2xx.
|
|
612
|
+
|
|
613
|
+
Examples
|
|
614
|
+
--------
|
|
615
|
+
>>> ensemble_definition = app.ensemble_definition("instance-123")
|
|
616
|
+
>>> print(ensemble_definition.name)
|
|
617
|
+
'Production Ensemble Definition'
|
|
618
|
+
"""
|
|
619
|
+
|
|
620
|
+
response = self.client.request(
|
|
621
|
+
method="GET",
|
|
622
|
+
endpoint=f"{self.ensembles_endpoint}/{ensemble_definition_id}",
|
|
623
|
+
)
|
|
624
|
+
|
|
625
|
+
return EnsembleDefinition.from_dict(response.json())
|
|
626
|
+
|
|
566
627
|
@staticmethod
|
|
567
628
|
def exists(client: Client, id: str) -> bool:
|
|
568
629
|
"""
|
|
@@ -748,6 +809,36 @@ class Application:
|
|
|
748
809
|
|
|
749
810
|
return [BatchExperimentMetadata.from_dict(batch_experiment) for batch_experiment in response.json()]
|
|
750
811
|
|
|
812
|
+
def list_ensemble_definitions(self) -> list[EnsembleDefinition]:
|
|
813
|
+
"""
|
|
814
|
+
List all ensemble_definitions.
|
|
815
|
+
|
|
816
|
+
Returns
|
|
817
|
+
-------
|
|
818
|
+
list[EnsembleDefinition]
|
|
819
|
+
List of all ensemble definitions associated with this application.
|
|
820
|
+
|
|
821
|
+
Raises
|
|
822
|
+
------
|
|
823
|
+
requests.HTTPError
|
|
824
|
+
If the response status code is not 2xx.
|
|
825
|
+
|
|
826
|
+
Examples
|
|
827
|
+
--------
|
|
828
|
+
>>> ensemble_definitions = app.list_ensemble_definitions()
|
|
829
|
+
>>> for ensemble_definition in ensemble_definitions:
|
|
830
|
+
... print(ensemble_definition.name)
|
|
831
|
+
'Development Ensemble Definition'
|
|
832
|
+
'Production Ensemble Definition'
|
|
833
|
+
"""
|
|
834
|
+
|
|
835
|
+
response = self.client.request(
|
|
836
|
+
method="GET",
|
|
837
|
+
endpoint=f"{self.ensembles_endpoint}",
|
|
838
|
+
)
|
|
839
|
+
|
|
840
|
+
return [EnsembleDefinition.from_dict(ensemble_definition) for ensemble_definition in response.json()["items"]]
|
|
841
|
+
|
|
751
842
|
def list_input_sets(self) -> list[InputSet]:
|
|
752
843
|
"""
|
|
753
844
|
List all input sets.
|
|
@@ -1314,6 +1405,53 @@ class Application:
|
|
|
1314
1405
|
|
|
1315
1406
|
return self.batch_experiment_with_polling(batch_id=batch_id, polling_options=polling_options)
|
|
1316
1407
|
|
|
1408
|
+
def new_ensemble_defintion(
|
|
1409
|
+
self,
|
|
1410
|
+
id: str,
|
|
1411
|
+
run_groups: list[RunGroup],
|
|
1412
|
+
rules: list[EvaluationRule],
|
|
1413
|
+
name: Optional[str] = None,
|
|
1414
|
+
description: Optional[str] = None,
|
|
1415
|
+
) -> EnsembleDefinition:
|
|
1416
|
+
"""
|
|
1417
|
+
Create a new ensemble definition.
|
|
1418
|
+
|
|
1419
|
+
Parameters
|
|
1420
|
+
----------
|
|
1421
|
+
id: str
|
|
1422
|
+
ID of the ensemble defintion.
|
|
1423
|
+
run_groups: list[RunGroup]
|
|
1424
|
+
Information to facilitate the execution of child runs.
|
|
1425
|
+
rules: list[EvaluationRule]
|
|
1426
|
+
Information to facilitate the selection of
|
|
1427
|
+
a result for the ensemble run from child runs.
|
|
1428
|
+
name: Optional[str]
|
|
1429
|
+
Name of the ensemble definition.
|
|
1430
|
+
description: Optional[str]
|
|
1431
|
+
Description of the ensemble definition.
|
|
1432
|
+
"""
|
|
1433
|
+
|
|
1434
|
+
if name is None:
|
|
1435
|
+
name = id
|
|
1436
|
+
if description is None:
|
|
1437
|
+
description = name
|
|
1438
|
+
|
|
1439
|
+
payload = {
|
|
1440
|
+
"id": id,
|
|
1441
|
+
"run_groups": [run_group.to_dict() for run_group in run_groups],
|
|
1442
|
+
"rules": [rule.to_dict() for rule in rules],
|
|
1443
|
+
"name": name,
|
|
1444
|
+
"description": description,
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
response = self.client.request(
|
|
1448
|
+
method="POST",
|
|
1449
|
+
endpoint=f"{self.ensembles_endpoint}",
|
|
1450
|
+
payload=payload,
|
|
1451
|
+
)
|
|
1452
|
+
|
|
1453
|
+
return EnsembleDefinition.from_dict(response.json())
|
|
1454
|
+
|
|
1317
1455
|
def new_input_set(
|
|
1318
1456
|
self,
|
|
1319
1457
|
id: str,
|
|
@@ -2236,13 +2374,14 @@ class Application:
|
|
|
2236
2374
|
|
|
2237
2375
|
if id is None:
|
|
2238
2376
|
id = safe_id(prefix="version")
|
|
2377
|
+
if name is None:
|
|
2378
|
+
name = id
|
|
2239
2379
|
|
|
2240
2380
|
payload = {
|
|
2241
2381
|
"id": id,
|
|
2382
|
+
"name": name,
|
|
2242
2383
|
}
|
|
2243
2384
|
|
|
2244
|
-
if name is not None:
|
|
2245
|
-
payload["name"] = name
|
|
2246
2385
|
if description is not None:
|
|
2247
2386
|
payload["description"] = description
|
|
2248
2387
|
|
|
@@ -2934,6 +3073,98 @@ class Application:
|
|
|
2934
3073
|
output_dir_path=output_dir_path,
|
|
2935
3074
|
)
|
|
2936
3075
|
|
|
3076
|
+
def update_batch_experiment(
|
|
3077
|
+
self,
|
|
3078
|
+
batch_experiment_id: str,
|
|
3079
|
+
name: Optional[str] = None,
|
|
3080
|
+
description: Optional[str] = None,
|
|
3081
|
+
) -> BatchExperimentInformation:
|
|
3082
|
+
"""
|
|
3083
|
+
Update a batch experiment.
|
|
3084
|
+
|
|
3085
|
+
Parameters
|
|
3086
|
+
----------
|
|
3087
|
+
batch_experiment_id : str
|
|
3088
|
+
ID of the batch experiment to update.
|
|
3089
|
+
name : Optional[str], default=None
|
|
3090
|
+
Optional name of the batch experiment.
|
|
3091
|
+
description : Optional[str], default=None
|
|
3092
|
+
Optional description of the batch experiment.
|
|
3093
|
+
|
|
3094
|
+
Returns
|
|
3095
|
+
-------
|
|
3096
|
+
BatchExperimentInformation
|
|
3097
|
+
The information with the updated batch experiment.
|
|
3098
|
+
|
|
3099
|
+
Raises
|
|
3100
|
+
------
|
|
3101
|
+
requests.HTTPError
|
|
3102
|
+
If the response status code is not 2xx.
|
|
3103
|
+
"""
|
|
3104
|
+
|
|
3105
|
+
payload = {}
|
|
3106
|
+
|
|
3107
|
+
if name is not None:
|
|
3108
|
+
payload["name"] = name
|
|
3109
|
+
if description is not None:
|
|
3110
|
+
payload["description"] = description
|
|
3111
|
+
|
|
3112
|
+
response = self.client.request(
|
|
3113
|
+
method="PATCH",
|
|
3114
|
+
endpoint=f"{self.experiments_endpoint}/batch/{batch_experiment_id}",
|
|
3115
|
+
payload=payload,
|
|
3116
|
+
)
|
|
3117
|
+
|
|
3118
|
+
return BatchExperimentInformation.from_dict(response.json())
|
|
3119
|
+
|
|
3120
|
+
def update_ensemble_definition(
|
|
3121
|
+
self,
|
|
3122
|
+
id: str,
|
|
3123
|
+
name: Optional[str] = None,
|
|
3124
|
+
description: Optional[str] = None,
|
|
3125
|
+
) -> EnsembleDefinition:
|
|
3126
|
+
"""
|
|
3127
|
+
Update an ensemble definition.
|
|
3128
|
+
|
|
3129
|
+
Parameters
|
|
3130
|
+
----------
|
|
3131
|
+
id : str
|
|
3132
|
+
ID of the ensemble definition to update.
|
|
3133
|
+
name : Optional[str], default=None
|
|
3134
|
+
Optional name of the ensemble definition.
|
|
3135
|
+
description : Optional[str], default=None
|
|
3136
|
+
Optional description of the ensemble definition.
|
|
3137
|
+
|
|
3138
|
+
Returns
|
|
3139
|
+
-------
|
|
3140
|
+
EnsembleDefinition
|
|
3141
|
+
The updated ensemble definition.
|
|
3142
|
+
|
|
3143
|
+
Raises
|
|
3144
|
+
------
|
|
3145
|
+
ValueError
|
|
3146
|
+
If neither name nor description is updated
|
|
3147
|
+
requests.HTTPError
|
|
3148
|
+
If the response status code is not 2xx.
|
|
3149
|
+
"""
|
|
3150
|
+
|
|
3151
|
+
payload = {}
|
|
3152
|
+
|
|
3153
|
+
if name is None and description is None:
|
|
3154
|
+
raise ValueError("Must define at least one value among name and description to modify")
|
|
3155
|
+
if name is not None:
|
|
3156
|
+
payload["name"] = name
|
|
3157
|
+
if description is not None:
|
|
3158
|
+
payload["description"] = description
|
|
3159
|
+
|
|
3160
|
+
response = self.client.request(
|
|
3161
|
+
method="PATCH",
|
|
3162
|
+
endpoint=f"{self.ensembles_endpoint}/{id}",
|
|
3163
|
+
payload=payload,
|
|
3164
|
+
)
|
|
3165
|
+
|
|
3166
|
+
return EnsembleDefinition.from_dict(response.json())
|
|
3167
|
+
|
|
2937
3168
|
def update_instance(
|
|
2938
3169
|
self,
|
|
2939
3170
|
id: str,
|
|
@@ -2997,50 +3228,6 @@ class Application:
|
|
|
2997
3228
|
|
|
2998
3229
|
return Instance.from_dict(response.json())
|
|
2999
3230
|
|
|
3000
|
-
def update_batch_experiment(
|
|
3001
|
-
self,
|
|
3002
|
-
batch_experiment_id: str,
|
|
3003
|
-
name: Optional[str] = None,
|
|
3004
|
-
description: Optional[str] = None,
|
|
3005
|
-
) -> BatchExperimentInformation:
|
|
3006
|
-
"""
|
|
3007
|
-
Update a batch experiment.
|
|
3008
|
-
|
|
3009
|
-
Parameters
|
|
3010
|
-
----------
|
|
3011
|
-
batch_experiment_id : str
|
|
3012
|
-
ID of the batch experiment to update.
|
|
3013
|
-
name : Optional[str], default=None
|
|
3014
|
-
Optional name of the batch experiment.
|
|
3015
|
-
description : Optional[str], default=None
|
|
3016
|
-
Optional description of the batch experiment.
|
|
3017
|
-
|
|
3018
|
-
Returns
|
|
3019
|
-
-------
|
|
3020
|
-
BatchExperimentInformation
|
|
3021
|
-
The information with the updated batch experiment.
|
|
3022
|
-
|
|
3023
|
-
Raises
|
|
3024
|
-
------
|
|
3025
|
-
requests.HTTPError
|
|
3026
|
-
If the response status code is not 2xx.
|
|
3027
|
-
"""
|
|
3028
|
-
|
|
3029
|
-
payload = {}
|
|
3030
|
-
|
|
3031
|
-
if name is not None:
|
|
3032
|
-
payload["name"] = name
|
|
3033
|
-
if description is not None:
|
|
3034
|
-
payload["description"] = description
|
|
3035
|
-
|
|
3036
|
-
response = self.client.request(
|
|
3037
|
-
method="PATCH",
|
|
3038
|
-
endpoint=f"{self.experiments_endpoint}/batch/{batch_experiment_id}",
|
|
3039
|
-
payload=payload,
|
|
3040
|
-
)
|
|
3041
|
-
|
|
3042
|
-
return BatchExperimentInformation.from_dict(response.json())
|
|
3043
|
-
|
|
3044
3231
|
def update_managed_input(
|
|
3045
3232
|
self,
|
|
3046
3233
|
managed_input_id: str,
|
|
@@ -3681,65 +3868,40 @@ class Application:
|
|
|
3681
3868
|
"""
|
|
3682
3869
|
Auxiliary function to validate the directory path and configuration.
|
|
3683
3870
|
"""
|
|
3871
|
+
input_type = self.__get_input_type(configuration)
|
|
3684
3872
|
|
|
3685
|
-
|
|
3873
|
+
# If no explicit input type is defined, there is nothing to validate.
|
|
3874
|
+
if input_type is None:
|
|
3686
3875
|
return
|
|
3687
3876
|
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
)
|
|
3692
|
-
|
|
3693
|
-
config_format = self.__extract_config_format(configuration)
|
|
3694
|
-
|
|
3695
|
-
if config_format is None:
|
|
3696
|
-
raise ValueError(
|
|
3697
|
-
"If dir_path is provided, RunConfiguration.format must also be provided.",
|
|
3698
|
-
)
|
|
3699
|
-
|
|
3700
|
-
input_type = self.__extract_input_type(config_format)
|
|
3701
|
-
|
|
3702
|
-
if input_type is None or input_type in (InputFormat.JSON, InputFormat.TEXT):
|
|
3877
|
+
# Validate that the input directory path is provided when explicitly required.
|
|
3878
|
+
dir_types = (InputFormat.MULTI_FILE, InputFormat.CSV_ARCHIVE)
|
|
3879
|
+
if input_type in dir_types and not input_dir_path:
|
|
3703
3880
|
raise ValueError(
|
|
3704
|
-
"If
|
|
3705
|
-
|
|
3881
|
+
f"If RunConfiguration.format.format_input.input_type is set to {input_type}, "
|
|
3882
|
+
"then input_dir_path must be provided.",
|
|
3706
3883
|
)
|
|
3707
3884
|
|
|
3708
|
-
def
|
|
3709
|
-
"""
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
if isinstance(configuration, dict):
|
|
3714
|
-
config_format = configuration.get("format")
|
|
3715
|
-
if config_format is not None and isinstance(config_format, dict):
|
|
3716
|
-
return Format.from_dict(config_format) if hasattr(Format, "from_dict") else config_format
|
|
3717
|
-
|
|
3718
|
-
return config_format
|
|
3719
|
-
|
|
3720
|
-
raise ValueError("Configuration must be a RunConfiguration object or a dict.")
|
|
3721
|
-
|
|
3722
|
-
def __extract_input_type(self, config_format: Any) -> Any:
|
|
3723
|
-
"""Extract input type from config format."""
|
|
3724
|
-
if isinstance(config_format, dict):
|
|
3725
|
-
format_input = config_format.get("format_input") or config_format.get("input")
|
|
3726
|
-
if format_input is None:
|
|
3727
|
-
raise ValueError(
|
|
3728
|
-
"If dir_path is provided, RunConfiguration.format.format_input must also be provided.",
|
|
3729
|
-
)
|
|
3885
|
+
def __get_input_type(self, config: Union[RunConfiguration, dict[str, Any]]) -> Optional[InputFormat]:
|
|
3886
|
+
"""
|
|
3887
|
+
Auxiliary function to extract the input type from the run configuration.
|
|
3888
|
+
"""
|
|
3730
3889
|
|
|
3731
|
-
|
|
3732
|
-
|
|
3890
|
+
if config is None:
|
|
3891
|
+
return None
|
|
3733
3892
|
|
|
3734
|
-
|
|
3893
|
+
if isinstance(config, dict):
|
|
3894
|
+
config = RunConfiguration.from_dict(config)
|
|
3735
3895
|
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3896
|
+
if (
|
|
3897
|
+
isinstance(config, RunConfiguration)
|
|
3898
|
+
and config.format is not None
|
|
3899
|
+
and config.format.format_input is not None
|
|
3900
|
+
and config.format.format_input.input_type is not None
|
|
3901
|
+
):
|
|
3902
|
+
return config.format.format_input.input_type
|
|
3741
3903
|
|
|
3742
|
-
return
|
|
3904
|
+
return None
|
|
3743
3905
|
|
|
3744
3906
|
def __package_inputs(self, dir_path: str) -> str:
|
|
3745
3907
|
"""
|