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
nextmv/cloud/shadow.py ADDED
@@ -0,0 +1,190 @@
1
+ """
2
+ Classes for working with Nextmv Cloud shadow tests.
3
+
4
+ This module provides classes for interacting with shadow tests in Nextmv Cloud.
5
+ It details the core data structures for these types of experiments.
6
+
7
+ Classes
8
+ -------
9
+ TestComparison
10
+ A structure to define comparison parameters for tests.
11
+ StartEvents
12
+ A structure to define start events for tests.
13
+ TerminationEvents
14
+ A structure to define termination events for tests.
15
+ ShadowTestMetadata
16
+ Metadata for a Nextmv Cloud shadow test.
17
+ ShadowTest
18
+ A Nextmv Cloud shadow test definition.
19
+ """
20
+
21
+ from datetime import datetime
22
+ from typing import Any
23
+
24
+ from pydantic import AliasChoices, Field
25
+
26
+ from nextmv.base_model import BaseModel
27
+ from nextmv.cloud.batch_experiment import ExperimentStatus
28
+ from nextmv.run import Run
29
+
30
+
31
+ class TestComparison(BaseModel):
32
+ """
33
+ A structure to define comparison parameters for tests.
34
+
35
+ You can import the `TestComparison` class directly from `cloud`:
36
+
37
+ ```python
38
+ from nextmv.cloud import TestComparison
39
+ ```
40
+
41
+ Parameters
42
+ ----------
43
+ baseline_instance_id : str
44
+ ID of the baseline instance for comparison.
45
+ candidate_instance_ids : list[str]
46
+ List of candidate instance IDs to compare against the baseline.
47
+ """
48
+
49
+ baseline_instance_id: str
50
+ """ID of the baseline instance for comparison."""
51
+ candidate_instance_ids: list[str]
52
+ """List of candidate instance IDs to compare against the baseline."""
53
+
54
+
55
+ class StartEvents(BaseModel):
56
+ """
57
+ A structure to define start events for tests.
58
+
59
+ You can import the `StartEvents` class directly from `cloud`:
60
+
61
+ ```python
62
+ from nextmv.cloud import StartEvents
63
+ ```
64
+
65
+ Parameters
66
+ ----------
67
+ time : datetime, optional
68
+ Scheduled time for the test to start.
69
+ """
70
+
71
+ time: datetime | None = None
72
+ """Scheduled time for the test to start."""
73
+
74
+
75
+ class TerminationEvents(BaseModel):
76
+ """
77
+ A structure to define termination events for tests.
78
+
79
+ You can import the `TerminationEvents` class directly from `cloud`:
80
+
81
+ ```python
82
+ from nextmv.cloud import TerminationEvents
83
+ ```
84
+
85
+ Parameters
86
+ ----------
87
+ time : datetime, optional
88
+ Scheduled time for the test to terminate.
89
+ """
90
+
91
+ maximum_runs: int
92
+ """
93
+ Maximum number of runs for the test. Min should be 1, max should be 300.
94
+ """
95
+ time: datetime | None = None
96
+ """
97
+ Scheduled time for the test to terminate. A zero value means no
98
+ limit.
99
+ """
100
+
101
+ def model_post_init(self, __context):
102
+ if self.maximum_runs < 1:
103
+ raise ValueError("maximum_runs must be at least 1")
104
+
105
+
106
+ class ShadowTestMetadata(BaseModel):
107
+ """
108
+ Metadata for a Nextmv Cloud shadow test.
109
+
110
+ You can import the `ShadowTestMetadata` class directly from `cloud`:
111
+
112
+ ```python
113
+ from nextmv.cloud import ShadowTestMetadata
114
+ ```
115
+
116
+ Parameters
117
+ ----------
118
+ shadow_test_id : str, optional
119
+ The unique identifier of the shadow test.
120
+ name : str, optional
121
+ Name of the shadow test.
122
+ description : str, optional
123
+ Description of the shadow test.
124
+ app_id : str, optional
125
+ ID of the application to which the shadow test belongs.
126
+ created_at : datetime, optional
127
+ Creation date of the shadow test.
128
+ updated_at : datetime, optional
129
+ Last update date of the shadow test.
130
+ status : ExperimentStatus, optional
131
+ The current status of the shadow test.
132
+ """
133
+
134
+ shadow_test_id: str | None = Field(
135
+ serialization_alias="id",
136
+ validation_alias=AliasChoices("id", "shadow_test_id"),
137
+ default=None,
138
+ )
139
+ """The unique identifier of the shadow test."""
140
+ name: str | None = None
141
+ """Name of the shadow test."""
142
+ description: str | None = None
143
+ """Description of the shadow test."""
144
+ app_id: str | None = None
145
+ """ID of the application to which the shadow test belongs."""
146
+ created_at: datetime | None = None
147
+ """Creation date of the shadow test."""
148
+ updated_at: datetime | None = None
149
+ """Last update date of the shadow test."""
150
+ status: ExperimentStatus | None = None
151
+ """The current status of the shadow test."""
152
+
153
+
154
+ class ShadowTest(ShadowTestMetadata):
155
+ """
156
+ A Nextmv Cloud shadow test definition.
157
+
158
+ A shadow test is a type of experiment where runs are executed in parallel
159
+ to compare different instances.
160
+
161
+ You can import the `ShadowTest` class directly from `cloud`:
162
+
163
+ ```python
164
+ from nextmv.cloud import ShadowTest
165
+ ```
166
+
167
+ Parameters
168
+ ----------
169
+ completed_at : datetime, optional
170
+ Completion date of the shadow test, if applicable.
171
+ comparisons : list[TestComparison], optional
172
+ List of test comparisons defined in the shadow test.
173
+ start_events : StartEvents, optional
174
+ Start events for the shadow test.
175
+ termination_events : TerminationEvents, optional
176
+ Termination events for the shadow test.
177
+ """
178
+
179
+ completed_at: datetime | None = None
180
+ """Completion date of the shadow test, if applicable."""
181
+ comparisons: list[TestComparison] | None = None
182
+ """List of test comparisons defined in the shadow test."""
183
+ start_events: StartEvents | None = None
184
+ """Start events for the shadow test."""
185
+ termination_events: TerminationEvents | None = None
186
+ """Termination events for the shadow test."""
187
+ grouped_distributional_summaries: list[dict[str, Any]] | None = None
188
+ """Grouped distributional summaries of the shadow test."""
189
+ runs: list[Run] | None = None
190
+ """List of runs in the shadow test."""
nextmv/cloud/url.py ADDED
@@ -0,0 +1,73 @@
1
+ """
2
+ Module for declarations related to upload and download URLs in Nextmv Cloud.
3
+
4
+ Classes
5
+ -------
6
+ DownloadURL
7
+ Represents a download URL for fetching content from Nextmv Cloud.
8
+ UploadURL
9
+ Represents an upload URL for sending content to Nextmv Cloud.
10
+ """
11
+
12
+ from nextmv.base_model import BaseModel
13
+
14
+
15
+ class DownloadURL(BaseModel):
16
+ """
17
+ Result of getting a download URL.
18
+
19
+ You can import the `DownloadURL` class directly from `cloud`:
20
+
21
+ ```python
22
+ from nextmv.cloud import DownloadURL
23
+ ```
24
+
25
+ This class represents a download URL that can be used to fetch content
26
+ from Nextmv Cloud, typically used for downloading large run results.
27
+
28
+ Attributes
29
+ ----------
30
+ url : str
31
+ URL to use for downloading the file.
32
+
33
+ Examples
34
+ --------
35
+ >>> download_url = DownloadURL(url="https://example.com/download")
36
+ >>> response = requests.get(download_url.url)
37
+ """
38
+
39
+ url: str
40
+ """URL to use for downloading the file."""
41
+
42
+
43
+ class UploadURL(BaseModel):
44
+ """
45
+ Result of getting an upload URL.
46
+
47
+ You can import the `UploadURL` class directly from `cloud`:
48
+
49
+ ```python
50
+ from nextmv.cloud import UploadURL
51
+ ```
52
+
53
+ This class represents an upload URL that can be used to send data to
54
+ Nextmv Cloud, typically used for uploading large inputs for runs.
55
+
56
+ Attributes
57
+ ----------
58
+ upload_id : str
59
+ ID of the upload, used to reference the uploaded content.
60
+ upload_url : str
61
+ URL to use for uploading the file.
62
+
63
+ Examples
64
+ --------
65
+ >>> upload_url = UploadURL(upload_id="123", upload_url="https://example.com/upload")
66
+ >>> with open("large_input.json", "rb") as f:
67
+ ... requests.put(upload_url.upload_url, data=f)
68
+ """
69
+
70
+ upload_id: str
71
+ """ID of the upload."""
72
+ upload_url: str
73
+ """URL to use for uploading the file."""
nextmv/cloud/version.py CHANGED
@@ -1,4 +1,20 @@
1
- """This module contains definitions for versions."""
1
+ """Manages application versions within the Nextmv Cloud API.
2
+
3
+ This module provides data models for representing application versions,
4
+ their executables, and associated requirements. These models are used
5
+ for interacting with version-related endpoints of the Nextmv Cloud API,
6
+ allowing users to define, retrieve, and manage different versions of their
7
+ decision applications.
8
+
9
+ Classes
10
+ -------
11
+ VersionExecutableRequirements
12
+ Defines the requirements for a version's executable, such as type and runtime.
13
+ VersionExecutable
14
+ Represents the executable artifact for a specific application version.
15
+ Version
16
+ Represents a version of an application, linking to its executable and metadata.
17
+ """
2
18
 
3
19
  from datetime import datetime
4
20
 
@@ -6,7 +22,34 @@ from nextmv.base_model import BaseModel
6
22
 
7
23
 
8
24
  class VersionExecutableRequirements(BaseModel):
9
- """Requirements for a version executable."""
25
+ """
26
+ Requirements for a version executable.
27
+
28
+ You can import the `VersionExecutableRequirements` class directly from `cloud`:
29
+
30
+ ```python
31
+ from nextmv.cloud import VersionExecutableRequirements
32
+ ```
33
+
34
+ These requirements specify the environment and type of executable needed
35
+ to run a particular version of an application.
36
+
37
+ Parameters
38
+ ----------
39
+ executable_type : str
40
+ The type of the executable (e.g., "binary", "docker").
41
+ runtime : str
42
+ The runtime environment for the executable (e.g., "go", "python").
43
+
44
+ Examples
45
+ --------
46
+ >>> requirements = VersionExecutableRequirements(
47
+ ... executable_type="binary",
48
+ ... runtime="go1.x"
49
+ ... )
50
+ >>> print(requirements.executable_type)
51
+ binary
52
+ """
10
53
 
11
54
  executable_type: str
12
55
  """Type of the executable."""
@@ -15,7 +58,42 @@ class VersionExecutableRequirements(BaseModel):
15
58
 
16
59
 
17
60
  class VersionExecutable(BaseModel):
18
- """Executable for a version."""
61
+ """
62
+ Executable for a version.
63
+
64
+ You can import the `VersionExecutable` class directly from `cloud`:
65
+
66
+ ```python
67
+ from nextmv.cloud import VersionExecutable
68
+ ```
69
+
70
+ This class holds information about the actual executable file or image
71
+ associated with an application version, including who uploaded it and when.
72
+
73
+ Parameters
74
+ ----------
75
+ id : str
76
+ Unique identifier for the version executable.
77
+ user_email : str
78
+ Email of the user who uploaded the executable.
79
+ uploaded_at : datetime
80
+ Timestamp indicating when the executable was uploaded.
81
+ requirements : VersionExecutableRequirements
82
+ The specific requirements for this executable.
83
+
84
+ Examples
85
+ --------
86
+ >>> from datetime import datetime
87
+ >>> reqs = VersionExecutableRequirements(executable_type="docker", runtime="custom")
88
+ >>> executable = VersionExecutable(
89
+ ... id="exec-123",
90
+ ... user_email="user@example.com",
91
+ ... uploaded_at=datetime.now(),
92
+ ... requirements=reqs
93
+ ... )
94
+ >>> print(executable.id)
95
+ exec-123
96
+ """
19
97
 
20
98
  id: str
21
99
  """ID of the version."""
@@ -28,7 +106,57 @@ class VersionExecutable(BaseModel):
28
106
 
29
107
 
30
108
  class Version(BaseModel):
31
- """A version of an application representing a code artifact or a compiled binary."""
109
+ """
110
+ A version of an application representing a code artifact or a compiled binary.
111
+
112
+ You can import the `Version` class directly from `cloud`:
113
+
114
+ ```python
115
+ from nextmv.cloud import Version
116
+ ```
117
+
118
+ This class encapsulates all details of a specific version of an application,
119
+ including its metadata, associated executable, and timestamps.
120
+
121
+ Parameters
122
+ ----------
123
+ id : str
124
+ Unique identifier for the version.
125
+ application_id : str
126
+ Identifier of the application to which this version belongs.
127
+ name : str
128
+ User-defined name for the version (e.g., "v1.0.0", "feature-branch-build").
129
+ description : str
130
+ A more detailed description of the version and its changes.
131
+ executable : VersionExecutable
132
+ The executable artifact associated with this version.
133
+ created_at : datetime
134
+ Timestamp indicating when the version was created.
135
+ updated_at : datetime
136
+ Timestamp indicating when the version was last updated.
137
+
138
+ Examples
139
+ --------
140
+ >>> from datetime import datetime
141
+ >>> reqs = VersionExecutableRequirements(executable_type="binary", runtime="java11")
142
+ >>> exe = VersionExecutable(
143
+ ... id="exec-abc",
144
+ ... user_email="dev@example.com",
145
+ ... uploaded_at=datetime.now(),
146
+ ... requirements=reqs
147
+ ... )
148
+ >>> version_info = Version(
149
+ ... id="ver-xyz",
150
+ ... application_id="app-123",
151
+ ... name="Initial Release",
152
+ ... description="First stable release of the model.",
153
+ ... executable=exe,
154
+ ... created_at=datetime.now(),
155
+ ... updated_at=datetime.now()
156
+ ... )
157
+ >>> print(version_info.name)
158
+ Initial Release
159
+ """
32
160
 
33
161
  id: str
34
162
  """ID of the version."""
@@ -0,0 +1 @@
1
+ .nextmv
@@ -0,0 +1,32 @@
1
+ # Nextmv application
2
+
3
+ This is the basic structure of a Nextmv application.
4
+
5
+ ```text
6
+ ├── app.yaml
7
+ ├── main.py
8
+ ├── README.md
9
+ ├── requirements.txt
10
+ └── src
11
+ ```
12
+
13
+ * `app.yaml`: App manifest, containing the configuration to run the app
14
+ remotely on Nextmv Cloud.
15
+ * `main.py`: Entry point for the app.
16
+ * `README.md`: Description of the app.
17
+ * `requirements.txt`: Python dependencies for the app.
18
+ * `src/`: Source code for the app.
19
+
20
+ A sample input file is also provided as `input.json`.
21
+
22
+ 1. Install packages.
23
+
24
+ ```bash
25
+ pip install -r requirements.txt
26
+ ```
27
+
28
+ 2. Run the app.
29
+
30
+ ```bash
31
+ cat input.json | python main.py
32
+ ```
@@ -0,0 +1,12 @@
1
+ # This manifest holds the information the app needs to run on the Nextmv Cloud.
2
+ type: python
3
+ runtime: ghcr.io/nextmv-io/runtime/python:3.11
4
+ python:
5
+ # All listed packages will get bundled with the app.
6
+ pip-requirements: requirements.txt
7
+
8
+ # List all files/directories that should be included in the app. Globbing
9
+ # (e.g.: configs/*.json) is supported.
10
+ files:
11
+ - src/
12
+ - main.py
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "Patches",
3
+ "radius": 6378,
4
+ "distance": 147.6
5
+ }
@@ -0,0 +1,37 @@
1
+ from src.visuals import create_visuals
2
+
3
+ import nextmv
4
+
5
+ # Read the input from stdin.
6
+ input = nextmv.load()
7
+ name = input.data["name"]
8
+
9
+ options = nextmv.Options(
10
+ nextmv.Option("details", bool, True, "Print details to logs. Default true.", False),
11
+ )
12
+
13
+ ##### Insert model here
14
+
15
+ # Print logs that render in the run view in Nextmv Console.
16
+ message = f"Hello, {name}"
17
+ nextmv.log(message)
18
+
19
+ if options.details:
20
+ detail = f"You are {input.data['distance']} million km from the sun"
21
+ nextmv.log(detail)
22
+
23
+ assets = create_visuals(name, input.data["radius"], input.data["distance"])
24
+
25
+ # Write output and statistics.
26
+ output = nextmv.Output(
27
+ options=options,
28
+ solution={"message": message},
29
+ statistics=nextmv.Statistics(
30
+ result=nextmv.ResultStatistics(
31
+ value=1.23,
32
+ custom={"message": message},
33
+ ),
34
+ ),
35
+ assets=assets,
36
+ )
37
+ nextmv.write(output)
@@ -0,0 +1,2 @@
1
+ nextmv>=0.29.3
2
+ plotly>=6.2.0
File without changes
@@ -0,0 +1,36 @@
1
+ import json
2
+
3
+ import plotly.graph_objects as go
4
+
5
+ import nextmv
6
+
7
+
8
+ def create_visuals(name: str, radius: float, distance: float) -> list[nextmv.Asset]:
9
+ """Create a Plotly bar chart with radius and distance for a planet."""
10
+
11
+ fig = go.Figure()
12
+ fig.add_trace(
13
+ go.Bar(x=[name], y=[radius], name="Radius (km)", marker_color="red", opacity=0.5),
14
+ )
15
+ fig.add_trace(
16
+ go.Bar(x=[name], y=[distance], name="Distance (Millions km)", marker_color="blue", opacity=0.5),
17
+ )
18
+ fig.update_layout(
19
+ title="Radius and Distance by Planet", xaxis_title="Planet", yaxis_title="Values", barmode="group"
20
+ )
21
+ fig = fig.to_json()
22
+
23
+ assets = [
24
+ nextmv.Asset(
25
+ name="Plotly example",
26
+ content_type="json",
27
+ visual=nextmv.Visual(
28
+ visual_schema=nextmv.VisualSchema.PLOTLY,
29
+ visual_type="custom-tab",
30
+ label="Charts",
31
+ ),
32
+ content=[json.loads(fig)],
33
+ )
34
+ ]
35
+
36
+ return assets
nextmv/deprecated.py ADDED
@@ -0,0 +1,47 @@
1
+ """Utilities for handling deprecated functionality within the Nextmv Python SDK.
2
+
3
+ This module provides tools to mark functions, methods, or features as deprecated,
4
+ emitting appropriate warnings to users. These warnings inform users that the
5
+ functionality will be removed in a future release and suggest alternative approaches.
6
+
7
+ The main purpose of this module is to help with the smooth transition when
8
+ API changes are necessary, giving users time to update their code before
9
+ functionality is removed completely.
10
+ """
11
+
12
+ import warnings
13
+
14
+
15
+ def deprecated(name: str, reason: str) -> None:
16
+ """Mark functionality as deprecated with a warning message.
17
+
18
+ This function emits a DeprecationWarning when called, indicating that
19
+ the functionality will be removed in a future release.
20
+
21
+ Parameters
22
+ ----------
23
+ name : str
24
+ The name of the function, method, or feature being deprecated.
25
+ reason : str
26
+ The reason why the functionality is being deprecated, possibly
27
+ with suggestions for alternative approaches.
28
+
29
+ Notes
30
+ -----
31
+ This function temporarily changes the warning filter to ensure the
32
+ deprecation warning is shown, then resets it afterward.
33
+
34
+ Examples
35
+ --------
36
+ >>> def some_function():
37
+ ... deprecated("feature_x", "Use feature_y instead")
38
+ ... # function implementation
39
+ """
40
+
41
+ warnings.simplefilter("always", DeprecationWarning)
42
+ warnings.warn(
43
+ f"{name}: {reason}. This functionality will be removed in a future release",
44
+ category=DeprecationWarning,
45
+ stacklevel=2,
46
+ )
47
+ warnings.simplefilter("default", DeprecationWarning)