nextmv 0.18.0__py3-none-any.whl → 1.0.0.dev2__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.
Files changed (175) hide show
  1. nextmv/__about__.py +1 -1
  2. nextmv/__entrypoint__.py +8 -13
  3. nextmv/__init__.py +53 -0
  4. nextmv/_serialization.py +96 -0
  5. nextmv/base_model.py +54 -9
  6. nextmv/cli/CONTRIBUTING.md +511 -0
  7. nextmv/cli/__init__.py +0 -0
  8. nextmv/cli/cloud/__init__.py +47 -0
  9. nextmv/cli/cloud/acceptance/__init__.py +27 -0
  10. nextmv/cli/cloud/acceptance/create.py +393 -0
  11. nextmv/cli/cloud/acceptance/delete.py +68 -0
  12. nextmv/cli/cloud/acceptance/get.py +104 -0
  13. nextmv/cli/cloud/acceptance/list.py +62 -0
  14. nextmv/cli/cloud/acceptance/update.py +95 -0
  15. nextmv/cli/cloud/account/__init__.py +28 -0
  16. nextmv/cli/cloud/account/create.py +83 -0
  17. nextmv/cli/cloud/account/delete.py +60 -0
  18. nextmv/cli/cloud/account/get.py +66 -0
  19. nextmv/cli/cloud/account/update.py +70 -0
  20. nextmv/cli/cloud/app/__init__.py +35 -0
  21. nextmv/cli/cloud/app/create.py +141 -0
  22. nextmv/cli/cloud/app/delete.py +58 -0
  23. nextmv/cli/cloud/app/exists.py +44 -0
  24. nextmv/cli/cloud/app/get.py +66 -0
  25. nextmv/cli/cloud/app/list.py +61 -0
  26. nextmv/cli/cloud/app/push.py +137 -0
  27. nextmv/cli/cloud/app/update.py +124 -0
  28. nextmv/cli/cloud/batch/__init__.py +29 -0
  29. nextmv/cli/cloud/batch/create.py +454 -0
  30. nextmv/cli/cloud/batch/delete.py +68 -0
  31. nextmv/cli/cloud/batch/get.py +104 -0
  32. nextmv/cli/cloud/batch/list.py +63 -0
  33. nextmv/cli/cloud/batch/metadata.py +66 -0
  34. nextmv/cli/cloud/batch/update.py +95 -0
  35. nextmv/cli/cloud/data/__init__.py +26 -0
  36. nextmv/cli/cloud/data/upload.py +162 -0
  37. nextmv/cli/cloud/ensemble/__init__.py +31 -0
  38. nextmv/cli/cloud/ensemble/create.py +414 -0
  39. nextmv/cli/cloud/ensemble/delete.py +67 -0
  40. nextmv/cli/cloud/ensemble/get.py +65 -0
  41. nextmv/cli/cloud/ensemble/update.py +103 -0
  42. nextmv/cli/cloud/input_set/__init__.py +30 -0
  43. nextmv/cli/cloud/input_set/create.py +170 -0
  44. nextmv/cli/cloud/input_set/get.py +63 -0
  45. nextmv/cli/cloud/input_set/list.py +63 -0
  46. nextmv/cli/cloud/input_set/update.py +123 -0
  47. nextmv/cli/cloud/instance/__init__.py +35 -0
  48. nextmv/cli/cloud/instance/create.py +290 -0
  49. nextmv/cli/cloud/instance/delete.py +62 -0
  50. nextmv/cli/cloud/instance/exists.py +39 -0
  51. nextmv/cli/cloud/instance/get.py +62 -0
  52. nextmv/cli/cloud/instance/list.py +60 -0
  53. nextmv/cli/cloud/instance/update.py +216 -0
  54. nextmv/cli/cloud/managed_input/__init__.py +31 -0
  55. nextmv/cli/cloud/managed_input/create.py +146 -0
  56. nextmv/cli/cloud/managed_input/delete.py +65 -0
  57. nextmv/cli/cloud/managed_input/get.py +63 -0
  58. nextmv/cli/cloud/managed_input/list.py +60 -0
  59. nextmv/cli/cloud/managed_input/update.py +97 -0
  60. nextmv/cli/cloud/run/__init__.py +37 -0
  61. nextmv/cli/cloud/run/cancel.py +37 -0
  62. nextmv/cli/cloud/run/create.py +530 -0
  63. nextmv/cli/cloud/run/get.py +199 -0
  64. nextmv/cli/cloud/run/input.py +86 -0
  65. nextmv/cli/cloud/run/list.py +80 -0
  66. nextmv/cli/cloud/run/logs.py +167 -0
  67. nextmv/cli/cloud/run/metadata.py +67 -0
  68. nextmv/cli/cloud/run/track.py +501 -0
  69. nextmv/cli/cloud/scenario/__init__.py +29 -0
  70. nextmv/cli/cloud/scenario/create.py +451 -0
  71. nextmv/cli/cloud/scenario/delete.py +65 -0
  72. nextmv/cli/cloud/scenario/get.py +102 -0
  73. nextmv/cli/cloud/scenario/list.py +63 -0
  74. nextmv/cli/cloud/scenario/metadata.py +67 -0
  75. nextmv/cli/cloud/scenario/update.py +93 -0
  76. nextmv/cli/cloud/secrets/__init__.py +33 -0
  77. nextmv/cli/cloud/secrets/create.py +206 -0
  78. nextmv/cli/cloud/secrets/delete.py +67 -0
  79. nextmv/cli/cloud/secrets/get.py +66 -0
  80. nextmv/cli/cloud/secrets/list.py +60 -0
  81. nextmv/cli/cloud/secrets/update.py +147 -0
  82. nextmv/cli/cloud/shadow/__init__.py +33 -0
  83. nextmv/cli/cloud/shadow/create.py +184 -0
  84. nextmv/cli/cloud/shadow/delete.py +68 -0
  85. nextmv/cli/cloud/shadow/get.py +61 -0
  86. nextmv/cli/cloud/shadow/list.py +63 -0
  87. nextmv/cli/cloud/shadow/metadata.py +66 -0
  88. nextmv/cli/cloud/shadow/start.py +43 -0
  89. nextmv/cli/cloud/shadow/stop.py +43 -0
  90. nextmv/cli/cloud/shadow/update.py +95 -0
  91. nextmv/cli/cloud/upload/__init__.py +22 -0
  92. nextmv/cli/cloud/upload/create.py +39 -0
  93. nextmv/cli/cloud/version/__init__.py +33 -0
  94. nextmv/cli/cloud/version/create.py +97 -0
  95. nextmv/cli/cloud/version/delete.py +62 -0
  96. nextmv/cli/cloud/version/exists.py +39 -0
  97. nextmv/cli/cloud/version/get.py +62 -0
  98. nextmv/cli/cloud/version/list.py +60 -0
  99. nextmv/cli/cloud/version/update.py +92 -0
  100. nextmv/cli/community/__init__.py +24 -0
  101. nextmv/cli/community/clone.py +270 -0
  102. nextmv/cli/community/list.py +265 -0
  103. nextmv/cli/configuration/__init__.py +23 -0
  104. nextmv/cli/configuration/config.py +195 -0
  105. nextmv/cli/configuration/create.py +94 -0
  106. nextmv/cli/configuration/delete.py +67 -0
  107. nextmv/cli/configuration/list.py +77 -0
  108. nextmv/cli/main.py +188 -0
  109. nextmv/cli/message.py +153 -0
  110. nextmv/cli/options.py +206 -0
  111. nextmv/cli/version.py +38 -0
  112. nextmv/cloud/__init__.py +71 -17
  113. nextmv/cloud/acceptance_test.py +757 -51
  114. nextmv/cloud/account.py +406 -17
  115. nextmv/cloud/application/__init__.py +957 -0
  116. nextmv/cloud/application/_acceptance.py +419 -0
  117. nextmv/cloud/application/_batch_scenario.py +860 -0
  118. nextmv/cloud/application/_ensemble.py +251 -0
  119. nextmv/cloud/application/_input_set.py +227 -0
  120. nextmv/cloud/application/_instance.py +289 -0
  121. nextmv/cloud/application/_managed_input.py +227 -0
  122. nextmv/cloud/application/_run.py +1393 -0
  123. nextmv/cloud/application/_secrets.py +294 -0
  124. nextmv/cloud/application/_shadow.py +314 -0
  125. nextmv/cloud/application/_utils.py +54 -0
  126. nextmv/cloud/application/_version.py +303 -0
  127. nextmv/cloud/assets.py +48 -0
  128. nextmv/cloud/batch_experiment.py +294 -33
  129. nextmv/cloud/client.py +307 -66
  130. nextmv/cloud/ensemble.py +247 -0
  131. nextmv/cloud/input_set.py +120 -2
  132. nextmv/cloud/instance.py +133 -8
  133. nextmv/cloud/integration.py +533 -0
  134. nextmv/cloud/package.py +168 -53
  135. nextmv/cloud/scenario.py +410 -0
  136. nextmv/cloud/secrets.py +234 -0
  137. nextmv/cloud/shadow.py +190 -0
  138. nextmv/cloud/url.py +73 -0
  139. nextmv/cloud/version.py +132 -4
  140. nextmv/default_app/.gitignore +1 -0
  141. nextmv/default_app/README.md +32 -0
  142. nextmv/default_app/app.yaml +12 -0
  143. nextmv/default_app/input.json +5 -0
  144. nextmv/default_app/main.py +37 -0
  145. nextmv/default_app/requirements.txt +2 -0
  146. nextmv/default_app/src/__init__.py +0 -0
  147. nextmv/default_app/src/visuals.py +36 -0
  148. nextmv/deprecated.py +47 -0
  149. nextmv/input.py +861 -90
  150. nextmv/local/__init__.py +5 -0
  151. nextmv/local/application.py +1251 -0
  152. nextmv/local/executor.py +1042 -0
  153. nextmv/local/geojson_handler.py +323 -0
  154. nextmv/local/local.py +97 -0
  155. nextmv/local/plotly_handler.py +61 -0
  156. nextmv/local/runner.py +274 -0
  157. nextmv/logger.py +80 -9
  158. nextmv/manifest.py +1466 -0
  159. nextmv/model.py +241 -66
  160. nextmv/options.py +708 -115
  161. nextmv/output.py +1301 -274
  162. nextmv/polling.py +325 -0
  163. nextmv/run.py +1702 -0
  164. nextmv/safe.py +145 -0
  165. nextmv/status.py +122 -0
  166. nextmv-1.0.0.dev2.dist-info/METADATA +311 -0
  167. nextmv-1.0.0.dev2.dist-info/RECORD +170 -0
  168. {nextmv-0.18.0.dist-info → nextmv-1.0.0.dev2.dist-info}/WHEEL +1 -1
  169. nextmv-1.0.0.dev2.dist-info/entry_points.txt +2 -0
  170. nextmv/cloud/application.py +0 -1405
  171. nextmv/cloud/manifest.py +0 -234
  172. nextmv/cloud/status.py +0 -29
  173. nextmv-0.18.0.dist-info/METADATA +0 -770
  174. nextmv-0.18.0.dist-info/RECORD +0 -25
  175. {nextmv-0.18.0.dist-info → nextmv-1.0.0.dev2.dist-info}/licenses/LICENSE +0 -0
@@ -1,14 +1,79 @@
1
- """This module contains definitions for acceptance tests."""
1
+ """
2
+ Definitions for acceptance tests in the Nextmv Cloud platform.
3
+
4
+ This module provides classes and enumerations for working with acceptance tests
5
+ in the Nextmv Cloud platform. Acceptance tests are used to compare the performance
6
+ of different versions of an app against a set of metrics.
7
+
8
+ Classes
9
+ -------
10
+ MetricType : Enum
11
+ Type of metric when doing a comparison.
12
+ StatisticType : Enum
13
+ Type of statistical process for collapsing multiple values of a metric.
14
+ Comparison : Enum
15
+ Comparison operators to use for comparing two metrics.
16
+ ToleranceType : Enum
17
+ Type of tolerance used for a metric.
18
+ ExperimentStatus : Enum
19
+ Status of an acceptance test experiment.
20
+ MetricTolerance : BaseModel
21
+ Tolerance used for a metric in an acceptance test.
22
+ MetricParams : BaseModel
23
+ Parameters of a metric comparison in an acceptance test.
24
+ Metric : BaseModel
25
+ A metric used to evaluate the performance of a test.
26
+ ComparisonInstance : BaseModel
27
+ An app instance used for a comparison in an acceptance test.
28
+ DistributionSummaryStatistics : BaseModel
29
+ Statistics of a distribution summary for metric results.
30
+ DistributionPercentiles : BaseModel
31
+ Percentiles of a metric value distribution.
32
+ ResultStatistics : BaseModel
33
+ Statistics of a single instance's metric results.
34
+ MetricStatistics : BaseModel
35
+ Statistics of a metric comparing control and candidate instances.
36
+ MetricResult : BaseModel
37
+ Result of a metric evaluation in an acceptance test.
38
+ AcceptanceTestResults : BaseModel
39
+ Results of an acceptance test.
40
+ AcceptanceTest : BaseModel
41
+ An acceptance test for evaluating app instances.
42
+ """
2
43
 
3
44
  from datetime import datetime
4
45
  from enum import Enum
5
- from typing import Optional
6
46
 
7
47
  from nextmv.base_model import BaseModel
48
+ from nextmv.cloud.batch_experiment import ExperimentStatus
49
+ from nextmv.deprecated import deprecated
8
50
 
9
51
 
10
52
  class MetricType(str, Enum):
11
- """Type of metric when doing a comparison."""
53
+ """
54
+ Type of metric when doing a comparison.
55
+
56
+ You can import the `MetricType` class directly from `cloud`:
57
+
58
+ ```python
59
+ from nextmv.cloud import MetricType
60
+ ```
61
+
62
+ This enumeration defines the different types of metrics that can be used
63
+ when comparing two runs in an acceptance test.
64
+
65
+ Attributes
66
+ ----------
67
+ direct_comparison : str
68
+ Direct comparison between metric values.
69
+
70
+ Examples
71
+ --------
72
+ >>> from nextmv.cloud import MetricType
73
+ >>> metric_type = MetricType.direct_comparison
74
+ >>> metric_type
75
+ <MetricType.direct_comparison: 'direct-comparison'>
76
+ """
12
77
 
13
78
  direct_comparison = "direct-comparison"
14
79
  """Direct comparison metric type."""
@@ -16,8 +81,55 @@ class MetricType(str, Enum):
16
81
 
17
82
  class StatisticType(str, Enum):
18
83
  """
19
- Type of statistical process for collapsing multiple values of a metric
20
- (from multiple runs) into a single value.
84
+ Type of statistical process for collapsing multiple values of a metric.
85
+
86
+ You can import the `StatisticType` class directly from `cloud`:
87
+
88
+ ```python
89
+ from nextmv.cloud import StatisticType
90
+ ```
91
+
92
+ This enumeration defines the different statistical methods that can be used
93
+ to summarize multiple values of a metric from multiple runs into a single
94
+ value.
95
+
96
+ Attributes
97
+ ----------
98
+ min : str
99
+ Minimum value.
100
+ max : str
101
+ Maximum value.
102
+ mean : str
103
+ Mean value.
104
+ std : str
105
+ Standard deviation.
106
+ shifted_geometric_mean : str
107
+ Shifted geometric mean.
108
+ p01 : str
109
+ 1st percentile.
110
+ p05 : str
111
+ 5th percentile.
112
+ p10 : str
113
+ 10th percentile.
114
+ p25 : str
115
+ 25th percentile.
116
+ p50 : str
117
+ 50th percentile (median).
118
+ p75 : str
119
+ 75th percentile.
120
+ p90 : str
121
+ 90th percentile.
122
+ p95 : str
123
+ 95th percentile.
124
+ p99 : str
125
+ 99th percentile.
126
+
127
+ Examples
128
+ --------
129
+ >>> from nextmv.cloud import StatisticType
130
+ >>> stat_type = StatisticType.mean
131
+ >>> stat_type
132
+ <StatisticType.mean: 'mean'>
21
133
  """
22
134
 
23
135
  min = "min"
@@ -51,7 +163,40 @@ class StatisticType(str, Enum):
51
163
 
52
164
 
53
165
  class Comparison(str, Enum):
54
- """Comparison to use for two metrics."""
166
+ """
167
+ Comparison operators to use for comparing two metrics.
168
+
169
+ You can import the `Comparison` class directly from `cloud`:
170
+
171
+ ```python
172
+ from nextmv.cloud import Comparison
173
+ ```
174
+
175
+ This enumeration defines the different comparison operators that can be used
176
+ to compare two metric values in an acceptance test.
177
+
178
+ Attributes
179
+ ----------
180
+ equal_to : str
181
+ Equal to operator (==).
182
+ greater_than : str
183
+ Greater than operator (>).
184
+ greater_than_or_equal_to : str
185
+ Greater than or equal to operator (>=).
186
+ less_than : str
187
+ Less than operator (<).
188
+ less_than_or_equal_to : str
189
+ Less than or equal to operator (<=).
190
+ not_equal_to : str
191
+ Not equal to operator (!=).
192
+
193
+ Examples
194
+ --------
195
+ >>> from nextmv.cloud import Comparison
196
+ >>> op = Comparison.greater_than
197
+ >>> op
198
+ <Comparison.greater_than: 'gt'>
199
+ """
55
200
 
56
201
  equal_to = "eq"
57
202
  """Equal to metric type."""
@@ -68,44 +213,172 @@ class Comparison(str, Enum):
68
213
 
69
214
 
70
215
  class ToleranceType(str, Enum):
71
- """Type of tolerance used for a metric."""
216
+ """
217
+ !!! warning
218
+ `ToleranceType` is deprecated, use `MetricToleranceType` instead.
219
+
220
+ Type of tolerance used for a metric.
221
+
222
+ You can import the `ToleranceType` class directly from `cloud`:
223
+
224
+ ```python
225
+ from nextmv.cloud import ToleranceType
226
+ ```
227
+
228
+ This enumeration defines the different types of tolerances that can be used
229
+ when comparing metrics in acceptance tests.
230
+
231
+ Attributes
232
+ ----------
233
+ undefined : str
234
+ Undefined tolerance type (empty string).
235
+ absolute : str
236
+ Absolute tolerance type, using a fixed value.
237
+ relative : str
238
+ Relative tolerance type, using a percentage.
239
+
240
+ Examples
241
+ --------
242
+ >>> from nextmv.cloud import ToleranceType
243
+ >>> tol_type = ToleranceType.absolute
244
+ >>> tol_type
245
+ <ToleranceType.absolute: 'absolute'>
246
+ """
72
247
 
73
248
  undefined = ""
74
- """Undefined tolerance type."""
249
+ """ToleranceType is deprecated, please use MetricToleranceType instead.
250
+ Undefined tolerance type."""
75
251
  absolute = "absolute"
76
- """Absolute tolerance type."""
252
+ """ToleranceType is deprecated, please use MetricToleranceType instead.
253
+ Absolute tolerance type."""
77
254
  relative = "relative"
78
- """Relative tolerance type."""
255
+ """ToleranceType is deprecated, please use MetricToleranceType instead.
256
+ Relative tolerance type."""
79
257
 
80
258
 
81
- class ExperimentStatus(str, Enum):
82
- """Status of an acceptance test."""
259
+ # Override __getattribute__ to emit deprecation warnings when enum values are accessed
260
+ _original_getattribute = ToleranceType.__class__.__getattribute__
83
261
 
84
- started = "started"
85
- """The experiment has started."""
86
- completed = "completed"
87
- """The experiment was completed."""
88
- failed = "failed"
89
- """The experiment failed."""
90
- draft = "draft"
91
- """The experiment is a draft."""
92
- canceled = "canceled"
93
- """The experiment was canceled."""
94
- unknown = "unknown"
95
- """The experiment status is unknown."""
262
+
263
+ def _deprecated_getattribute(cls, name: str):
264
+ # Only emit deprecation warning if this is specifically the ToleranceType class
265
+ if cls is ToleranceType and name in ("undefined", "absolute", "relative"):
266
+ deprecated(
267
+ f"ToleranceType.{name}",
268
+ "ToleranceType is deprecated and will be removed in a future version. "
269
+ "Please use MetricToleranceType instead",
270
+ )
271
+
272
+ return _original_getattribute(cls, name)
273
+
274
+
275
+ ToleranceType.__class__.__getattribute__ = _deprecated_getattribute
276
+
277
+
278
+ class MetricToleranceType(str, Enum):
279
+ """
280
+ Type of tolerance used for a metric.
281
+
282
+ You can import the `MetricToleranceType` class directly from `cloud`:
283
+
284
+ ```python
285
+ from nextmv.cloud import MetricToleranceType
286
+ ```
287
+
288
+ This enumeration defines the different types of tolerances that can be used
289
+ when comparing metrics in acceptance tests.
290
+
291
+ Attributes
292
+ ----------
293
+ undefined : str
294
+ Undefined tolerance type (empty string).
295
+ absolute : str
296
+ Absolute tolerance type, using a fixed value.
297
+ relative : str
298
+ Relative tolerance type, using a percentage.
299
+
300
+ Examples
301
+ --------
302
+ >>> from nextmv.cloud import MetricToleranceType
303
+ >>> tol_type = MetricToleranceType.absolute
304
+ >>> tol_type
305
+ <MetricToleranceType.absolute: 'absolute'>
306
+ """
307
+
308
+ undefined = ""
309
+ """Undefined tolerance type."""
310
+ absolute = "absolute"
311
+ """Absolute tolerance type."""
312
+ relative = "relative"
313
+ """Relative tolerance type."""
96
314
 
97
315
 
98
316
  class MetricTolerance(BaseModel):
99
- """Tolerance used for a metric."""
317
+ """
318
+ Tolerance used for a metric in an acceptance test.
319
+
320
+ You can import the `MetricTolerance` class directly from `cloud`:
321
+
322
+ ```python
323
+ from nextmv.cloud import MetricTolerance
324
+ ```
325
+
326
+ This class defines the tolerance to be applied when comparing metric values,
327
+ which can be either absolute or relative.
328
+
329
+ Attributes
330
+ ----------
331
+ type : MetricToleranceType
332
+ Type of tolerance (absolute or relative).
333
+ value : float
334
+ Value of the tolerance.
335
+
336
+ Examples
337
+ --------
338
+ >>> from nextmv.cloud import MetricTolerance, MetricToleranceType
339
+ >>> tolerance = MetricTolerance(type=MetricToleranceType.absolute, value=0.1)
340
+ >>> tolerance.type
341
+ <MetricToleranceType.absolute: 'absolute'>
342
+ >>> tolerance.value
343
+ 0.1
344
+ """
100
345
 
101
- type: ToleranceType
346
+ type: MetricToleranceType
102
347
  """Type of tolerance."""
103
348
  value: float
104
349
  """Value of the tolerance."""
105
350
 
106
351
 
107
352
  class MetricParams(BaseModel):
108
- """Parameters of an acceptance test."""
353
+ """
354
+ Parameters of a metric comparison in an acceptance test.
355
+
356
+ You can import the `MetricParams` class directly from `cloud`:
357
+
358
+ ```python
359
+ from nextmv.cloud import MetricParams
360
+ ```
361
+
362
+ This class defines the parameters used for comparing metric values,
363
+ including the comparison operator and tolerance.
364
+
365
+ Attributes
366
+ ----------
367
+ operator : Comparison
368
+ Operator used to compare two metrics (e.g., greater than, less than).
369
+ tolerance : MetricTolerance
370
+ Tolerance used for the comparison.
371
+
372
+ Examples
373
+ --------
374
+ >>> from nextmv.cloud import MetricParams, Comparison, MetricTolerance, ToleranceType
375
+ >>> params = MetricParams(
376
+ ... operator=Comparison.less_than,
377
+ ... tolerance=MetricTolerance(type=ToleranceType.absolute, value=0.5)
378
+ ... )
379
+ >>> params.operator
380
+ <Comparison.less_than: 'lt'>
381
+ """
109
382
 
110
383
  operator: Comparison
111
384
  """Operator used to compare two metrics."""
@@ -114,8 +387,51 @@ class MetricParams(BaseModel):
114
387
 
115
388
 
116
389
  class Metric(BaseModel):
117
- """A metric is a key performance indicator that is used to evaluate the
118
- performance of a test."""
390
+ """
391
+ A metric used to evaluate the performance of a test.
392
+
393
+ You can import the `Metric` class directly from `cloud`:
394
+
395
+ ```python
396
+ from nextmv.cloud import Metric
397
+ ```
398
+
399
+ A metric is a key performance indicator that is used to evaluate the
400
+ performance of a test. It defines the field to measure, the type of
401
+ comparison, and the statistical method to use.
402
+
403
+ Attributes
404
+ ----------
405
+ field : str
406
+ Field of the metric to measure (e.g., "solution.objective").
407
+ metric_type : MetricType
408
+ Type of the metric comparison.
409
+ params : MetricParams
410
+ Parameters of the metric comparison.
411
+ statistic : StatisticType
412
+ Type of statistical process for collapsing multiple values into a single value.
413
+
414
+ Examples
415
+ --------
416
+ >>> from nextmv.cloud import (
417
+ ... Metric, MetricType, MetricParams, Comparison,
418
+ ... MetricTolerance, ToleranceType, StatisticType
419
+ ... )
420
+ >>> metric = Metric(
421
+ ... field="solution.objective",
422
+ ... metric_type=MetricType.direct_comparison,
423
+ ... params=MetricParams(
424
+ ... operator=Comparison.less_than,
425
+ ... tolerance=MetricTolerance(
426
+ ... type=ToleranceType.relative,
427
+ ... value=0.05
428
+ ... )
429
+ ... ),
430
+ ... statistic=StatisticType.mean
431
+ ... )
432
+ >>> metric.field
433
+ 'solution.objective'
434
+ """
119
435
 
120
436
  field: str
121
437
  """Field of the metric."""
@@ -131,7 +447,37 @@ class Metric(BaseModel):
131
447
 
132
448
 
133
449
  class ComparisonInstance(BaseModel):
134
- """An app instance used for a comparison."""
450
+ """
451
+ An app instance used for a comparison in an acceptance test.
452
+
453
+ You can import the `ComparisonInstance` class directly from `cloud`:
454
+
455
+ ```python
456
+ from nextmv.cloud import ComparisonInstance
457
+ ```
458
+
459
+ This class represents an app instance used in a comparison,
460
+ identifying both the instance and its version.
461
+
462
+ Attributes
463
+ ----------
464
+ instance_id : str
465
+ ID of the instance.
466
+ version_id : str
467
+ ID of the version.
468
+
469
+ Examples
470
+ --------
471
+ >>> from nextmv.cloud import ComparisonInstance
472
+ >>> instance = ComparisonInstance(
473
+ ... instance_id="instance-123",
474
+ ... version_id="version-456"
475
+ ... )
476
+ >>> instance.instance_id
477
+ 'instance-123'
478
+ >>> instance.version_id
479
+ 'version-456'
480
+ """
135
481
 
136
482
  instance_id: str
137
483
  """ID of the instance."""
@@ -140,7 +486,52 @@ class ComparisonInstance(BaseModel):
140
486
 
141
487
 
142
488
  class DistributionSummaryStatistics(BaseModel):
143
- """Statistics of a distribution summary."""
489
+ """
490
+ Statistics of a distribution summary for metric results.
491
+
492
+ You can import the `DistributionSummaryStatistics` class directly from `cloud`:
493
+
494
+ ```python
495
+ from nextmv.cloud import DistributionSummaryStatistics
496
+ ```
497
+
498
+ This class contains statistical measures summarizing the distribution of
499
+ metric values across multiple runs.
500
+
501
+ Attributes
502
+ ----------
503
+ min : float
504
+ Minimum value in the distribution.
505
+ max : float
506
+ Maximum value in the distribution.
507
+ count : int
508
+ Count of runs in the distribution.
509
+ mean : float
510
+ Mean value of the distribution.
511
+ std : float
512
+ Standard deviation of the distribution.
513
+ shifted_geometric_mean : float
514
+ Shifted geometric mean of the distribution.
515
+ shift_parameter : float
516
+ Shift parameter used for the geometric mean calculation.
517
+
518
+ Examples
519
+ --------
520
+ >>> from nextmv.cloud import DistributionSummaryStatistics
521
+ >>> stats = DistributionSummaryStatistics(
522
+ ... min=10.0,
523
+ ... max=20.0,
524
+ ... count=5,
525
+ ... mean=15.0,
526
+ ... std=4.0,
527
+ ... shifted_geometric_mean=14.5,
528
+ ... shift_parameter=1.0
529
+ ... )
530
+ >>> stats.mean
531
+ 15.0
532
+ >>> stats.count
533
+ 5
534
+ """
144
535
 
145
536
  min: float
146
537
  """Minimum value."""
@@ -159,7 +550,56 @@ class DistributionSummaryStatistics(BaseModel):
159
550
 
160
551
 
161
552
  class DistributionPercentiles(BaseModel):
162
- """Percentiles of a distribution."""
553
+ """
554
+ Percentiles of a metric value distribution.
555
+
556
+ You can import the `DistributionPercentiles` class directly from `cloud`:
557
+
558
+ ```python
559
+ from nextmv.cloud import DistributionPercentiles
560
+ ```
561
+
562
+ This class contains the different percentiles of a distribution of metric values
563
+ across multiple runs.
564
+
565
+ Attributes
566
+ ----------
567
+ p01 : float
568
+ 1st percentile of the distribution.
569
+ p05 : float
570
+ 5th percentile of the distribution.
571
+ p10 : float
572
+ 10th percentile of the distribution.
573
+ p25 : float
574
+ 25th percentile of the distribution.
575
+ p50 : float
576
+ 50th percentile of the distribution (median).
577
+ p75 : float
578
+ 75th percentile of the distribution.
579
+ p90 : float
580
+ 90th percentile of the distribution.
581
+ p95 : float
582
+ 95th percentile of the distribution.
583
+ p99 : float
584
+ 99th percentile of the distribution.
585
+
586
+ Examples
587
+ --------
588
+ >>> from nextmv.cloud import DistributionPercentiles
589
+ >>> percentiles = DistributionPercentiles(
590
+ ... p01=10.0,
591
+ ... p05=12.0,
592
+ ... p10=13.0,
593
+ ... p25=14.0,
594
+ ... p50=15.0,
595
+ ... p75=16.0,
596
+ ... p90=17.0,
597
+ ... p95=18.0,
598
+ ... p99=19.0
599
+ ... )
600
+ >>> percentiles.p50 # median
601
+ 15.0
602
+ """
163
603
 
164
604
  p01: float
165
605
  """1st percentile."""
@@ -182,7 +622,64 @@ class DistributionPercentiles(BaseModel):
182
622
 
183
623
 
184
624
  class ResultStatistics(BaseModel):
185
- """Statistics of a metric result."""
625
+ """
626
+ Statistics of a single instance's metric results.
627
+
628
+ You can import the `ResultStatistics` class directly from `cloud`:
629
+
630
+ ```python
631
+ from nextmv.cloud import ResultStatistics
632
+ ```
633
+
634
+ This class aggregates the statistical information about the metric results
635
+ for a specific instance in a comparison.
636
+
637
+ Attributes
638
+ ----------
639
+ instance_id : str
640
+ ID of the instance.
641
+ version_id : str
642
+ ID of the version.
643
+ number_of_runs_total : int
644
+ Total number of runs included in the statistics.
645
+ distribution_summary_statistics : DistributionSummaryStatistics
646
+ Summary statistics of the metric value distribution.
647
+ distribution_percentiles : DistributionPercentiles
648
+ Percentiles of the metric value distribution.
649
+
650
+ Examples
651
+ --------
652
+ >>> from nextmv.cloud import (
653
+ ... ResultStatistics, DistributionSummaryStatistics, DistributionPercentiles
654
+ ... )
655
+ >>> result_stats = ResultStatistics(
656
+ ... instance_id="instance-123",
657
+ ... version_id="version-456",
658
+ ... number_of_runs_total=10,
659
+ ... distribution_summary_statistics=DistributionSummaryStatistics(
660
+ ... min=10.0,
661
+ ... max=20.0,
662
+ ... count=10,
663
+ ... mean=15.0,
664
+ ... std=3.0,
665
+ ... shifted_geometric_mean=14.5,
666
+ ... shift_parameter=1.0
667
+ ... ),
668
+ ... distribution_percentiles=DistributionPercentiles(
669
+ ... p01=10.5,
670
+ ... p05=11.0,
671
+ ... p10=12.0,
672
+ ... p25=13.5,
673
+ ... p50=15.0,
674
+ ... p75=16.5,
675
+ ... p90=18.0,
676
+ ... p95=19.0,
677
+ ... p99=19.5
678
+ ... )
679
+ ... )
680
+ >>> result_stats.number_of_runs_total
681
+ 10
682
+ """
186
683
 
187
684
  instance_id: str
188
685
  """ID of the instance."""
@@ -197,7 +694,62 @@ class ResultStatistics(BaseModel):
197
694
 
198
695
 
199
696
  class MetricStatistics(BaseModel):
200
- """Statistics of a metric."""
697
+ """
698
+ Statistics of a metric comparing control and candidate instances.
699
+
700
+ You can import the `MetricStatistics` class directly from `cloud`:
701
+
702
+ ```python
703
+ from nextmv.cloud import MetricStatistics
704
+ ```
705
+
706
+ This class holds the statistical information for both the control and candidate
707
+ instances being compared in the acceptance test.
708
+
709
+ Attributes
710
+ ----------
711
+ control : ResultStatistics
712
+ Statistics for the control instance.
713
+ candidate : ResultStatistics
714
+ Statistics for the candidate instance.
715
+
716
+ Examples
717
+ --------
718
+ >>> from nextmv.cloud import (
719
+ ... MetricStatistics, ResultStatistics,
720
+ ... DistributionSummaryStatistics, DistributionPercentiles
721
+ ... )
722
+ >>> stats = MetricStatistics(
723
+ ... control=ResultStatistics(
724
+ ... instance_id="control-instance",
725
+ ... version_id="control-version",
726
+ ... number_of_runs_total=10,
727
+ ... distribution_summary_statistics=DistributionSummaryStatistics(
728
+ ... min=10.0, max=20.0, count=10, mean=15.0, std=3.0,
729
+ ... shifted_geometric_mean=14.5, shift_parameter=1.0
730
+ ... ),
731
+ ... distribution_percentiles=DistributionPercentiles(
732
+ ... p01=10.5, p05=11.0, p10=12.0, p25=13.5, p50=15.0,
733
+ ... p75=16.5, p90=18.0, p95=19.0, p99=19.5
734
+ ... )
735
+ ... ),
736
+ ... candidate=ResultStatistics(
737
+ ... instance_id="candidate-instance",
738
+ ... version_id="candidate-version",
739
+ ... number_of_runs_total=10,
740
+ ... distribution_summary_statistics=DistributionSummaryStatistics(
741
+ ... min=9.0, max=18.0, count=10, mean=13.0, std=2.5,
742
+ ... shifted_geometric_mean=12.8, shift_parameter=1.0
743
+ ... ),
744
+ ... distribution_percentiles=DistributionPercentiles(
745
+ ... p01=9.5, p05=10.0, p10=11.0, p25=12.0, p50=13.0,
746
+ ... p75=14.0, p90=15.5, p95=16.5, p99=17.5
747
+ ... )
748
+ ... )
749
+ ... )
750
+ >>> stats.control.mean > stats.candidate.mean
751
+ True
752
+ """
201
753
 
202
754
  control: ResultStatistics
203
755
  """Control statistics."""
@@ -206,7 +758,53 @@ class MetricStatistics(BaseModel):
206
758
 
207
759
 
208
760
  class MetricResult(BaseModel):
209
- """Result of a metric."""
761
+ """
762
+ Result of a metric evaluation in an acceptance test.
763
+
764
+ You can import the `MetricResult` class directly from `cloud`:
765
+
766
+ ```python
767
+ from nextmv.cloud import MetricResult
768
+ ```
769
+
770
+ This class represents the result of evaluating a specific metric in an
771
+ acceptance test, including whether the candidate passed according to this metric.
772
+
773
+ Attributes
774
+ ----------
775
+ metric : Metric
776
+ The metric that was evaluated.
777
+ statistics : MetricStatistics
778
+ Statistics comparing control and candidate instances for this metric.
779
+ passed : bool
780
+ Whether the candidate passed for this metric.
781
+
782
+ Examples
783
+ --------
784
+ >>> from nextmv.cloud import (
785
+ ... MetricResult, Metric, MetricType, MetricParams, Comparison,
786
+ ... MetricTolerance, ToleranceType, StatisticType, MetricStatistics
787
+ ... )
788
+ >>> # Assume we have statistics object already created
789
+ >>> result = MetricResult(
790
+ ... metric=Metric(
791
+ ... field="solution.objective",
792
+ ... metric_type=MetricType.direct_comparison,
793
+ ... params=MetricParams(
794
+ ... operator=Comparison.less_than,
795
+ ... tolerance=MetricTolerance(
796
+ ... type=ToleranceType.relative,
797
+ ... value=0.05
798
+ ... )
799
+ ... ),
800
+ ... statistic=StatisticType.mean
801
+ ... ),
802
+ ... statistics=statistics, # previously created statistics object
803
+ ... passed=True
804
+ ... )
805
+ >>> result.passed
806
+ True
807
+ """
210
808
 
211
809
  metric: Metric
212
810
  """Metric of the result."""
@@ -217,19 +815,126 @@ class MetricResult(BaseModel):
217
815
 
218
816
 
219
817
  class AcceptanceTestResults(BaseModel):
220
- """Results of an acceptance test."""
818
+ """
819
+ Results of an acceptance test.
820
+
821
+ You can import the `AcceptanceTestResults` class directly from `cloud`:
822
+
823
+ ```python
824
+ from nextmv.cloud import AcceptanceTestResults
825
+ ```
826
+
827
+ This class contains the overall results of an acceptance test, including
828
+ whether the test passed and detailed results for each metric.
829
+
830
+ Attributes
831
+ ----------
832
+ passed : bool
833
+ Whether the acceptance test passed overall.
834
+ metric_results : list[MetricResult], optional
835
+ Results for each metric in the test.
836
+ error : str, optional
837
+ Error message if the acceptance test failed.
838
+
839
+ Examples
840
+ --------
841
+ >>> from nextmv.cloud import AcceptanceTestResults
842
+ >>> # Assume metric_results is a list of MetricResult objects
843
+ >>> results = AcceptanceTestResults(
844
+ ... passed=True,
845
+ ... metric_results=metric_results # previously created list of results
846
+ ... )
847
+ >>> results.passed
848
+ True
849
+ >>>
850
+ >>> # Example with error
851
+ >>> error_results = AcceptanceTestResults(
852
+ ... passed=False,
853
+ ... error="Experiment failed to complete"
854
+ ... )
855
+ >>> error_results.passed
856
+ False
857
+ >>> error_results.error
858
+ 'Experiment failed to complete'
859
+ """
221
860
 
222
861
  passed: bool
223
862
  """Whether the acceptance test passed (or not)."""
224
- metric_results: Optional[list[MetricResult]] = None
863
+ metric_results: list[MetricResult] | None = None
225
864
  """Results of the metrics."""
226
- error: Optional[str] = None
865
+ error: str | None = None
227
866
  """Error message if the acceptance test failed."""
228
867
 
229
868
 
230
869
  class AcceptanceTest(BaseModel):
231
- """An acceptance test gives a go/no-go decision criteria for a set of
232
- metrics. It relies on a batch experiment."""
870
+ """
871
+ An acceptance test for evaluating app instances.
872
+
873
+ You can import the `AcceptanceTest` class directly from `cloud`:
874
+
875
+ ```python
876
+ from nextmv.cloud import AcceptanceTest
877
+ ```
878
+
879
+ An acceptance test gives a go/no-go decision criteria for a set of
880
+ metrics. It relies on a batch experiment to compare a candidate app instance
881
+ against a control app instance.
882
+
883
+ Attributes
884
+ ----------
885
+ id : str
886
+ ID of the acceptance test.
887
+ name : str
888
+ Name of the acceptance test.
889
+ description : str
890
+ Description of the acceptance test.
891
+ created_at : datetime
892
+ Creation date of the acceptance test.
893
+ updated_at : datetime
894
+ Last update date of the acceptance test.
895
+ app_id : str, optional
896
+ ID of the app that owns the acceptance test.
897
+ experiment_id : str, optional
898
+ ID of the batch experiment underlying the acceptance test.
899
+ control : ComparisonInstance, optional
900
+ Control instance of the acceptance test.
901
+ candidate : ComparisonInstance, optional
902
+ Candidate instance of the acceptance test.
903
+ metrics : list[Metric], optional
904
+ Metrics to evaluate in the acceptance test.
905
+ status : ExperimentStatus, optional
906
+ Status of the acceptance test.
907
+ results : AcceptanceTestResults, optional
908
+ Results of the acceptance test.
909
+
910
+ Examples
911
+ --------
912
+ >>> from nextmv.cloud import (
913
+ ... AcceptanceTest, ComparisonInstance, Metric, ExperimentStatus
914
+ ... )
915
+ >>> from datetime import datetime
916
+ >>> test = AcceptanceTest(
917
+ ... id="test-123",
918
+ ... name="Performance acceptance test",
919
+ ... description="Testing performance improvements",
920
+ ... app_id="app-456",
921
+ ... experiment_id="exp-789",
922
+ ... control=ComparisonInstance(
923
+ ... instance_id="control-instance",
924
+ ... version_id="control-version"
925
+ ... ),
926
+ ... candidate=ComparisonInstance(
927
+ ... instance_id="candidate-instance",
928
+ ... version_id="candidate-version"
929
+ ... ),
930
+ ... metrics=[metric1, metric2], # previously created metrics
931
+ ... created_at=datetime.now(),
932
+ ... updated_at=datetime.now(),
933
+ ... status=ExperimentStatus.started
934
+ ... )
935
+ >>> test.status
936
+ <ExperimentStatus.started: 'started'>
937
+ """
233
938
 
234
939
  id: str
235
940
  """ID of the acceptance test."""
@@ -237,21 +942,22 @@ class AcceptanceTest(BaseModel):
237
942
  """Name of the acceptance test."""
238
943
  description: str
239
944
  """Description of the acceptance test."""
240
- app_id: str
945
+ created_at: datetime
946
+ """Creation date of the acceptance test."""
947
+ updated_at: datetime
948
+ """Last update date of the acceptance test."""
949
+
950
+ app_id: str | None = None
241
951
  """ID of the app that owns the acceptance test."""
242
- experiment_id: str
952
+ experiment_id: str | None = None
243
953
  """ID of the batch experiment underlying in the acceptance test."""
244
- control: ComparisonInstance
954
+ control: ComparisonInstance | None = None
245
955
  """Control instance of the acceptance test."""
246
- candidate: ComparisonInstance
956
+ candidate: ComparisonInstance | None = None
247
957
  """Candidate instance of the acceptance test."""
248
- metrics: list[Metric]
958
+ metrics: list[Metric] | None = None
249
959
  """Metrics of the acceptance test."""
250
- created_at: datetime
251
- """Creation date of the acceptance test."""
252
- updated_at: datetime
253
- """Last update date of the acceptance test."""
254
- status: Optional[ExperimentStatus] = ExperimentStatus.unknown
960
+ status: ExperimentStatus | None = ExperimentStatus.UNKNOWN
255
961
  """Status of the acceptance test."""
256
- results: Optional[AcceptanceTestResults] = None
962
+ results: AcceptanceTestResults | None = None
257
963
  """Results of the acceptance test."""