devnomads-cli 0.5.3__tar.gz → 0.5.5__tar.gz

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 (20) hide show
  1. {devnomads_cli-0.5.3 → devnomads_cli-0.5.5}/PKG-INFO +8 -3
  2. {devnomads_cli-0.5.3 → devnomads_cli-0.5.5}/README.md +7 -2
  3. {devnomads_cli-0.5.3 → devnomads_cli-0.5.5}/devnomads_cli.egg-info/PKG-INFO +8 -3
  4. {devnomads_cli-0.5.3 → devnomads_cli-0.5.5}/dncli.py +132 -116
  5. {devnomads_cli-0.5.3 → devnomads_cli-0.5.5}/pyproject.toml +1 -1
  6. {devnomads_cli-0.5.3 → devnomads_cli-0.5.5}/tests/test_cert.py +1 -1
  7. {devnomads_cli-0.5.3 → devnomads_cli-0.5.5}/tests/test_cli.py +14 -24
  8. {devnomads_cli-0.5.3 → devnomads_cli-0.5.5}/tests/test_generated_cli.py +8 -9
  9. {devnomads_cli-0.5.3 → devnomads_cli-0.5.5}/tests/test_helpers.py +10 -10
  10. {devnomads_cli-0.5.3 → devnomads_cli-0.5.5}/tests/test_transfer.py +1 -2
  11. {devnomads_cli-0.5.3 → devnomads_cli-0.5.5}/LICENSE +0 -0
  12. {devnomads_cli-0.5.3 → devnomads_cli-0.5.5}/devnomads_cli.egg-info/SOURCES.txt +0 -0
  13. {devnomads_cli-0.5.3 → devnomads_cli-0.5.5}/devnomads_cli.egg-info/dependency_links.txt +0 -0
  14. {devnomads_cli-0.5.3 → devnomads_cli-0.5.5}/devnomads_cli.egg-info/entry_points.txt +0 -0
  15. {devnomads_cli-0.5.3 → devnomads_cli-0.5.5}/devnomads_cli.egg-info/requires.txt +0 -0
  16. {devnomads_cli-0.5.3 → devnomads_cli-0.5.5}/devnomads_cli.egg-info/top_level.txt +0 -0
  17. {devnomads_cli-0.5.3 → devnomads_cli-0.5.5}/setup.cfg +0 -0
  18. {devnomads_cli-0.5.3 → devnomads_cli-0.5.5}/tests/test_config.py +0 -0
  19. {devnomads_cli-0.5.3 → devnomads_cli-0.5.5}/tests/test_generate.py +0 -0
  20. {devnomads_cli-0.5.3 → devnomads_cli-0.5.5}/tests/test_hook.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devnomads-cli
3
- Version: 0.5.3
3
+ Version: 0.5.5
4
4
  Summary: Manage your DevNomads services from the command line
5
5
  Author-email: DevNomads <support@devnomads.nl>
6
6
  License: MIT
@@ -111,11 +111,16 @@ export DN_PROFILE=acme
111
111
  ## Scripting
112
112
 
113
113
  Output is a human-readable table on a terminal and JSON when piped,
114
- so pipelines get parseable output without any flags; `--output
115
- json|table` forces either. Data goes to stdout, everything else
114
+ so pipelines get parseable output without any flags; `--json` and
115
+ `--table` force either. Data goes to stdout, everything else
116
116
  (warnings, prompts, status messages) to stderr, so `dncli ... | jq .`
117
117
  is always safe.
118
118
 
119
+ List tables show a focused set of columns: fields that are empty for
120
+ every row, and nested collections (a server's IPs, a container's
121
+ instances, a mailbox list) are left out of the overview. Use `<group>
122
+ show <id>` or `--json` for the complete record.
123
+
119
124
  In CI and pipelines, skip the credentials file and pass the key via
120
125
  the environment:
121
126
 
@@ -95,11 +95,16 @@ export DN_PROFILE=acme
95
95
  ## Scripting
96
96
 
97
97
  Output is a human-readable table on a terminal and JSON when piped,
98
- so pipelines get parseable output without any flags; `--output
99
- json|table` forces either. Data goes to stdout, everything else
98
+ so pipelines get parseable output without any flags; `--json` and
99
+ `--table` force either. Data goes to stdout, everything else
100
100
  (warnings, prompts, status messages) to stderr, so `dncli ... | jq .`
101
101
  is always safe.
102
102
 
103
+ List tables show a focused set of columns: fields that are empty for
104
+ every row, and nested collections (a server's IPs, a container's
105
+ instances, a mailbox list) are left out of the overview. Use `<group>
106
+ show <id>` or `--json` for the complete record.
107
+
103
108
  In CI and pipelines, skip the credentials file and pass the key via
104
109
  the environment:
105
110
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devnomads-cli
3
- Version: 0.5.3
3
+ Version: 0.5.5
4
4
  Summary: Manage your DevNomads services from the command line
5
5
  Author-email: DevNomads <support@devnomads.nl>
6
6
  License: MIT
@@ -111,11 +111,16 @@ export DN_PROFILE=acme
111
111
  ## Scripting
112
112
 
113
113
  Output is a human-readable table on a terminal and JSON when piped,
114
- so pipelines get parseable output without any flags; `--output
115
- json|table` forces either. Data goes to stdout, everything else
114
+ so pipelines get parseable output without any flags; `--json` and
115
+ `--table` force either. Data goes to stdout, everything else
116
116
  (warnings, prompts, status messages) to stderr, so `dncli ... | jq .`
117
117
  is always safe.
118
118
 
119
+ List tables show a focused set of columns: fields that are empty for
120
+ every row, and nested collections (a server's IPs, a container's
121
+ instances, a mailbox list) are left out of the overview. Use `<group>
122
+ show <id>` or `--json` for the complete record.
123
+
119
124
  In CI and pipelines, skip the credentials file and pass the key via
120
125
  the environment:
121
126
 
@@ -176,13 +176,25 @@ class AppState:
176
176
  client: DevNomadsClient | None = None
177
177
 
178
178
 
179
- def state_from(ctx: typer.Context, output: OutputFormat | None = None) -> AppState:
179
+ def _format_flag(as_json: bool | None) -> OutputFormat | None:
180
+ """Map the ``--json``/``--table`` flag to a format: True is JSON, False is
181
+ table, None means "not given - decide from the terminal"."""
182
+
183
+ if as_json is True:
184
+ return OutputFormat.json
185
+ if as_json is False:
186
+ return OutputFormat.table
187
+ return None
188
+
189
+
190
+ def state_from(ctx: typer.Context, output: bool | None = None) -> AppState:
180
191
  state = ctx.obj
181
192
  if not isinstance(state, AppState): # direct invocation in tests
182
193
  state = AppState()
183
194
  ctx.obj = state
184
- if output is not None: # per-command --output overrides the global one
185
- state.output = output
195
+ fmt = _format_flag(output)
196
+ if fmt is not None: # per-command --json/--table overrides the global one
197
+ state.output = fmt
186
198
  return state
187
199
 
188
200
 
@@ -342,14 +354,14 @@ def _render_kv(data: dict[str, Any], title: str | None) -> None:
342
354
  def _auto_columns(rows: list[dict[str, Any]]) -> list[str]:
343
355
  """Choose the columns worth showing in a list view, from the data itself.
344
356
 
345
- Three things get dropped, because a list is an overview and the full record
357
+ Two things get dropped, because a list is an overview and the full record
346
358
  is always available via the matching ``show`` command (or ``-o json``):
347
359
 
348
360
  * columns empty in every row (no information at all);
349
361
  * columns holding a list of objects (instances, mailboxes, ips, ...) -
350
- these are detail, belonging in the ``show`` view, not the overview;
351
- * columns whose value never changes across rows - they cost width without
352
- helping tell the rows apart (the first column is kept as an anchor).
362
+ these are detail, belonging in the ``show`` view, not the overview.
363
+
364
+ Every other field is kept, even if its value is the same on every row.
353
365
  """
354
366
 
355
367
  cols: list[str] = []
@@ -370,17 +382,11 @@ def _auto_columns(rows: list[dict[str, Any]]) -> list[str]:
370
382
  for row in rows
371
383
  )
372
384
 
373
- cols = [
385
+ return [
374
386
  c
375
387
  for c in cols
376
388
  if any(not empty(row.get(c)) for row in rows) and not is_object_list(c)
377
389
  ]
378
- if len(rows) > 1 and cols:
379
- anchor = cols[0]
380
- rendered = {c: {_cell(row.get(c)) for row in rows} for c in cols}
381
- if any(len(values) > 1 for values in rendered.values()):
382
- cols = [c for c in cols if c == anchor or len(rendered[c]) > 1]
383
- return cols
384
390
 
385
391
 
386
392
  def _render_rows(
@@ -1001,8 +1007,11 @@ SortOption = Annotated[
1001
1007
  ),
1002
1008
  ]
1003
1009
  OutputOption = Annotated[
1004
- OutputFormat | None,
1005
- typer.Option("--output", "-o", help="Output format (table or json)."),
1010
+ bool | None,
1011
+ typer.Option(
1012
+ "--json/--table",
1013
+ help="Force JSON or table output (default: table on a TTY, JSON piped).",
1014
+ ),
1006
1015
  ]
1007
1016
 
1008
1017
 
@@ -1028,11 +1037,11 @@ def main(
1028
1037
  ),
1029
1038
  ] = None,
1030
1039
  output: Annotated[
1031
- OutputFormat | None,
1040
+ bool | None,
1032
1041
  typer.Option(
1033
- "--output",
1034
- "-o",
1035
- help="Output format; default: table on a TTY, json when piped.",
1042
+ "--json/--table",
1043
+ help="Force JSON or table output; default: table on a TTY, "
1044
+ "JSON when piped.",
1036
1045
  ),
1037
1046
  ] = None,
1038
1047
  debug: Annotated[
@@ -1048,7 +1057,12 @@ def main(
1048
1057
  ),
1049
1058
  ] = False,
1050
1059
  ) -> None:
1051
- ctx.obj = AppState(profile=profile, api_key=api_key, output=output, debug=debug)
1060
+ ctx.obj = AppState(
1061
+ profile=profile,
1062
+ api_key=api_key,
1063
+ output=_format_flag(output),
1064
+ debug=debug,
1065
+ )
1052
1066
 
1053
1067
 
1054
1068
  # --- configure -------------------------------------------------------------
@@ -2067,7 +2081,9 @@ _SORT_OPT = typer.Option(
2067
2081
  )
2068
2082
  _YES_OPT = typer.Option(False, "--yes", "-y", help="Do not ask for confirmation.")
2069
2083
  _OUTPUT_OPT = typer.Option(
2070
- None, "--output", "-o", help="Output format (table or json)."
2084
+ None,
2085
+ "--json/--table",
2086
+ help="Force JSON or table output (default: table on a TTY, JSON piped).",
2071
2087
  )
2072
2088
 
2073
2089
 
@@ -2082,7 +2098,7 @@ def _generated_call(
2082
2098
  columns: list[str] | None = None,
2083
2099
  confirm: str | None = None,
2084
2100
  yes: bool = False,
2085
- output: OutputFormat | None = None,
2101
+ output: bool | None = None,
2086
2102
  ) -> None:
2087
2103
  """Shared runtime for generated commands: build the path, confirm if
2088
2104
  needed, call the API, render the result."""
@@ -2239,7 +2255,7 @@ def gen_handles_create(
2239
2255
  city: str | None = typer.Option(None),
2240
2256
  region: str | None = typer.Option(None),
2241
2257
  country: str | None = typer.Option(None),
2242
- output: OutputFormat | None = _OUTPUT_OPT,
2258
+ output: bool | None = _OUTPUT_OPT,
2243
2259
  ) -> None:
2244
2260
  """Create a contact handle."""
2245
2261
 
@@ -2274,7 +2290,7 @@ def gen_handles_create(
2274
2290
  def gen_handles_index(
2275
2291
  ctx: typer.Context,
2276
2292
  sort: str | None = _SORT_OPT,
2277
- output: OutputFormat | None = _OUTPUT_OPT,
2293
+ output: bool | None = _OUTPUT_OPT,
2278
2294
  ) -> None:
2279
2295
  """List your contact handles."""
2280
2296
 
@@ -2292,7 +2308,7 @@ def gen_handles_index(
2292
2308
  def gen_handles_show(
2293
2309
  ctx: typer.Context,
2294
2310
  handle_id: int = typer.Argument(..., metavar="HANDLE_ID"),
2295
- output: OutputFormat | None = _OUTPUT_OPT,
2311
+ output: bool | None = _OUTPUT_OPT,
2296
2312
  ) -> None:
2297
2313
  """Show one contact handle."""
2298
2314
 
@@ -2309,7 +2325,7 @@ def gen_handles_show(
2309
2325
  def gen_services_apps_index(
2310
2326
  ctx: typer.Context,
2311
2327
  sort: str | None = _SORT_OPT,
2312
- output: OutputFormat | None = _OUTPUT_OPT,
2328
+ output: bool | None = _OUTPUT_OPT,
2313
2329
  ) -> None:
2314
2330
  """List apps."""
2315
2331
 
@@ -2327,7 +2343,7 @@ def gen_services_apps_index(
2327
2343
  def gen_services_apps_show(
2328
2344
  ctx: typer.Context,
2329
2345
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
2330
- output: OutputFormat | None = _OUTPUT_OPT,
2346
+ output: bool | None = _OUTPUT_OPT,
2331
2347
  ) -> None:
2332
2348
  """Show apps details."""
2333
2349
 
@@ -2346,7 +2362,7 @@ def gen_services_apps_state(
2346
2362
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
2347
2363
  state: str = typer.Argument(..., metavar="STATE"),
2348
2364
  yes: bool = _YES_OPT,
2349
- output: OutputFormat | None = _OUTPUT_OPT,
2365
+ output: bool | None = _OUTPUT_OPT,
2350
2366
  ) -> None:
2351
2367
  """Change the state of an app service."""
2352
2368
 
@@ -2365,7 +2381,7 @@ def gen_services_apps_state(
2365
2381
  def gen_services_buckets_index(
2366
2382
  ctx: typer.Context,
2367
2383
  sort: str | None = _SORT_OPT,
2368
- output: OutputFormat | None = _OUTPUT_OPT,
2384
+ output: bool | None = _OUTPUT_OPT,
2369
2385
  ) -> None:
2370
2386
  """List buckets."""
2371
2387
 
@@ -2383,7 +2399,7 @@ def gen_services_buckets_index(
2383
2399
  def gen_services_buckets_show(
2384
2400
  ctx: typer.Context,
2385
2401
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
2386
- output: OutputFormat | None = _OUTPUT_OPT,
2402
+ output: bool | None = _OUTPUT_OPT,
2387
2403
  ) -> None:
2388
2404
  """Show buckets details."""
2389
2405
 
@@ -2401,7 +2417,7 @@ def gen_services_containers_deploy(
2401
2417
  ctx: typer.Context,
2402
2418
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
2403
2419
  yes: bool = _YES_OPT,
2404
- output: OutputFormat | None = _OUTPUT_OPT,
2420
+ output: bool | None = _OUTPUT_OPT,
2405
2421
  ) -> None:
2406
2422
  """Deploy a container service."""
2407
2423
 
@@ -2420,7 +2436,7 @@ def gen_services_containers_deploy(
2420
2436
  def gen_services_containers_index(
2421
2437
  ctx: typer.Context,
2422
2438
  sort: str | None = _SORT_OPT,
2423
- output: OutputFormat | None = _OUTPUT_OPT,
2439
+ output: bool | None = _OUTPUT_OPT,
2424
2440
  ) -> None:
2425
2441
  """List containers."""
2426
2442
 
@@ -2440,7 +2456,7 @@ def gen_services_containers_instances_deploy(
2440
2456
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
2441
2457
  instance_id: int = typer.Argument(..., metavar="INSTANCE_ID"),
2442
2458
  yes: bool = _YES_OPT,
2443
- output: OutputFormat | None = _OUTPUT_OPT,
2459
+ output: bool | None = _OUTPUT_OPT,
2444
2460
  ) -> None:
2445
2461
  """Deploy a container instance."""
2446
2462
 
@@ -2460,7 +2476,7 @@ def gen_services_containers_instances_index(
2460
2476
  ctx: typer.Context,
2461
2477
  service_id: str = typer.Argument(..., metavar="SERVICE_ID"),
2462
2478
  sort: str | None = _SORT_OPT,
2463
- output: OutputFormat | None = _OUTPUT_OPT,
2479
+ output: bool | None = _OUTPUT_OPT,
2464
2480
  ) -> None:
2465
2481
  """List containers instances."""
2466
2482
 
@@ -2479,7 +2495,7 @@ def gen_services_containers_instances_logs(
2479
2495
  ctx: typer.Context,
2480
2496
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
2481
2497
  instance_id: int = typer.Argument(..., metavar="INSTANCE_ID"),
2482
- output: OutputFormat | None = _OUTPUT_OPT,
2498
+ output: bool | None = _OUTPUT_OPT,
2483
2499
  ) -> None:
2484
2500
  """Show the logs of a container instance."""
2485
2501
 
@@ -2497,7 +2513,7 @@ def gen_services_containers_instances_show(
2497
2513
  ctx: typer.Context,
2498
2514
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
2499
2515
  instance_id: int = typer.Argument(..., metavar="INSTANCE_ID"),
2500
- output: OutputFormat | None = _OUTPUT_OPT,
2516
+ output: bool | None = _OUTPUT_OPT,
2501
2517
  ) -> None:
2502
2518
  """Show containers instances details."""
2503
2519
 
@@ -2517,7 +2533,7 @@ def gen_services_containers_instances_state(
2517
2533
  instance_id: int = typer.Argument(..., metavar="INSTANCE_ID"),
2518
2534
  state: str = typer.Argument(..., metavar="STATE"),
2519
2535
  yes: bool = _YES_OPT,
2520
- output: OutputFormat | None = _OUTPUT_OPT,
2536
+ output: bool | None = _OUTPUT_OPT,
2521
2537
  ) -> None:
2522
2538
  """Change the state of a container instance."""
2523
2539
 
@@ -2538,7 +2554,7 @@ def gen_services_containers_instances_update(
2538
2554
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
2539
2555
  instance_id: int = typer.Argument(..., metavar="INSTANCE_ID"),
2540
2556
  image: str | None = typer.Option(None),
2541
- output: OutputFormat | None = _OUTPUT_OPT,
2557
+ output: bool | None = _OUTPUT_OPT,
2542
2558
  ) -> None:
2543
2559
  """Update containers instances."""
2544
2560
 
@@ -2558,7 +2574,7 @@ def gen_services_containers_instances_volumes_index(
2558
2574
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
2559
2575
  instance_id: int = typer.Argument(..., metavar="INSTANCE_ID"),
2560
2576
  sort: str | None = _SORT_OPT,
2561
- output: OutputFormat | None = _OUTPUT_OPT,
2577
+ output: bool | None = _OUTPUT_OPT,
2562
2578
  ) -> None:
2563
2579
  """List containers instances volumes."""
2564
2580
 
@@ -2578,7 +2594,7 @@ def gen_services_containers_instances_volumes_show(
2578
2594
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
2579
2595
  instance_id: int = typer.Argument(..., metavar="INSTANCE_ID"),
2580
2596
  volume_id: int = typer.Argument(..., metavar="VOLUME_ID"),
2581
- output: OutputFormat | None = _OUTPUT_OPT,
2597
+ output: bool | None = _OUTPUT_OPT,
2582
2598
  ) -> None:
2583
2599
  """Show containers instances volumes details."""
2584
2600
 
@@ -2599,7 +2615,7 @@ def gen_services_containers_instances_volumes_update(
2599
2615
  volume_id: int = typer.Argument(..., metavar="VOLUME_ID"),
2600
2616
  path: str | None = typer.Option(None),
2601
2617
  uid: str | None = typer.Option(None),
2602
- output: OutputFormat | None = _OUTPUT_OPT,
2618
+ output: bool | None = _OUTPUT_OPT,
2603
2619
  ) -> None:
2604
2620
  """Update containers instances volumes."""
2605
2621
 
@@ -2617,7 +2633,7 @@ def gen_services_containers_instances_volumes_update(
2617
2633
  def gen_services_containers_show(
2618
2634
  ctx: typer.Context,
2619
2635
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
2620
- output: OutputFormat | None = _OUTPUT_OPT,
2636
+ output: bool | None = _OUTPUT_OPT,
2621
2637
  ) -> None:
2622
2638
  """Show containers details."""
2623
2639
 
@@ -2637,7 +2653,7 @@ def gen_services_containers_update(
2637
2653
  registry_url: str | None = typer.Option(None),
2638
2654
  description: str | None = typer.Option(None),
2639
2655
  port: int | None = typer.Option(None),
2640
- output: OutputFormat | None = _OUTPUT_OPT,
2656
+ output: bool | None = _OUTPUT_OPT,
2641
2657
  ) -> None:
2642
2658
  """Update containers."""
2643
2659
 
@@ -2655,7 +2671,7 @@ def gen_services_containers_update(
2655
2671
  def gen_services_databases_clusters_index(
2656
2672
  ctx: typer.Context,
2657
2673
  sort: str | None = _SORT_OPT,
2658
- output: OutputFormat | None = _OUTPUT_OPT,
2674
+ output: bool | None = _OUTPUT_OPT,
2659
2675
  ) -> None:
2660
2676
  """List databases clusters."""
2661
2677
 
@@ -2673,7 +2689,7 @@ def gen_services_databases_clusters_index(
2673
2689
  def gen_services_databases_clusters_show(
2674
2690
  ctx: typer.Context,
2675
2691
  cluster_id: int = typer.Argument(..., metavar="CLUSTER_ID"),
2676
- output: OutputFormat | None = _OUTPUT_OPT,
2692
+ output: bool | None = _OUTPUT_OPT,
2677
2693
  ) -> None:
2678
2694
  """Show databases clusters details."""
2679
2695
 
@@ -2691,7 +2707,7 @@ def gen_services_databases_clusters_users_index(
2691
2707
  ctx: typer.Context,
2692
2708
  cluster_id: int = typer.Argument(..., metavar="CLUSTER_ID"),
2693
2709
  sort: str | None = _SORT_OPT,
2694
- output: OutputFormat | None = _OUTPUT_OPT,
2710
+ output: bool | None = _OUTPUT_OPT,
2695
2711
  ) -> None:
2696
2712
  """List databases clusters users."""
2697
2713
 
@@ -2710,7 +2726,7 @@ def gen_services_databases_clusters_users_show(
2710
2726
  ctx: typer.Context,
2711
2727
  cluster_id: int = typer.Argument(..., metavar="CLUSTER_ID"),
2712
2728
  user_id: int = typer.Argument(..., metavar="USER_ID"),
2713
- output: OutputFormat | None = _OUTPUT_OPT,
2729
+ output: bool | None = _OUTPUT_OPT,
2714
2730
  ) -> None:
2715
2731
  """Show databases clusters users details."""
2716
2732
 
@@ -2727,7 +2743,7 @@ def gen_services_databases_clusters_users_show(
2727
2743
  def gen_services_databases_index(
2728
2744
  ctx: typer.Context,
2729
2745
  sort: str | None = _SORT_OPT,
2730
- output: OutputFormat | None = _OUTPUT_OPT,
2746
+ output: bool | None = _OUTPUT_OPT,
2731
2747
  ) -> None:
2732
2748
  """List databases."""
2733
2749
 
@@ -2747,7 +2763,7 @@ def gen_services_databases_permissions_create(
2747
2763
  service_id: str = typer.Argument(..., metavar="SERVICE_ID"),
2748
2764
  user_id: str | None = typer.Option(None),
2749
2765
  permissions: list[str] | None = typer.Option(None),
2750
- output: OutputFormat | None = _OUTPUT_OPT,
2766
+ output: bool | None = _OUTPUT_OPT,
2751
2767
  ) -> None:
2752
2768
  """Create databases permissions."""
2753
2769
 
@@ -2765,7 +2781,7 @@ def gen_services_databases_permissions_create(
2765
2781
  def gen_services_databases_show(
2766
2782
  ctx: typer.Context,
2767
2783
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
2768
- output: OutputFormat | None = _OUTPUT_OPT,
2784
+ output: bool | None = _OUTPUT_OPT,
2769
2785
  ) -> None:
2770
2786
  """Show databases details."""
2771
2787
 
@@ -2784,7 +2800,7 @@ def gen_services_databases_store(
2784
2800
  name: str | None = typer.Option(None),
2785
2801
  client_id: int | None = typer.Option(None),
2786
2802
  cluster_id: int | None = typer.Option(None),
2787
- output: OutputFormat | None = _OUTPUT_OPT,
2803
+ output: bool | None = _OUTPUT_OPT,
2788
2804
  ) -> None:
2789
2805
  """Create databases."""
2790
2806
 
@@ -2805,7 +2821,7 @@ def gen_services_databases_users_store(
2805
2821
  username: str | None = typer.Option(None),
2806
2822
  password: str | None = typer.Option(None),
2807
2823
  client_id: int | None = typer.Option(None),
2808
- output: OutputFormat | None = _OUTPUT_OPT,
2824
+ output: bool | None = _OUTPUT_OPT,
2809
2825
  ) -> None:
2810
2826
  """Create databases users."""
2811
2827
 
@@ -2825,7 +2841,7 @@ def gen_services_databases_users_update(
2825
2841
  cluster_id: str = typer.Argument(..., metavar="CLUSTER_ID"),
2826
2842
  user_id: str = typer.Argument(..., metavar="USER_ID"),
2827
2843
  password: str | None = typer.Option(None),
2828
- output: OutputFormat | None = _OUTPUT_OPT,
2844
+ output: bool | None = _OUTPUT_OPT,
2829
2845
  ) -> None:
2830
2846
  """Update databases users."""
2831
2847
 
@@ -2850,7 +2866,7 @@ def gen_services_domains_create(
2850
2866
  handle_id_owner: int | None = typer.Option(None),
2851
2867
  handle_id_administrative: int | None = typer.Option(None),
2852
2868
  handle_id_technical: int | None = typer.Option(None),
2853
- output: OutputFormat | None = _OUTPUT_OPT,
2869
+ output: bool | None = _OUTPUT_OPT,
2854
2870
  ) -> None:
2855
2871
  """Create domains."""
2856
2872
 
@@ -2877,7 +2893,7 @@ def gen_services_domains_create(
2877
2893
  def gen_services_domains_index(
2878
2894
  ctx: typer.Context,
2879
2895
  sort: str | None = _SORT_OPT,
2880
- output: OutputFormat | None = _OUTPUT_OPT,
2896
+ output: bool | None = _OUTPUT_OPT,
2881
2897
  ) -> None:
2882
2898
  """List domains."""
2883
2899
 
@@ -2895,7 +2911,7 @@ def gen_services_domains_index(
2895
2911
  def gen_services_domains_show(
2896
2912
  ctx: typer.Context,
2897
2913
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
2898
- output: OutputFormat | None = _OUTPUT_OPT,
2914
+ output: bool | None = _OUTPUT_OPT,
2899
2915
  ) -> None:
2900
2916
  """Show domains details."""
2901
2917
 
@@ -2914,7 +2930,7 @@ def gen_services_emails_aliases_create(
2914
2930
  service_id: str = typer.Argument(..., metavar="SERVICE_ID"),
2915
2931
  emailaddress: str | None = typer.Option(None),
2916
2932
  alias: str | None = typer.Option(None),
2917
- output: OutputFormat | None = _OUTPUT_OPT,
2933
+ output: bool | None = _OUTPUT_OPT,
2918
2934
  ) -> None:
2919
2935
  """Create emails aliases."""
2920
2936
 
@@ -2934,7 +2950,7 @@ def gen_services_emails_aliases_delete(
2934
2950
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
2935
2951
  alias_id: int = typer.Argument(..., metavar="ALIAS_ID"),
2936
2952
  yes: bool = _YES_OPT,
2937
- output: OutputFormat | None = _OUTPUT_OPT,
2953
+ output: bool | None = _OUTPUT_OPT,
2938
2954
  ) -> None:
2939
2955
  """Delete emails aliases."""
2940
2956
 
@@ -2954,7 +2970,7 @@ def gen_services_emails_aliases_index(
2954
2970
  ctx: typer.Context,
2955
2971
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
2956
2972
  sort: str | None = _SORT_OPT,
2957
- output: OutputFormat | None = _OUTPUT_OPT,
2973
+ output: bool | None = _OUTPUT_OPT,
2958
2974
  ) -> None:
2959
2975
  """List emails aliases."""
2960
2976
 
@@ -2973,7 +2989,7 @@ def gen_services_emails_aliases_show(
2973
2989
  ctx: typer.Context,
2974
2990
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
2975
2991
  alias_id: int = typer.Argument(..., metavar="ALIAS_ID"),
2976
- output: OutputFormat | None = _OUTPUT_OPT,
2992
+ output: bool | None = _OUTPUT_OPT,
2977
2993
  ) -> None:
2978
2994
  """Show emails aliases details."""
2979
2995
 
@@ -2995,7 +3011,7 @@ def gen_services_emails_create(
2995
3011
  return_path_domain: str | None = typer.Option(None),
2996
3012
  relay_hosts: list[str] | None = typer.Option(None),
2997
3013
  delivery_rate: int | None = typer.Option(None),
2998
- output: OutputFormat | None = _OUTPUT_OPT,
3014
+ output: bool | None = _OUTPUT_OPT,
2999
3015
  ) -> None:
3000
3016
  """Create emails."""
3001
3017
 
@@ -3021,7 +3037,7 @@ def gen_services_emails_delete(
3021
3037
  ctx: typer.Context,
3022
3038
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3023
3039
  yes: bool = _YES_OPT,
3024
- output: OutputFormat | None = _OUTPUT_OPT,
3040
+ output: bool | None = _OUTPUT_OPT,
3025
3041
  ) -> None:
3026
3042
  """Delete emails."""
3027
3043
 
@@ -3040,7 +3056,7 @@ def gen_services_emails_delete(
3040
3056
  def gen_services_emails_dkim_show(
3041
3057
  ctx: typer.Context,
3042
3058
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3043
- output: OutputFormat | None = _OUTPUT_OPT,
3059
+ output: bool | None = _OUTPUT_OPT,
3044
3060
  ) -> None:
3045
3061
  """Show the DKIM configuration of an email service."""
3046
3062
 
@@ -3059,7 +3075,7 @@ def gen_services_emails_forwardings_create(
3059
3075
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3060
3076
  emailaddress: str | None = typer.Option(None),
3061
3077
  target: str | None = typer.Option(None),
3062
- output: OutputFormat | None = _OUTPUT_OPT,
3078
+ output: bool | None = _OUTPUT_OPT,
3063
3079
  ) -> None:
3064
3080
  """Create emails forwardings."""
3065
3081
 
@@ -3079,7 +3095,7 @@ def gen_services_emails_forwardings_delete(
3079
3095
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3080
3096
  forwarding_id: int = typer.Argument(..., metavar="FORWARDING_ID"),
3081
3097
  yes: bool = _YES_OPT,
3082
- output: OutputFormat | None = _OUTPUT_OPT,
3098
+ output: bool | None = _OUTPUT_OPT,
3083
3099
  ) -> None:
3084
3100
  """Delete emails forwardings."""
3085
3101
 
@@ -3099,7 +3115,7 @@ def gen_services_emails_forwardings_index(
3099
3115
  ctx: typer.Context,
3100
3116
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3101
3117
  sort: str | None = _SORT_OPT,
3102
- output: OutputFormat | None = _OUTPUT_OPT,
3118
+ output: bool | None = _OUTPUT_OPT,
3103
3119
  ) -> None:
3104
3120
  """List emails forwardings."""
3105
3121
 
@@ -3118,7 +3134,7 @@ def gen_services_emails_forwardings_show(
3118
3134
  ctx: typer.Context,
3119
3135
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3120
3136
  forwarding_id: int = typer.Argument(..., metavar="FORWARDING_ID"),
3121
- output: OutputFormat | None = _OUTPUT_OPT,
3137
+ output: bool | None = _OUTPUT_OPT,
3122
3138
  ) -> None:
3123
3139
  """Show emails forwardings details."""
3124
3140
 
@@ -3135,7 +3151,7 @@ def gen_services_emails_forwardings_show(
3135
3151
  def gen_services_emails_index(
3136
3152
  ctx: typer.Context,
3137
3153
  sort: str | None = _SORT_OPT,
3138
- output: OutputFormat | None = _OUTPUT_OPT,
3154
+ output: bool | None = _OUTPUT_OPT,
3139
3155
  ) -> None:
3140
3156
  """List emails."""
3141
3157
 
@@ -3155,7 +3171,7 @@ def gen_services_emails_mailboxes_create(
3155
3171
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3156
3172
  emailaddress: str | None = typer.Option(None),
3157
3173
  password: str | None = typer.Option(None),
3158
- output: OutputFormat | None = _OUTPUT_OPT,
3174
+ output: bool | None = _OUTPUT_OPT,
3159
3175
  ) -> None:
3160
3176
  """Create emails mailboxes."""
3161
3177
 
@@ -3175,7 +3191,7 @@ def gen_services_emails_mailboxes_delete(
3175
3191
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3176
3192
  emailaddress: str = typer.Argument(..., metavar="EMAILADDRESS"),
3177
3193
  yes: bool = _YES_OPT,
3178
- output: OutputFormat | None = _OUTPUT_OPT,
3194
+ output: bool | None = _OUTPUT_OPT,
3179
3195
  ) -> None:
3180
3196
  """Delete emails mailboxes."""
3181
3197
 
@@ -3195,7 +3211,7 @@ def gen_services_emails_mailboxes_index(
3195
3211
  ctx: typer.Context,
3196
3212
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3197
3213
  sort: str | None = _SORT_OPT,
3198
- output: OutputFormat | None = _OUTPUT_OPT,
3214
+ output: bool | None = _OUTPUT_OPT,
3199
3215
  ) -> None:
3200
3216
  """List emails mailboxes."""
3201
3217
 
@@ -3214,7 +3230,7 @@ def gen_services_emails_mailboxes_show(
3214
3230
  ctx: typer.Context,
3215
3231
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3216
3232
  emailaddress: str = typer.Argument(..., metavar="EMAILADDRESS"),
3217
- output: OutputFormat | None = _OUTPUT_OPT,
3233
+ output: bool | None = _OUTPUT_OPT,
3218
3234
  ) -> None:
3219
3235
  """Show emails mailboxes details."""
3220
3236
 
@@ -3233,7 +3249,7 @@ def gen_services_emails_mailboxes_update(
3233
3249
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3234
3250
  emailaddress: str = typer.Argument(..., metavar="EMAILADDRESS"),
3235
3251
  password: str | None = typer.Option(None),
3236
- output: OutputFormat | None = _OUTPUT_OPT,
3252
+ output: bool | None = _OUTPUT_OPT,
3237
3253
  ) -> None:
3238
3254
  """Update emails mailboxes."""
3239
3255
 
@@ -3252,7 +3268,7 @@ def gen_services_emails_records_index(
3252
3268
  ctx: typer.Context,
3253
3269
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3254
3270
  sort: str | None = _SORT_OPT,
3255
- output: OutputFormat | None = _OUTPUT_OPT,
3271
+ output: bool | None = _OUTPUT_OPT,
3256
3272
  ) -> None:
3257
3273
  """List the DNS records an email service needs."""
3258
3274
 
@@ -3270,7 +3286,7 @@ def gen_services_emails_records_index(
3270
3286
  def gen_services_emails_show(
3271
3287
  ctx: typer.Context,
3272
3288
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3273
- output: OutputFormat | None = _OUTPUT_OPT,
3289
+ output: bool | None = _OUTPUT_OPT,
3274
3290
  ) -> None:
3275
3291
  """Show emails details."""
3276
3292
 
@@ -3288,7 +3304,7 @@ def gen_services_emails_transactional_aliases_create(
3288
3304
  ctx: typer.Context,
3289
3305
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3290
3306
  domain: str | None = typer.Option(None),
3291
- output: OutputFormat | None = _OUTPUT_OPT,
3307
+ output: bool | None = _OUTPUT_OPT,
3292
3308
  ) -> None:
3293
3309
  """Create emails transactional aliases."""
3294
3310
 
@@ -3308,7 +3324,7 @@ def gen_services_emails_transactional_aliases_delete(
3308
3324
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3309
3325
  alias_id: int = typer.Argument(..., metavar="ALIAS_ID"),
3310
3326
  yes: bool = _YES_OPT,
3311
- output: OutputFormat | None = _OUTPUT_OPT,
3327
+ output: bool | None = _OUTPUT_OPT,
3312
3328
  ) -> None:
3313
3329
  """Delete emails transactional aliases."""
3314
3330
 
@@ -3328,7 +3344,7 @@ def gen_services_emails_transactional_aliases_index(
3328
3344
  ctx: typer.Context,
3329
3345
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3330
3346
  sort: str | None = _SORT_OPT,
3331
- output: OutputFormat | None = _OUTPUT_OPT,
3347
+ output: bool | None = _OUTPUT_OPT,
3332
3348
  ) -> None:
3333
3349
  """List emails transactional aliases."""
3334
3350
 
@@ -3349,7 +3365,7 @@ def gen_services_emails_transactional_keys_create(
3349
3365
  name: str | None = typer.Option(None),
3350
3366
  key: str | None = typer.Option(None),
3351
3367
  active: bool | None = typer.Option(None),
3352
- output: OutputFormat | None = _OUTPUT_OPT,
3368
+ output: bool | None = _OUTPUT_OPT,
3353
3369
  ) -> None:
3354
3370
  """Create emails transactional keys."""
3355
3371
 
@@ -3369,7 +3385,7 @@ def gen_services_emails_transactional_keys_delete(
3369
3385
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3370
3386
  key_id: int = typer.Argument(..., metavar="KEY_ID"),
3371
3387
  yes: bool = _YES_OPT,
3372
- output: OutputFormat | None = _OUTPUT_OPT,
3388
+ output: bool | None = _OUTPUT_OPT,
3373
3389
  ) -> None:
3374
3390
  """Delete emails transactional keys."""
3375
3391
 
@@ -3389,7 +3405,7 @@ def gen_services_emails_transactional_keys_index(
3389
3405
  ctx: typer.Context,
3390
3406
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3391
3407
  sort: str | None = _SORT_OPT,
3392
- output: OutputFormat | None = _OUTPUT_OPT,
3408
+ output: bool | None = _OUTPUT_OPT,
3393
3409
  ) -> None:
3394
3410
  """List emails transactional keys."""
3395
3411
 
@@ -3408,7 +3424,7 @@ def gen_services_emails_transactional_keys_show(
3408
3424
  ctx: typer.Context,
3409
3425
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3410
3426
  key_id: int = typer.Argument(..., metavar="KEY_ID"),
3411
- output: OutputFormat | None = _OUTPUT_OPT,
3427
+ output: bool | None = _OUTPUT_OPT,
3412
3428
  ) -> None:
3413
3429
  """Show emails transactional keys details."""
3414
3430
 
@@ -3429,7 +3445,7 @@ def gen_services_emails_transactional_keys_update(
3429
3445
  name: str | None = typer.Option(None),
3430
3446
  key: str | None = typer.Option(None),
3431
3447
  active: bool | None = typer.Option(None),
3432
- output: OutputFormat | None = _OUTPUT_OPT,
3448
+ output: bool | None = _OUTPUT_OPT,
3433
3449
  ) -> None:
3434
3450
  """Update emails transactional keys."""
3435
3451
 
@@ -3450,7 +3466,7 @@ def gen_services_emails_transactional_users_create(
3450
3466
  emailaddress: str | None = typer.Option(None),
3451
3467
  password: str | None = typer.Option(None),
3452
3468
  delivery_mode: str | None = typer.Option(None),
3453
- output: OutputFormat | None = _OUTPUT_OPT,
3469
+ output: bool | None = _OUTPUT_OPT,
3454
3470
  ) -> None:
3455
3471
  """Create emails transactional users."""
3456
3472
 
@@ -3474,7 +3490,7 @@ def gen_services_emails_transactional_users_delete(
3474
3490
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3475
3491
  user_id: int = typer.Argument(..., metavar="USER_ID"),
3476
3492
  yes: bool = _YES_OPT,
3477
- output: OutputFormat | None = _OUTPUT_OPT,
3493
+ output: bool | None = _OUTPUT_OPT,
3478
3494
  ) -> None:
3479
3495
  """Delete emails transactional users."""
3480
3496
 
@@ -3494,7 +3510,7 @@ def gen_services_emails_transactional_users_index(
3494
3510
  ctx: typer.Context,
3495
3511
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3496
3512
  sort: str | None = _SORT_OPT,
3497
- output: OutputFormat | None = _OUTPUT_OPT,
3513
+ output: bool | None = _OUTPUT_OPT,
3498
3514
  ) -> None:
3499
3515
  """List emails transactional users."""
3500
3516
 
@@ -3513,7 +3529,7 @@ def gen_services_emails_transactional_users_show(
3513
3529
  ctx: typer.Context,
3514
3530
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3515
3531
  user_id: int = typer.Argument(..., metavar="USER_ID"),
3516
- output: OutputFormat | None = _OUTPUT_OPT,
3532
+ output: bool | None = _OUTPUT_OPT,
3517
3533
  ) -> None:
3518
3534
  """Show emails transactional users details."""
3519
3535
 
@@ -3533,7 +3549,7 @@ def gen_services_emails_transactional_users_update(
3533
3549
  user_id: int = typer.Argument(..., metavar="USER_ID"),
3534
3550
  password: str | None = typer.Option(None),
3535
3551
  delivery_mode: str | None = typer.Option(None),
3536
- output: OutputFormat | None = _OUTPUT_OPT,
3552
+ output: bool | None = _OUTPUT_OPT,
3537
3553
  ) -> None:
3538
3554
  """Update emails transactional users."""
3539
3555
 
@@ -3551,7 +3567,7 @@ def gen_services_emails_transactional_users_update(
3551
3567
  def gen_services_forwards_index(
3552
3568
  ctx: typer.Context,
3553
3569
  sort: str | None = _SORT_OPT,
3554
- output: OutputFormat | None = _OUTPUT_OPT,
3570
+ output: bool | None = _OUTPUT_OPT,
3555
3571
  ) -> None:
3556
3572
  """List forwards."""
3557
3573
 
@@ -3569,7 +3585,7 @@ def gen_services_forwards_index(
3569
3585
  def gen_services_forwards_show(
3570
3586
  ctx: typer.Context,
3571
3587
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3572
- output: OutputFormat | None = _OUTPUT_OPT,
3588
+ output: bool | None = _OUTPUT_OPT,
3573
3589
  ) -> None:
3574
3590
  """Show forwards details."""
3575
3591
 
@@ -3587,7 +3603,7 @@ def gen_services_proxies_down(
3587
3603
  ctx: typer.Context,
3588
3604
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3589
3605
  yes: bool = _YES_OPT,
3590
- output: OutputFormat | None = _OUTPUT_OPT,
3606
+ output: bool | None = _OUTPUT_OPT,
3591
3607
  ) -> None:
3592
3608
  """Bring a proxy down."""
3593
3609
 
@@ -3606,7 +3622,7 @@ def gen_services_proxies_down(
3606
3622
  def gen_services_proxies_index(
3607
3623
  ctx: typer.Context,
3608
3624
  sort: str | None = _SORT_OPT,
3609
- output: OutputFormat | None = _OUTPUT_OPT,
3625
+ output: bool | None = _OUTPUT_OPT,
3610
3626
  ) -> None:
3611
3627
  """List proxies."""
3612
3628
 
@@ -3624,7 +3640,7 @@ def gen_services_proxies_index(
3624
3640
  def gen_services_proxies_show(
3625
3641
  ctx: typer.Context,
3626
3642
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3627
- output: OutputFormat | None = _OUTPUT_OPT,
3643
+ output: bool | None = _OUTPUT_OPT,
3628
3644
  ) -> None:
3629
3645
  """Show proxies details."""
3630
3646
 
@@ -3642,7 +3658,7 @@ def gen_services_proxies_up(
3642
3658
  ctx: typer.Context,
3643
3659
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3644
3660
  yes: bool = _YES_OPT,
3645
- output: OutputFormat | None = _OUTPUT_OPT,
3661
+ output: bool | None = _OUTPUT_OPT,
3646
3662
  ) -> None:
3647
3663
  """Bring a proxy up."""
3648
3664
 
@@ -3661,7 +3677,7 @@ def gen_services_proxies_up(
3661
3677
  def gen_services_searches_index(
3662
3678
  ctx: typer.Context,
3663
3679
  sort: str | None = _SORT_OPT,
3664
- output: OutputFormat | None = _OUTPUT_OPT,
3680
+ output: bool | None = _OUTPUT_OPT,
3665
3681
  ) -> None:
3666
3682
  """List searches."""
3667
3683
 
@@ -3679,7 +3695,7 @@ def gen_services_searches_index(
3679
3695
  def gen_services_searches_show(
3680
3696
  ctx: typer.Context,
3681
3697
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3682
- output: OutputFormat | None = _OUTPUT_OPT,
3698
+ output: bool | None = _OUTPUT_OPT,
3683
3699
  ) -> None:
3684
3700
  """Show searches details."""
3685
3701
 
@@ -3696,7 +3712,7 @@ def gen_services_searches_show(
3696
3712
  def gen_services_servers_index(
3697
3713
  ctx: typer.Context,
3698
3714
  sort: str | None = _SORT_OPT,
3699
- output: OutputFormat | None = _OUTPUT_OPT,
3715
+ output: bool | None = _OUTPUT_OPT,
3700
3716
  ) -> None:
3701
3717
  """List servers."""
3702
3718
 
@@ -3714,7 +3730,7 @@ def gen_services_servers_index(
3714
3730
  def gen_services_servers_show(
3715
3731
  ctx: typer.Context,
3716
3732
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3717
- output: OutputFormat | None = _OUTPUT_OPT,
3733
+ output: bool | None = _OUTPUT_OPT,
3718
3734
  ) -> None:
3719
3735
  """Show servers details."""
3720
3736
 
@@ -3733,7 +3749,7 @@ def gen_services_servers_state(
3733
3749
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3734
3750
  state: str = typer.Argument(..., metavar="STATE"),
3735
3751
  yes: bool = _YES_OPT,
3736
- output: OutputFormat | None = _OUTPUT_OPT,
3752
+ output: bool | None = _OUTPUT_OPT,
3737
3753
  ) -> None:
3738
3754
  """Change the state of a server."""
3739
3755
 
@@ -3752,7 +3768,7 @@ def gen_services_servers_state(
3752
3768
  def gen_services_sites_index(
3753
3769
  ctx: typer.Context,
3754
3770
  sort: str | None = _SORT_OPT,
3755
- output: OutputFormat | None = _OUTPUT_OPT,
3771
+ output: bool | None = _OUTPUT_OPT,
3756
3772
  ) -> None:
3757
3773
  """List sites."""
3758
3774
 
@@ -3770,7 +3786,7 @@ def gen_services_sites_index(
3770
3786
  def gen_services_sites_show(
3771
3787
  ctx: typer.Context,
3772
3788
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3773
- output: OutputFormat | None = _OUTPUT_OPT,
3789
+ output: bool | None = _OUTPUT_OPT,
3774
3790
  ) -> None:
3775
3791
  """Show sites details."""
3776
3792
 
@@ -3787,7 +3803,7 @@ def gen_services_sites_show(
3787
3803
  def gen_services_spams_clusters_index(
3788
3804
  ctx: typer.Context,
3789
3805
  sort: str | None = _SORT_OPT,
3790
- output: OutputFormat | None = _OUTPUT_OPT,
3806
+ output: bool | None = _OUTPUT_OPT,
3791
3807
  ) -> None:
3792
3808
  """List spams clusters."""
3793
3809
 
@@ -3805,7 +3821,7 @@ def gen_services_spams_clusters_index(
3805
3821
  def gen_services_spams_clusters_show(
3806
3822
  ctx: typer.Context,
3807
3823
  cluster_id: int = typer.Argument(..., metavar="CLUSTER_ID"),
3808
- output: OutputFormat | None = _OUTPUT_OPT,
3824
+ output: bool | None = _OUTPUT_OPT,
3809
3825
  ) -> None:
3810
3826
  """Show spams clusters details."""
3811
3827
 
@@ -3823,7 +3839,7 @@ def gen_services_spams_domain_create(
3823
3839
  ctx: typer.Context,
3824
3840
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3825
3841
  domain: str | None = typer.Option(None),
3826
- output: OutputFormat | None = _OUTPUT_OPT,
3842
+ output: bool | None = _OUTPUT_OPT,
3827
3843
  ) -> None:
3828
3844
  """Create spams domain."""
3829
3845
 
@@ -3843,7 +3859,7 @@ def gen_services_spams_domain_delete(
3843
3859
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3844
3860
  domain: str = typer.Argument(..., metavar="DOMAIN"),
3845
3861
  yes: bool = _YES_OPT,
3846
- output: OutputFormat | None = _OUTPUT_OPT,
3862
+ output: bool | None = _OUTPUT_OPT,
3847
3863
  ) -> None:
3848
3864
  """Delete spams domain."""
3849
3865
 
@@ -3864,7 +3880,7 @@ def gen_services_spams_domain_dkim_disable(
3864
3880
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3865
3881
  domain: str = typer.Argument(..., metavar="DOMAIN"),
3866
3882
  yes: bool = _YES_OPT,
3867
- output: OutputFormat | None = _OUTPUT_OPT,
3883
+ output: bool | None = _OUTPUT_OPT,
3868
3884
  ) -> None:
3869
3885
  """Disable DKIM for a spam filter domain."""
3870
3886
 
@@ -3885,7 +3901,7 @@ def gen_services_spams_domain_dkim_enable(
3885
3901
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3886
3902
  domain: str = typer.Argument(..., metavar="DOMAIN"),
3887
3903
  yes: bool = _YES_OPT,
3888
- output: OutputFormat | None = _OUTPUT_OPT,
3904
+ output: bool | None = _OUTPUT_OPT,
3889
3905
  ) -> None:
3890
3906
  """Enable DKIM for a spam filter domain."""
3891
3907
 
@@ -3905,7 +3921,7 @@ def gen_services_spams_domain_index(
3905
3921
  ctx: typer.Context,
3906
3922
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3907
3923
  sort: str | None = _SORT_OPT,
3908
- output: OutputFormat | None = _OUTPUT_OPT,
3924
+ output: bool | None = _OUTPUT_OPT,
3909
3925
  ) -> None:
3910
3926
  """List spams domain."""
3911
3927
 
@@ -3924,7 +3940,7 @@ def gen_services_spams_domain_show(
3924
3940
  ctx: typer.Context,
3925
3941
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3926
3942
  domain: str = typer.Argument(..., metavar="DOMAIN"),
3927
- output: OutputFormat | None = _OUTPUT_OPT,
3943
+ output: bool | None = _OUTPUT_OPT,
3928
3944
  ) -> None:
3929
3945
  """Show spams domain details."""
3930
3946
 
@@ -3941,7 +3957,7 @@ def gen_services_spams_domain_show(
3941
3957
  def gen_services_spams_index(
3942
3958
  ctx: typer.Context,
3943
3959
  sort: str | None = _SORT_OPT,
3944
- output: OutputFormat | None = _OUTPUT_OPT,
3960
+ output: bool | None = _OUTPUT_OPT,
3945
3961
  ) -> None:
3946
3962
  """List spams."""
3947
3963
 
@@ -3959,7 +3975,7 @@ def gen_services_spams_index(
3959
3975
  def gen_services_spams_show(
3960
3976
  ctx: typer.Context,
3961
3977
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
3962
- output: OutputFormat | None = _OUTPUT_OPT,
3978
+ output: bool | None = _OUTPUT_OPT,
3963
3979
  ) -> None:
3964
3980
  """Show spams details."""
3965
3981
 
@@ -3979,7 +3995,7 @@ def gen_services_spams_transports_create(
3979
3995
  domain: str | None = typer.Option(None),
3980
3996
  host: str | None = typer.Option(None),
3981
3997
  port: int | None = typer.Option(None),
3982
- output: OutputFormat | None = _OUTPUT_OPT,
3998
+ output: bool | None = _OUTPUT_OPT,
3983
3999
  ) -> None:
3984
4000
  """Create spams transports."""
3985
4001
 
@@ -3999,7 +4015,7 @@ def gen_services_spams_transports_delete(
3999
4015
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
4000
4016
  domain: str = typer.Argument(..., metavar="DOMAIN"),
4001
4017
  yes: bool = _YES_OPT,
4002
- output: OutputFormat | None = _OUTPUT_OPT,
4018
+ output: bool | None = _OUTPUT_OPT,
4003
4019
  ) -> None:
4004
4020
  """Delete spams transports."""
4005
4021
 
@@ -4019,7 +4035,7 @@ def gen_services_spams_transports_index(
4019
4035
  ctx: typer.Context,
4020
4036
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
4021
4037
  sort: str | None = _SORT_OPT,
4022
- output: OutputFormat | None = _OUTPUT_OPT,
4038
+ output: bool | None = _OUTPUT_OPT,
4023
4039
  ) -> None:
4024
4040
  """List spams transports."""
4025
4041
 
@@ -4038,7 +4054,7 @@ def gen_services_spams_transports_show(
4038
4054
  ctx: typer.Context,
4039
4055
  service_id: int = typer.Argument(..., metavar="SERVICE_ID"),
4040
4056
  domain: str = typer.Argument(..., metavar="DOMAIN"),
4041
- output: OutputFormat | None = _OUTPUT_OPT,
4057
+ output: bool | None = _OUTPUT_OPT,
4042
4058
  ) -> None:
4043
4059
  """Show spams transports details."""
4044
4060
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "devnomads-cli"
3
- version = "0.5.3"
3
+ version = "0.5.5"
4
4
  description = "Manage your DevNomads services from the command line"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -386,7 +386,7 @@ def test_cert_list_shows_issued(configured, isolated_config):
386
386
  import json
387
387
 
388
388
  _write_cert(dncli.config_dir() / "certs" / "example.com", days=45)
389
- result = runner.invoke(app, ["cert", "list", "-o", "json"])
389
+ result = runner.invoke(app, ["cert", "list", "--json"])
390
390
  assert result.exit_code == 0, result.output
391
391
  rows = json.loads(result.output)
392
392
  assert rows[0]["domain"] == "example.com"
@@ -45,7 +45,7 @@ def test_services_list_emits_json_and_bearer_header(configured):
45
45
  }
46
46
  ]
47
47
  route = respx.get(f"{API}/services").mock(return_value=Response(200, json=services))
48
- result = runner.invoke(app, ["--output", "json", "services", "list"])
48
+ result = runner.invoke(app, ["--json", "services", "list"])
49
49
  assert result.exit_code == 0
50
50
  assert json.loads(result.output) == services
51
51
  request = route.calls.last.request
@@ -57,11 +57,9 @@ def test_services_list_emits_json_and_bearer_header(configured):
57
57
  def test_trailing_output_option_beats_global(configured):
58
58
  services = [{"service_id": 1}]
59
59
  respx.get(f"{API}/services").mock(return_value=Response(200, json=services))
60
- # per-command --output works after the subcommand and wins over the
61
- # global one
62
- result = runner.invoke(
63
- app, ["--output", "table", "services", "list", "--output", "json"]
64
- )
60
+ # per-command --json works after the subcommand and wins over the
61
+ # global --table
62
+ result = runner.invoke(app, ["--table", "services", "list", "--json"])
65
63
  assert result.exit_code == 0
66
64
  assert json.loads(result.stdout) == services
67
65
 
@@ -72,7 +70,7 @@ def test_services_list_unwraps_laravel_envelope(configured):
72
70
  respx.get(f"{API}/services").mock(
73
71
  return_value=Response(200, json={"data": services})
74
72
  )
75
- result = runner.invoke(app, ["--output", "json", "services", "list"])
73
+ result = runner.invoke(app, ["--json", "services", "list"])
76
74
  assert result.exit_code == 0
77
75
  assert json.loads(result.output) == services
78
76
 
@@ -84,9 +82,7 @@ def test_services_list_sort_option(configured):
84
82
  {"service_id": 1, "entity": "geleijn.net"},
85
83
  ]
86
84
  respx.get(f"{API}/services").mock(return_value=Response(200, json=services))
87
- result = runner.invoke(
88
- app, ["--output", "json", "services", "list", "--sort", "entity"]
89
- )
85
+ result = runner.invoke(app, ["--json", "services", "list", "--sort", "entity"])
90
86
  assert result.exit_code == 0
91
87
  assert [s["entity"] for s in json.loads(result.output)] == [
92
88
  "geleijn.net",
@@ -116,7 +112,7 @@ def test_records_list_sort_descending(configured):
116
112
  )
117
113
  result = runner.invoke(
118
114
  app,
119
- ["--output", "json", "dns", "records", "list", "example.com", "--sort", "-ttl"],
115
+ ["--json", "dns", "records", "list", "example.com", "--sort", "-ttl"],
120
116
  )
121
117
  assert result.exit_code == 0
122
118
  assert [r["ttl"] for r in json.loads(result.output)] == [3600, 60]
@@ -137,7 +133,7 @@ def test_services_show(configured):
137
133
  respx.get(f"{API}/services/42").mock(
138
134
  return_value=Response(200, json={"service_id": 42, "type": "email"})
139
135
  )
140
- result = runner.invoke(app, ["--output", "json", "services", "show", "42"])
136
+ result = runner.invoke(app, ["--json", "services", "show", "42"])
141
137
  assert result.exit_code == 0
142
138
  assert json.loads(result.output)["service_id"] == 42
143
139
 
@@ -146,7 +142,7 @@ def test_services_show(configured):
146
142
  def test_zones_list(configured):
147
143
  zones = [{"id": "example.com.", "name": "example.com.", "kind": "Master"}]
148
144
  respx.get(f"{API}/services/dns/zones").mock(return_value=Response(200, json=zones))
149
- result = runner.invoke(app, ["--output", "json", "dns", "zones", "list"])
145
+ result = runner.invoke(app, ["--json", "dns", "zones", "list"])
150
146
  assert result.exit_code == 0
151
147
  assert json.loads(result.output) == zones
152
148
 
@@ -172,9 +168,7 @@ def test_zones_show_table_mode(configured):
172
168
  respx.get(f"{API}/services/dns/zones/example.com.").mock(
173
169
  return_value=Response(200, json=ZONE)
174
170
  )
175
- result = runner.invoke(
176
- app, ["--output", "table", "dns", "zones", "show", "example.com"]
177
- )
171
+ result = runner.invoke(app, ["--table", "dns", "zones", "show", "example.com"])
178
172
  assert result.exit_code == 0
179
173
  assert "www.example.com." in result.output
180
174
  assert "192.0.2.1" in result.output
@@ -187,9 +181,7 @@ def test_zones_show_accepts_trailing_dot_form_too(configured):
187
181
  )
188
182
  # both spellings resolve to the canonical PowerDNS zone id
189
183
  for zone_arg in ("example.com", "example.com."):
190
- result = runner.invoke(
191
- app, ["--output", "json", "dns", "zones", "show", zone_arg]
192
- )
184
+ result = runner.invoke(app, ["--json", "dns", "zones", "show", zone_arg])
193
185
  assert result.exit_code == 0, result.output
194
186
  assert route.call_count == 2
195
187
 
@@ -199,9 +191,7 @@ def test_records_list_flattens_rrsets(configured):
199
191
  respx.get(f"{API}/services/dns/zones/example.com.").mock(
200
192
  return_value=Response(200, json=ZONE)
201
193
  )
202
- result = runner.invoke(
203
- app, ["--output", "json", "dns", "records", "list", "example.com"]
204
- )
194
+ result = runner.invoke(app, ["--json", "dns", "records", "list", "example.com"])
205
195
  assert result.exit_code == 0
206
196
  rows = json.loads(result.output)
207
197
  assert rows == [
@@ -318,7 +308,7 @@ def test_retry_on_429_honors_retry_after(configured, monkeypatch):
318
308
  Response(429, headers={"Retry-After": "3"}),
319
309
  Response(200, json=[]),
320
310
  ]
321
- result = runner.invoke(app, ["--output", "json", "services", "list"])
311
+ result = runner.invoke(app, ["--json", "services", "list"])
322
312
  assert result.exit_code == 0
323
313
  assert route.call_count == 2
324
314
  assert sleeps == [3.0]
@@ -397,7 +387,7 @@ def test_configure_unknown_provider(isolated_config):
397
387
  def test_configure_list_masks_secrets(write_profile):
398
388
  write_profile(api_key="dn_abcdefghijklmnop")
399
389
  write_profile("transip:personal", login="loek", private_key_file="/x.pem")
400
- result = runner.invoke(app, ["--output", "json", "configure", "list"])
390
+ result = runner.invoke(app, ["--json", "configure", "list"])
401
391
  assert result.exit_code == 0
402
392
  rows = {row["profile"]: row for row in json.loads(result.output)}
403
393
  assert rows["default"]["type"] == "devnomads"
@@ -22,7 +22,7 @@ def configured(write_profile):
22
22
  def test_handles_list(configured):
23
23
  handles = [{"handle_id": 7, "firstname": "Loek"}]
24
24
  respx.get(f"{API}/handles").mock(return_value=Response(200, json={"data": handles}))
25
- result = runner.invoke(app, ["--output", "json", "handles", "list"])
25
+ result = runner.invoke(app, ["--json", "handles", "list"])
26
26
  assert result.exit_code == 0
27
27
  assert json.loads(result.output) == handles
28
28
 
@@ -35,8 +35,7 @@ def test_nested_path_params(configured):
35
35
  result = runner.invoke(
36
36
  app,
37
37
  [
38
- "--output",
39
- "json",
38
+ "--json",
40
39
  "containers",
41
40
  "instances",
42
41
  "volumes",
@@ -138,7 +137,7 @@ def test_table_mode_flattens_nested_detail_objects(configured):
138
137
  )
139
138
  result = runner.invoke(
140
139
  app,
141
- ["--output", "table", "proxies", "list"],
140
+ ["--table", "proxies", "list"],
142
141
  env={"COLUMNS": "200"}, # wide terminal so rich does not truncate
143
142
  )
144
143
  assert result.exit_code == 0
@@ -153,7 +152,7 @@ def test_json_mode_keeps_raw_nested_shape(configured):
153
152
  respx.get(f"{API}/services/proxies").mock(
154
153
  return_value=Response(200, json={"data": PROXIES})
155
154
  )
156
- result = runner.invoke(app, ["--output", "json", "proxies", "list"])
155
+ result = runner.invoke(app, ["--json", "proxies", "list"])
157
156
  assert result.exit_code == 0
158
157
  assert json.loads(result.output) == PROXIES
159
158
 
@@ -163,7 +162,7 @@ def test_trailing_output_option_on_generated_command(configured):
163
162
  respx.get(f"{API}/services/forwards/2493").mock(
164
163
  return_value=Response(200, json={"data": {"service_id": 2493}})
165
164
  )
166
- result = runner.invoke(app, ["forwards", "show", "2493", "--output", "json"])
165
+ result = runner.invoke(app, ["forwards", "show", "2493", "--json"])
167
166
  assert result.exit_code == 0, result.output
168
167
  assert json.loads(result.stdout)["service_id"] == 2493
169
168
 
@@ -172,7 +171,7 @@ def test_trailing_output_option_on_generated_command(configured):
172
171
  def test_unique_command_prefixes_resolve(configured):
173
172
  respx.get(f"{API}/services/emails").mock(return_value=Response(200, json=[]))
174
173
  # `dncli e l` -> `dncli emails list`
175
- result = runner.invoke(app, ["e", "l", "--output", "json"])
174
+ result = runner.invoke(app, ["e", "l", "--json"])
176
175
  assert result.exit_code == 0, result.output
177
176
  assert json.loads(result.stdout) == []
178
177
 
@@ -196,7 +195,7 @@ def test_exact_command_name_always_wins(configured):
196
195
  @respx.mock
197
196
  def test_plain_get_does_not_confirm(configured):
198
197
  respx.get(f"{API}/services/servers").mock(return_value=Response(200, json=[]))
199
- result = runner.invoke(app, ["--output", "json", "servers", "list"])
198
+ result = runner.invoke(app, ["--json", "servers", "list"])
200
199
  assert result.exit_code == 0
201
200
 
202
201
 
@@ -206,7 +205,7 @@ def test_generated_list_supports_sort(configured):
206
205
  respx.get(f"{API}/services/servers").mock(return_value=Response(200, json=servers))
207
206
  result = runner.invoke(
208
207
  app,
209
- ["--output", "json", "servers", "list", "--sort", "service_id"],
208
+ ["--json", "servers", "list", "--sort", "service_id"],
210
209
  )
211
210
  assert result.exit_code == 0
212
211
  assert [s["service_id"] for s in json.loads(result.output)] == [1, 2]
@@ -231,25 +231,25 @@ def test_cell_detail_keeps_per_item_lines():
231
231
  assert _cell(insts) == "id=7 state_last_known=running"
232
232
 
233
233
 
234
- def test_auto_columns_drops_empty_constant_and_object_lists():
234
+ def test_auto_columns_drops_empty_and_object_lists_only():
235
235
  rows = [
236
236
  {"id": 1, "port": 80, "registry": "same", "blank": "", "instances": [{"i": 7}]},
237
237
  {"id": 2, "port": 81, "registry": "same", "blank": "", "instances": [{"i": 8}]},
238
238
  ]
239
- # registry is constant, blank is empty, instances is an object list -> all
240
- # dropped; id (anchor) and port (varies) remain.
241
- assert _auto_columns(rows) == ["id", "port"]
239
+ # blank is empty and instances is an object list -> dropped; every other
240
+ # scalar is kept, including the constant `registry`.
241
+ assert _auto_columns(rows) == ["id", "port", "registry"]
242
242
 
243
243
 
244
- def test_auto_columns_keeps_anchor_even_if_constant():
244
+ def test_auto_columns_keeps_constant_scalar_columns():
245
245
  rows = [{"id": 1, "x": 9, "y": "a"}, {"id": 1, "x": 9, "y": "b"}]
246
- # x is constant -> dropped; id is constant but the anchor -> kept
247
- assert _auto_columns(rows) == ["id", "y"]
246
+ # constant columns are no longer dropped - normal fields always show
247
+ assert _auto_columns(rows) == ["id", "x", "y"]
248
248
 
249
249
 
250
250
  def test_auto_columns_single_row_keeps_nonempty_scalars():
251
251
  rows = [{"id": 1, "name": "x", "blank": None, "items": [{"a": 1}]}]
252
- # one row: no constant-drop, but empty and object-list columns still go
252
+ # empty and object-list columns go, scalars stay
253
253
  assert _auto_columns(rows) == ["id", "name"]
254
254
 
255
255
 
@@ -266,8 +266,8 @@ def test_object_table_uses_auto_columns():
266
266
  {"emailaddress": "b@x", "quota": 2, "domain": "x"},
267
267
  ]
268
268
  table = _object_table(items)
269
- # constant `domain` dropped; the differing fields are kept as headers
270
- assert [c.header for c in table.columns] == ["emailaddress", "quota"]
269
+ # all scalar sub-fields are kept (empties/object-lists would be dropped)
270
+ assert [c.header for c in table.columns] == ["emailaddress", "quota", "domain"]
271
271
 
272
272
 
273
273
  def test_render_kv_drops_empty_and_nests_objects(capsys):
@@ -370,8 +370,7 @@ def test_transfer_dry_run_does_not_patch(transfer_setup):
370
370
  result = runner.invoke(
371
371
  app,
372
372
  [
373
- "--output",
374
- "json",
373
+ "--json",
375
374
  "dns",
376
375
  "transfer",
377
376
  "--from",
File without changes
File without changes