nextmv 1.0.0.dev7__py3-none-any.whl → 1.0.0.dev9__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.
@@ -2,18 +2,18 @@
2
2
  This module defines the community list command for the Nextmv CLI.
3
3
  """
4
4
 
5
- from typing import Annotated
5
+ from typing import Annotated, Any
6
6
 
7
+ import requests
7
8
  import rich
8
9
  import typer
10
+ import yaml
9
11
  from rich.console import Console
10
12
  from rich.table import Table
11
13
 
12
14
  from nextmv.cli.configuration.config import build_client
13
15
  from nextmv.cli.message import error
14
16
  from nextmv.cli.options import ProfileOption
15
- from nextmv.cloud.client import Client
16
- from nextmv.cloud.community import CommunityApp, list_community_apps
17
17
 
18
18
  # Set up subcommand application.
19
19
  app = typer.Typer()
@@ -62,73 +62,96 @@ def list(
62
62
  if app is not None and app == "":
63
63
  error("The --app flag cannot be an empty string.")
64
64
 
65
- client = build_client(profile)
65
+ manifest = download_manifest(profile=profile)
66
66
  if flat and app is None:
67
- _apps_list(client)
67
+ apps_list(manifest)
68
68
  raise typer.Exit()
69
69
  elif not flat and app is None:
70
- _apps_table(client)
70
+ apps_table(manifest)
71
71
  raise typer.Exit()
72
72
  elif flat and app is not None and app != "":
73
- _versions_list(client, app)
73
+ versions_list(manifest, app)
74
74
  raise typer.Exit()
75
75
  elif not flat and app is not None and app != "":
76
- _versions_table(client, app)
76
+ versions_table(manifest, app)
77
77
  raise typer.Exit()
78
78
 
79
79
 
80
- def _apps_table(client: Client) -> None:
80
+ def download_manifest(profile: str | None = None) -> dict:
81
81
  """
82
- This function prints a table of community apps.
82
+ Downloads and returns the community apps manifest.
83
83
 
84
84
  Parameters
85
85
  ----------
86
- client : Client
87
- The Nextmv Cloud client to use for the request.
86
+ profile : str | None
87
+ The profile name to use. If None, the default profile is used.
88
+
89
+ Returns
90
+ -------
91
+ dict
92
+ The community apps manifest as a dictionary.
93
+
94
+ Raises
95
+ requests.HTTPError
96
+ If the response status code is not 2xx.
97
+ """
98
+
99
+ response = download_file(directory="community-apps", file="manifest.yml", profile=profile)
100
+ manifest = yaml.safe_load(response.text)
101
+
102
+ return manifest
103
+
104
+
105
+ def apps_table(manifest: dict[str, Any]) -> None:
106
+ """
107
+ This function prints a table of community apps from the manifest.
108
+
109
+ Parameters
110
+ ----------
111
+ manifest : dict[str, Any]
112
+ The community apps manifest.
88
113
  """
89
114
 
90
- apps = list_community_apps(client)
91
115
  table = Table("Name", "Type", "Latest", "Description", border_style="cyan", header_style="cyan")
92
- for app in apps:
116
+ for app in manifest.get("apps", []):
93
117
  table.add_row(
94
- app.name,
95
- app.app_type,
96
- app.latest_app_version if app.latest_app_version is not None else "",
97
- app.description,
118
+ app.get("name", ""),
119
+ app.get("type", ""),
120
+ app.get("latest_app_version", ""),
121
+ app.get("description", ""),
98
122
  )
99
123
 
100
124
  console.print(table)
101
125
 
102
126
 
103
- def _apps_list(client: Client) -> None:
127
+ def apps_list(manifest: dict[str, Any]) -> None:
104
128
  """
105
- This function prints a flat list of community app names.
129
+ This function prints a flat list of community app names from the manifest.
106
130
 
107
131
  Parameters
108
132
  ----------
109
- client : Client
110
- The Nextmv Cloud client to use for the request.
133
+ manifest : dict[str, Any]
134
+ The community apps manifest.
111
135
  """
112
136
 
113
- apps = list_community_apps(client)
114
- names = [app.name for app in apps]
137
+ names = [app.get("name", "") for app in manifest.get("apps", [])]
115
138
  print("\n".join(names))
116
139
 
117
140
 
118
- def _versions_table(client: Client, app: str) -> None:
141
+ def versions_table(manifest: dict[str, Any], app: str) -> None:
119
142
  """
120
143
  This function prints a table of versions for a specific community app.
121
144
 
122
145
  Parameters
123
146
  ----------
124
- client : Client
125
- The Nextmv Cloud client to use for the request.
147
+ manifest : dict[str, Any]
148
+ The community apps manifest.
126
149
  app : str
127
150
  The name of the community app.
128
151
  """
129
152
 
130
- comm_app = _find_app(client, app)
131
- latest_version = comm_app.latest_app_version if comm_app.latest_app_version is not None else ""
153
+ app_obj = find_app(manifest, app)
154
+ latest_version = app_obj.get("latest_app_version", "")
132
155
 
133
156
  # Add the latest version with indicator
134
157
  table = Table("Version", "Latest?", border_style="cyan", header_style="cyan")
@@ -136,7 +159,7 @@ def _versions_table(client: Client, app: str) -> None:
136
159
  table.add_row("", "") # Empty row to separate latest from others.
137
160
 
138
161
  # Add all other versions (excluding the latest)
139
- versions = comm_app.app_versions if comm_app.app_versions is not None else []
162
+ versions = app_obj.get("app_versions", [])
140
163
  for version in versions:
141
164
  if version != latest_version:
142
165
  table.add_row(version, "")
@@ -144,52 +167,99 @@ def _versions_table(client: Client, app: str) -> None:
144
167
  console.print(table)
145
168
 
146
169
 
147
- def _versions_list(client: Client, app: str) -> None:
170
+ def versions_list(manifest: dict[str, Any], app: str) -> None:
148
171
  """
149
172
  This function prints a flat list of versions for a specific community app.
150
173
 
151
174
  Parameters
152
175
  ----------
153
- client : Client
154
- The Nextmv Cloud client to use for the request.
176
+ manifest : dict[str, Any]
177
+ The community apps manifest.
155
178
  app : str
156
179
  The name of the community app.
157
180
  """
158
181
 
159
- comm_app = _find_app(client, app)
160
- versions = comm_app.app_versions if comm_app.app_versions is not None else []
182
+ app_obj = find_app(manifest, app)
183
+ versions = app_obj.get("app_versions", [])
161
184
 
162
185
  versions_output = ""
163
186
  for version in versions:
164
187
  versions_output += f"{version}\n"
165
188
 
166
- print("\n".join(versions_output))
189
+ print("\n".join(app_obj.get("app_versions", [])))
190
+
191
+
192
+ def download_file(
193
+ directory: str,
194
+ file: str,
195
+ profile: str | None = None,
196
+ ) -> requests.Response:
197
+ """
198
+ Gets a file from an internal bucket and return it.
199
+
200
+ Parameters
201
+ ----------
202
+ directory : str
203
+ The directory in the bucket where the file is located.
204
+ file : str
205
+ The name of the file to download.
206
+ profile : str | None
207
+ The profile name to use. If None, the default profile is used.
208
+
209
+ Returns
210
+ -------
211
+ requests.Response
212
+ The response object containing the file data.
213
+
214
+ Raises
215
+ requests.HTTPError
216
+ If the response status code is not 2xx.
217
+ """
218
+
219
+ client = build_client(profile)
220
+
221
+ # Request the download URL for the file.
222
+ response = client.request(
223
+ method="GET",
224
+ endpoint="v0/internal/tools",
225
+ headers=client.headers | {"request-source": "cli"}, # Pass `client.headers` to preserve auth.
226
+ query_params={"file": f"{directory}/{file}"},
227
+ )
228
+
229
+ # Use the URL obtained to download the file.
230
+ body = response.json()
231
+ download_response = client.request(
232
+ method="GET",
233
+ endpoint=body.get("url"),
234
+ headers={"Content-Type": "application/json"},
235
+ )
236
+
237
+ return download_response
167
238
 
168
239
 
169
- def _find_app(client: Client, app: str) -> CommunityApp | None:
240
+ def find_app(manifest: dict[str, Any], app: str) -> dict[str, Any] | None:
170
241
  """
171
242
  Finds and returns a community app from the manifest by its name.
172
243
 
173
244
  Parameters
174
245
  ----------
175
- client : Client
176
- The Nextmv Cloud client to use for the request.
246
+ manifest : dict[str, Any]
247
+ The community apps manifest.
177
248
  app : str
178
249
  The name of the community app to find.
179
250
 
180
251
  Returns
181
252
  -------
182
- CommunityApp | None
183
- The community app if found, otherwise None.
253
+ dict[str, Any] | None
254
+ The community app dictionary if found, otherwise None.
184
255
  """
185
256
 
186
- comm_apps = list_community_apps(client)
187
- for comm_app in comm_apps:
188
- if comm_app.name == app:
189
- return comm_app
257
+ for manifest_app in manifest.get("apps", []):
258
+ if manifest_app.get("name", "") == app:
259
+ return manifest_app
190
260
 
191
261
  # We don't use error() here to allow printing something before exiting.
192
262
  rich.print(f"[red]Error:[/red] Community app [magenta]{app}[/magenta] was not found. Here are the available apps:")
193
- _apps_table(client)
263
+ apps_table(manifest)
194
264
 
195
265
  raise typer.Exit(code=1)
nextmv/cloud/__init__.py CHANGED
@@ -30,9 +30,6 @@ from .batch_experiment import BatchExperimentRun as BatchExperimentRun
30
30
  from .batch_experiment import ExperimentStatus as ExperimentStatus
31
31
  from .client import Client as Client
32
32
  from .client import get_size as get_size
33
- from .community import CommunityApp as CommunityApp
34
- from .community import clone_community_app as clone_community_app
35
- from .community import list_community_apps as list_community_apps
36
33
  from .ensemble import EnsembleDefinition as EnsembleDefinition
37
34
  from .ensemble import EvaluationRule as EvaluationRule
38
35
  from .ensemble import RuleObjective as RuleObjective
@@ -58,7 +55,6 @@ from .secrets import SecretType as SecretType
58
55
  from .shadow import ShadowTest as ShadowTest
59
56
  from .shadow import ShadowTestMetadata as ShadowTestMetadata
60
57
  from .shadow import StartEvents as StartEvents
61
- from .shadow import StopIntent as StopIntent
62
58
  from .shadow import TerminationEvents as TerminationEvents
63
59
  from .shadow import TestComparison as TestComparison
64
60
  from .switchback import SwitchbackPlan as SwitchbackPlan
@@ -21,7 +21,7 @@ list_application
21
21
  import json
22
22
  import shutil
23
23
  import sys
24
- from datetime import datetime
24
+ from datetime import datetime, timezone
25
25
  from enum import Enum
26
26
  from typing import Any
27
27
 
@@ -46,7 +46,9 @@ from nextmv.cloud.application._switchback import ApplicationSwitchbackMixin
46
46
  from nextmv.cloud.application._utils import _is_not_exist_error
47
47
  from nextmv.cloud.application._version import ApplicationVersionMixin
48
48
  from nextmv.cloud.client import Client
49
+ from nextmv.cloud.instance import Instance
49
50
  from nextmv.cloud.url import UploadURL
51
+ from nextmv.cloud.version import Version
50
52
  from nextmv.logger import log
51
53
  from nextmv.manifest import Manifest
52
54
  from nextmv.model import Model, ModelConfiguration
@@ -405,6 +407,14 @@ class Application(
405
407
  model: Model | None = None,
406
408
  model_configuration: ModelConfiguration | None = None,
407
409
  rich_print: bool = False,
410
+ auto_create: bool = False,
411
+ version_id: str | None = None,
412
+ version_name: str | None = None,
413
+ version_description: str | None = None,
414
+ instance_id: str | None = None,
415
+ instance_name: str | None = None,
416
+ instance_description: str | None = None,
417
+ update_default_instance: bool = False,
408
418
  ) -> None:
409
419
  """
410
420
  Push an app to Nextmv Cloud.
@@ -422,6 +432,17 @@ class Application(
422
432
  `nextmv.Model`. The model is encoded, some dependencies and
423
433
  accompanying files are packaged, and the app is pushed to Nextmv Cloud.
424
434
 
435
+ By default, this function only pushes the app. If you want to
436
+ automatically create a new version and instance after pushing, set
437
+ `auto_create=True`. The `version_id`, `version_name`, and
438
+ `version_description` arguments allow you to customize the new version
439
+ that is created. If not specified, defaults will be generated (random
440
+ ID, timestamped name/description). Similarly, `instance_id`,
441
+ `instance_name`, and `instance_description` can be used to customize
442
+ the new instance. If `update_default_instance` is True, the
443
+ application's default instance will be updated to the newly created
444
+ instance.
445
+
425
446
  Parameters
426
447
  ----------
427
448
  manifest : Optional[Manifest], default=None
@@ -440,6 +461,30 @@ class Application(
440
461
  with `model`.
441
462
  rich_print : bool, default=False
442
463
  Whether to use rich printing when verbose output is enabled.
464
+ auto_create : bool, default=False
465
+ If True, automatically create a new version and instance after
466
+ pushing the app.
467
+ version_id : Optional[str], default=None
468
+ ID of the version to create after pushing the app. If None, a unique
469
+ ID will be generated.
470
+ version_name : Optional[str], default=None
471
+ Name of the version to create after pushing the app. If None, a
472
+ name will be generated.
473
+ version_description : Optional[str], default=None
474
+ Description of the version to create after pushing the app. If None, a
475
+ generic description with a timestamp will be generated.
476
+ instance_id : Optional[str], default=None
477
+ ID of the instance to create after pushing the app. If None, a unique
478
+ ID will be generated.
479
+ instance_name : Optional[str], default=None
480
+ Name of the instance to create after pushing the app. If None, a
481
+ name will be generated.
482
+ instance_description : Optional[str], default=None
483
+ Description of the instance to create after pushing the app. If None,
484
+ a generic description with a timestamp will be generated.
485
+ update_default_instance : bool, default=False
486
+ If True, update the application's default instance to the newly
487
+ created instance.
443
488
 
444
489
  Raises
445
490
  ------
@@ -543,6 +588,44 @@ class Application(
543
588
  except OSError as e:
544
589
  raise Exception(f"error deleting output directory: {e}") from e
545
590
 
591
+ if not auto_create:
592
+ return
593
+
594
+ if verbose:
595
+ if rich_print:
596
+ rich.print(
597
+ f":hourglass_flowing_sand: Push completed for Nextmv application [magenta]{self.id}[/magenta], "
598
+ "creating a new version and instance...",
599
+ file=sys.stderr,
600
+ )
601
+ else:
602
+ log("⌛️ Push completed for the Nextmv application, creating a new version and instance...")
603
+
604
+ now = datetime.now(timezone.utc)
605
+ version = self.__version_on_push(
606
+ now=now,
607
+ version_id=version_id,
608
+ version_name=version_name,
609
+ version_description=version_description,
610
+ verbose=verbose,
611
+ rich_print=rich_print,
612
+ )
613
+ instance = self.__instance_on_push(
614
+ now=now,
615
+ version_id=version.id,
616
+ instance_id=instance_id,
617
+ instance_name=instance_name,
618
+ instance_description=instance_description,
619
+ verbose=verbose,
620
+ rich_print=rich_print,
621
+ )
622
+ self.__update_on_push(
623
+ instance=instance,
624
+ update_default_instance=update_default_instance,
625
+ verbose=verbose,
626
+ rich_print=rich_print,
627
+ )
628
+
546
629
  def update(
547
630
  self,
548
631
  name: str | None = None,
@@ -858,6 +941,120 @@ class Application(
858
941
  log(f'💥️ Successfully pushed to application: "{self.id}".')
859
942
  log(json.dumps(data, indent=2))
860
943
 
944
+ def __version_on_push(
945
+ self,
946
+ now: datetime,
947
+ version_id: str | None = None,
948
+ version_name: str | None = None,
949
+ version_description: str | None = None,
950
+ verbose: bool = False,
951
+ rich_print: bool = False,
952
+ ) -> Version:
953
+ if version_description is None or version_description == "":
954
+ version_description = f"Version created automatically from push at {now.strftime('%Y-%m-%dT%H:%M:%SZ')}"
955
+
956
+ version = self.new_version(
957
+ id=version_id,
958
+ name=version_name,
959
+ description=version_description,
960
+ )
961
+ version_dict = version.to_dict()
962
+
963
+ if not verbose:
964
+ return version
965
+
966
+ if rich_print:
967
+ rich.print(
968
+ f":white_check_mark: Automatically created new version [magenta]{version.id}[/magenta].",
969
+ file=sys.stderr,
970
+ )
971
+ rich.print_json(data=version_dict)
972
+
973
+ return version
974
+
975
+ log(f'✅ Automatically created new version "{version.id}".')
976
+ log(json.dumps(version_dict, indent=2))
977
+
978
+ return version
979
+
980
+ def __instance_on_push(
981
+ self,
982
+ now: datetime,
983
+ version_id: str,
984
+ instance_id: str | None = None,
985
+ instance_name: str | None = None,
986
+ instance_description: str | None = None,
987
+ verbose: bool = False,
988
+ rich_print: bool = False,
989
+ ) -> Instance:
990
+ if instance_description is None or instance_description == "":
991
+ instance_description = f"Instance created automatically from push at {now.strftime('%Y-%m-%dT%H:%M:%SZ')}"
992
+
993
+ instance = self.new_instance(
994
+ version_id=version_id,
995
+ id=instance_id,
996
+ name=instance_name,
997
+ description=instance_description,
998
+ )
999
+ instance_dict = instance.to_dict()
1000
+
1001
+ if not verbose:
1002
+ return instance
1003
+
1004
+ if rich_print:
1005
+ rich.print(
1006
+ f":white_check_mark: Automatically created new instance [magenta]{instance.id}[/magenta] "
1007
+ f"using version [magenta]{version_id}[/magenta].",
1008
+ file=sys.stderr,
1009
+ )
1010
+ rich.print_json(data=instance_dict)
1011
+
1012
+ return instance
1013
+
1014
+ log(f'✅ Automatically created new instance "{instance.id}" using version "{version_id}".')
1015
+ log(json.dumps(instance_dict, indent=2))
1016
+
1017
+ return instance
1018
+
1019
+ def __update_on_push(
1020
+ self,
1021
+ instance: Instance,
1022
+ update_default_instance: bool = False,
1023
+ verbose: bool = False,
1024
+ rich_print: bool = False,
1025
+ ) -> None:
1026
+ if not update_default_instance:
1027
+ return
1028
+
1029
+ if verbose:
1030
+ if rich_print:
1031
+ rich.print(
1032
+ f":hourglass_flowing_sand: Updating default instance for app [magenta]{self.id}[/magenta]...",
1033
+ file=sys.stderr,
1034
+ )
1035
+ else:
1036
+ log("⌛️ Updating default instance for the Nextmv application...")
1037
+
1038
+ updated_app = self.update(default_instance_id=instance.id)
1039
+ if not verbose:
1040
+ return
1041
+
1042
+ if rich_print:
1043
+ rich.print(
1044
+ f":white_check_mark: Updated default instance to "
1045
+ f"[magenta]{updated_app.default_instance_id}[/magenta] for application "
1046
+ f"[magenta]{self.id}[/magenta].",
1047
+ file=sys.stderr,
1048
+ )
1049
+ rich.print_json(data=updated_app.to_dict())
1050
+
1051
+ return
1052
+
1053
+ log(
1054
+ f'✅ Updated default instance to "{updated_app.default_instance_id}" for application "{self.id}".',
1055
+ )
1056
+ log(json.dumps(updated_app.to_dict(), indent=2))
1057
+
861
1058
 
862
1059
  def list_applications(client: Client) -> list[Application]:
863
1060
  """
@@ -9,7 +9,6 @@ import requests
9
9
  from nextmv.cloud.acceptance_test import AcceptanceTest, Metric
10
10
  from nextmv.cloud.batch_experiment import BatchExperimentRun, ExperimentStatus
11
11
  from nextmv.polling import DEFAULT_POLLING_OPTIONS, PollingOptions, poll
12
- from nextmv.safe import safe_id
13
12
 
14
13
  if TYPE_CHECKING:
15
14
  from . import Application
@@ -164,8 +163,8 @@ class ApplicationAcceptanceMixin:
164
163
  self: "Application",
165
164
  candidate_instance_id: str,
166
165
  baseline_instance_id: str,
166
+ id: str,
167
167
  metrics: list[Metric | dict[str, Any]],
168
- id: str | None = None,
169
168
  name: str | None = None,
170
169
  input_set_id: str | None = None,
171
170
  description: str | None = None,
@@ -186,8 +185,8 @@ class ApplicationAcceptanceMixin:
186
185
  ID of the candidate instance.
187
186
  baseline_instance_id : str
188
187
  ID of the baseline instance.
189
- id : str | None, default=None
190
- ID of the acceptance test. Will be generated if not provided.
188
+ id : str
189
+ ID of the acceptance test.
191
190
  metrics : list[Union[Metric, dict[str, Any]]]
192
191
  List of metrics to use for the acceptance test.
193
192
  name : Optional[str], default=None
@@ -211,11 +210,6 @@ class ApplicationAcceptanceMixin:
211
210
  If the batch experiment ID does not match the acceptance test ID.
212
211
  """
213
212
 
214
- # Generate ID if not provided
215
- if id is None or id == "":
216
- id = safe_id("acceptance")
217
-
218
- # Use ID as name if name not provided
219
213
  if name is None or name == "":
220
214
  name = id
221
215
 
@@ -271,10 +265,11 @@ class ApplicationAcceptanceMixin:
271
265
  "metrics": payload_metrics,
272
266
  "experiment_id": batch_experiment_id,
273
267
  "name": name,
274
- "id": id,
275
268
  }
276
269
  if description is not None:
277
270
  payload["description"] = description
271
+ if id is not None:
272
+ payload["id"] = id
278
273
 
279
274
  response = self.client.request(
280
275
  method="POST",
@@ -288,8 +283,8 @@ class ApplicationAcceptanceMixin:
288
283
  self: "Application",
289
284
  candidate_instance_id: str,
290
285
  baseline_instance_id: str,
286
+ id: str,
291
287
  metrics: list[Metric | dict[str, Any]],
292
- id: str | None = None,
293
288
  name: str | None = None,
294
289
  input_set_id: str | None = None,
295
290
  description: str | None = None,
@@ -307,8 +302,8 @@ class ApplicationAcceptanceMixin:
307
302
  ID of the candidate instance.
308
303
  baseline_instance_id : str
309
304
  ID of the baseline instance.
310
- id : str | None, default=None
311
- ID of the acceptance test. Will be generated if not provided.
305
+ id : str
306
+ ID of the acceptance test.
312
307
  metrics : list[Union[Metric, dict[str, Any]]]
313
308
  List of metrics to use for the acceptance test.
314
309
  name : Optional[str], default=None
@@ -6,7 +6,6 @@ from datetime import datetime
6
6
  from typing import TYPE_CHECKING
7
7
 
8
8
  from nextmv.cloud.input_set import InputSet, ManagedInput
9
- from nextmv.safe import safe_id
10
9
 
11
10
  if TYPE_CHECKING:
12
11
  from . import Application
@@ -17,32 +16,6 @@ class ApplicationInputSetMixin:
17
16
  Mixin class for managing app input sets within an application.
18
17
  """
19
18
 
20
- def delete_input_set(self: "Application", input_set_id: str) -> None:
21
- """
22
- Delete an input set.
23
-
24
- Deletes an input set along with all the associated information.
25
-
26
- Parameters
27
- ----------
28
- input_set_id : str
29
- ID of the input set to delete.
30
-
31
- Raises
32
- ------
33
- requests.HTTPError
34
- If the response status code is not 2xx.
35
-
36
- Examples
37
- --------
38
- >>> app.delete_input_set("input-set-123")
39
- """
40
-
41
- _ = self.client.request(
42
- method="DELETE",
43
- endpoint=f"{self.experiments_endpoint}/inputsets/{input_set_id}",
44
- )
45
-
46
19
  def input_set(self: "Application", input_set_id: str) -> InputSet:
47
20
  """
48
21
  Get an input set.
@@ -108,8 +81,8 @@ class ApplicationInputSetMixin:
108
81
 
109
82
  def new_input_set(
110
83
  self: "Application",
111
- id: str | None = None,
112
- name: str | None = None,
84
+ id: str,
85
+ name: str,
113
86
  description: str | None = None,
114
87
  end_time: datetime | None = None,
115
88
  instance_id: str | None = None,
@@ -134,11 +107,10 @@ class ApplicationInputSetMixin:
134
107
 
135
108
  Parameters
136
109
  ----------
137
- id: str | None = None
138
- ID of the input set, will be generated if not provided.
139
- name: str | None = None
140
- Name of the input set. If not provided, the ID will be used as
141
- the name.
110
+ id: str
111
+ ID of the input set
112
+ name: str
113
+ Name of the input set.
142
114
  description: Optional[str]
143
115
  Optional description of the input set.
144
116
  end_time: Optional[datetime]
@@ -173,14 +145,6 @@ class ApplicationInputSetMixin:
173
145
  If the response status code is not 2xx.
174
146
  """
175
147
 
176
- # Generate ID if not provided
177
- if id is None or id == "":
178
- id = safe_id("input-set")
179
-
180
- # Use ID as name if name not provided
181
- if name is None or name == "":
182
- name = id
183
-
184
148
  payload = {
185
149
  "id": id,
186
150
  "name": name,