cognite-toolkit 0.7.53__py3-none-any.whl → 0.7.55__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 (26) hide show
  1. cognite_toolkit/_cdf_tk/apps/_download_app.py +19 -42
  2. cognite_toolkit/_cdf_tk/apps/_migrate_app.py +28 -36
  3. cognite_toolkit/_cdf_tk/apps/_purge.py +14 -15
  4. cognite_toolkit/_cdf_tk/apps/_upload_app.py +3 -9
  5. cognite_toolkit/_cdf_tk/commands/_profile.py +1 -1
  6. cognite_toolkit/_cdf_tk/commands/_purge.py +3 -3
  7. cognite_toolkit/_cdf_tk/commands/auth.py +12 -15
  8. cognite_toolkit/_cdf_tk/commands/clean.py +2 -1
  9. cognite_toolkit/_cdf_tk/commands/dump_resource.py +30 -19
  10. cognite_toolkit/_cdf_tk/commands/init.py +3 -3
  11. cognite_toolkit/_cdf_tk/commands/modules.py +17 -10
  12. cognite_toolkit/_cdf_tk/commands/pull.py +2 -2
  13. cognite_toolkit/_cdf_tk/commands/repo.py +1 -1
  14. cognite_toolkit/_cdf_tk/commands/resources.py +8 -5
  15. cognite_toolkit/_cdf_tk/commands/run.py +8 -7
  16. cognite_toolkit/_cdf_tk/resource_classes/migration.py +1 -1
  17. cognite_toolkit/_cdf_tk/utils/auth.py +7 -7
  18. cognite_toolkit/_cdf_tk/utils/interactive_select.py +49 -49
  19. cognite_toolkit/_repo_files/GitHub/.github/workflows/deploy.yaml +1 -1
  20. cognite_toolkit/_repo_files/GitHub/.github/workflows/dry-run.yaml +1 -1
  21. cognite_toolkit/_resources/cdf.toml +1 -1
  22. cognite_toolkit/_version.py +1 -1
  23. {cognite_toolkit-0.7.53.dist-info → cognite_toolkit-0.7.55.dist-info}/METADATA +1 -1
  24. {cognite_toolkit-0.7.53.dist-info → cognite_toolkit-0.7.55.dist-info}/RECORD +26 -26
  25. {cognite_toolkit-0.7.53.dist-info → cognite_toolkit-0.7.55.dist-info}/WHEEL +0 -0
  26. {cognite_toolkit-0.7.53.dist-info → cognite_toolkit-0.7.55.dist-info}/entry_points.txt +0 -0
@@ -129,7 +129,7 @@ class InitCommand(ToolkitCommand):
129
129
  "Select a task:",
130
130
  choices=choices,
131
131
  default=default_value,
132
- ).ask()
132
+ ).unsafe_ask()
133
133
 
134
134
  # User cancelled (Ctrl+C or similar)
135
135
  if selected is None:
@@ -161,7 +161,7 @@ class InitCommand(ToolkitCommand):
161
161
  confirm = questionary.confirm(
162
162
  f"'{selected_item.description}' was already run {status_text}",
163
163
  default=False,
164
- ).ask()
164
+ ).unsafe_ask()
165
165
  if not confirm:
166
166
  continue
167
167
 
@@ -218,7 +218,7 @@ class InitCommand(ToolkitCommand):
218
218
  opt_in = questionary.confirm(
219
219
  "Do you want to opt in to collect usage statistics? This will help us improve the Toolkit.",
220
220
  default=True,
221
- ).ask()
221
+ ).unsafe_ask()
222
222
  if dry_run:
223
223
  print("Would opt in to collect data" if opt_in else "Would not opt in to collect data")
224
224
  return
@@ -181,7 +181,7 @@ class ModulesCommand(ToolkitCommand):
181
181
  if questionary.confirm(
182
182
  f"{INDENT}Module {module.name} already exists in folder {target_dir}. Would you like to overwrite?",
183
183
  default=False,
184
- ).ask():
184
+ ).unsafe_ask():
185
185
  safe_rmtree(target_dir)
186
186
  else:
187
187
  continue
@@ -351,7 +351,10 @@ class ModulesCommand(ToolkitCommand):
351
351
  # Need to rerun the mode as bootcamp has a hardcoded organization directory
352
352
  mode = self._verify_clean(bootcamp_org / MODULES, clean)
353
353
  # We only ask to verify if the user has not already selected overwrite in the _verify_clean method
354
- if mode == "clean" or questionary.confirm("Would you like to continue with creation?", default=True).ask():
354
+ if (
355
+ mode == "clean"
356
+ or questionary.confirm("Would you like to continue with creation?", default=True).unsafe_ask()
357
+ ):
355
358
  self._create(
356
359
  organization_dir=bootcamp_org,
357
360
  selected_packages=selected,
@@ -363,7 +366,7 @@ class ModulesCommand(ToolkitCommand):
363
366
 
364
367
  if (
365
368
  not is_interactive
366
- and not questionary.confirm("Would you like to continue with creation?", default=True).ask()
369
+ and not questionary.confirm("Would you like to continue with creation?", default=True).unsafe_ask()
367
370
  ):
368
371
  print("Exiting...")
369
372
  raise typer.Exit()
@@ -380,7 +383,8 @@ class ModulesCommand(ToolkitCommand):
380
383
  qmark=INDENT,
381
384
  pointer=POINTER,
382
385
  style=custom_style_fancy,
383
- ).ask()
386
+ validate=lambda choices: True if choices else "You must select at least one environment.",
387
+ ).unsafe_ask()
384
388
  else:
385
389
  environments = user_environments
386
390
 
@@ -425,7 +429,7 @@ class ModulesCommand(ToolkitCommand):
425
429
  )
426
430
  )
427
431
 
428
- organization_dir_raw = questionary.text(message="", default="").ask()
432
+ organization_dir_raw = questionary.text(message="", default="").unsafe_ask()
429
433
  return Path(organization_dir_raw.strip())
430
434
 
431
435
  @staticmethod
@@ -438,7 +442,7 @@ class ModulesCommand(ToolkitCommand):
438
442
  download_data = questionary.confirm(
439
443
  f"The modules {humanize_collection(example_data)} has example data. Would you like to download it?",
440
444
  default=True,
441
- ).ask()
445
+ ).unsafe_ask()
442
446
  return download_data
443
447
 
444
448
  def _select_modules_in_package(self, package: Package) -> list[ModuleLocation]:
@@ -467,7 +471,8 @@ class ModulesCommand(ToolkitCommand):
467
471
  qmark=INDENT,
468
472
  pointer=POINTER,
469
473
  style=custom_style_fancy,
470
- ).ask()
474
+ validate=lambda choices: True if choices else "You must select at least one module.",
475
+ ).unsafe_ask()
471
476
 
472
477
  def _select_packages(self, packages: Packages, existing_module_names: list[str] | None = None) -> Packages:
473
478
  adding_to_existing = False
@@ -488,7 +493,9 @@ class ModulesCommand(ToolkitCommand):
488
493
  print(Padding.indent(tree, 5))
489
494
  print("\n")
490
495
 
491
- if not questionary.confirm("Would you like to make changes to the selection?", default=False).ask():
496
+ if not questionary.confirm(
497
+ "Would you like to make changes to the selection?", default=False
498
+ ).unsafe_ask():
492
499
  break
493
500
 
494
501
  if not any([len(package.modules) > 0 for package in packages.values()]):
@@ -510,7 +517,7 @@ class ModulesCommand(ToolkitCommand):
510
517
  choices=choices,
511
518
  pointer=POINTER,
512
519
  style=custom_style_fancy,
513
- ).ask()
520
+ ).unsafe_ask()
514
521
 
515
522
  if package is None:
516
523
  raise typer.Exit(code=0)
@@ -545,7 +552,7 @@ class ModulesCommand(ToolkitCommand):
545
552
  pointer=POINTER,
546
553
  style=custom_style_fancy,
547
554
  instruction="use arrow up/down and " + "⮐ " + " to save",
548
- ).ask()
555
+ ).unsafe_ask()
549
556
  if user_selection == "abort":
550
557
  print("Aborting...")
551
558
  raise typer.Exit()
@@ -436,7 +436,7 @@ class PullCommand(ToolkitCommand):
436
436
  selected = questionary.select(
437
437
  "Select a module to pull",
438
438
  choices=[Choice(title=module.name, value=module.name) for module in modules],
439
- ).ask()
439
+ ).unsafe_ask()
440
440
  else:
441
441
  selected = parse_user_selected_modules([module_name_or_path])[0]
442
442
  build_module: str | Path
@@ -629,7 +629,7 @@ class PullCommand(ToolkitCommand):
629
629
  return questionary.select(
630
630
  f"Select a {loader.display_name} to pull",
631
631
  choices=[Choice(title=f"{r.identifier!r} - ({r.module_name})", value=r) for r in local_resources],
632
- ).ask()
632
+ ).unsafe_ask()
633
633
  if id_ not in local_resources.identifiers:
634
634
  raise ToolkitMissingResourceError(
635
635
  f"No {loader.display_name} with external id {id_} found in the current configuration in {organization_dir}."
@@ -52,7 +52,7 @@ class RepoCommand(ToolkitCommand):
52
52
  )
53
53
 
54
54
  if host is None:
55
- repo_host = questionary.select("Where do are you hosting the repository?", REPOSITORY_HOSTING).ask()
55
+ repo_host = questionary.select("Where do are you hosting the repository?", REPOSITORY_HOSTING).unsafe_ask()
56
56
  else:
57
57
  repo_host = next(
58
58
  (provider for provider in REPOSITORY_HOSTING if provider.casefold() == host.casefold()), "Other"
@@ -32,7 +32,7 @@ class ResourcesCommand(ToolkitCommand):
32
32
  if mod.name.casefold() == module.casefold():
33
33
  return mod.dir
34
34
 
35
- if questionary.confirm(f"{module} module not found. Do you want to create a new one?").ask():
35
+ if questionary.confirm(f"{module} module not found. Do you want to create a new one?").unsafe_ask():
36
36
  return organization_dir / MODULES / module
37
37
 
38
38
  if verbose:
@@ -44,10 +44,10 @@ class ResourcesCommand(ToolkitCommand):
44
44
  choices = [Choice(title=mod.name, value=mod.dir) for mod in present_modules]
45
45
  choices.append(Choice(title="<Create new module>", value="NEW"))
46
46
 
47
- selected = questionary.select("Select a module:", choices=choices).ask()
47
+ selected = questionary.select("Select a module:", choices=choices).unsafe_ask()
48
48
 
49
49
  if selected == "NEW":
50
- new_module_name = questionary.text("Enter name for new module:").ask()
50
+ new_module_name = questionary.text("Enter name for new module:").unsafe_ask()
51
51
  if not new_module_name:
52
52
  print("[red]No module name provided. Aborting...[/red]")
53
53
  raise typer.Exit()
@@ -69,7 +69,7 @@ class ResourcesCommand(ToolkitCommand):
69
69
  sorted_cruds = sorted(RESOURCE_CRUD_LIST, key=lambda x: x.kind)
70
70
  choices = [Choice(title=crud.kind, value=crud) for crud in sorted_cruds]
71
71
 
72
- selected = questionary.select("Select resource type:", choices=choices).ask()
72
+ selected = questionary.select("Select resource type:", choices=choices).unsafe_ask()
73
73
  if not selected:
74
74
  print("[red]No resource type selected. Aborting...[/red]")
75
75
  raise typer.Exit()
@@ -142,7 +142,10 @@ class ResourcesCommand(ToolkitCommand):
142
142
  file_name = f"{final_prefix}.{resource_crud.kind}.yaml"
143
143
  file_path: Path = resource_dir / file_name
144
144
 
145
- if file_path.exists() and not questionary.confirm(f"{file_path.name} file already exists. Overwrite?").ask():
145
+ if (
146
+ file_path.exists()
147
+ and not questionary.confirm(f"{file_path.name} file already exists. Overwrite?").unsafe_ask()
148
+ ):
146
149
  print("[red]Skipping...[/red]")
147
150
  return
148
151
 
@@ -153,7 +153,7 @@ if __name__ == "__main__":
153
153
  )
154
154
 
155
155
  if is_interactive:
156
- wait = questionary.confirm("Do you want to wait for the function to complete?").ask()
156
+ wait = questionary.confirm("Do you want to wait for the function to complete?").unsafe_ask()
157
157
 
158
158
  # Todo: Get one shot token using the call_args.authentication
159
159
  session = client.iam.sessions.create(session_type="ONESHOT_TOKEN_EXCHANGE")
@@ -220,7 +220,7 @@ if __name__ == "__main__":
220
220
  # Interactive mode
221
221
  external_id = questionary.select(
222
222
  "Select function to run", choices=list(function_builds_by_identifier.keys())
223
- ).ask()
223
+ ).unsafe_ask()
224
224
  elif external_id not in function_builds_by_identifier.keys():
225
225
  raise ToolkitMissingResourceError(f"Could not find function with external id {external_id}")
226
226
  return function_builds_by_identifier[external_id]
@@ -235,7 +235,8 @@ if __name__ == "__main__":
235
235
  is_interactive: bool,
236
236
  ) -> FunctionCallArgs:
237
237
  if data_source is None and (
238
- not is_interactive or not questionary.confirm("Do you want to provide input data for the function?").ask()
238
+ not is_interactive
239
+ or not questionary.confirm("Do you want to provide input data for the function?").unsafe_ask()
239
240
  ):
240
241
  return FunctionCallArgs()
241
242
  if is_interactive:
@@ -315,7 +316,7 @@ if __name__ == "__main__":
315
316
  if len(options) == 0:
316
317
  print(f"No schedules or workflows found for this {function_external_id} function.")
317
318
  return {}, None
318
- selected_name: str = questionary.select("Select schedule to run", choices=options).ask() # type: ignore[arg-type]
319
+ selected_name: str = questionary.select("Select schedule to run", choices=options).unsafe_ask() # type: ignore[arg-type]
319
320
  selected = options[selected_name]
320
321
  if isinstance(selected, BuiltResourceFull):
321
322
  # Schedule
@@ -689,7 +690,7 @@ class RunWorkflowCommand(ToolkitCommand):
689
690
  if external_id is None:
690
691
  # Interactive mode
691
692
  choices = [questionary.Choice(title=f"{build.identifier!r}", value=build) for build in workflows]
692
- selected = questionary.select("Select workflow to run", choices=choices).ask()
693
+ selected = questionary.select("Select workflow to run", choices=choices).unsafe_ask()
693
694
  else:
694
695
  selected_ = next(
695
696
  (
@@ -719,7 +720,7 @@ class RunWorkflowCommand(ToolkitCommand):
719
720
  is_interactive
720
721
  and not questionary.confirm(
721
722
  "Do you want to use input data and authentication from this trigger?"
722
- ).ask()
723
+ ).unsafe_ask()
723
724
  ):
724
725
  break
725
726
  credentials = (
@@ -750,7 +751,7 @@ class RunWorkflowCommand(ToolkitCommand):
750
751
  raise AuthorizationError(f"Could not create oneshot session for workflow {id_!r}: {e!s}") from e
751
752
 
752
753
  if is_interactive:
753
- wait = questionary.confirm("Do you want to wait for the workflow to complete?").ask()
754
+ wait = questionary.confirm("Do you want to wait for the workflow to complete?").unsafe_ask()
754
755
  if id_.version is None:
755
756
  raise ToolkitValueError("Version is required for workflow.")
756
757
  execution = client.workflows.executions.run(
@@ -15,7 +15,7 @@ class ResourceViewMappingYAML(ToolkitResource):
15
15
  max_length=256,
16
16
  pattern=INSTANCE_EXTERNAL_ID_PATTERN,
17
17
  )
18
- resource_type: Literal["asset", "event", "file", "timeSeries", "sequence", "assetAnnotation", "fileAnnotation"] = (
18
+ resource_type: Literal["asset", "event", "file", "timeseries", "sequence", "assetAnnotation", "fileAnnotation"] = (
19
19
  Field(
20
20
  description="The type of the resource to map to the view.",
21
21
  )
@@ -450,7 +450,7 @@ def prompt_user_environment_variables(current: EnvironmentVariables | None = Non
450
450
  if provider != "cdf"
451
451
  ],
452
452
  default=current.PROVIDER if current else "entra_id",
453
- ).ask()
453
+ ).unsafe_ask()
454
454
  exclude = set()
455
455
  if provider == "cdf":
456
456
  exclude = set(VALID_LOGIN_FLOWS) - {"client_credentials"}
@@ -467,10 +467,10 @@ def prompt_user_environment_variables(current: EnvironmentVariables | None = Non
467
467
  "Choose the login flow (How do you going to authenticate?)",
468
468
  choices=choices,
469
469
  default=current.LOGIN_FLOW if current else "client_credentials",
470
- ).ask()
470
+ ).unsafe_ask()
471
471
 
472
- cdf_cluster = questionary.text("Enter the CDF cluster", default=current.CDF_CLUSTER if current else "").ask()
473
- cdf_project = questionary.text("Enter the CDF project", default=current.CDF_PROJECT if current else "").ask()
472
+ cdf_cluster = questionary.text("Enter the CDF cluster", default=current.CDF_CLUSTER if current else "").unsafe_ask()
473
+ cdf_project = questionary.text("Enter the CDF project", default=current.CDF_PROJECT if current else "").unsafe_ask()
474
474
  args: dict[str, Any] = (
475
475
  current.dump(include_os=False)
476
476
  if current and _is_unchanged(current, provider, login_flow, cdf_project, cdf_cluster) # type: ignore[arg-type]
@@ -490,7 +490,7 @@ def prompt_user_environment_variables(current: EnvironmentVariables | None = Non
490
490
  optional_values = env_vars.get_optional_with_value()
491
491
  for field_, value in optional_values:
492
492
  print(f" {field_.name}={value}")
493
- if questionary.confirm("Do you want to change any of these variables?", default=False).ask():
493
+ if questionary.confirm("Do you want to change any of these variables?", default=False).unsafe_ask():
494
494
  for field_, value in optional_values:
495
495
  user_value = get_user_value(field_, value, provider, cdf_cluster, cdf_project, idp_tenant_id)
496
496
  setattr(env_vars, field_.name, user_value)
@@ -517,9 +517,9 @@ def get_user_value(
517
517
  elif value is not None and not isinstance(value, str):
518
518
  default = str(value)
519
519
  if is_secret:
520
- user_value = questionary.password(f"Enter the {display_name}:", default=default).ask()
520
+ user_value = questionary.password(f"Enter the {display_name}:", default=default).unsafe_ask()
521
521
  else:
522
- user_value = questionary.text(f"Enter the {display_name}:", default=default).ask()
522
+ user_value = questionary.text(f"Enter the {display_name}:", default=default).unsafe_ask()
523
523
  if user_value is None:
524
524
  raise typer.Exit(0)
525
525
  if field_.type is int:
@@ -140,9 +140,7 @@ class AssetCentricInteractiveSelect(ABC):
140
140
  def select_hierarchies_or_data_sets(self) -> Literal["Hierarchy", "Data Set"]:
141
141
  what = questionary.select(
142
142
  f"Do you want to {self.operation} a hierarchy or a data set?", choices=["Hierarchy", "Data Set"]
143
- ).ask()
144
- if what is None:
145
- raise ToolkitValueError("No selection made. Aborting.")
143
+ ).unsafe_ask()
146
144
  if what not in ["Hierarchy", "Data Set"]:
147
145
  raise ToolkitValueError(f"Unexpected selection: {what}. Aborting.")
148
146
  return what
@@ -209,9 +207,13 @@ class AssetCentricInteractiveSelect(ABC):
209
207
 
210
208
  message = f"Select a {what} to {self.operation} listed as 'name (external_id) [count]'"
211
209
  if plurality == "multiple":
212
- selected = questionary.checkbox(message, choices=choices).ask()
210
+ selected = questionary.checkbox(
211
+ message,
212
+ choices=choices,
213
+ validate=lambda choices: "You must select at least one." if not choices else True,
214
+ ).unsafe_ask()
213
215
  else:
214
- selected = questionary.select(message, choices=choices).ask()
216
+ selected = questionary.select(message, choices=choices).unsafe_ask()
215
217
  if selected is None:
216
218
  raise ToolkitValueError(f"No {what} selected. Aborting.")
217
219
  elif selected is none_sentinel or (isinstance(selected, list) and none_sentinel in selected):
@@ -267,9 +269,7 @@ class RawTableInteractiveSelect:
267
269
  selected_database = questionary.select(
268
270
  f"Select a Raw Database to {self.operation}",
269
271
  choices=[questionary.Choice(title=db, value=db) for db in databases],
270
- ).ask()
271
- if selected_database is None:
272
- raise ToolkitValueError("No database selected. Aborting.")
272
+ ).unsafe_ask()
273
273
  available_tables = self._available_tables(selected_database)
274
274
  if not available_tables:
275
275
  raise ToolkitValueError(f"No raw tables available in database '{selected_database}'. Aborting.")
@@ -277,10 +277,9 @@ class RawTableInteractiveSelect:
277
277
  selected_tables = questionary.checkbox(
278
278
  f"Select Raw Tables in {selected_database} to {self.operation}",
279
279
  choices=[questionary.Choice(title=f"{table.table_name}", value=table) for table in available_tables],
280
- ).ask()
280
+ validate=lambda choices: True if choices else "You must select at least one table.",
281
+ ).unsafe_ask()
281
282
 
282
- if selected_tables is None:
283
- raise ToolkitValueError("No tables selected. Aborting.")
284
283
  return selected_tables
285
284
 
286
285
 
@@ -330,9 +329,7 @@ class InteractiveCanvasSelect:
330
329
  user_response = questionary.select(
331
330
  "Which Canvases do you want to select?",
332
331
  choices=cls.opening_choices,
333
- ).ask()
334
- if user_response is None:
335
- raise ToolkitValueError("No Canvas selection made. Aborting.")
332
+ ).unsafe_ask()
336
333
  return user_response
337
334
 
338
335
  def _select_external_ids(self, select_filter: CanvasFilter) -> list[str]:
@@ -356,12 +353,15 @@ class InteractiveCanvasSelect:
356
353
  for user in users
357
354
  if user.user_identifier in canvas_by_user
358
355
  ],
359
- ).ask()
356
+ ).unsafe_ask()
360
357
  available_canvases = NodeList[Canvas](user_response)
361
358
 
362
359
  if select_filter.select_all:
363
360
  return [canvas.external_id for canvas in available_canvases]
364
361
 
362
+ if not available_canvases:
363
+ raise ToolkitValueError("No Canvases available to select. Aborting.")
364
+
365
365
  selected_canvases = questionary.checkbox(
366
366
  "Select Canvases",
367
367
  choices=[
@@ -371,7 +371,8 @@ class InteractiveCanvasSelect:
371
371
  )
372
372
  for canvas in available_canvases
373
373
  ],
374
- ).ask()
374
+ validate=lambda selected: "You must select at least one Canvas." if not selected else True,
375
+ ).unsafe_ask()
375
376
 
376
377
  return selected_canvases or []
377
378
 
@@ -403,9 +404,7 @@ class InteractiveChartSelect:
403
404
  user_response = questionary.select(
404
405
  "Which Charts do you want to select?",
405
406
  choices=cls.opening_choices,
406
- ).ask()
407
- if user_response is None:
408
- raise ToolkitValueError("No Chart selection made. Aborting.")
407
+ ).unsafe_ask()
409
408
  return user_response
410
409
 
411
410
  def _select_external_ids(self, select_filter: ChartFilter) -> list[str]:
@@ -432,7 +431,8 @@ class InteractiveChartSelect:
432
431
  )
433
432
  for chart in available_charts
434
433
  ],
435
- ).ask()
434
+ validate=lambda selected: "You must select at least one Chart." if not selected else True,
435
+ ).unsafe_ask()
436
436
  return selected_charts or []
437
437
 
438
438
  @classmethod
@@ -450,7 +450,7 @@ class InteractiveChartSelect:
450
450
  for user in users
451
451
  if user.user_identifier in chart_by_user
452
452
  ],
453
- ).ask()
453
+ ).unsafe_ask()
454
454
  available_charts = ChartList(user_response)
455
455
  return available_charts
456
456
 
@@ -473,9 +473,7 @@ class AssetCentricDestinationSelect:
473
473
  destination_type = questionary.select(
474
474
  "Select a destination type",
475
475
  choices=[questionary.Choice(title=dest.capitalize(), value=dest) for dest in cls.valid_destinations],
476
- ).ask()
477
- if destination_type is None:
478
- raise ToolkitValueError("No destination type selected. Aborting.")
476
+ ).unsafe_ask()
479
477
  # We only input valid destination types, so we can safely skip MyPy's type checking here
480
478
  return destination_type
481
479
 
@@ -579,11 +577,13 @@ class DataModelingSelect:
579
577
  question = message or f"Which view do you want to use to select instances to {self.operation}?"
580
578
  choices = [Choice(title=f"{view.external_id} (version={view.version})", value=view) for view in views]
581
579
  if multiselect:
582
- selected_views = questionary.checkbox(question, choices=choices).ask()
580
+ selected_views = questionary.checkbox(
581
+ question,
582
+ choices=choices,
583
+ validate=lambda choises: True if choises else "You must select at least one view.",
584
+ ).unsafe_ask()
583
585
  else:
584
- selected_views = questionary.select(question, choices=choices).ask()
585
- if selected_views is None:
586
- raise ToolkitValueError("No view(s) selected")
586
+ selected_views = questionary.select(question, choices=choices).unsafe_ask()
587
587
  if multiselect:
588
588
  if not isinstance(selected_views, list) or not all(isinstance(v, View) for v in selected_views):
589
589
  raise ToolkitValueError(f"Selected views is not a valid list of View objects: {selected_views!r}")
@@ -607,9 +607,7 @@ class DataModelingSelect:
607
607
  selected_space = questionary.select(
608
608
  message,
609
609
  [Choice(title=space.space, value=space) for space in sorted(spaces, key=lambda s: s.space)],
610
- ).ask()
611
- if selected_space is None:
612
- raise ToolkitValueError("No space selected")
610
+ ).unsafe_ask()
613
611
  if not isinstance(selected_space, Space):
614
612
  raise ToolkitValueError(f"Selected space is not a valid Space object: {selected_space!r}")
615
613
  return selected_space
@@ -634,9 +632,8 @@ class DataModelingSelect:
634
632
  Choice(title="Nodes", value="node"),
635
633
  Choice(title="Edges", value="edge"),
636
634
  ],
637
- ).ask()
638
- if selected_instance_type is None:
639
- raise ToolkitValueError("No instance type selected")
635
+ ).unsafe_ask()
636
+
640
637
  if selected_instance_type not in ("node", "edge"):
641
638
  raise ToolkitValueError(f"Selected instance type is not valid: {selected_instance_type!r}")
642
639
  return selected_instance_type
@@ -649,9 +646,7 @@ class DataModelingSelect:
649
646
  Choice(title="Schema spaces with schema", value="schema"),
650
647
  Choice(title="Empty spaces without schema or instances", value="empty"),
651
648
  ],
652
- ).ask()
653
- if selected_space_type is None:
654
- raise ToolkitValueError("No space type selected")
649
+ ).unsafe_ask()
655
650
  if selected_space_type not in ["instance", "schema", "empty"]:
656
651
  raise ToolkitValueError(f"Selected space type is not valid: {selected_space_type!r}")
657
652
  return selected_space_type
@@ -718,9 +713,13 @@ class DataModelingSelect:
718
713
  for space, count in sorted(count_by_space.items(), key=lambda item: item[1], reverse=True)
719
714
  ]
720
715
  if multiselect:
721
- selected_spaces = questionary.checkbox(message, choices=choices).ask()
716
+ selected_spaces = questionary.checkbox(
717
+ message,
718
+ choices=choices,
719
+ validate=lambda choises: True if choises else "You must select at least one space.",
720
+ ).unsafe_ask()
722
721
  else:
723
- selected_spaces = questionary.select(message, choices=choices).ask()
722
+ selected_spaces = questionary.select(message, choices=choices).unsafe_ask()
724
723
  if selected_spaces is None or (isinstance(selected_spaces, list) and len(selected_spaces) == 0):
725
724
  raise ToolkitValueError(
726
725
  f"No instance space selected to {self.operation}. Use arrow keys to navigate and space key to select. Press enter to confirm."
@@ -748,9 +747,13 @@ class DataModelingSelect:
748
747
  message = f"In which empty Space{'(s)' if multiselect else ''} do you want to {self.operation}?"
749
748
  choices = [Choice(title=f"{space}", value=space) for space in sorted(empty_spaces)]
750
749
  if multiselect:
751
- selected_spaces = questionary.checkbox(message, choices=choices).ask()
750
+ selected_spaces = questionary.checkbox(
751
+ message,
752
+ choices=choices,
753
+ validate=lambda choises: True if choises else "You must select at least one space.",
754
+ ).unsafe_ask()
752
755
  else:
753
- selected_spaces = questionary.select(message, choices=choices).ask()
756
+ selected_spaces = questionary.select(message, choices=choices).unsafe_ask()
754
757
  if selected_spaces is None or (isinstance(selected_spaces, list) and len(selected_spaces) == 0):
755
758
  raise ToolkitValueError(f"No empty space selected to {self.operation}. Aborting.")
756
759
  return selected_spaces
@@ -816,9 +819,7 @@ class ResourceViewMappingInteractiveSelect:
816
819
  selected_mapping = questionary.select(
817
820
  f"Which Resource View Mapping do you want to use to {self.operation}? [identifier] (ingestion view)",
818
821
  choices=choices,
819
- ).ask()
820
- if selected_mapping is None:
821
- raise ToolkitValueError("No Resource View Mapping selected.")
822
+ ).unsafe_ask()
822
823
  if not isinstance(selected_mapping, ResourceViewMapping):
823
824
  raise ToolkitValueError(
824
825
  f"Selected Resource View Mapping is not a valid ResourceViewMapping object: {selected_mapping!r}"
@@ -840,9 +841,7 @@ class ThreeDInteractiveSelect:
840
841
  Choice(title="Classic models", value="classic"),
841
842
  Choice(title="Data modeling 3D", value="dm"),
842
843
  ],
843
- ).ask()
844
- if model_type is None:
845
- raise ToolkitValueError("No 3D model type selected.")
844
+ ).unsafe_ask()
846
845
  published = questionary.select(
847
846
  f"Do you want to {self.operation} published or unpublished 3D models?",
848
847
  choices=[
@@ -850,7 +849,7 @@ class ThreeDInteractiveSelect:
850
849
  Choice(title="Unpublished models", value=False),
851
850
  Choice(title="Both published and unpublished models", value=None),
852
851
  ],
853
- ).ask()
852
+ ).unsafe_ask()
854
853
 
855
854
  models = self.client.tool.three_d.models_classic.list(
856
855
  published=published, include_revision_info=True, limit=None
@@ -868,7 +867,8 @@ class ThreeDInteractiveSelect:
868
867
  selected_models = questionary.checkbox(
869
868
  f"Select 3D models to {self.operation}:",
870
869
  choices=choices,
871
- ).ask()
870
+ validate=lambda choices: True if choices else "You must select at least one 3D model.",
871
+ ).unsafe_ask()
872
872
  if selected_models is None or len(selected_models) == 0:
873
873
  raise ToolkitValueError("No 3D models selected.")
874
874
  return selected_models
@@ -12,7 +12,7 @@ jobs:
12
12
  environment: dev
13
13
  name: Deploy
14
14
  container:
15
- image: cognite/toolkit:0.7.53
15
+ image: cognite/toolkit:0.7.55
16
16
  env:
17
17
  CDF_CLUSTER: ${{ vars.CDF_CLUSTER }}
18
18
  CDF_PROJECT: ${{ vars.CDF_PROJECT }}
@@ -10,7 +10,7 @@ jobs:
10
10
  environment: dev
11
11
  name: Deploy Dry Run
12
12
  container:
13
- image: cognite/toolkit:0.7.53
13
+ image: cognite/toolkit:0.7.55
14
14
  env:
15
15
  CDF_CLUSTER: ${{ vars.CDF_CLUSTER }}
16
16
  CDF_PROJECT: ${{ vars.CDF_PROJECT }}
@@ -4,7 +4,7 @@ default_env = "<DEFAULT_ENV_PLACEHOLDER>"
4
4
  [modules]
5
5
  # This is the version of the modules. It should not be changed manually.
6
6
  # It will be updated by the 'cdf modules upgrade' command.
7
- version = "0.7.53"
7
+ version = "0.7.55"
8
8
 
9
9
 
10
10
  [plugins]
@@ -1 +1 @@
1
- __version__ = "0.7.53"
1
+ __version__ = "0.7.55"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cognite_toolkit
3
- Version: 0.7.53
3
+ Version: 0.7.55
4
4
  Summary: Official Cognite Data Fusion tool for project templates and configuration deployment
5
5
  Author: Cognite AS
6
6
  Author-email: Cognite AS <support@cognite.com>