nextmv 0.30.0__py3-none-any.whl → 0.32.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.
@@ -1,15 +1,16 @@
1
- """Module with the logic for handling an app manifest.
1
+ """
2
+ Module with the logic for handling an app manifest.
2
3
 
3
4
  This module provides classes and functions for managing Nextmv app manifests.
4
5
  Manifest files (app.yaml) define how an application is built, run, and deployed
5
- on the Nextmv Cloud platform.
6
+ on the Nextmv platform.
6
7
 
7
8
  Classes
8
9
  -------
9
10
  ManifestType
10
11
  Enum for application types based on programming language.
11
12
  ManifestRuntime
12
- Enum for runtime environments where apps run on Nextmv Cloud.
13
+ Enum for runtime environments where apps run on Nextmv.
13
14
  ManifestBuild
14
15
  Class for build-specific attributes in the manifest.
15
16
  ManifestPythonModel
@@ -24,14 +25,22 @@ ManifestOptions
24
25
  Class containing a list of options for the decision model.
25
26
  ManifestValidation
26
27
  Class for validation rules for options in the manifest.
28
+ ManifestContentMultiFileInput
29
+ Class for multi-file content format input configuration.
30
+ ManifestContentMultiFileOutput
31
+ Class for multi-file content format output configuration.
32
+ ManifestContentMultiFile
33
+ Class for multi-file content format configuration.
34
+ ManifestContent
35
+ Class for content configuration specifying how app input/output is handled.
27
36
  ManifestConfiguration
28
37
  Class for configuration settings for the decision model.
29
38
  Manifest
30
- Main class representing an app manifest for Nextmv Cloud.
39
+ Main class representing an app manifest for Nextmv.
31
40
 
32
41
  Constants
33
42
  --------
34
- FILE_NAME
43
+ MANIFEST_FILE_NAME
35
44
  Name of the app manifest file.
36
45
  """
37
46
 
@@ -52,10 +61,10 @@ MANIFEST_FILE_NAME = "app.yaml"
52
61
 
53
62
  This constant defines the standard filename for Nextmv app manifest files.
54
63
 
55
- You can import the `FILE_NAME` constant directly from `cloud`:
64
+ You can import the `MANIFEST_FILE_NAME` constant directly from `nextmv`:
56
65
 
57
66
  ```python
58
- from nextmv.cloud import FILE_NAME
67
+ from nextmv import MANIFEST_FILE_NAME
59
68
  ```
60
69
 
61
70
  Notes
@@ -68,10 +77,10 @@ class ManifestType(str, Enum):
68
77
  """
69
78
  Type of application in the manifest, based on the programming language.
70
79
 
71
- You can import the `ManifestType` class directly from `cloud`:
80
+ You can import the `ManifestType` class directly from `nextmv`:
72
81
 
73
82
  ```python
74
- from nextmv.cloud import ManifestType
83
+ from nextmv import ManifestType
75
84
  ```
76
85
 
77
86
  This enum defines the supported programming languages for applications
@@ -88,7 +97,7 @@ class ManifestType(str, Enum):
88
97
 
89
98
  Examples
90
99
  --------
91
- >>> from nextmv.cloud import ManifestType
100
+ >>> from nextmv import ManifestType
92
101
  >>> manifest_type = ManifestType.PYTHON
93
102
  >>> manifest_type
94
103
  <ManifestType.PYTHON: 'python'>
@@ -108,10 +117,10 @@ class ManifestRuntime(str, Enum):
108
117
  """
109
118
  Runtime (environment) where the app will be run on Nextmv Cloud.
110
119
 
111
- You can import the `ManifestRuntime` class directly from `cloud`:
120
+ You can import the `ManifestRuntime` class directly from `nextmv`:
112
121
 
113
122
  ```python
114
- from nextmv.cloud import ManifestRuntime
123
+ from nextmv import ManifestRuntime
115
124
  ```
116
125
 
117
126
  This enum defines the supported runtime environments for applications
@@ -133,7 +142,7 @@ class ManifestRuntime(str, Enum):
133
142
 
134
143
  Examples
135
144
  --------
136
- >>> from nextmv.cloud import ManifestRuntime
145
+ >>> from nextmv import ManifestRuntime
137
146
  >>> runtime = ManifestRuntime.PYTHON
138
147
  >>> runtime
139
148
  <ManifestRuntime.PYTHON: 'ghcr.io/nextmv-io/runtime/python:3.11'>
@@ -163,10 +172,10 @@ class ManifestBuild(BaseModel):
163
172
  """
164
173
  Build-specific attributes.
165
174
 
166
- You can import the `ManifestBuild` class directly from `cloud`:
175
+ You can import the `ManifestBuild` class directly from `nextmv`:
167
176
 
168
177
  ```python
169
- from nextmv.cloud import ManifestBuild
178
+ from nextmv import ManifestBuild
170
179
  ```
171
180
 
172
181
  Parameters
@@ -182,7 +191,7 @@ class ManifestBuild(BaseModel):
182
191
 
183
192
  Examples
184
193
  --------
185
- >>> from nextmv.cloud import ManifestBuild
194
+ >>> from nextmv import ManifestBuild
186
195
  >>> build_config = ManifestBuild(
187
196
  ... command="make build",
188
197
  ... environment={"DEBUG": "true"}
@@ -216,7 +225,7 @@ class ManifestBuild(BaseModel):
216
225
 
217
226
  Examples
218
227
  --------
219
- >>> from nextmv.cloud import ManifestBuild
228
+ >>> from nextmv import ManifestBuild
220
229
  >>> build_config = ManifestBuild(environment={"COUNT": 1, "NAME": "test"})
221
230
  >>> build_config.environment_to_dict()
222
231
  {'COUNT': '1', 'NAME': 'test'}
@@ -235,10 +244,10 @@ class ManifestPythonModel(BaseModel):
235
244
  """
236
245
  Model-specific instructions for a Python app.
237
246
 
238
- You can import the `ManifestPythonModel` class directly from `cloud`:
247
+ You can import the `ManifestPythonModel` class directly from `nextmv`:
239
248
 
240
249
  ```python
241
- from nextmv.cloud import ManifestPythonModel
250
+ from nextmv import ManifestPythonModel
242
251
  ```
243
252
 
244
253
  Parameters
@@ -253,7 +262,7 @@ class ManifestPythonModel(BaseModel):
253
262
 
254
263
  Examples
255
264
  --------
256
- >>> from nextmv.cloud import ManifestPythonModel
265
+ >>> from nextmv import ManifestPythonModel
257
266
  >>> python_model_config = ManifestPythonModel(
258
267
  ... name="routing_model",
259
268
  ... options=[{"name": "max_vehicles", "type": "int", "default": 10}]
@@ -277,10 +286,10 @@ class ManifestPython(BaseModel):
277
286
  """
278
287
  Python-specific instructions.
279
288
 
280
- You can import the `ManifestPython` class directly from `cloud`:
289
+ You can import the `ManifestPython` class directly from `nextmv`:
281
290
 
282
291
  ```python
283
- from nextmv.cloud import ManifestPython
292
+ from nextmv import ManifestPython
284
293
  ```
285
294
 
286
295
  Parameters
@@ -297,7 +306,7 @@ class ManifestPython(BaseModel):
297
306
 
298
307
  Examples
299
308
  --------
300
- >>> from nextmv.cloud import ManifestPython, ManifestPythonModel
309
+ >>> from nextmv import ManifestPython, ManifestPythonModel
301
310
  >>> python_config = ManifestPython(
302
311
  ... pip_requirements="requirements.txt",
303
312
  ... model=ManifestPythonModel(name="my_model")
@@ -328,10 +337,10 @@ class ManifestOptionUI(BaseModel):
328
337
  """
329
338
  UI attributes for an option in the manifest.
330
339
 
331
- You can import the `ManifestOptionUI` class directly from `cloud`:
340
+ You can import the `ManifestOptionUI` class directly from `nextmv`:
332
341
 
333
342
  ```python
334
- from nextmv.cloud import ManifestOptionUI
343
+ from nextmv import ManifestOptionUI
335
344
  ```
336
345
 
337
346
  Parameters
@@ -343,7 +352,7 @@ class ManifestOptionUI(BaseModel):
343
352
  "toggle". This attribute is not used in the local `Options` class, but
344
353
  it is used in the Nextmv Cloud UI to define the type of control to use for
345
354
  the option. This will be validated by the Nextmv Cloud, and availability
346
- is based on options_type.
355
+ is based on option_type.
347
356
  hidden_from : list[str], optional
348
357
  A list of team roles to which this option will be hidden in the UI. For
349
358
  example, if you want to hide an option from the "operator" role, you can
@@ -354,7 +363,7 @@ class ManifestOptionUI(BaseModel):
354
363
 
355
364
  Examples
356
365
  --------
357
- >>> from nextmv.cloud import ManifestOptionUI
366
+ >>> from nextmv import ManifestOptionUI
358
367
  >>> ui_config = ManifestOptionUI(control_type="input")
359
368
  >>> ui_config.control_type
360
369
  'input'
@@ -374,10 +383,10 @@ class ManifestOption(BaseModel):
374
383
  """
375
384
  An option for the decision model that is recorded in the manifest.
376
385
 
377
- You can import the `ManifestOption` class directly from `cloud`:
386
+ You can import the `ManifestOption` class directly from `nextmv`:
378
387
 
379
388
  ```python
380
- from nextmv.cloud import ManifestOption
389
+ from nextmv import ManifestOption
381
390
  ```
382
391
 
383
392
  Parameters
@@ -409,7 +418,7 @@ class ManifestOption(BaseModel):
409
418
 
410
419
  Examples
411
420
  --------
412
- >>> from nextmv.cloud import ManifestOption
421
+ >>> from nextmv import ManifestOption
413
422
  >>> option = ManifestOption(
414
423
  ... name="solve.duration",
415
424
  ... option_type="string",
@@ -462,7 +471,7 @@ class ManifestOption(BaseModel):
462
471
  Examples
463
472
  --------
464
473
  >>> from nextmv.options import Option
465
- >>> from nextmv.cloud import ManifestOption
474
+ >>> from nextmv import ManifestOption
466
475
  >>> sdk_option = Option(name="max_stops", option_type=int, default=100)
467
476
  >>> manifest_opt = ManifestOption.from_option(sdk_option)
468
477
  >>> manifest_opt.name
@@ -514,7 +523,7 @@ class ManifestOption(BaseModel):
514
523
 
515
524
  Examples
516
525
  --------
517
- >>> from nextmv.cloud import ManifestOption
526
+ >>> from nextmv import ManifestOption
518
527
  >>> manifest_opt = ManifestOption(name="max_stops", option_type="int", default=100)
519
528
  >>> sdk_option = manifest_opt.to_option()
520
529
  >>> sdk_option.name
@@ -552,10 +561,10 @@ class ManifestValidation(BaseModel):
552
561
  """
553
562
  Validation rules for options in the manifest.
554
563
 
555
- You can import the `ManifestValidation` class directly from `cloud`:
564
+ You can import the `ManifestValidation` class directly from `nextmv`:
556
565
 
557
566
  ```python
558
- from nextmv.cloud import ManifestValidation
567
+ from nextmv import ManifestValidation
559
568
  ```
560
569
 
561
570
  Parameters
@@ -569,7 +578,7 @@ class ManifestValidation(BaseModel):
569
578
 
570
579
  Examples
571
580
  --------
572
- >>> from nextmv.cloud import ManifestValidation
581
+ >>> from nextmv import ManifestValidation
573
582
  >>> validation = ManifestValidation(enforce="all")
574
583
  >>> validation.enforce
575
584
  'all'
@@ -588,10 +597,10 @@ class ManifestOptions(BaseModel):
588
597
  """
589
598
  Options for the decision model.
590
599
 
591
- You can import the `ManifestOptions` class directly from `cloud`:
600
+ You can import the `ManifestOptions` class directly from `nextmv`:
592
601
 
593
602
  ```python
594
- from nextmv.cloud import ManifestOptions
603
+ from nextmv import ManifestOptions
595
604
  ```
596
605
 
597
606
  Parameters
@@ -603,7 +612,7 @@ class ManifestOptions(BaseModel):
603
612
  is a parameter that configures the decision model.
604
613
  validation: Optional[ManifestValidation], default=None
605
614
  Optional validation rules for all options.
606
- format: Optional[list[str]], default=None
615
+ format : Optional[list[str]], default=None
607
616
  A list of strings that define how options are transformed into command
608
617
  line arguments. Use `{{name}}` to refer to the option name and
609
618
  `{{value}}` to refer to the option value.
@@ -611,7 +620,7 @@ class ManifestOptions(BaseModel):
611
620
 
612
621
  Examples
613
622
  --------
614
- >>> from nextmv.cloud import ManifestOptions, ManifestOption
623
+ >>> from nextmv import ManifestOptions, ManifestOption
615
624
  >>> options_config = ManifestOptions(
616
625
  ... strict=True,
617
626
  ... validation=ManifestValidation(enforce="all"),
@@ -677,7 +686,7 @@ class ManifestOptions(BaseModel):
677
686
  Examples
678
687
  --------
679
688
  >>> from nextmv.options import Options, Option
680
- >>> from nextmv.cloud import ManifestOptions
689
+ >>> from nextmv import ManifestOptions
681
690
  >>> sdk_options = Options(Option("max_vehicles", int, 5))
682
691
  >>> manifest_options = ManifestOptions.from_options(sdk_options)
683
692
  >>> manifest_options.items[0].name
@@ -697,10 +706,10 @@ class ManifestContentMultiFileInput(BaseModel):
697
706
  """
698
707
  Configuration for multi-file content format input.
699
708
 
700
- You can import the `ManifestContentMultiFileInput` class directly from `cloud`:
709
+ You can import the `ManifestContentMultiFileInput` class directly from `nextmv`:
701
710
 
702
711
  ```python
703
- from nextmv.cloud import ManifestContentMultiFileInput
712
+ from nextmv import ManifestContentMultiFileInput
704
713
  ```
705
714
 
706
715
  Parameters
@@ -711,7 +720,7 @@ class ManifestContentMultiFileInput(BaseModel):
711
720
 
712
721
  Examples
713
722
  --------
714
- >>> from nextmv.cloud import ManifestContentMultiFileInput
723
+ >>> from nextmv import ManifestContentMultiFileInput
715
724
  >>> input_config = ManifestContentMultiFileInput(path="data/input/")
716
725
  >>> input_config.path
717
726
  'data/input/'
@@ -725,10 +734,10 @@ class ManifestContentMultiFileOutput(BaseModel):
725
734
  """
726
735
  Configuration for multi-file content format output.
727
736
 
728
- You can import the `ManifestContentMultiFileOutput` class directly from `cloud`:
737
+ You can import the `ManifestContentMultiFileOutput` class directly from `nextmv`:
729
738
 
730
739
  ```python
731
- from nextmv.cloud import ManifestContentMultiFileOutput
740
+ from nextmv import ManifestContentMultiFileOutput
732
741
  ```
733
742
 
734
743
  Parameters
@@ -742,7 +751,7 @@ class ManifestContentMultiFileOutput(BaseModel):
742
751
 
743
752
  Examples
744
753
  --------
745
- >>> from nextmv.cloud import ManifestContentMultiFileOutput
754
+ >>> from nextmv import ManifestContentMultiFileOutput
746
755
  >>> output_config = ManifestContentMultiFileOutput(
747
756
  ... statistics="my-outputs/statistics.json",
748
757
  ... assets="my-outputs/assets.json",
@@ -764,10 +773,10 @@ class ManifestContentMultiFile(BaseModel):
764
773
  """
765
774
  Configuration for multi-file content format.
766
775
 
767
- You can import the `ManifestContentMultiFile` class directly from `cloud`:
776
+ You can import the `ManifestContentMultiFile` class directly from `nextmv`:
768
777
 
769
778
  ```python
770
- from nextmv.cloud import ManifestContentMultiFile
779
+ from nextmv import ManifestContentMultiFile
771
780
  ```
772
781
 
773
782
  Parameters
@@ -779,7 +788,7 @@ class ManifestContentMultiFile(BaseModel):
779
788
 
780
789
  Examples
781
790
  --------
782
- >>> from nextmv.cloud import ManifestContentMultiFile, ManifestContentMultiFileInput, ManifestContentMultiFileOutput
791
+ >>> from nextmv import ManifestContentMultiFile, ManifestContentMultiFileInput, ManifestContentMultiFileOutput
783
792
  >>> multi_file_config = ManifestContentMultiFile(
784
793
  ... input=ManifestContentMultiFileInput(path="data/input/"),
785
794
  ... output=ManifestContentMultiFileOutput(
@@ -803,10 +812,10 @@ class ManifestContent(BaseModel):
803
812
  """
804
813
  Content configuration for specifying how the app input/output is handled.
805
814
 
806
- You can import the `ManifestContent` class directly from `cloud`:
815
+ You can import the `ManifestContent` class directly from `nextmv`:
807
816
 
808
817
  ```python
809
- from nextmv.cloud import ManifestContent
818
+ from nextmv import ManifestContent
810
819
  ```
811
820
 
812
821
  Parameters
@@ -818,7 +827,7 @@ class ManifestContent(BaseModel):
818
827
 
819
828
  Examples
820
829
  --------
821
- >>> from nextmv.cloud import ManifestContent
830
+ >>> from nextmv import ManifestContent
822
831
  >>> content_config = ManifestContent(
823
832
  ... format="multi-file",
824
833
  ... multi_file=ManifestContentMultiFile(
@@ -836,9 +845,11 @@ class ManifestContent(BaseModel):
836
845
  'data/input/'
837
846
  """
838
847
 
839
- format: str
840
- """The format of the content. Must be one of "json", "multi-file",
841
- or "csv-archive"."""
848
+ format: InputFormat
849
+ """
850
+ The format of the content. Can only be `InputFormat.JSON`,
851
+ `InputFormat.MULTI_FILE`, or `InputFormat.CSV_ARCHIVE`.
852
+ """
842
853
  multi_file: Optional[ManifestContentMultiFile] = Field(
843
854
  serialization_alias="multi-file",
844
855
  validation_alias=AliasChoices("multi-file", "multi_file"),
@@ -846,7 +857,7 @@ class ManifestContent(BaseModel):
846
857
  )
847
858
  """Configuration for multi-file content format."""
848
859
 
849
- def __post_init__(self):
860
+ def model_post_init(self, __context) -> None:
850
861
  """Post-initialization to validate fields."""
851
862
  acceptable_formats = [InputFormat.JSON, InputFormat.MULTI_FILE, InputFormat.CSV_ARCHIVE]
852
863
  if self.format not in acceptable_formats:
@@ -857,10 +868,10 @@ class ManifestConfiguration(BaseModel):
857
868
  """
858
869
  Configuration for the decision model.
859
870
 
860
- You can import the `ManifestConfiguration` class directly from `cloud`:
871
+ You can import the `ManifestConfiguration` class directly from `nextmv`:
861
872
 
862
873
  ```python
863
- from nextmv.cloud import ManifestConfiguration
874
+ from nextmv import ManifestConfiguration
864
875
  ```
865
876
 
866
877
  Parameters
@@ -870,7 +881,7 @@ class ManifestConfiguration(BaseModel):
870
881
 
871
882
  Examples
872
883
  --------
873
- >>> from nextmv.cloud import ManifestConfiguration, ManifestOptions, ManifestOption
884
+ >>> from nextmv import ManifestConfiguration, ManifestOptions, ManifestOption
874
885
  >>> model_config = ManifestConfiguration(
875
886
  ... options=ManifestOptions(
876
887
  ... items=[ManifestOption(name="debug_mode", option_type="bool", default=False)]
@@ -890,10 +901,10 @@ class Manifest(BaseModel):
890
901
  """
891
902
  Represents an app manifest (`app.yaml`) for Nextmv Cloud.
892
903
 
893
- You can import the `Manifest` class directly from `cloud`:
904
+ You can import the `Manifest` class directly from `nextmv`:
894
905
 
895
906
  ```python
896
- from nextmv.cloud import Manifest
907
+ from nextmv import Manifest
897
908
  ```
898
909
 
899
910
  An application that runs on the Nextmv Platform must contain a file named
@@ -935,10 +946,16 @@ class Manifest(BaseModel):
935
946
  configuration : Optional[ManifestConfiguration], default=None
936
947
  A list of options for the decision model. An option is a
937
948
  parameter that configures the decision model.
949
+ entrypoint : Optional[str], default=None
950
+ Optional entrypoint for the decision model. When not specified, the
951
+ following default entrypoints are used, according to the `.runtime`:
952
+ - `ManifestRuntime.PYTHON`, `ManifestRuntime.HEXALY`, `ManifestRuntime.PYOMO`: `./main.py`
953
+ - `ManifestRuntime.DEFAULT`: `./main`
954
+ - Java: `./main.jar`
938
955
 
939
956
  Examples
940
957
  --------
941
- >>> from nextmv.cloud import Manifest, ManifestRuntime, ManifestType
958
+ >>> from nextmv import Manifest, ManifestRuntime, ManifestType
942
959
  >>> manifest = Manifest(
943
960
  ... files=["main.py", "model_logic/"],
944
961
  ... runtime=ManifestRuntime.PYTHON,
@@ -996,6 +1013,29 @@ class Manifest(BaseModel):
996
1013
  Configuration for the decision model. A list of options for the decision
997
1014
  model. An option is a parameter that configures the decision model.
998
1015
  """
1016
+ entrypoint: Optional[str] = None
1017
+ """
1018
+ Optional entrypoint for the decision model. When not specified, the
1019
+ following default entrypoints are used, according to the `.runtime`:
1020
+
1021
+ - `ManifestRuntime.PYTHON`, `ManifestRuntime.HEXALY`, `ManifestRuntime.PYOMO`: `./main.py`
1022
+ - `ManifestRuntime.DEFAULT`: `./main`
1023
+ - Java: `./main.jar`
1024
+ """
1025
+
1026
+ def model_post_init(self, __context) -> None:
1027
+ if self.entrypoint is None:
1028
+ if self.runtime in (ManifestRuntime.PYTHON, ManifestRuntime.HEXALY, ManifestRuntime.PYOMO):
1029
+ self.entrypoint = "./main.py"
1030
+ elif self.runtime == ManifestRuntime.DEFAULT:
1031
+ self.entrypoint = "./main"
1032
+ elif self.runtime == ManifestRuntime.JAVA:
1033
+ self.entrypoint = "./main.jar"
1034
+ else:
1035
+ raise ValueError(
1036
+ f'entrypoint is not provided but the runtime "{self.runtime}" could not '
1037
+ "be resolved to establish a default entrypoint"
1038
+ )
999
1039
 
1000
1040
  @classmethod
1001
1041
  def from_yaml(cls, dirpath: str) -> "Manifest":
@@ -1034,7 +1074,7 @@ class Manifest(BaseModel):
1034
1074
  type: python
1035
1075
  ```
1036
1076
 
1037
- >>> from nextmv.cloud import Manifest
1077
+ >>> from nextmv import Manifest
1038
1078
  >>> # manifest = Manifest.from_yaml("./my_app_dir") # This would be run
1039
1079
  >>> # assert manifest.type == "python"
1040
1080
  """
@@ -1065,7 +1105,7 @@ class Manifest(BaseModel):
1065
1105
 
1066
1106
  Examples
1067
1107
  --------
1068
- >>> from nextmv.cloud import Manifest
1108
+ >>> from nextmv import Manifest
1069
1109
  >>> manifest = Manifest(files=["solver.py"], type="python")
1070
1110
  >>> # manifest.to_yaml("./output_dir") # This would create ./output_dir/app.yaml
1071
1111
  """
@@ -1088,7 +1128,7 @@ class Manifest(BaseModel):
1088
1128
 
1089
1129
  Examples
1090
1130
  --------
1091
- >>> from nextmv.cloud import Manifest, ManifestConfiguration, ManifestOptions, ManifestOption
1131
+ >>> from nextmv import Manifest, ManifestConfiguration, ManifestOptions, ManifestOption
1092
1132
  >>> manifest = Manifest(
1093
1133
  ... files=["main.py"],
1094
1134
  ... configuration=ManifestConfiguration(
@@ -1150,8 +1190,9 @@ class Manifest(BaseModel):
1150
1190
 
1151
1191
  Examples
1152
1192
  --------
1153
- >>> from nextmv.model import ModelConfiguration, Options, Option
1154
- >>> from nextmv.cloud import Manifest
1193
+ >>> from nextmv.model import ModelConfiguration
1194
+ >>> from nextmv.options import Options, Option
1195
+ >>> from nextmv import Manifest
1155
1196
  >>> opts = Options(Option(name="vehicle_count", option_type=int, default=5))
1156
1197
  >>> mc = ModelConfiguration(name="vehicle_router", options=opts)
1157
1198
  >>> manifest = Manifest.from_model_configuration(mc)
@@ -1213,7 +1254,7 @@ class Manifest(BaseModel):
1213
1254
  ----------
1214
1255
  options : nextmv.options.Options
1215
1256
  The options to include in the manifest.
1216
- validation : nextmv.options.OptionsEnforcement default=None
1257
+ validation : nextmv.options.OptionsEnforcement, default=None
1217
1258
  The validation rules for the options. This is used to set the
1218
1259
  `validation` attribute of the `ManifestOptions`.
1219
1260
 
@@ -1225,7 +1266,7 @@ class Manifest(BaseModel):
1225
1266
  Examples
1226
1267
  --------
1227
1268
  >>> from nextmv.options import Options, Option
1228
- >>> from nextmv.cloud import Manifest
1269
+ >>> from nextmv import Manifest
1229
1270
  >>> opts = Options(
1230
1271
  ... Option(name="max_runtime", option_type=str, default="60s"),
1231
1272
  ... Option(name="use_heuristic", option_type=bool, default=True)
nextmv/output.py CHANGED
@@ -40,6 +40,17 @@ Functions
40
40
  ---------
41
41
  write
42
42
  Write the output to the specified destination.
43
+
44
+ Attributes
45
+ ----------
46
+ ASSETS_KEY : str
47
+ Assets key constant used for identifying assets in the run output.
48
+ STATISTICS_KEY : str
49
+ Statistics key constant used for identifying statistics in the run output.
50
+ SOLUTIONS_KEY : str
51
+ Solutions key constant used for identifying solutions in the run output.
52
+ OUTPUTS_KEY : str
53
+ Outputs key constant used for identifying outputs in the run output.
43
54
  """
44
55
 
45
56
  import copy
@@ -59,6 +70,23 @@ from nextmv.deprecated import deprecated
59
70
  from nextmv.logger import reset_stdout
60
71
  from nextmv.options import Options
61
72
 
73
+ ASSETS_KEY = "assets"
74
+ """
75
+ Assets key constant used for identifying assets in the run output.
76
+ """
77
+ STATISTICS_KEY = "statistics"
78
+ """
79
+ Statistics key constant used for identifying statistics in the run output.
80
+ """
81
+ SOLUTIONS_KEY = "solutions"
82
+ """
83
+ Solutions key constant used for identifying solutions in the run output.
84
+ """
85
+ OUTPUTS_KEY = "outputs"
86
+ """
87
+ Outputs key constant used for identifying outputs in the run output.
88
+ """
89
+
62
90
 
63
91
  class RunStatistics(BaseModel):
64
92
  """
@@ -495,6 +523,8 @@ class OutputFormat(str, Enum):
495
523
  CSV archive format: multiple CSV files.
496
524
  MULTI_FILE : str
497
525
  Multi-file format: multiple files in a directory.
526
+ TEXT : str
527
+ Text format, utf-8 encoded.
498
528
  """
499
529
 
500
530
  JSON = "json"
@@ -503,6 +533,8 @@ class OutputFormat(str, Enum):
503
533
  """CSV archive format: multiple CSV files."""
504
534
  MULTI_FILE = "multi-file"
505
535
  """Multi-file format: multiple files in a directory."""
536
+ TEXT = "text"
537
+ """Text format, utf-8 encoded."""
506
538
 
507
539
 
508
540
  @dataclass
@@ -1072,8 +1104,8 @@ class Output:
1072
1104
  output_dict = {
1073
1105
  "options": options,
1074
1106
  "solution": self.solution if self.solution is not None else {},
1075
- "statistics": statistics,
1076
- "assets": assets,
1107
+ STATISTICS_KEY: statistics,
1108
+ ASSETS_KEY: assets,
1077
1109
  }
1078
1110
 
1079
1111
  # Add the auxiliary configurations to the output dictionary if they are
@@ -1232,8 +1264,8 @@ class LocalOutputWriter(OutputWriter):
1232
1264
  serialized = serialize_json(
1233
1265
  {
1234
1266
  "options": output_dict.get("options", {}),
1235
- "statistics": output_dict.get("statistics", {}),
1236
- "assets": output_dict.get("assets", []),
1267
+ STATISTICS_KEY: output_dict.get(STATISTICS_KEY, {}),
1268
+ ASSETS_KEY: output_dict.get(ASSETS_KEY, []),
1237
1269
  },
1238
1270
  json_configurations=json_configurations,
1239
1271
  )
@@ -1281,7 +1313,7 @@ class LocalOutputWriter(OutputWriter):
1281
1313
  ValueError
1282
1314
  If the path is an existing file instead of a directory.
1283
1315
  """
1284
- dir_path = "outputs"
1316
+ dir_path = OUTPUTS_KEY
1285
1317
  if path is not None and path != "":
1286
1318
  if os.path.isfile(path):
1287
1319
  raise ValueError(f"The path refers to an existing file: {path}")
@@ -1299,13 +1331,13 @@ class LocalOutputWriter(OutputWriter):
1299
1331
  parent_dir=dir_path,
1300
1332
  json_configurations=json_configurations,
1301
1333
  output_dict=output_dict,
1302
- element_key="statistics",
1334
+ element_key=STATISTICS_KEY,
1303
1335
  )
1304
1336
  self._write_multi_file_element(
1305
1337
  parent_dir=dir_path,
1306
1338
  json_configurations=json_configurations,
1307
1339
  output_dict=output_dict,
1308
- element_key="assets",
1340
+ element_key=ASSETS_KEY,
1309
1341
  )
1310
1342
  self._write_multi_file_solution(dir_path=dir_path, output=output)
1311
1343
 
@@ -1350,7 +1382,7 @@ class LocalOutputWriter(OutputWriter):
1350
1382
  if output.solution_files is None:
1351
1383
  return
1352
1384
 
1353
- solutions_dir = os.path.join(dir_path, "solutions")
1385
+ solutions_dir = os.path.join(dir_path, SOLUTIONS_KEY)
1354
1386
 
1355
1387
  if not os.path.exists(solutions_dir):
1356
1388
  os.makedirs(solutions_dir)
@@ -1381,6 +1413,7 @@ class LocalOutputWriter(OutputWriter):
1381
1413
  OutputFormat.JSON: _write_json,
1382
1414
  OutputFormat.CSV_ARCHIVE: _write_archive,
1383
1415
  OutputFormat.MULTI_FILE: _write_multi_file,
1416
+ OutputFormat.TEXT: _write_json,
1384
1417
  }
1385
1418
  """Dictionary mapping output formats to writer functions."""
1386
1419