nextmv 0.29.5.dev1__py3-none-any.whl → 0.31.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,4 +1,5 @@
1
- """This module contains definitions for an app run.
1
+ """
2
+ This module contains definitions for an app run.
2
3
 
3
4
  Classes
4
5
  -------
@@ -50,19 +51,19 @@ from pydantic import AliasChoices, Field
50
51
 
51
52
  from nextmv._serialization import serialize_json
52
53
  from nextmv.base_model import BaseModel
53
- from nextmv.cloud.status import Status, StatusV2
54
54
  from nextmv.input import Input, InputFormat
55
55
  from nextmv.output import Output, OutputFormat
56
+ from nextmv.status import Status, StatusV2
56
57
 
57
58
 
58
59
  def run_duration(start: Union[datetime, float], end: Union[datetime, float]) -> int:
59
60
  """
60
61
  Calculate the duration of a run in milliseconds.
61
62
 
62
- You can import the `run_duration` function directly from `cloud`:
63
+ You can import the `run_duration` function directly from `nextmv`:
63
64
 
64
65
  ```python
65
- from nextmv.cloud import run_duration
66
+ from nextmv import run_duration
66
67
  ```
67
68
 
68
69
  Parameters
@@ -116,16 +117,27 @@ class FormatInput(BaseModel):
116
117
  """
117
118
  Input format for a run configuration.
118
119
 
119
- You can import the `FormatInput` class directly from `cloud`:
120
+ You can import the `FormatInput` class directly from `nextmv`:
120
121
 
121
122
  ```python
122
- from nextmv.cloud import FormatInput
123
+ from nextmv import FormatInput
123
124
  ```
124
125
 
125
126
  Parameters
126
127
  ----------
127
128
  input_type : InputFormat, optional
128
129
  Type of the input format. Defaults to `InputFormat.JSON`.
130
+
131
+ Examples
132
+ --------
133
+ >>> from nextmv import FormatInput, InputFormat
134
+ >>> format_input = FormatInput()
135
+ >>> format_input.input_type
136
+ <InputFormat.JSON: 'json'>
137
+
138
+ >>> format_input = FormatInput(input_type=InputFormat.TEXT)
139
+ >>> format_input.input_type
140
+ <InputFormat.TEXT: 'text'>
129
141
  """
130
142
 
131
143
  input_type: InputFormat = Field(
@@ -140,16 +152,27 @@ class FormatOutput(BaseModel):
140
152
  """
141
153
  Output format for a run configuration.
142
154
 
143
- You can import the `FormatOutput` class directly from `cloud`:
155
+ You can import the `FormatOutput` class directly from `nextmv`:
144
156
 
145
157
  ```python
146
- from nextmv.cloud import FormatOutput
158
+ from nextmv import FormatOutput
147
159
  ```
148
160
 
149
161
  Parameters
150
162
  ----------
151
163
  output_type : OutputFormat, optional
152
164
  Type of the output format. Defaults to `OutputFormat.JSON`.
165
+
166
+ Examples
167
+ --------
168
+ >>> from nextmv import FormatOutput, OutputFormat
169
+ >>> format_output = FormatOutput()
170
+ >>> format_output.output_type
171
+ <OutputFormat.JSON: 'json'>
172
+
173
+ >>> format_output = FormatOutput(output_type=OutputFormat.CSV_ARCHIVE)
174
+ >>> format_output.output_type
175
+ <OutputFormat.CSV_ARCHIVE: 'csv_archive'>
153
176
  """
154
177
 
155
178
  output_type: OutputFormat = Field(
@@ -164,16 +187,30 @@ class Format(BaseModel):
164
187
  """
165
188
  Format for a run configuration.
166
189
 
167
- You can import the `Format` class directly from `cloud`:
190
+ You can import the `Format` class directly from `nextmv`:
168
191
 
169
192
  ```python
170
- from nextmv.cloud import Format
193
+ from nextmv import Format
171
194
  ```
172
195
 
173
196
  Parameters
174
197
  ----------
175
198
  format_input : FormatInput
176
199
  Input format for the run configuration.
200
+ format_output : FormatOutput, optional
201
+ Output format for the run configuration. Defaults to None.
202
+
203
+ Examples
204
+ --------
205
+ >>> from nextmv import Format, FormatInput, FormatOutput, InputFormat, OutputFormat
206
+ >>> format_config = Format(
207
+ ... format_input=FormatInput(input_type=InputFormat.JSON),
208
+ ... format_output=FormatOutput(output_type=OutputFormat.JSON)
209
+ ... )
210
+ >>> format_config.format_input.input_type
211
+ <InputFormat.JSON: 'json'>
212
+ >>> format_config.format_output.output_type
213
+ <OutputFormat.JSON: 'json'>
177
214
  """
178
215
 
179
216
  format_input: FormatInput = Field(
@@ -193,10 +230,10 @@ class Metadata(BaseModel):
193
230
  """
194
231
  Metadata of a run, whether it was successful or not.
195
232
 
196
- You can import the `Metadata` class directly from `cloud`:
233
+ You can import the `Metadata` class directly from `nextmv`:
197
234
 
198
235
  ```python
199
- from nextmv.cloud import Metadata
236
+ from nextmv import Metadata
200
237
  ```
201
238
 
202
239
  Parameters
@@ -217,6 +254,8 @@ class Metadata(BaseModel):
217
254
  Size of the input in bytes.
218
255
  output_size : float
219
256
  Size of the output in bytes.
257
+ format : Format
258
+ Format of the input and output of the run.
220
259
  status : Status
221
260
  Deprecated: use status_v2.
222
261
  status_v2 : StatusV2
@@ -241,20 +280,21 @@ class Metadata(BaseModel):
241
280
  """Size of the output in bytes."""
242
281
  format: Format
243
282
  """Format of the input and output of the run."""
244
- status: Status
245
- """Deprecated: use status_v2."""
246
283
  status_v2: StatusV2
247
284
  """Status of the run."""
248
285
 
286
+ status: Optional[Status] = None
287
+ """Deprecated: use status_v2."""
288
+
249
289
 
250
290
  class RunInformation(BaseModel):
251
291
  """
252
292
  Information of a run.
253
293
 
254
- You can import the `RunInformation` class directly from `cloud`:
294
+ You can import the `RunInformation` class directly from `nextmv`:
255
295
 
256
296
  ```python
257
- from nextmv.cloud import RunInformation
297
+ from nextmv import RunInformation
258
298
  ```
259
299
 
260
300
  Parameters
@@ -284,16 +324,33 @@ class RunInformation(BaseModel):
284
324
  user_email: str
285
325
  """Email of the user who submitted the run."""
286
326
  console_url: str = Field(default="")
327
+ """
328
+ URL to the run in the Nextmv console.
329
+ """
330
+ synced_run_id: Optional[str] = None
331
+ """
332
+ ID of the synced remote run, if applicable. When the `Application.sync`
333
+ method is used, this field marks the association between the local run
334
+ (`id`) and the remote run (`synced_run_id`). This field is None if the run
335
+ was not created using `Application.sync` or if the run has not been synced
336
+ yet.
337
+ """
338
+ synced_at: Optional[datetime] = None
339
+ """
340
+ Timestamp when the run was synced with the remote run. This field is
341
+ None if the run was not created using `Application.sync` or if the run
342
+ has not been synced yet.
343
+ """
287
344
 
288
345
 
289
346
  class ErrorLog(BaseModel):
290
347
  """
291
348
  Error log of a run, when it was not successful.
292
349
 
293
- You can import the `ErrorLog` class directly from `cloud`:
350
+ You can import the `ErrorLog` class directly from `nextmv`:
294
351
 
295
352
  ```python
296
- from nextmv.cloud import ErrorLog
353
+ from nextmv import ErrorLog
297
354
  ```
298
355
 
299
356
  Parameters
@@ -318,10 +375,10 @@ class RunResult(RunInformation):
318
375
  """
319
376
  Result of a run, whether it was successful or not.
320
377
 
321
- You can import the `RunResult` class directly from `cloud`:
378
+ You can import the `RunResult` class directly from `nextmv`:
322
379
 
323
380
  ```python
324
- from nextmv.cloud import RunResult
381
+ from nextmv import RunResult
325
382
  ```
326
383
 
327
384
  Parameters
@@ -344,16 +401,28 @@ class RunLog(BaseModel):
344
401
  """
345
402
  Log of a run.
346
403
 
347
- You can import the `RunLog` class directly from `cloud`:
404
+ You can import the `RunLog` class directly from `nextmv`:
348
405
 
349
406
  ```python
350
- from nextmv.cloud import RunLog
407
+ from nextmv import RunLog
351
408
  ```
352
409
 
353
410
  Parameters
354
411
  ----------
355
412
  log : str
356
413
  Log of the run.
414
+
415
+ Examples
416
+ --------
417
+ >>> from nextmv import RunLog
418
+ >>> run_log = RunLog(log="Optimization completed successfully")
419
+ >>> run_log.log
420
+ 'Optimization completed successfully'
421
+
422
+ >>> # Multi-line log
423
+ >>> multi_line_log = RunLog(log="Starting optimization\\nProcessing data\\nCompleted")
424
+ >>> multi_line_log.log
425
+ 'Starting optimization\\nProcessing data\\nCompleted'
357
426
  """
358
427
 
359
428
  log: str
@@ -364,10 +433,10 @@ class RunType(str, Enum):
364
433
  """
365
434
  The actual type of the run.
366
435
 
367
- You can import the `RunType` class directly from `cloud`:
436
+ You can import the `RunType` class directly from `nextmv`:
368
437
 
369
438
  ```python
370
- from nextmv.cloud import RunType
439
+ from nextmv import RunType
371
440
  ```
372
441
 
373
442
  Parameters
@@ -378,6 +447,24 @@ class RunType(str, Enum):
378
447
  External run type.
379
448
  ENSEMBLE : str
380
449
  Ensemble run type.
450
+
451
+ Examples
452
+ --------
453
+ >>> from nextmv import RunType
454
+ >>> run_type = RunType.STANDARD
455
+ >>> run_type
456
+ <RunType.STANDARD: 'standard'>
457
+ >>> run_type.value
458
+ 'standard'
459
+
460
+ >>> # Creating from string
461
+ >>> external_type = RunType("external")
462
+ >>> external_type
463
+ <RunType.EXTERNAL: 'external'>
464
+
465
+ >>> # All available types
466
+ >>> list(RunType)
467
+ [<RunType.STANDARD: 'standard'>, <RunType.EXTERNAL: 'external'>, <RunType.ENSEMBLE: 'ensemble'>]
381
468
  """
382
469
 
383
470
  STANDARD = "standard"
@@ -393,10 +480,10 @@ class RunTypeConfiguration(BaseModel):
393
480
  Defines the configuration for the type of the run that is being executed
394
481
  on an application.
395
482
 
396
- You can import the `RunTypeConfiguration` class directly from `cloud`:
483
+ You can import the `RunTypeConfiguration` class directly from `nextmv`:
397
484
 
398
485
  ```python
399
- from nextmv.cloud import RunTypeConfiguration
486
+ from nextmv import RunTypeConfiguration
400
487
  ```
401
488
 
402
489
  Parameters
@@ -407,6 +494,35 @@ class RunTypeConfiguration(BaseModel):
407
494
  ID of the definition for the run type. Defaults to None.
408
495
  reference_id : str, optional
409
496
  ID of the reference for the run type. Defaults to None.
497
+
498
+ Examples
499
+ --------
500
+ >>> from nextmv import RunTypeConfiguration, RunType
501
+ >>> config = RunTypeConfiguration(run_type=RunType.STANDARD)
502
+ >>> config.run_type
503
+ <RunType.STANDARD: 'standard'>
504
+ >>> config.definition_id is None
505
+ True
506
+
507
+ >>> # External run with reference
508
+ >>> external_config = RunTypeConfiguration(
509
+ ... run_type=RunType.EXTERNAL,
510
+ ... reference_id="ref-12345"
511
+ ... )
512
+ >>> external_config.run_type
513
+ <RunType.EXTERNAL: 'external'>
514
+ >>> external_config.reference_id
515
+ 'ref-12345'
516
+
517
+ >>> # Ensemble run with definition
518
+ >>> ensemble_config = RunTypeConfiguration(
519
+ ... run_type=RunType.ENSEMBLE,
520
+ ... definition_id="def-67890"
521
+ ... )
522
+ >>> ensemble_config.run_type
523
+ <RunType.ENSEMBLE: 'ensemble'>
524
+ >>> ensemble_config.definition_id
525
+ 'def-67890'
410
526
  """
411
527
 
412
528
  run_type: RunType = Field(
@@ -424,10 +540,10 @@ class RunQueuing(BaseModel):
424
540
  """
425
541
  RunQueuing configuration for a run.
426
542
 
427
- You can import the `RunQueuing` class directly from `cloud`:
543
+ You can import the `RunQueuing` class directly from `nextmv`:
428
544
 
429
545
  ```python
430
- from nextmv.cloud import RunQueuing
546
+ from nextmv import RunQueuing
431
547
  ```
432
548
 
433
549
  Parameters
@@ -438,6 +554,25 @@ class RunQueuing(BaseModel):
438
554
  disabled : bool, optional
439
555
  Whether the run should be queued, or not. If True, the run will not be
440
556
  queued. If False, the run will be queued. Defaults to None.
557
+
558
+ Examples
559
+ --------
560
+ >>> from nextmv import RunQueuing
561
+ >>> queuing = RunQueuing(priority=1, disabled=False)
562
+ >>> queuing.priority
563
+ 1
564
+ >>> queuing.disabled
565
+ False
566
+
567
+ >>> # High priority run
568
+ >>> high_priority = RunQueuing(priority=1)
569
+ >>> high_priority.priority
570
+ 1
571
+
572
+ >>> # Disabled queuing
573
+ >>> no_queue = RunQueuing(disabled=True)
574
+ >>> no_queue.disabled
575
+ True
441
576
  """
442
577
 
443
578
  priority: Optional[int] = None
@@ -473,10 +608,10 @@ class RunConfiguration(BaseModel):
473
608
  """
474
609
  Configuration for an app run.
475
610
 
476
- You can import the `RunConfiguration` class directly from `cloud`:
611
+ You can import the `RunConfiguration` class directly from `nextmv`:
477
612
 
478
613
  ```python
479
- from nextmv.cloud import RunConfiguration
614
+ from nextmv import RunConfiguration
480
615
  ```
481
616
 
482
617
  Parameters
@@ -491,6 +626,23 @@ class RunConfiguration(BaseModel):
491
626
  ID of the secrets collection to use for the run. Defaults to None.
492
627
  queuing : RunQueuing, optional
493
628
  Queuing configuration for the run. Defaults to None.
629
+
630
+ Examples
631
+ --------
632
+ >>> from nextmv import RunConfiguration, RunQueuing
633
+ >>> config = RunConfiguration(
634
+ ... execution_class="large",
635
+ ... queuing=RunQueuing(priority=1)
636
+ ... )
637
+ >>> config.execution_class
638
+ 'large'
639
+ >>> config.queuing.priority
640
+ 1
641
+
642
+ >>> # Basic configuration
643
+ >>> basic_config = RunConfiguration()
644
+ >>> basic_config.format is None
645
+ True
494
646
  """
495
647
 
496
648
  execution_class: Optional[str] = None
@@ -515,10 +667,28 @@ class RunConfiguration(BaseModel):
515
667
 
516
668
  Parameters
517
669
  ----------
518
- input : Input or dict[str, Any] or BaseModel or str, optional
670
+ input : Input or dict[str, Any] or BaseModel or str
519
671
  The input to use for resolving the run configuration.
520
672
  dir_path : str, optional
521
673
  The directory path where inputs can be loaded from.
674
+
675
+ Examples
676
+ --------
677
+ >>> from nextmv import RunConfiguration
678
+ >>> config = RunConfiguration()
679
+ >>> config.resolve({"key": "value"})
680
+ >>> config.format.format_input.input_type
681
+ <InputFormat.JSON: 'json'>
682
+
683
+ >>> config = RunConfiguration()
684
+ >>> config.resolve("text input")
685
+ >>> config.format.format_input.input_type
686
+ <InputFormat.TEXT: 'text'>
687
+
688
+ >>> config = RunConfiguration()
689
+ >>> config.resolve({}, dir_path="/path/to/files")
690
+ >>> config.format.format_input.input_type
691
+ <InputFormat.MULTI_FILE: 'multi_file'>
522
692
  """
523
693
 
524
694
  # If the value is set by the user, do not change it.
@@ -560,10 +730,10 @@ class ExternalRunResult(BaseModel):
560
730
  Result of a run used to configure a new application run as an
561
731
  external one.
562
732
 
563
- You can import the `ExternalRunResult` class directly from `cloud`:
733
+ You can import the `ExternalRunResult` class directly from `nextmv`:
564
734
 
565
735
  ```python
566
- from nextmv.cloud import ExternalRunResult
736
+ from nextmv import ExternalRunResult
567
737
  ```
568
738
 
569
739
  Parameters
@@ -578,6 +748,32 @@ class ExternalRunResult(BaseModel):
578
748
  Error message of the run. Defaults to None.
579
749
  execution_duration : int, optional
580
750
  Duration of the run, in milliseconds. Defaults to None.
751
+
752
+ Examples
753
+ --------
754
+ >>> from nextmv import ExternalRunResult
755
+ >>> # Successful external run
756
+ >>> result = ExternalRunResult(
757
+ ... output_upload_id="upload-12345",
758
+ ... status="succeeded",
759
+ ... execution_duration=5000
760
+ ... )
761
+ >>> result.status
762
+ 'succeeded'
763
+ >>> result.execution_duration
764
+ 5000
765
+
766
+ >>> # Failed external run
767
+ >>> failed_result = ExternalRunResult(
768
+ ... error_upload_id="error-67890",
769
+ ... status="failed",
770
+ ... error_message="Optimization failed due to invalid constraints",
771
+ ... execution_duration=2000
772
+ ... )
773
+ >>> failed_result.status
774
+ 'failed'
775
+ >>> failed_result.error_message
776
+ 'Optimization failed due to invalid constraints'
581
777
  """
582
778
 
583
779
  output_upload_id: Optional[str] = None
@@ -610,10 +806,10 @@ class TrackedRunStatus(str, Enum):
610
806
  """
611
807
  The status of a tracked run.
612
808
 
613
- You can import the `TrackedRunStatus` class directly from `cloud`:
809
+ You can import the `TrackedRunStatus` class directly from `nextmv`:
614
810
 
615
811
  ```python
616
- from nextmv.cloud import TrackedRunStatus
812
+ from nextmv import TrackedRunStatus
617
813
  ```
618
814
 
619
815
  Parameters
@@ -622,6 +818,24 @@ class TrackedRunStatus(str, Enum):
622
818
  The run succeeded.
623
819
  FAILED : str
624
820
  The run failed.
821
+
822
+ Examples
823
+ --------
824
+ >>> from nextmv import TrackedRunStatus
825
+ >>> status = TrackedRunStatus.SUCCEEDED
826
+ >>> status
827
+ <TrackedRunStatus.SUCCEEDED: 'succeeded'>
828
+ >>> status.value
829
+ 'succeeded'
830
+
831
+ >>> # Creating from string
832
+ >>> failed_status = TrackedRunStatus("failed")
833
+ >>> failed_status
834
+ <TrackedRunStatus.FAILED: 'failed'>
835
+
836
+ >>> # All available statuses
837
+ >>> list(TrackedRunStatus)
838
+ [<TrackedRunStatus.SUCCEEDED: 'succeeded'>, <TrackedRunStatus.FAILED: 'failed'>]
625
839
  """
626
840
 
627
841
  SUCCEEDED = "succeeded"
@@ -635,24 +849,26 @@ class TrackedRun:
635
849
  """
636
850
  An external run that is tracked in the Nextmv platform.
637
851
 
638
- You can import the `TrackedRun` class directly from `cloud`:
852
+ You can import the `TrackedRun` class directly from `nextmv`:
639
853
 
640
854
  ```python
641
- from nextmv.cloud import TrackedRun
855
+ from nextmv import TrackedRun
642
856
  ```
643
857
 
644
858
  Parameters
645
859
  ----------
646
- input : Input or dict[str, Any] or str
647
- The input of the run being tracked. Please note that if the input
648
- format is JSON, then the input data must be JSON serializable. This
649
- field is required.
650
- output : Output or dict[str, Any] or str
651
- The output of the run being tracked. Please note that if the output
652
- format is JSON, then the output data must be JSON serializable. This
653
- field is required. Only JSON output_format is supported.
654
860
  status : TrackedRunStatus
655
861
  The status of the run being tracked. This field is required.
862
+ input : Input or dict[str, Any] or str, optional
863
+ The input of the run being tracked. Please note that if the input
864
+ format is JSON, then the input data must be JSON serializable. If both
865
+ `input` and `input_dir_path` are specified, the `input` is ignored, and
866
+ the files in the directory are used instead. Defaults to None.
867
+ output : Output or dict[str, Any] or str, optional
868
+ The output of the run being tracked. Please note that if the output
869
+ format is JSON, then the output data must be JSON serializable. If both
870
+ `output` and `output_dir_path` are specified, the `output` is ignored, and
871
+ the files in the directory are used instead. Defaults to None.
656
872
  duration : int, optional
657
873
  The duration of the run being tracked, in milliseconds. This field is
658
874
  optional. Defaults to None.
@@ -663,6 +879,64 @@ class TrackedRun:
663
879
  logs : list[str], optional
664
880
  The logs of the run being tracked. Each element of the list is a line in
665
881
  the log. This field is optional. Defaults to None.
882
+ name : str, optional
883
+ Optional name for the run being tracked. Defaults to None.
884
+ description : str, optional
885
+ Optional description for the run being tracked. Defaults to None.
886
+ input_dir_path : str, optional
887
+ Path to a directory containing input files. If specified, the calling
888
+ function will package the files in the directory into a tar file and upload
889
+ it as a large input. This is useful for non-JSON input formats, such as
890
+ when working with `CSV_ARCHIVE` or `MULTI_FILE`. If both `input` and
891
+ `input_dir_path` are specified, the `input` is ignored, and the files in
892
+ the directory are used instead. Defaults to None.
893
+ output_dir_path : str, optional
894
+ Path to a directory containing output files. If specified, the calling
895
+ function will package the files in the directory into a tar file and upload
896
+ it as a large output. This is useful for non-JSON output formats, such as
897
+ when working with `CSV_ARCHIVE` or `MULTI_FILE`. If both `output` and
898
+ `output_dir_path` are specified, the `output` is ignored, and the files
899
+ are saved in the directory instead. Defaults to None.
900
+
901
+ Examples
902
+ --------
903
+ >>> from nextmv import TrackedRun, TrackedRunStatus
904
+ >>> # Successful run
905
+ >>> run = TrackedRun(
906
+ ... status=TrackedRunStatus.SUCCEEDED,
907
+ ... input={"vehicles": 5, "locations": 10},
908
+ ... output={"routes": [{"stops": [1, 2, 3]}]},
909
+ ... duration=5000,
910
+ ... name="test-run",
911
+ ... description="A test optimization run"
912
+ ... )
913
+ >>> run.status
914
+ <TrackedRunStatus.SUCCEEDED: 'succeeded'>
915
+ >>> run.duration
916
+ 5000
917
+
918
+ >>> # Failed run with error
919
+ >>> failed_run = TrackedRun(
920
+ ... status=TrackedRunStatus.FAILED,
921
+ ... input={"vehicles": 0},
922
+ ... error="No vehicles available for routing",
923
+ ... duration=1000,
924
+ ... logs=["Starting optimization", "Error: No vehicles found"]
925
+ ... )
926
+ >>> failed_run.status
927
+ <TrackedRunStatus.FAILED: 'failed'>
928
+ >>> failed_run.error
929
+ 'No vehicles available for routing'
930
+
931
+ >>> # Run with directory-based input/output
932
+ >>> dir_run = TrackedRun(
933
+ ... status=TrackedRunStatus.SUCCEEDED,
934
+ ... input_dir_path="/path/to/input/files",
935
+ ... output_dir_path="/path/to/output/files",
936
+ ... duration=10000
937
+ ... )
938
+ >>> dir_run.input_dir_path
939
+ '/path/to/input/files'
666
940
 
667
941
  Raises
668
942
  ------
@@ -672,13 +946,23 @@ class TrackedRun:
672
946
  input/output dicts are not JSON serializable.
673
947
  """
674
948
 
675
- input: Union[Input, dict[str, Any], str]
676
- """The input of the run being tracked."""
677
- output: Union[Output, dict[str, Any], str]
678
- """The output of the run being tracked. Only JSON output_format is supported."""
679
949
  status: TrackedRunStatus
680
950
  """The status of the run being tracked"""
681
951
 
952
+ input: Optional[Union[Input, dict[str, Any], str]] = None
953
+ """
954
+ The input of the run being tracked. Please note that if the input
955
+ format is JSON, then the input data must be JSON serializable. If both
956
+ `input` and `input_dir_path` are specified, the `input` is ignored, and
957
+ the files in the directory are used instead.
958
+ """
959
+ output: Optional[Union[Output, dict[str, Any], str]] = None
960
+ """
961
+ The output of the run being tracked. Please note that if the output
962
+ format is JSON, then the output data must be JSON serializable. If both
963
+ `output` and `output_dir_path` are specified, the `output` is ignored, and
964
+ the files in the directory are used instead.
965
+ """
682
966
  duration: Optional[int] = None
683
967
  """The duration of the run being tracked, in milliseconds."""
684
968
  error: Optional[str] = None
@@ -687,6 +971,32 @@ class TrackedRun:
687
971
  logs: Optional[list[str]] = None
688
972
  """The logs of the run being tracked. Each element of the list is a line in
689
973
  the log."""
974
+ name: Optional[str] = None
975
+ """
976
+ Optional name for the run being tracked.
977
+ """
978
+ description: Optional[str] = None
979
+ """
980
+ Optional description for the run being tracked.
981
+ """
982
+ input_dir_path: Optional[str] = None
983
+ """
984
+ Path to a directory containing input files. If specified, the calling
985
+ function will package the files in the directory into a tar file and upload
986
+ it as a large input. This is useful for non-JSON input formats, such as
987
+ when working with `CSV_ARCHIVE` or `MULTI_FILE`. If both `input` and
988
+ `input_dir_path` are specified, the `input` is ignored, and the files in
989
+ the directory are used instead.
990
+ """
991
+ output_dir_path: Optional[str] = None
992
+ """
993
+ Path to a directory containing output files. If specified, the calling
994
+ function will package the files in the directory into a tar file and upload
995
+ it as a large output. This is useful for non-JSON output formats, such as
996
+ when working with `CSV_ARCHIVE` or `MULTI_FILE`. If both `output` and
997
+ `output_dir_path` are specified, the `output` is ignored, and the files
998
+ are saved in the directory instead.
999
+ """
690
1000
 
691
1001
  def __post_init__(self): # noqa: C901
692
1002
  """
@@ -708,8 +1018,10 @@ class TrackedRun:
708
1018
  raise ValueError("Error message must be empty if the run succeeded.")
709
1019
 
710
1020
  if isinstance(self.input, Input):
711
- if self.input.input_format != InputFormat.JSON:
712
- raise ValueError("Input.input_format must be JSON.")
1021
+ try:
1022
+ _ = serialize_json(self.input.data)
1023
+ except (TypeError, OverflowError) as e:
1024
+ raise ValueError("Input.data is not JSON serializable") from e
713
1025
  elif isinstance(self.input, dict):
714
1026
  try:
715
1027
  _ = serialize_json(self.input)
@@ -717,8 +1029,10 @@ class TrackedRun:
717
1029
  raise ValueError("Input is dict[str, Any] but it is not JSON serializable") from e
718
1030
 
719
1031
  if isinstance(self.output, Output):
720
- if self.output.output_format != OutputFormat.JSON:
721
- raise ValueError("Output.output_format must be JSON.")
1032
+ try:
1033
+ _ = serialize_json(self.output.data)
1034
+ except (TypeError, OverflowError) as e:
1035
+ raise ValueError("Output.data is not JSON serializable") from e
722
1036
  elif isinstance(self.output, dict):
723
1037
  try:
724
1038
  _ = serialize_json(self.output)
@@ -737,6 +1051,29 @@ class TrackedRun:
737
1051
  The logs as a single string. If no logs are present, an empty
738
1052
  string is returned.
739
1053
 
1054
+ Examples
1055
+ --------
1056
+ >>> from nextmv import TrackedRun, TrackedRunStatus
1057
+ >>> run = TrackedRun(
1058
+ ... status=TrackedRunStatus.SUCCEEDED,
1059
+ ... logs=["Starting optimization", "Processing data", "Optimization complete"]
1060
+ ... )
1061
+ >>> run.logs_text()
1062
+ 'Starting optimization\\nProcessing data\\nOptimization complete'
1063
+
1064
+ >>> # Single string log
1065
+ >>> run_with_string_log = TrackedRun(
1066
+ ... status=TrackedRunStatus.SUCCEEDED,
1067
+ ... logs="Single log entry"
1068
+ ... )
1069
+ >>> run_with_string_log.logs_text()
1070
+ 'Single log entry'
1071
+
1072
+ >>> # No logs
1073
+ >>> run_no_logs = TrackedRun(status=TrackedRunStatus.SUCCEEDED)
1074
+ >>> run_no_logs.logs_text()
1075
+ ''
1076
+
740
1077
  Raises
741
1078
  ------
742
1079
  TypeError