nextmv 0.28.5__py3-none-any.whl → 0.29.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nextmv/__about__.py +1 -1
- nextmv/__init__.py +8 -0
- nextmv/cloud/application.py +210 -21
- nextmv/cloud/client.py +28 -9
- nextmv/cloud/manifest.py +142 -14
- nextmv/cloud/package.py +1 -1
- nextmv/cloud/run.py +34 -0
- nextmv/input.py +476 -6
- nextmv/model.py +12 -3
- nextmv/options.py +88 -0
- nextmv/output.py +535 -51
- {nextmv-0.28.5.dist-info → nextmv-0.29.0.dist-info}/METADATA +13 -1
- {nextmv-0.28.5.dist-info → nextmv-0.29.0.dist-info}/RECORD +15 -15
- {nextmv-0.28.5.dist-info → nextmv-0.29.0.dist-info}/WHEEL +0 -0
- {nextmv-0.28.5.dist-info → nextmv-0.29.0.dist-info}/licenses/LICENSE +0 -0
nextmv/cloud/manifest.py
CHANGED
|
@@ -16,10 +16,14 @@ ManifestPythonModel
|
|
|
16
16
|
Class for model-specific instructions for Python apps.
|
|
17
17
|
ManifestPython
|
|
18
18
|
Class for Python-specific instructions in the manifest.
|
|
19
|
+
ManifestOptionUI
|
|
20
|
+
Class for UI attributes of options in the manifest.
|
|
19
21
|
ManifestOption
|
|
20
22
|
Class representing an option for the decision model in the manifest.
|
|
21
23
|
ManifestOptions
|
|
22
24
|
Class containing a list of options for the decision model.
|
|
25
|
+
ManifestValidation
|
|
26
|
+
Class for validation rules for options in the manifest.
|
|
23
27
|
ManifestConfiguration
|
|
24
28
|
Class for configuration settings for the decision model.
|
|
25
29
|
Manifest
|
|
@@ -40,7 +44,7 @@ from pydantic import AliasChoices, Field
|
|
|
40
44
|
|
|
41
45
|
from nextmv.base_model import BaseModel
|
|
42
46
|
from nextmv.model import _REQUIREMENTS_FILE, ModelConfiguration
|
|
43
|
-
from nextmv.options import Option, Options
|
|
47
|
+
from nextmv.options import Option, Options, OptionsEnforcement
|
|
44
48
|
|
|
45
49
|
MANIFEST_FILE_NAME = "app.yaml"
|
|
46
50
|
"""Name of the app manifest file.
|
|
@@ -318,6 +322,43 @@ class ManifestPython(BaseModel):
|
|
|
318
322
|
from the app bundle.
|
|
319
323
|
"""
|
|
320
324
|
|
|
325
|
+
class ManifestOptionUI(BaseModel):
|
|
326
|
+
"""
|
|
327
|
+
UI attributes for an option in the manifest.
|
|
328
|
+
|
|
329
|
+
You can import the `ManifestOptionUI` class directly from `cloud`:
|
|
330
|
+
|
|
331
|
+
```python
|
|
332
|
+
from nextmv.cloud import ManifestOptionUI
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
Parameters
|
|
336
|
+
----------
|
|
337
|
+
control_type : str, optional
|
|
338
|
+
The type of control to use for the option in the Nextmv Cloud UI. This is
|
|
339
|
+
useful for defining how the option should be presented in the Nextmv
|
|
340
|
+
Cloud UI. Current control types include "input", "select", "slider", and
|
|
341
|
+
"toggle". This attribute is not used in the local `Options` class, but
|
|
342
|
+
it is used in the Nextmv Cloud UI to define the type of control to use for
|
|
343
|
+
the option. This will be validated by the Nextmv Cloud, and availability
|
|
344
|
+
is based on options_type.
|
|
345
|
+
hidden_from : list[str], optional
|
|
346
|
+
A list of team roles to which this option will be hidden in the UI. For
|
|
347
|
+
example, if you want to hide an option from the "operator" role, you can
|
|
348
|
+
pass `hidden_from=["operator"]`.
|
|
349
|
+
|
|
350
|
+
Examples
|
|
351
|
+
--------
|
|
352
|
+
>>> from nextmv.cloud import ManifestOptionUI
|
|
353
|
+
>>> ui_config = ManifestOptionUI(control_type="input")
|
|
354
|
+
>>> ui_config.control_type
|
|
355
|
+
'input'
|
|
356
|
+
"""
|
|
357
|
+
|
|
358
|
+
control_type: Optional[str] = None
|
|
359
|
+
"""The type of control to use for the option in the Nextmv Cloud UI."""
|
|
360
|
+
hidden_from: Optional[list[str]] = None
|
|
361
|
+
"""A list of team roles for which this option will be hidden in the UI."""
|
|
321
362
|
|
|
322
363
|
class ManifestOption(BaseModel):
|
|
323
364
|
"""
|
|
@@ -349,6 +390,12 @@ class ManifestOption(BaseModel):
|
|
|
349
390
|
length of a string or the maximum value of an integer. These
|
|
350
391
|
additional attributes will be shown in the help message of the
|
|
351
392
|
`Options`.
|
|
393
|
+
ui : Optional[ManifestOptionUI], default=None
|
|
394
|
+
Optional UI attributes for the option. This is a dictionary that can
|
|
395
|
+
contain additional information about how the option should be displayed
|
|
396
|
+
in the Nextmv Cloud UI. This is not used in the local `Options` class,
|
|
397
|
+
but it is used in the Nextmv Cloud UI to define how the option should be
|
|
398
|
+
presented.
|
|
352
399
|
|
|
353
400
|
Examples
|
|
354
401
|
--------
|
|
@@ -378,12 +425,10 @@ class ManifestOption(BaseModel):
|
|
|
378
425
|
required: bool = False
|
|
379
426
|
"""Whether the option is required or not"""
|
|
380
427
|
additional_attributes: Optional[dict[str, Any]] = None
|
|
381
|
-
"""Optional additional attributes for the option.
|
|
428
|
+
"""Optional additional attributes for the option."""
|
|
429
|
+
ui: Optional[ManifestOptionUI] = None
|
|
430
|
+
"""Optional UI attributes for the option."""
|
|
382
431
|
|
|
383
|
-
The Nextmv Cloud may perform validation on these attributes. For example,
|
|
384
|
-
the maximum length of a string or the maximum value of an integer. These
|
|
385
|
-
additional attributes will be shown in the help message of the `Options`.
|
|
386
|
-
"""
|
|
387
432
|
|
|
388
433
|
@classmethod
|
|
389
434
|
def from_option(cls, option: Option) -> "ManifestOption":
|
|
@@ -435,6 +480,10 @@ class ManifestOption(BaseModel):
|
|
|
435
480
|
description=option.description,
|
|
436
481
|
required=option.required,
|
|
437
482
|
additional_attributes=option.additional_attributes,
|
|
483
|
+
ui=ManifestOptionUI(
|
|
484
|
+
control_type=option.control_type,
|
|
485
|
+
hidden_from=option.hidden_from,
|
|
486
|
+
) if option.control_type or option.hidden_from else None,
|
|
438
487
|
)
|
|
439
488
|
|
|
440
489
|
def to_option(self) -> Option:
|
|
@@ -481,8 +530,44 @@ class ManifestOption(BaseModel):
|
|
|
481
530
|
description=self.description,
|
|
482
531
|
required=self.required,
|
|
483
532
|
additional_attributes=self.additional_attributes,
|
|
533
|
+
control_type=self.ui.control_type if self.ui else None,
|
|
534
|
+
hidden_from=self.ui.hidden_from if self.ui else None,
|
|
484
535
|
)
|
|
485
536
|
|
|
537
|
+
class ManifestValidation(BaseModel):
|
|
538
|
+
"""
|
|
539
|
+
Validation rules for options in the manifest.
|
|
540
|
+
|
|
541
|
+
You can import the `ManifestValidation` class directly from `cloud`:
|
|
542
|
+
|
|
543
|
+
```python
|
|
544
|
+
from nextmv.cloud import ManifestValidation
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
Parameters
|
|
548
|
+
----------
|
|
549
|
+
enforce : str, default="none"
|
|
550
|
+
The enforcement level for the validation rules. This can be set to
|
|
551
|
+
"none" or "all". If set to "none", no validation will be performed
|
|
552
|
+
on the options prior to creating a run. If set to "all", all validation
|
|
553
|
+
rules will be enforced on the options, and runs will not be created
|
|
554
|
+
if any of the rules of the options are violated.
|
|
555
|
+
|
|
556
|
+
Examples
|
|
557
|
+
--------
|
|
558
|
+
>>> from nextmv.cloud import ManifestValidation
|
|
559
|
+
>>> validation = ManifestValidation(enforce="all")
|
|
560
|
+
>>> validation.enforce
|
|
561
|
+
'all'
|
|
562
|
+
"""
|
|
563
|
+
|
|
564
|
+
enforce: str = "none"
|
|
565
|
+
"""The enforcement level for the validation rules.
|
|
566
|
+
This can be set to "none" or "all". If set to "none", no validation will
|
|
567
|
+
be performed on the options prior to creating a run. If set to "all", all
|
|
568
|
+
validation rules will be enforced on the options, and runs will not be
|
|
569
|
+
created if any of the rules of the options are violated.
|
|
570
|
+
"""
|
|
486
571
|
|
|
487
572
|
class ManifestOptions(BaseModel):
|
|
488
573
|
"""
|
|
@@ -501,12 +586,16 @@ class ManifestOptions(BaseModel):
|
|
|
501
586
|
items : Optional[list[ManifestOption]], default=None
|
|
502
587
|
The actual list of options for the decision model. An option
|
|
503
588
|
is a parameter that configures the decision model.
|
|
589
|
+
validation: Optional[ManifestValidation], default=None
|
|
590
|
+
Optional validation rules for all options.
|
|
591
|
+
|
|
504
592
|
|
|
505
593
|
Examples
|
|
506
594
|
--------
|
|
507
595
|
>>> from nextmv.cloud import ManifestOptions, ManifestOption
|
|
508
596
|
>>> options_config = ManifestOptions(
|
|
509
597
|
... strict=True,
|
|
598
|
+
... validation=ManifestValidation(enforce="all"),
|
|
510
599
|
... items=[
|
|
511
600
|
... ManifestOption(name="timeout", option_type="int", default=60),
|
|
512
601
|
... ManifestOption(name="vehicle_capacity", option_type="float", default=100.0)
|
|
@@ -520,12 +609,48 @@ class ManifestOptions(BaseModel):
|
|
|
520
609
|
|
|
521
610
|
strict: Optional[bool] = False
|
|
522
611
|
"""If strict is set to `True`, only the listed options will be allowed."""
|
|
612
|
+
validation: Optional[ManifestValidation] = None
|
|
613
|
+
"""Optional validation rules for all options."""
|
|
523
614
|
items: Optional[list[ManifestOption]] = None
|
|
524
615
|
"""The actual list of options for the decision model.
|
|
525
616
|
|
|
526
617
|
An option is a parameter that configures the decision model.
|
|
527
618
|
"""
|
|
528
619
|
|
|
620
|
+
@classmethod
|
|
621
|
+
def from_options(cls, options: Options, validation: OptionsEnforcement = None) -> "ManifestOptions":
|
|
622
|
+
"""
|
|
623
|
+
Create a `ManifestOptions` from a `nextmv.Options`.
|
|
624
|
+
|
|
625
|
+
Parameters
|
|
626
|
+
----------
|
|
627
|
+
options : nextmv.options.Options
|
|
628
|
+
The options to convert.
|
|
629
|
+
validation : Optional[OptionsEnforcement], default=None
|
|
630
|
+
Optional validation rules for the options. If provided, it will be
|
|
631
|
+
used to set the `validation` attribute of the `ManifestOptions`.
|
|
632
|
+
|
|
633
|
+
Returns
|
|
634
|
+
-------
|
|
635
|
+
ManifestOptions
|
|
636
|
+
The converted options.
|
|
637
|
+
|
|
638
|
+
Examples
|
|
639
|
+
--------
|
|
640
|
+
>>> from nextmv.options import Options, Option
|
|
641
|
+
>>> from nextmv.cloud import ManifestOptions
|
|
642
|
+
>>> sdk_options = Options(Option("max_vehicles", int, 5))
|
|
643
|
+
>>> manifest_options = ManifestOptions.from_options(sdk_options)
|
|
644
|
+
>>> manifest_options.items[0].name
|
|
645
|
+
'max_vehicles'
|
|
646
|
+
"""
|
|
647
|
+
|
|
648
|
+
items = [ManifestOption.from_option(option) for option in options.options]
|
|
649
|
+
return cls(
|
|
650
|
+
strict=validation.strict if validation else False,
|
|
651
|
+
validation=ManifestValidation(enforce="all" if validation and validation.validation_enforce else "none"),
|
|
652
|
+
items=items
|
|
653
|
+
)
|
|
529
654
|
|
|
530
655
|
class ManifestConfiguration(BaseModel):
|
|
531
656
|
"""
|
|
@@ -852,16 +977,16 @@ class Manifest(BaseModel):
|
|
|
852
977
|
|
|
853
978
|
if model_configuration.options is not None:
|
|
854
979
|
manifest.configuration = ManifestConfiguration(
|
|
855
|
-
options=ManifestOptions(
|
|
856
|
-
|
|
857
|
-
|
|
980
|
+
options=ManifestOptions.from_options(
|
|
981
|
+
options=model_configuration.options,
|
|
982
|
+
validation=model_configuration.options_enforcement,
|
|
858
983
|
),
|
|
859
984
|
)
|
|
860
985
|
|
|
861
986
|
return manifest
|
|
862
987
|
|
|
863
988
|
@classmethod
|
|
864
|
-
def from_options(cls, options: Options) -> "Manifest":
|
|
989
|
+
def from_options(cls, options: Options, validation: OptionsEnforcement = None) -> "Manifest":
|
|
865
990
|
"""
|
|
866
991
|
Create a basic Python manifest from `nextmv.options.Options`.
|
|
867
992
|
|
|
@@ -882,6 +1007,9 @@ class Manifest(BaseModel):
|
|
|
882
1007
|
----------
|
|
883
1008
|
options : nextmv.options.Options
|
|
884
1009
|
The options to include in the manifest.
|
|
1010
|
+
validation : nextmv.options.OptionsEnforcement default=None
|
|
1011
|
+
The validation rules for the options. This is used to set the
|
|
1012
|
+
`validation` attribute of the `ManifestOptions`.
|
|
885
1013
|
|
|
886
1014
|
Returns
|
|
887
1015
|
-------
|
|
@@ -913,11 +1041,11 @@ class Manifest(BaseModel):
|
|
|
913
1041
|
type=ManifestType.PYTHON,
|
|
914
1042
|
python=ManifestPython(pip_requirements="requirements.txt"),
|
|
915
1043
|
configuration=ManifestConfiguration(
|
|
916
|
-
options=ManifestOptions(
|
|
917
|
-
|
|
918
|
-
|
|
1044
|
+
options= ManifestOptions.from_options(
|
|
1045
|
+
options=options,
|
|
1046
|
+
validation=validation
|
|
919
1047
|
),
|
|
920
|
-
)
|
|
1048
|
+
)
|
|
921
1049
|
)
|
|
922
1050
|
|
|
923
1051
|
return manifest
|
nextmv/cloud/package.py
CHANGED
|
@@ -28,7 +28,7 @@ def _package(
|
|
|
28
28
|
model_configuration: Optional[ModelConfiguration] = None,
|
|
29
29
|
verbose: bool = False,
|
|
30
30
|
) -> tuple[str, str]:
|
|
31
|
-
"""Package the app into a tarball
|
|
31
|
+
"""Package the app into a tarball."""
|
|
32
32
|
|
|
33
33
|
with tempfile.TemporaryDirectory(prefix="nextmv-temp-") as temp_dir:
|
|
34
34
|
if manifest.type == ManifestType.PYTHON:
|
nextmv/cloud/run.py
CHANGED
|
@@ -470,6 +470,40 @@ class RunConfiguration(BaseModel):
|
|
|
470
470
|
queuing: Optional[RunQueuing] = None
|
|
471
471
|
"""Queuing configuration for the run."""
|
|
472
472
|
|
|
473
|
+
def resolve(
|
|
474
|
+
self,
|
|
475
|
+
input: Union[Input, dict[str, Any], BaseModel, str],
|
|
476
|
+
dir_path: Optional[str] = None,
|
|
477
|
+
) -> None:
|
|
478
|
+
"""
|
|
479
|
+
Resolves the run configuration by modifying or setting the `format`,
|
|
480
|
+
based on the type of input that is provided.
|
|
481
|
+
|
|
482
|
+
Parameters
|
|
483
|
+
----------
|
|
484
|
+
input : Input or dict[str, Any] or BaseModel or str, optional
|
|
485
|
+
The input to use for resolving the run configuration.
|
|
486
|
+
dir_path : str, optional
|
|
487
|
+
The directory path where inputs can be loaded from.
|
|
488
|
+
"""
|
|
489
|
+
|
|
490
|
+
# If the value is set by the user, do not change it.
|
|
491
|
+
if self.format is not None:
|
|
492
|
+
return
|
|
493
|
+
|
|
494
|
+
self.format = Format(format_input=FormatInput(input_type=InputFormat.JSON))
|
|
495
|
+
|
|
496
|
+
if isinstance(input, dict):
|
|
497
|
+
self.format.format_input.input_type = InputFormat.JSON
|
|
498
|
+
elif isinstance(input, str):
|
|
499
|
+
self.format.format_input.input_type = InputFormat.TEXT
|
|
500
|
+
elif dir_path is not None and dir_path != "":
|
|
501
|
+
# Kinda hard to detect if we should be working with CSV_ARCHIVE or
|
|
502
|
+
# MULTI_FILE, so we default to MULTI_FILE.
|
|
503
|
+
self.format.format_input.input_type = InputFormat.MULTI_FILE
|
|
504
|
+
elif isinstance(input, Input):
|
|
505
|
+
self.format.format_input.input_type = input.input_format
|
|
506
|
+
|
|
473
507
|
|
|
474
508
|
class ExternalRunResult(BaseModel):
|
|
475
509
|
"""
|