cacholong-cloud-cli 1.2.0__tar.gz → 1.4.0__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 (83) hide show
  1. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/PKG-INFO +1 -1
  2. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_cli/AsyncTyper.py +11 -1
  3. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_cli/commands/accounts.py +12 -1
  4. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_cli/commands/addresses.py +26 -3
  5. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_cli/commands/companies.py +16 -1
  6. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_cli/commands/dns_records.py +22 -3
  7. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_cli/commands/dns_templates.py +22 -3
  8. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_cli/commands/dns_zones.py +22 -3
  9. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_cli/commands/mail_address_aliases.py +24 -3
  10. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_cli/commands/mail_addresses.py +26 -3
  11. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_cli/commands/mail_domains.py +16 -1
  12. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_cli/commands/mail_forwards.py +24 -3
  13. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_cli/commands/products.py +10 -1
  14. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_cli/commands/purchases.py +10 -1
  15. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_cli/commands/users.py +10 -1
  16. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_cli/common.py +40 -11
  17. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/__init__.py +3 -0
  18. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/common.py +8 -4
  19. cacholong_cloud_cli-1.4.0/cacholong_sdk/exception.py +17 -0
  20. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/pyproject.toml +1 -1
  21. cacholong_cloud_cli-1.2.0/cacholong_sdk/exception.py +0 -7
  22. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/README.md +0 -0
  23. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_cli/__init__.py +0 -0
  24. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_cli/cli.py +0 -0
  25. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_cli/connection.py +0 -0
  26. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/account_base.py +0 -0
  27. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/account_show.py +0 -0
  28. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/address_base.py +0 -0
  29. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/address_create_with_company.py +0 -0
  30. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/address_create_with_user.py +0 -0
  31. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/address_show.py +0 -0
  32. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/address_update.py +0 -0
  33. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/api_schema.py +0 -0
  34. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/company_base.py +0 -0
  35. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/company_show.py +0 -0
  36. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/company_update.py +0 -0
  37. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/connection.py +0 -0
  38. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/dns_record_base.py +0 -0
  39. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/dns_record_create_with_template.py +0 -0
  40. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/dns_record_create_with_zone.py +0 -0
  41. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/dns_record_show.py +0 -0
  42. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/dns_record_update.py +0 -0
  43. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/dns_template_base.py +0 -0
  44. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/dns_template_create.py +0 -0
  45. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/dns_template_show.py +0 -0
  46. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/dns_template_update.py +0 -0
  47. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/dns_zone_base.py +0 -0
  48. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/dns_zone_create.py +0 -0
  49. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/dns_zone_show.py +0 -0
  50. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/dns_zone_update.py +0 -0
  51. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/mail_address_alias_base.py +0 -0
  52. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/mail_address_alias_create.py +0 -0
  53. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/mail_address_alias_show.py +0 -0
  54. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/mail_address_alias_update.py +0 -0
  55. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/mail_address_base.py +0 -0
  56. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/mail_address_create.py +0 -0
  57. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/mail_address_show.py +0 -0
  58. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/mail_address_update.py +0 -0
  59. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/mail_domain_base.py +0 -0
  60. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/mail_domain_show.py +0 -0
  61. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/mail_forward_base.py +0 -0
  62. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/mail_forward_create.py +0 -0
  63. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/mail_forward_show.py +0 -0
  64. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/mail_forward_update.py +0 -0
  65. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/product_base.py +0 -0
  66. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/product_show.py +0 -0
  67. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/purchase_base.py +0 -0
  68. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/purchase_show.py +0 -0
  69. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/service_mail_base.py +0 -0
  70. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/service_mail_show.py +0 -0
  71. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/user_base.py +0 -0
  72. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/user_role_base.py +0 -0
  73. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/user_role_show.py +0 -0
  74. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/cacholong_sdk/user_show.py +0 -0
  75. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/jsonapi-client/src/jsonapi_client/__init__.py +0 -0
  76. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/jsonapi-client/src/jsonapi_client/common.py +0 -0
  77. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/jsonapi-client/src/jsonapi_client/document.py +0 -0
  78. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/jsonapi-client/src/jsonapi_client/exceptions.py +0 -0
  79. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/jsonapi-client/src/jsonapi_client/filter.py +0 -0
  80. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/jsonapi-client/src/jsonapi_client/objects.py +0 -0
  81. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/jsonapi-client/src/jsonapi_client/relationships.py +0 -0
  82. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/jsonapi-client/src/jsonapi_client/resourceobject.py +0 -0
  83. {cacholong_cloud_cli-1.2.0 → cacholong_cloud_cli-1.4.0}/jsonapi-client/src/jsonapi_client/session.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cacholong-cloud-cli
3
- Version: 1.2.0
3
+ Version: 1.4.0
4
4
  Summary: Cacholong CLI, manage cloud environments at Cacholong!
5
5
  License: MIT
6
6
  Author: Matthijs Möhlmann
@@ -1,8 +1,12 @@
1
1
  from asyncio import run
2
2
  from functools import wraps
3
3
  from typing import Callable, Any
4
+ import sys
4
5
 
5
6
  import typer
7
+ from rich.console import Console
8
+
9
+ _error_console = Console(stderr=True)
6
10
 
7
11
 
8
12
  class AsyncTyper(typer.Typer):
@@ -12,7 +16,13 @@ class AsyncTyper(typer.Typer):
12
16
  def decorator(async_func: Callable) -> Callable:
13
17
  @wraps(async_func)
14
18
  def sync_func(*_args: Any, **_kwargs: Any) -> Any:
15
- return run(async_func(*_args, **_kwargs))
19
+ try:
20
+ return run(async_func(*_args, **_kwargs))
21
+ except SystemExit:
22
+ raise
23
+ except Exception as e:
24
+ _error_console.print(f"[bold red]Unexpected error:[/bold red] {e}")
25
+ sys.exit(1)
16
26
 
17
27
  self.command(*args, **kwargs)(sync_func)
18
28
  return async_func
@@ -11,10 +11,17 @@ from cacholong_cli.common import (
11
11
  list_relation_resources,
12
12
  show_resource,
13
13
  print_document_error,
14
+ print_validation_error,
14
15
  TableDef,
15
16
  )
16
17
  from cacholong_cli.connection import Connection
17
- from cacholong_sdk import Filter, Inclusion, DocumentError, ResourceTuple
18
+ from cacholong_sdk import (
19
+ Filter,
20
+ Inclusion,
21
+ DocumentError,
22
+ ResourceTuple,
23
+ ValidationException,
24
+ )
18
25
  from cacholong_sdk import AccountBase, AccountBaseModel
19
26
 
20
27
  from cacholong_sdk.api_schema import api_schema
@@ -246,6 +253,8 @@ async def show(
246
253
  model = await ctrl.fetch(account_id)
247
254
 
248
255
  show_resource(ctx, model)
256
+ except ValidationException as e:
257
+ print_validation_error(e)
249
258
  except DocumentError as e:
250
259
  await print_document_error(e)
251
260
 
@@ -427,5 +436,7 @@ async def list_user_roles(
427
436
  await list_relation_resources(
428
437
  ctx, parent_model, "user-roles", tabledef, modifier
429
438
  )
439
+ except ValidationException as e:
440
+ print_validation_error(e)
430
441
  except DocumentError as e:
431
442
  await print_document_error(e)
@@ -11,10 +11,17 @@ from cacholong_cli.common import (
11
11
  list_relation_resources,
12
12
  show_resource,
13
13
  print_document_error,
14
+ print_validation_error,
14
15
  TableDef,
15
16
  )
16
17
  from cacholong_cli.connection import Connection
17
- from cacholong_sdk import Filter, Inclusion, DocumentError, ResourceTuple
18
+ from cacholong_sdk import (
19
+ Filter,
20
+ Inclusion,
21
+ DocumentError,
22
+ ResourceTuple,
23
+ ValidationException,
24
+ )
18
25
  from cacholong_sdk import AddressShow, AddressShowModel
19
26
  from cacholong_sdk import AddressCreateWithUser, AddressCreateWithUserModel
20
27
  from cacholong_sdk import AddressCreateWithCompany, AddressCreateWithCompanyModel
@@ -298,6 +305,8 @@ async def show(
298
305
  model = await ctrl.fetch(address_id)
299
306
 
300
307
  show_resource(ctx, model)
308
+ except ValidationException as e:
309
+ print_validation_error(e)
301
310
  except DocumentError as e:
302
311
  await print_document_error(e)
303
312
 
@@ -380,6 +389,8 @@ async def create(
380
389
  await ctrl.store(model, ctx.obj["create_issue"]) # type: ignore[arg-type]
381
390
 
382
391
  show_resource(ctx, model)
392
+ except ValidationException as e:
393
+ print_validation_error(e)
383
394
  except DocumentError as e:
384
395
  await print_document_error(e)
385
396
 
@@ -444,6 +455,8 @@ async def update(
444
455
  await ctrl.update(model)
445
456
 
446
457
  show_resource(ctx, model)
458
+ except ValidationException as e:
459
+ print_validation_error(e)
447
460
  except DocumentError as e:
448
461
  await print_document_error(e)
449
462
 
@@ -458,8 +471,14 @@ async def delete(
458
471
  ctrl = AddressShow(conn, api_schema)
459
472
  for resource_id in address_id:
460
473
  tg.create_task(ctrl.destroy(resource_id))
461
- except DocumentError as e:
462
- await print_document_error(e)
474
+ except* ValidationException as eg:
475
+ for e in eg.exceptions:
476
+ if isinstance(e, ValidationException):
477
+ print_validation_error(e)
478
+ except* DocumentError as eg:
479
+ for e in eg.exceptions:
480
+ if isinstance(e, DocumentError):
481
+ await print_document_error(e)
463
482
 
464
483
 
465
484
  @app.async_command(
@@ -481,6 +500,8 @@ async def show_company(
481
500
  related = parent_model["company"].resource
482
501
 
483
502
  show_resource(ctx, related)
503
+ except ValidationException as e:
504
+ print_validation_error(e)
484
505
  except DocumentError as e:
485
506
  await print_document_error(e)
486
507
 
@@ -504,5 +525,7 @@ async def show_user(
504
525
  related = parent_model["user"].resource
505
526
 
506
527
  show_resource(ctx, related)
528
+ except ValidationException as e:
529
+ print_validation_error(e)
507
530
  except DocumentError as e:
508
531
  await print_document_error(e)
@@ -11,10 +11,17 @@ from cacholong_cli.common import (
11
11
  list_relation_resources,
12
12
  show_resource,
13
13
  print_document_error,
14
+ print_validation_error,
14
15
  TableDef,
15
16
  )
16
17
  from cacholong_cli.connection import Connection
17
- from cacholong_sdk import Filter, Inclusion, DocumentError, ResourceTuple
18
+ from cacholong_sdk import (
19
+ Filter,
20
+ Inclusion,
21
+ DocumentError,
22
+ ResourceTuple,
23
+ ValidationException,
24
+ )
18
25
  from cacholong_sdk import CompanyBase, CompanyBaseModel
19
26
 
20
27
  from cacholong_sdk.api_schema import api_schema
@@ -35,6 +42,8 @@ async def show(
35
42
  model = await ctrl.fetch(company_id)
36
43
 
37
44
  show_resource(ctx, model)
45
+ except ValidationException as e:
46
+ print_validation_error(e)
38
47
  except DocumentError as e:
39
48
  await print_document_error(e)
40
49
 
@@ -85,6 +94,8 @@ async def update(
85
94
  await ctrl.update(model)
86
95
 
87
96
  show_resource(ctx, model)
97
+ except ValidationException as e:
98
+ print_validation_error(e)
88
99
  except DocumentError as e:
89
100
  await print_document_error(e)
90
101
 
@@ -336,6 +347,8 @@ async def list_addresses(
336
347
  await list_relation_resources(
337
348
  ctx, parent_model, "addresses", tabledef, modifier
338
349
  )
350
+ except ValidationException as e:
351
+ print_validation_error(e)
339
352
  except DocumentError as e:
340
353
  await print_document_error(e)
341
354
 
@@ -359,5 +372,7 @@ async def show_account(
359
372
  related = parent_model["account"].resource
360
373
 
361
374
  show_resource(ctx, related)
375
+ except ValidationException as e:
376
+ print_validation_error(e)
362
377
  except DocumentError as e:
363
378
  await print_document_error(e)
@@ -11,10 +11,17 @@ from cacholong_cli.common import (
11
11
  list_relation_resources,
12
12
  show_resource,
13
13
  print_document_error,
14
+ print_validation_error,
14
15
  TableDef,
15
16
  )
16
17
  from cacholong_cli.connection import Connection
17
- from cacholong_sdk import Filter, Inclusion, DocumentError, ResourceTuple
18
+ from cacholong_sdk import (
19
+ Filter,
20
+ Inclusion,
21
+ DocumentError,
22
+ ResourceTuple,
23
+ ValidationException,
24
+ )
18
25
  from cacholong_sdk import DnsRecordBase, DnsRecordBaseModel
19
26
  from cacholong_sdk import DnsRecordCreateWithZone, DnsRecordCreateWithZoneModel
20
27
  from cacholong_sdk import DnsRecordCreateWithTemplate, DnsRecordCreateWithTemplateModel
@@ -273,6 +280,8 @@ async def show(
273
280
  model = await ctrl.fetch(dns_record_id)
274
281
 
275
282
  show_resource(ctx, model)
283
+ except ValidationException as e:
284
+ print_validation_error(e)
276
285
  except DocumentError as e:
277
286
  await print_document_error(e)
278
287
 
@@ -344,6 +353,8 @@ async def create(
344
353
  await ctrl.store(model, ctx.obj["create_issue"]) # type: ignore[arg-type]
345
354
 
346
355
  show_resource(ctx, model)
356
+ except ValidationException as e:
357
+ print_validation_error(e)
347
358
  except DocumentError as e:
348
359
  await print_document_error(e)
349
360
 
@@ -397,6 +408,8 @@ async def update(
397
408
  await ctrl.update(model)
398
409
 
399
410
  show_resource(ctx, model)
411
+ except ValidationException as e:
412
+ print_validation_error(e)
400
413
  except DocumentError as e:
401
414
  await print_document_error(e)
402
415
 
@@ -413,5 +426,11 @@ async def delete(
413
426
  ctrl = DnsRecordBase(conn, api_schema)
414
427
  for resource_id in dns_record_id:
415
428
  tg.create_task(ctrl.destroy(resource_id))
416
- except DocumentError as e:
417
- await print_document_error(e)
429
+ except* ValidationException as eg:
430
+ for e in eg.exceptions:
431
+ if isinstance(e, ValidationException):
432
+ print_validation_error(e)
433
+ except* DocumentError as eg:
434
+ for e in eg.exceptions:
435
+ if isinstance(e, DocumentError):
436
+ await print_document_error(e)
@@ -11,10 +11,17 @@ from cacholong_cli.common import (
11
11
  list_relation_resources,
12
12
  show_resource,
13
13
  print_document_error,
14
+ print_validation_error,
14
15
  TableDef,
15
16
  )
16
17
  from cacholong_cli.connection import Connection
17
- from cacholong_sdk import Filter, Inclusion, DocumentError, ResourceTuple
18
+ from cacholong_sdk import (
19
+ Filter,
20
+ Inclusion,
21
+ DocumentError,
22
+ ResourceTuple,
23
+ ValidationException,
24
+ )
18
25
  from cacholong_sdk import DnsTemplateShow, DnsTemplateShowModel
19
26
 
20
27
  from cacholong_sdk.api_schema import api_schema
@@ -226,6 +233,8 @@ async def show(
226
233
  model = await ctrl.fetch(dns_template_id)
227
234
 
228
235
  show_resource(ctx, model)
236
+ except ValidationException as e:
237
+ print_validation_error(e)
229
238
  except DocumentError as e:
230
239
  await print_document_error(e)
231
240
 
@@ -254,6 +263,8 @@ async def create(
254
263
  await ctrl.store(model, ctx.obj["create_issue"])
255
264
 
256
265
  show_resource(ctx, model)
266
+ except ValidationException as e:
267
+ print_validation_error(e)
257
268
  except DocumentError as e:
258
269
  await print_document_error(e)
259
270
 
@@ -277,6 +288,8 @@ async def update(
277
288
  await ctrl.update(model)
278
289
 
279
290
  show_resource(ctx, model)
291
+ except ValidationException as e:
292
+ print_validation_error(e)
280
293
  except DocumentError as e:
281
294
  await print_document_error(e)
282
295
 
@@ -293,5 +306,11 @@ async def delete(
293
306
  ctrl = DnsTemplateShow(conn, api_schema)
294
307
  for resource_id in dns_template_id:
295
308
  tg.create_task(ctrl.destroy(resource_id))
296
- except DocumentError as e:
297
- await print_document_error(e)
309
+ except* ValidationException as eg:
310
+ for e in eg.exceptions:
311
+ if isinstance(e, ValidationException):
312
+ print_validation_error(e)
313
+ except* DocumentError as eg:
314
+ for e in eg.exceptions:
315
+ if isinstance(e, DocumentError):
316
+ await print_document_error(e)
@@ -11,10 +11,17 @@ from cacholong_cli.common import (
11
11
  list_relation_resources,
12
12
  show_resource,
13
13
  print_document_error,
14
+ print_validation_error,
14
15
  TableDef,
15
16
  )
16
17
  from cacholong_cli.connection import Connection
17
- from cacholong_sdk import Filter, Inclusion, DocumentError, ResourceTuple
18
+ from cacholong_sdk import (
19
+ Filter,
20
+ Inclusion,
21
+ DocumentError,
22
+ ResourceTuple,
23
+ ValidationException,
24
+ )
18
25
  from cacholong_sdk import DnsZoneCreate, DnsZoneCreateModel
19
26
 
20
27
  from cacholong_sdk.api_schema import api_schema
@@ -308,6 +315,8 @@ async def show(
308
315
  model = await ctrl.fetch(dns_zone_id)
309
316
 
310
317
  show_resource(ctx, model)
318
+ except ValidationException as e:
319
+ print_validation_error(e)
311
320
  except DocumentError as e:
312
321
  await print_document_error(e)
313
322
 
@@ -346,6 +355,8 @@ async def create(
346
355
  await ctrl.store(model, ctx.obj["create_issue"])
347
356
 
348
357
  show_resource(ctx, model)
358
+ except ValidationException as e:
359
+ print_validation_error(e)
349
360
  except DocumentError as e:
350
361
  await print_document_error(e)
351
362
 
@@ -383,6 +394,8 @@ async def update(
383
394
  await ctrl.update(model)
384
395
 
385
396
  show_resource(ctx, model)
397
+ except ValidationException as e:
398
+ print_validation_error(e)
386
399
  except DocumentError as e:
387
400
  await print_document_error(e)
388
401
 
@@ -397,5 +410,11 @@ async def delete(
397
410
  ctrl = DnsZoneCreate(conn, api_schema)
398
411
  for resource_id in dns_zone_id:
399
412
  tg.create_task(ctrl.destroy(resource_id))
400
- except DocumentError as e:
401
- await print_document_error(e)
413
+ except* ValidationException as eg:
414
+ for e in eg.exceptions:
415
+ if isinstance(e, ValidationException):
416
+ print_validation_error(e)
417
+ except* DocumentError as eg:
418
+ for e in eg.exceptions:
419
+ if isinstance(e, DocumentError):
420
+ await print_document_error(e)
@@ -11,10 +11,17 @@ from cacholong_cli.common import (
11
11
  list_relation_resources,
12
12
  show_resource,
13
13
  print_document_error,
14
+ print_validation_error,
14
15
  TableDef,
15
16
  )
16
17
  from cacholong_cli.connection import Connection
17
- from cacholong_sdk import Filter, Inclusion, DocumentError, ResourceTuple
18
+ from cacholong_sdk import (
19
+ Filter,
20
+ Inclusion,
21
+ DocumentError,
22
+ ResourceTuple,
23
+ ValidationException,
24
+ )
18
25
  from cacholong_sdk import MailAddressAliasBase, MailAddressAliasBaseModel
19
26
 
20
27
  from cacholong_sdk.api_schema import api_schema
@@ -250,6 +257,8 @@ async def show(
250
257
  model = await ctrl.fetch(mail_address_alias_id)
251
258
 
252
259
  show_resource(ctx, model)
260
+ except ValidationException as e:
261
+ print_validation_error(e)
253
262
  except DocumentError as e:
254
263
  await print_document_error(e)
255
264
 
@@ -285,6 +294,8 @@ async def create(
285
294
  await ctrl.store(model, ctx.obj["create_issue"])
286
295
 
287
296
  show_resource(ctx, model)
297
+ except ValidationException as e:
298
+ print_validation_error(e)
288
299
  except DocumentError as e:
289
300
  await print_document_error(e)
290
301
 
@@ -320,6 +331,8 @@ async def update(
320
331
  await ctrl.update(model)
321
332
 
322
333
  show_resource(ctx, model)
334
+ except ValidationException as e:
335
+ print_validation_error(e)
323
336
  except DocumentError as e:
324
337
  await print_document_error(e)
325
338
 
@@ -336,8 +349,14 @@ async def delete(
336
349
  ctrl = MailAddressAliasBase(conn, api_schema)
337
350
  for resource_id in mail_address_alias_id:
338
351
  tg.create_task(ctrl.destroy(resource_id))
339
- except DocumentError as e:
340
- await print_document_error(e)
352
+ except* ValidationException as eg:
353
+ for e in eg.exceptions:
354
+ if isinstance(e, ValidationException):
355
+ print_validation_error(e)
356
+ except* DocumentError as eg:
357
+ for e in eg.exceptions:
358
+ if isinstance(e, DocumentError):
359
+ await print_document_error(e)
341
360
 
342
361
 
343
362
  @app.async_command(
@@ -360,5 +379,7 @@ async def show_mail_address(
360
379
  related = parent_model["mail-address"].resource
361
380
 
362
381
  show_resource(ctx, related)
382
+ except ValidationException as e:
383
+ print_validation_error(e)
363
384
  except DocumentError as e:
364
385
  await print_document_error(e)
@@ -11,10 +11,17 @@ from cacholong_cli.common import (
11
11
  list_relation_resources,
12
12
  show_resource,
13
13
  print_document_error,
14
+ print_validation_error,
14
15
  TableDef,
15
16
  )
16
17
  from cacholong_cli.connection import Connection
17
- from cacholong_sdk import Filter, Inclusion, DocumentError, ResourceTuple
18
+ from cacholong_sdk import (
19
+ Filter,
20
+ Inclusion,
21
+ DocumentError,
22
+ ResourceTuple,
23
+ ValidationException,
24
+ )
18
25
  from cacholong_sdk import MailAddressBase, MailAddressBaseModel
19
26
 
20
27
  from cacholong_sdk.api_schema import api_schema
@@ -285,6 +292,8 @@ async def show(
285
292
  model = await ctrl.fetch(mail_address_id)
286
293
 
287
294
  show_resource(ctx, model)
295
+ except ValidationException as e:
296
+ print_validation_error(e)
288
297
  except DocumentError as e:
289
298
  await print_document_error(e)
290
299
 
@@ -339,6 +348,8 @@ async def create(
339
348
  await ctrl.store(model, ctx.obj["create_issue"])
340
349
 
341
350
  show_resource(ctx, model)
351
+ except ValidationException as e:
352
+ print_validation_error(e)
342
353
  except DocumentError as e:
343
354
  await print_document_error(e)
344
355
 
@@ -398,6 +409,8 @@ async def update(
398
409
  await ctrl.update(model)
399
410
 
400
411
  show_resource(ctx, model)
412
+ except ValidationException as e:
413
+ print_validation_error(e)
401
414
  except DocumentError as e:
402
415
  await print_document_error(e)
403
416
 
@@ -414,8 +427,14 @@ async def delete(
414
427
  ctrl = MailAddressBase(conn, api_schema)
415
428
  for resource_id in mail_address_id:
416
429
  tg.create_task(ctrl.destroy(resource_id))
417
- except DocumentError as e:
418
- await print_document_error(e)
430
+ except* ValidationException as eg:
431
+ for e in eg.exceptions:
432
+ if isinstance(e, ValidationException):
433
+ print_validation_error(e)
434
+ except* DocumentError as eg:
435
+ for e in eg.exceptions:
436
+ if isinstance(e, DocumentError):
437
+ await print_document_error(e)
419
438
 
420
439
 
421
440
  @app.async_command(
@@ -438,6 +457,8 @@ async def show_mail_domain(
438
457
  related = parent_model["mail-domain"].resource
439
458
 
440
459
  show_resource(ctx, related)
460
+ except ValidationException as e:
461
+ print_validation_error(e)
441
462
  except DocumentError as e:
442
463
  await print_document_error(e)
443
464
 
@@ -668,5 +689,7 @@ async def list_aliases(
668
689
  await list_relation_resources(
669
690
  ctx, parent_model, "aliases", tabledef, modifier
670
691
  )
692
+ except ValidationException as e:
693
+ print_validation_error(e)
671
694
  except DocumentError as e:
672
695
  await print_document_error(e)
@@ -11,10 +11,17 @@ from cacholong_cli.common import (
11
11
  list_relation_resources,
12
12
  show_resource,
13
13
  print_document_error,
14
+ print_validation_error,
14
15
  TableDef,
15
16
  )
16
17
  from cacholong_cli.connection import Connection
17
- from cacholong_sdk import Filter, Inclusion, DocumentError, ResourceTuple
18
+ from cacholong_sdk import (
19
+ Filter,
20
+ Inclusion,
21
+ DocumentError,
22
+ ResourceTuple,
23
+ ValidationException,
24
+ )
18
25
  from cacholong_sdk import MailDomainBase, MailDomainBaseModel
19
26
 
20
27
  from cacholong_sdk.api_schema import api_schema
@@ -259,6 +266,8 @@ async def show(
259
266
  model = await ctrl.fetch(mail_domain_id)
260
267
 
261
268
  show_resource(ctx, model)
269
+ except ValidationException as e:
270
+ print_validation_error(e)
262
271
  except DocumentError as e:
263
272
  await print_document_error(e)
264
273
 
@@ -282,6 +291,8 @@ async def show_account(
282
291
  related = parent_model["account"].resource
283
292
 
284
293
  show_resource(ctx, related)
294
+ except ValidationException as e:
295
+ print_validation_error(e)
285
296
  except DocumentError as e:
286
297
  await print_document_error(e)
287
298
 
@@ -551,6 +562,8 @@ async def list_mail_addresses(
551
562
  await list_relation_resources(
552
563
  ctx, parent_model, "mail-addresses", tabledef, modifier
553
564
  )
565
+ except ValidationException as e:
566
+ print_validation_error(e)
554
567
  except DocumentError as e:
555
568
  await print_document_error(e)
556
569
 
@@ -575,5 +588,7 @@ async def show_service_mail(
575
588
  related = parent_model["service-mail"].resource
576
589
 
577
590
  show_resource(ctx, related)
591
+ except ValidationException as e:
592
+ print_validation_error(e)
578
593
  except DocumentError as e:
579
594
  await print_document_error(e)
@@ -11,10 +11,17 @@ from cacholong_cli.common import (
11
11
  list_relation_resources,
12
12
  show_resource,
13
13
  print_document_error,
14
+ print_validation_error,
14
15
  TableDef,
15
16
  )
16
17
  from cacholong_cli.connection import Connection
17
- from cacholong_sdk import Filter, Inclusion, DocumentError, ResourceTuple
18
+ from cacholong_sdk import (
19
+ Filter,
20
+ Inclusion,
21
+ DocumentError,
22
+ ResourceTuple,
23
+ ValidationException,
24
+ )
18
25
  from cacholong_sdk import MailForwardBase, MailForwardBaseModel
19
26
 
20
27
  from cacholong_sdk.api_schema import api_schema
@@ -241,6 +248,8 @@ async def show(
241
248
  model = await ctrl.fetch(mail_forward_id)
242
249
 
243
250
  show_resource(ctx, model)
251
+ except ValidationException as e:
252
+ print_validation_error(e)
244
253
  except DocumentError as e:
245
254
  await print_document_error(e)
246
255
 
@@ -271,6 +280,8 @@ async def create(
271
280
  await ctrl.store(model, ctx.obj["create_issue"])
272
281
 
273
282
  show_resource(ctx, model)
283
+ except ValidationException as e:
284
+ print_validation_error(e)
274
285
  except DocumentError as e:
275
286
  await print_document_error(e)
276
287
 
@@ -299,6 +310,8 @@ async def update(
299
310
  await ctrl.update(model)
300
311
 
301
312
  show_resource(ctx, model)
313
+ except ValidationException as e:
314
+ print_validation_error(e)
302
315
  except DocumentError as e:
303
316
  await print_document_error(e)
304
317
 
@@ -315,8 +328,14 @@ async def delete(
315
328
  ctrl = MailForwardBase(conn, api_schema)
316
329
  for resource_id in mail_forward_id:
317
330
  tg.create_task(ctrl.destroy(resource_id))
318
- except DocumentError as e:
319
- await print_document_error(e)
331
+ except* ValidationException as eg:
332
+ for e in eg.exceptions:
333
+ if isinstance(e, ValidationException):
334
+ print_validation_error(e)
335
+ except* DocumentError as eg:
336
+ for e in eg.exceptions:
337
+ if isinstance(e, DocumentError):
338
+ await print_document_error(e)
320
339
 
321
340
 
322
341
  @app.async_command(
@@ -339,5 +358,7 @@ async def show_mail_domain(
339
358
  related = parent_model["mail-domain"].resource
340
359
 
341
360
  show_resource(ctx, related)
361
+ except ValidationException as e:
362
+ print_validation_error(e)
342
363
  except DocumentError as e:
343
364
  await print_document_error(e)
@@ -11,10 +11,17 @@ from cacholong_cli.common import (
11
11
  list_relation_resources,
12
12
  show_resource,
13
13
  print_document_error,
14
+ print_validation_error,
14
15
  TableDef,
15
16
  )
16
17
  from cacholong_cli.connection import Connection
17
- from cacholong_sdk import Filter, Inclusion, DocumentError, ResourceTuple
18
+ from cacholong_sdk import (
19
+ Filter,
20
+ Inclusion,
21
+ DocumentError,
22
+ ResourceTuple,
23
+ ValidationException,
24
+ )
18
25
  from cacholong_sdk import ProductBase, ProductBaseModel
19
26
 
20
27
  from cacholong_sdk.api_schema import api_schema
@@ -381,5 +388,7 @@ async def show(
381
388
  model = await ctrl.fetch(product_id)
382
389
 
383
390
  show_resource(ctx, model)
391
+ except ValidationException as e:
392
+ print_validation_error(e)
384
393
  except DocumentError as e:
385
394
  await print_document_error(e)
@@ -11,10 +11,17 @@ from cacholong_cli.common import (
11
11
  list_relation_resources,
12
12
  show_resource,
13
13
  print_document_error,
14
+ print_validation_error,
14
15
  TableDef,
15
16
  )
16
17
  from cacholong_cli.connection import Connection
17
- from cacholong_sdk import Filter, Inclusion, DocumentError, ResourceTuple
18
+ from cacholong_sdk import (
19
+ Filter,
20
+ Inclusion,
21
+ DocumentError,
22
+ ResourceTuple,
23
+ ValidationException,
24
+ )
18
25
  from cacholong_sdk import PurchaseBase, PurchaseBaseModel
19
26
 
20
27
  from cacholong_sdk.api_schema import api_schema
@@ -518,5 +525,7 @@ async def show(
518
525
  model = await ctrl.fetch(purchase_id)
519
526
 
520
527
  show_resource(ctx, model)
528
+ except ValidationException as e:
529
+ print_validation_error(e)
521
530
  except DocumentError as e:
522
531
  await print_document_error(e)
@@ -11,10 +11,17 @@ from cacholong_cli.common import (
11
11
  list_relation_resources,
12
12
  show_resource,
13
13
  print_document_error,
14
+ print_validation_error,
14
15
  TableDef,
15
16
  )
16
17
  from cacholong_cli.connection import Connection
17
- from cacholong_sdk import Filter, Inclusion, DocumentError, ResourceTuple
18
+ from cacholong_sdk import (
19
+ Filter,
20
+ Inclusion,
21
+ DocumentError,
22
+ ResourceTuple,
23
+ ValidationException,
24
+ )
18
25
  from cacholong_sdk import UserBase, UserBaseModel
19
26
 
20
27
  from cacholong_sdk.api_schema import api_schema
@@ -200,5 +207,7 @@ async def list_user_roles(
200
207
  await list_relation_resources(
201
208
  ctx, parent_model, "user-roles", tabledef, modifier
202
209
  )
210
+ except ValidationException as e:
211
+ print_validation_error(e)
203
212
  except DocumentError as e:
204
213
  await print_document_error(e)
@@ -3,15 +3,17 @@ from typing import List, Dict, Any, Optional, Callable, Union
3
3
  from enum import Enum
4
4
  import typer
5
5
  from rich.console import Console
6
+ from rich.panel import Panel
6
7
  from rich.table import Table
7
8
  from rich.table import Column
8
9
  from cacholong_cli.connection import Connection
9
10
  import json
10
11
  from cacholong_sdk import BaseController, BaseModel
11
12
  from cacholong_sdk import Modifier, Sort, SparseField, DocumentError
13
+ from cacholong_sdk.exception import ValidationException
12
14
  from uuid import UUID
13
15
 
14
- ErrorConsole = Console(stderr=True, style="bold red")
16
+ ErrorConsole = Console(stderr=True)
15
17
 
16
18
 
17
19
  class UUIDEncoder(json.JSONEncoder):
@@ -29,16 +31,43 @@ class OutputFormat(str, Enum):
29
31
  TableDef = List[Dict[str, Any]]
30
32
 
31
33
 
32
- async def print_document_error(doc_error: DocumentError):
33
- ErrorConsole.print("Status: {}".format(doc_error.errors["status_code"]))
34
+ def print_validation_error(exc: ValidationException) -> None:
35
+ rows = []
36
+ for entry in exc.errors:
37
+ if entry.field:
38
+ rows.append(f" [bold]{entry.field}[/bold] {entry.message}")
39
+ else:
40
+ rows.append(f" {entry.message}")
41
+ ErrorConsole.print(
42
+ Panel(
43
+ "\n".join(rows), title="[bold red]Validation Error[/bold red]", expand=False
44
+ )
45
+ )
46
+
47
+
48
+ async def print_document_error(doc_error: DocumentError) -> None:
49
+ status_code = doc_error.errors.get("status_code", "")
34
50
  js = await doc_error.response.json()
35
- i = 1
36
- for error in js["errors"]:
37
- detail = ""
38
- if "detail" in error:
39
- detail = error["detail"]
40
- ErrorConsole.print("{}: {}: {}".format(i, error["title"], detail))
41
- i = i + 1
51
+ rows = []
52
+ for error in js.get("errors", []):
53
+ title = error.get("title", "")
54
+ detail = error.get("detail", title)
55
+ source = error.get("source", {})
56
+ pointer = source.get("pointer", "")
57
+ if pointer.startswith("/data/attributes/"):
58
+ field = pointer[len("/data/attributes/") :]
59
+ rows.append(f" [bold]{field}[/bold] {detail}")
60
+ elif pointer:
61
+ rows.append(f" [bold]{pointer}[/bold] {detail}")
62
+ else:
63
+ rows.append(f" {detail}")
64
+ ErrorConsole.print(
65
+ Panel(
66
+ "\n".join(rows) if rows else "",
67
+ title=f"[bold red]API Error · {status_code}[/bold red]",
68
+ expand=False,
69
+ )
70
+ )
42
71
 
43
72
 
44
73
  async def _perform_list_resources(
@@ -112,7 +141,7 @@ async def list_resources(
112
141
  if d["column"] != "id"
113
142
  ]
114
143
  )
115
- )
144
+ ),
116
145
  )
117
146
  )
118
147
 
@@ -70,3 +70,6 @@ from .purchase_show import PurchaseShowModel, PurchaseShow
70
70
  from jsonapi_client import Modifier, Filter, Inclusion, Sort, SparseField
71
71
  from jsonapi_client import ResourceTuple
72
72
  from jsonapi_client.exceptions import DocumentError
73
+
74
+ # Import exceptions
75
+ from .exception import ValidationException
@@ -2,7 +2,7 @@ from typing import Generic, TypeVar, Optional, Any, Union, Awaitable, Type, Dict
2
2
  from jsonapi_client.resourceobject import ResourceObject
3
3
  from jsonapi_client import Modifier, Filter
4
4
  from jsonapi_client.exceptions import DocumentError
5
- from .exception import ValidationException
5
+ from .exception import ValidationException, ErrorEntry
6
6
 
7
7
  from rich.console import Console, ConsoleOptions, RenderResult
8
8
  from rich.json import JSON
@@ -133,7 +133,11 @@ class BaseController(Generic[Model]):
133
133
  try:
134
134
  jsonschema.validate(data_to_validate, json_schema)
135
135
  except jsonschema.ValidationError as e:
136
- raise ValidationException(f"Validation failed for {operation}", [str(e)])
136
+ field = str(e.path[0]) if e.path else None
137
+ raise ValidationException(
138
+ f"Validation failed for {operation}",
139
+ [ErrorEntry(field=field, message=e.message)],
140
+ )
137
141
 
138
142
  async def fetch(self, resource_id) -> Model:
139
143
  doc = await self._connection.get(self._resource, resource_id)
@@ -186,5 +190,5 @@ class BaseController(Generic[Model]):
186
190
  # the cache, just handle the exception and that's it. The resource
187
191
  # is succesfully removed from the server.
188
192
  pass
189
- except DocumentError as e:
190
- raise ValidationException("Validation failed", e.errors)
193
+ except DocumentError:
194
+ raise
@@ -0,0 +1,17 @@
1
+ from typing import List, Optional
2
+ from dataclasses import dataclass
3
+
4
+
5
+ @dataclass
6
+ class ErrorEntry:
7
+ field: Optional[str]
8
+ message: str
9
+
10
+
11
+ class ValidationException(Exception):
12
+ def __init__(self, message: str, errors: List[ErrorEntry]):
13
+ self.message = message
14
+ self.errors = errors
15
+
16
+ # call parent constructor
17
+ super().__init__(self.message)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "cacholong-cloud-cli"
3
- version = "1.2.0"
3
+ version = "1.4.0"
4
4
  description = "Cacholong CLI, manage cloud environments at Cacholong!"
5
5
  authors = ["Matthijs Möhlmann <matthijs@cacholong.nl>"]
6
6
  readme = "README.md"
@@ -1,7 +0,0 @@
1
- class ValidationException(Exception):
2
- def __init__(self, message, errors):
3
- self.message = message
4
- self.errors = errors
5
-
6
- # call parent constructor
7
- super().__init__(self.message)