pyegeria 5.4.0.20__py3-none-any.whl → 5.4.0.23__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. commands/cat/.DS_Store +0 -0
  2. commands/cat/.env +8 -0
  3. commands/cat/debug_log.log +0 -0
  4. commands/cat/list_collections.py +15 -6
  5. commands/cat/list_format_set.py +90 -85
  6. commands/cat/logs/pyegeria.log +136 -0
  7. commands/cli/debug_log.log +0 -0
  8. commands/ops/logs/pyegeria.log +0 -0
  9. md_processing/.DS_Store +0 -0
  10. md_processing/dr-egeria-outbox/Collections-2025-08-12-13-30-37.md +163 -0
  11. md_processing/dr-egeria-outbox/Collections-2025-08-12-13-35-58.md +474 -0
  12. md_processing/dr_egeria_inbox/Derive-Dr-Gov-Defs.md +8 -0
  13. md_processing/dr_egeria_inbox/Dr.Egeria Templates.md +873 -0
  14. md_processing/dr_egeria_inbox/arch_test.md +57 -0
  15. md_processing/dr_egeria_inbox/archive/dr_egeria_intro.md +254 -0
  16. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_more_terms.md +696 -0
  17. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part1.md +254 -0
  18. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part2.md +298 -0
  19. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part3.md +608 -0
  20. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part4.md +94 -0
  21. md_processing/dr_egeria_inbox/archive/freddie_intro.md +284 -0
  22. md_processing/dr_egeria_inbox/archive/freddie_intro_orig.md +275 -0
  23. md_processing/dr_egeria_inbox/archive/test-term.md +110 -0
  24. md_processing/dr_egeria_inbox/cat_test.md +100 -0
  25. md_processing/dr_egeria_inbox/collections.md +39 -0
  26. md_processing/dr_egeria_inbox/data_designer_debug.log +6 -0
  27. md_processing/dr_egeria_inbox/data_designer_out.md +60 -0
  28. md_processing/dr_egeria_inbox/data_designer_search_test.md +11 -0
  29. md_processing/dr_egeria_inbox/data_field.md +54 -0
  30. md_processing/dr_egeria_inbox/data_spec.md +77 -0
  31. md_processing/dr_egeria_inbox/data_spec_test.md +2406 -0
  32. md_processing/dr_egeria_inbox/data_test.md +179 -0
  33. md_processing/dr_egeria_inbox/data_test2.md +429 -0
  34. md_processing/dr_egeria_inbox/data_test3.md +462 -0
  35. md_processing/dr_egeria_inbox/dr_egeria_data_designer_1.md +124 -0
  36. md_processing/dr_egeria_inbox/dr_egeria_intro_categories.md +168 -0
  37. md_processing/dr_egeria_inbox/dr_egeria_intro_part1.md +280 -0
  38. md_processing/dr_egeria_inbox/dr_egeria_intro_part2.md +313 -0
  39. md_processing/dr_egeria_inbox/dr_egeria_intro_part3.md +1073 -0
  40. md_processing/dr_egeria_inbox/dr_egeria_isc1.md +44 -0
  41. md_processing/dr_egeria_inbox/generated_help_report.md +9 -0
  42. md_processing/dr_egeria_inbox/glossary_list.md +5 -0
  43. md_processing/dr_egeria_inbox/glossary_search_test.md +40 -0
  44. md_processing/dr_egeria_inbox/glossary_test1.md +324 -0
  45. md_processing/dr_egeria_inbox/gov_def.md +424 -0
  46. md_processing/dr_egeria_inbox/gov_def2.md +447 -0
  47. md_processing/dr_egeria_inbox/product.md +50 -0
  48. md_processing/dr_egeria_inbox/rel.md +8 -0
  49. md_processing/dr_egeria_inbox/sb.md +119 -0
  50. md_processing/dr_egeria_inbox/solution-components.md +136 -0
  51. md_processing/dr_egeria_inbox/solution_blueprints.md +118 -0
  52. md_processing/dr_egeria_inbox/synonym_test.md +42 -0
  53. md_processing/dr_egeria_inbox/t2.md +268 -0
  54. md_processing/dr_egeria_outbox/.obsidian/app.json +1 -0
  55. md_processing/dr_egeria_outbox/.obsidian/appearance.json +1 -0
  56. md_processing/dr_egeria_outbox/.obsidian/community-plugins.json +6 -0
  57. md_processing/dr_egeria_outbox/.obsidian/core-plugins.json +31 -0
  58. md_processing/dr_egeria_outbox/.obsidian/plugins/calendar/data.json +10 -0
  59. md_processing/dr_egeria_outbox/.obsidian/plugins/calendar/main.js +4459 -0
  60. md_processing/dr_egeria_outbox/.obsidian/plugins/calendar/manifest.json +10 -0
  61. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-kanban/data.json +3 -0
  62. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-kanban/main.js +153 -0
  63. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-kanban/manifest.json +11 -0
  64. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-kanban/styles.css +1 -0
  65. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-tasks-plugin/main.js +500 -0
  66. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-tasks-plugin/manifest.json +12 -0
  67. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-tasks-plugin/styles.css +1 -0
  68. md_processing/dr_egeria_outbox/.obsidian/plugins/templater-obsidian/main.js +37 -0
  69. md_processing/dr_egeria_outbox/.obsidian/plugins/templater-obsidian/manifest.json +11 -0
  70. md_processing/dr_egeria_outbox/.obsidian/plugins/templater-obsidian/styles.css +220 -0
  71. md_processing/dr_egeria_outbox/.obsidian/types.json +28 -0
  72. md_processing/dr_egeria_outbox/.obsidian/workspace.json +220 -0
  73. md_processing/dr_egeria_outbox/Untitled.canvas +1 -0
  74. md_processing/dr_egeria_outbox/friday/processed-2025-07-18 15:00-product.md +62 -0
  75. md_processing/dr_egeria_outbox/friday/processed-2025-07-18 15:13-product.md +62 -0
  76. md_processing/dr_egeria_outbox/friday/processed-2025-07-20 13:23-product.md +47 -0
  77. md_processing/dr_egeria_outbox/friday/processed-2025-08-01 11:55-data_test3.md +503 -0
  78. md_processing/dr_egeria_outbox/monday/processed-2025-07-14 12:38-data_designer_out.md +663 -0
  79. md_processing/dr_egeria_outbox/monday/processed-2025-07-21 10:52-generated_help_report.md +2744 -0
  80. md_processing/dr_egeria_outbox/monday/processed-2025-07-21 18:38-collections.md +62 -0
  81. md_processing/dr_egeria_outbox/monday/processed-2025-08-01 11:34-gov_def.md +444 -0
  82. md_processing/dr_egeria_outbox/processed-2025-08-03 16:05-glossary_list.md +37 -0
  83. md_processing/dr_egeria_outbox/sunday/processed-2025-07-20 14:55-product.md +77 -0
  84. md_processing/dr_egeria_outbox/sunday/processed-2025-07-20 15:05-product.md +75 -0
  85. md_processing/dr_egeria_outbox/sunday/processed-2025-07-20 15:11-product.md +74 -0
  86. md_processing/dr_egeria_outbox/sunday/processed-2025-07-20 20:40-collections.md +49 -0
  87. md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 15:00-Derive-Dr-Gov-Defs.md +719 -0
  88. md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 20:13-Derive-Dr-Gov-Defs.md +41 -0
  89. md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 20:14-Derive-Dr-Gov-Defs.md +33 -0
  90. md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 20:50-Derive-Dr-Gov-Defs.md +192 -0
  91. md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 22:08-gov_def2.md +486 -0
  92. md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 22:10-gov_def2.md +486 -0
  93. md_processing/dr_egeria_outbox/thursday/processed-2025-07-18 08:53-gov_def2.md +486 -0
  94. md_processing/dr_egeria_outbox/thursday/processed-2025-07-18 08:54-gov_def2.md +486 -0
  95. md_processing/dr_egeria_outbox/thursday/processed-2025-07-18 09:03-gov_def2.md +486 -0
  96. md_processing/dr_egeria_outbox/thursday/processed-2025-07-18 09:06-gov_def2.md +486 -0
  97. md_processing/dr_egeria_outbox/thursday/processed-2025-07-18 09:10-gov_def2.md +486 -0
  98. md_processing/dr_egeria_outbox/tuesday/processed-2025-07-16 19:15-gov_def2.md +527 -0
  99. md_processing/dr_egeria_outbox/tuesday/processed-2025-07-17 12:08-gov_def2.md +527 -0
  100. md_processing/dr_egeria_outbox/tuesday/processed-2025-07-17 14:27-gov_def2.md +485 -0
  101. md_processing/md_processing_utils/debug_log.log +0 -0
  102. md_processing/md_processing_utils/solution_architect_log.log +0 -0
  103. pyegeria/.DS_Store +0 -0
  104. pyegeria/__init__.py +2 -2
  105. pyegeria/_client_new.py +392 -98
  106. pyegeria/_exceptions_new.py +16 -13
  107. pyegeria/_output_format_models.py +22 -17
  108. pyegeria/_output_formats.py +107 -34
  109. pyegeria/collection_manager.py +703 -1429
  110. pyegeria/collection_manager_omvs.py +48 -19
  111. pyegeria/egeria_cat_client.py +1 -1
  112. pyegeria/egeria_client.py +6 -0
  113. pyegeria/egeria_tech_client.py +6 -1
  114. pyegeria/governance_officer.py +2515 -0
  115. pyegeria/models.py +23 -6
  116. pyegeria/output_formatter.py +298 -79
  117. {pyegeria-5.4.0.20.dist-info → pyegeria-5.4.0.23.dist-info}/METADATA +1 -1
  118. {pyegeria-5.4.0.20.dist-info → pyegeria-5.4.0.23.dist-info}/RECORD +121 -19
  119. {pyegeria-5.4.0.20.dist-info → pyegeria-5.4.0.23.dist-info}/LICENSE +0 -0
  120. {pyegeria-5.4.0.20.dist-info → pyegeria-5.4.0.23.dist-info}/WHEEL +0 -0
  121. {pyegeria-5.4.0.20.dist-info → pyegeria-5.4.0.23.dist-info}/entry_points.txt +0 -0
pyegeria/_client_new.py CHANGED
@@ -12,33 +12,31 @@ import inspect
12
12
  import json
13
13
  import os
14
14
  import re
15
- from datetime import datetime
15
+ from collections.abc import Callable
16
+ from typing import Any
16
17
 
17
18
  import httpcore
18
19
  import httpx
20
+ from httpx import AsyncClient, Response, HTTPStatusError
19
21
  # from venv import logger
20
22
  from loguru import logger
21
-
22
- from httpx import AsyncClient, Response, HTTPStatusError
23
23
  from pydantic import TypeAdapter
24
24
 
25
- from pyegeria.utils import body_slimmer
26
25
  from pyegeria._exceptions_new import (
27
- PyegeriaException, PyegeriaAPIException, PyegeriaConnectionException, PyegeriaInvalidParameterException,
28
- PyegeriaNotFoundException, PyegeriaUnknownException, PyegeriaErrorCode,
29
- PyegeriaUnauthorizedException, PyegeriaClientException
26
+ PyegeriaAPIException, PyegeriaConnectionException, PyegeriaInvalidParameterException,
27
+ PyegeriaUnknownException, PyegeriaClientException
30
28
  )
31
29
  from pyegeria._globals import enable_ssl_check, max_paging_size, NO_ELEMENTS_FOUND
32
30
  from pyegeria._validators import (
33
- is_json,
34
31
  validate_name,
35
32
  validate_server_name,
36
33
  validate_url,
37
34
  validate_user_id,
38
- )
35
+ )
39
36
  from pyegeria.models import SearchStringRequestBody, FilterRequestBody, GetRequestBody, NewElementRequestBody, \
40
37
  TemplateRequestBody, UpdateStatusRequestBody, UpdateElementRequestBody, NewRelationshipRequestBody, \
41
- DeleteRequestBody
38
+ DeleteRequestBody, UpdateRelationshipRequestBody, ResultsRequestBody
39
+ from pyegeria.utils import body_slimmer
42
40
 
43
41
  ...
44
42
 
@@ -84,16 +82,16 @@ class Client2:
84
82
  json_header = {"Content-Type": "application/json"}
85
83
 
86
84
  def __init__(
87
- self,
88
- server_name: str,
89
- platform_url: str,
90
- user_id: str = None,
91
- user_pwd: str = None,
92
- token: str = None,
93
- token_src: str = None,
94
- api_key: str = None,
95
- page_size: int = max_paging_size,
96
- ):
85
+ self,
86
+ server_name: str,
87
+ platform_url: str,
88
+ user_id: str = None,
89
+ user_pwd: str = None,
90
+ token: str = None,
91
+ token_src: str = None,
92
+ api_key: str = None,
93
+ page_size: int = max_paging_size,
94
+ ):
97
95
  self.server_name = validate_server_name(server_name)
98
96
  self.platform_url = validate_url(platform_url)
99
97
  self.user_id = user_id
@@ -121,10 +119,10 @@ class Client2:
121
119
 
122
120
  self.headers = {
123
121
  "Content-Type": "application/json",
124
- }
122
+ }
125
123
  self.text_headers = {
126
124
  "Content-Type": "text/plain",
127
- }
125
+ }
128
126
  if self.api_key is not None:
129
127
  self.headers["X-Api-Key"] = self.api_key
130
128
  self.text_headers["X-Api-Key"] = self.api_key
@@ -150,6 +148,8 @@ class Client2:
150
148
  self._new_relationship_request_adapter = TypeAdapter(NewRelationshipRequestBody)
151
149
  self._delete_request_adapter = TypeAdapter(DeleteRequestBody)
152
150
  self._template_request_adapter = TypeAdapter(TemplateRequestBody)
151
+ self._update_relationship_request_adapter = TypeAdapter(UpdateRelationshipRequestBody)
152
+ self._results_request_adapter = TypeAdapter(ResultsRequestBody)
153
153
 
154
154
  def __enter__(self):
155
155
  return self
@@ -178,8 +178,8 @@ class Client2:
178
178
  return
179
179
 
180
180
  async def _async_create_egeria_bearer_token(
181
- self, user_id: str = None, password: str = None
182
- ) -> str:
181
+ self, user_id: str = None, password: str = None
182
+ ) -> str:
183
183
  """Create and set an Egeria Bearer Token for the user. Async version
184
184
  Parameters
185
185
  ----------
@@ -235,8 +235,8 @@ class Client2:
235
235
  raise PyegeriaInvalidParameterException(None, None, additional_info)
236
236
 
237
237
  def create_egeria_bearer_token(
238
- self, user_id: str = None, password: str = None
239
- ) -> str:
238
+ self, user_id: str = None, password: str = None
239
+ ) -> str:
240
240
  """Create and set an Egeria Bearer Token for the user
241
241
  Parameters
242
242
  ----------
@@ -268,7 +268,7 @@ class Client2:
268
268
  loop = asyncio.get_event_loop()
269
269
  response = loop.run_until_complete(
270
270
  self._async_create_egeria_bearer_token(user_id, password)
271
- )
271
+ )
272
272
  return response
273
273
 
274
274
  async def _async_refresh_egeria_bearer_token(self) -> str:
@@ -289,19 +289,18 @@ class Client2:
289
289
  InvalidParameterException: If the token source is invalid.
290
290
  """
291
291
  if (
292
- (self.token_src == "Egeria")
293
- and validate_user_id(self.user_id)
294
- and validate_name(self.user_pwd)
292
+ (self.token_src == "Egeria")
293
+ and validate_user_id(self.user_id)
294
+ and validate_name(self.user_pwd)
295
295
  ):
296
296
  token = await self._async_create_egeria_bearer_token(
297
297
  self.user_id, self.user_pwd
298
- )
298
+ )
299
299
  return token
300
300
  else:
301
301
  additional_info = {"reason": "Invalid token source"}
302
302
  raise PyegeriaInvalidParameterException(None, None, additional_info)
303
303
 
304
-
305
304
  def refresh_egeria_bearer_token(self) -> None:
306
305
  """
307
306
  Refreshes the Egeria bearer token.
@@ -373,16 +372,15 @@ class Client2:
373
372
  else:
374
373
  logger.info(f"Got response from {origin_url}\n status_code: {response.status_code}")
375
374
 
376
-
377
375
  # @logger.catch
378
376
  def make_request(
379
- self,
380
- request_type: str,
381
- endpoint: str,
382
- payload: str | dict = None,
383
- time_out: int = 30,
384
- is_json: bool = True,
385
- ) -> Response | str:
377
+ self,
378
+ request_type: str,
379
+ endpoint: str,
380
+ payload: str | dict = None,
381
+ time_out: int = 30,
382
+ is_json: bool = True,
383
+ ) -> Response | str:
386
384
  """Make a request to the Egeria API."""
387
385
  try:
388
386
  loop = asyncio.get_running_loop()
@@ -390,19 +388,20 @@ class Client2:
390
388
  coro = self._async_make_request(request_type, endpoint, payload, time_out, is_json)
391
389
  return asyncio.run_coroutine_threadsafe(coro, loop).result()
392
390
  else:
393
- return loop.run_until_complete(self._async_make_request(request_type, endpoint, payload, time_out, is_json))
391
+ return loop.run_until_complete(
392
+ self._async_make_request(request_type, endpoint, payload, time_out, is_json))
394
393
  except RuntimeError:
395
394
  # No running loop exists; run the coroutine
396
395
  return asyncio.run(self._async_make_request(request_type, endpoint, payload, time_out, is_json))
397
396
 
398
397
  async def _async_make_request(
399
- self,
400
- request_type: str,
401
- endpoint: str,
402
- payload: str | dict = None,
403
- time_out: int = 30,
404
- is_json: bool = True,
405
- ) -> Response | str:
398
+ self,
399
+ request_type: str,
400
+ endpoint: str,
401
+ payload: str | dict = None,
402
+ time_out: int = 30,
403
+ is_json: bool = True,
404
+ ) -> Response | str:
406
405
  """Make a request to the Egeria API - Async Version
407
406
  Function to make an API call via the self.session Library. Raise an exception if the HTTP response code
408
407
  is not 200/201. IF there is a REST communication exception, raise InvalidParameterException.
@@ -427,13 +426,13 @@ class Client2:
427
426
  if request_type == "GET":
428
427
  response = await self.session.get(
429
428
  endpoint, params=payload, headers=self.headers, timeout=time_out
430
- )
429
+ )
431
430
 
432
431
  elif request_type == "POST":
433
432
  if payload is None:
434
433
  response = await self.session.post(
435
434
  endpoint, headers=self.headers, timeout=time_out
436
- )
435
+ )
437
436
  elif type(payload) is dict:
438
437
  response = await self.session.post(
439
438
  endpoint, json=payload, headers=self.headers, timeout=time_out
@@ -449,7 +448,7 @@ class Client2:
449
448
  headers=self.headers,
450
449
  content=payload,
451
450
  timeout=time_out,
452
- )
451
+ )
453
452
  else:
454
453
  # response = await self.session.post(
455
454
  # endpoint, headers=self.headers, json=payload, timeout=time_out)
@@ -460,14 +459,13 @@ class Client2:
460
459
  if True:
461
460
  response = await self.session.post(
462
461
  endpoint, headers=self.headers, data=payload, timeout=time_out
463
- )
462
+ )
464
463
  elif request_type == "DELETE":
465
464
  if True:
466
465
  response = await self.session.delete(
467
466
  endpoint, headers=self.headers, timeout=time_out
468
- )
467
+ )
469
468
  response.raise_for_status()
470
-
471
469
 
472
470
  status_code = response.status_code
473
471
 
@@ -517,11 +515,9 @@ class Client2:
517
515
  exc_info=True)
518
516
  context['caught_exception'] = e
519
517
  raise PyegeriaInvalidParameterException(
520
- response, context,e = e
518
+ response, context, e=e
521
519
  )
522
520
 
523
-
524
-
525
521
  def build_global_guid_lists(self) -> None:
526
522
  global template_guids, integration_guids
527
523
 
@@ -541,7 +537,8 @@ class Client2:
541
537
  # get tech type details
542
538
  display_name = tech_type["name"]
543
539
 
544
- url = f"{self.platform_url}/servers/{self.server_name}/api/open-metadata/automated-curation/technology-types/by-name"
540
+ url = (f"{self.platform_url}/servers/"
541
+ f"{self.server_name}/api/open-metadata/automated-curation/technology-types/by-name")
545
542
  body = {"filter": display_name}
546
543
  response = self.make_request("POST", url, body)
547
544
  details = response.json().get("element", "no type found")
@@ -568,16 +565,17 @@ class Client2:
568
565
  resource_type = resource["relatedElement"]["type"]["typeName"]
569
566
  if resource_type == "IntegrationConnector":
570
567
  integration_guids[display_name] = resource_guid
571
- # print(f"Added {display_name} integration connector with GUID {integration_guids[display_name]}")
568
+ # print(f"Added {display_name} integration connector with GUID {integration_guids[
569
+ # display_name]}")
572
570
 
573
571
  async def __async_get_guid__(
574
- self,
575
- guid: str = None,
576
- display_name: str = None,
577
- property_name: str = "qualifiedName",
578
- qualified_name: str = None,
579
- tech_type: str = None,
580
- ) -> str:
572
+ self,
573
+ guid: str = None,
574
+ display_name: str = None,
575
+ property_name: str = "qualifiedName",
576
+ qualified_name: str = None,
577
+ tech_type: str = None,
578
+ ) -> str:
581
579
  """Helper function to return a server_guid - one of server_guid, qualified_name or display_name should
582
580
  contain information. If all are None, an exception will be thrown. If all contain
583
581
  values, server_guid will be used first, followed by qualified_name. If the tech_type is supplied and the
@@ -600,7 +598,7 @@ class Client2:
600
598
  "forLineage": False,
601
599
  "forDuplicateProcessing": False,
602
600
  "effectiveTime": None,
603
- }
601
+ }
604
602
  url = (
605
603
  f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/classification-manager/"
606
604
  f"elements/guid-by-unique-name?forLineage=false&forDuplicateProcessing=false"
@@ -624,7 +622,7 @@ class Client2:
624
622
  "forLineage": False,
625
623
  "forDuplicateProcessing": False,
626
624
  "effectiveTime": None,
627
- }
625
+ }
628
626
  url = (
629
627
  f"{self.platform_url}/servers/{view_server}/api/open-metadata/classification-manager/"
630
628
  f"elements/guid-by-unique-name?forLineage=false&forDuplicateProcessing=false"
@@ -640,7 +638,7 @@ class Client2:
640
638
  "forLineage": False,
641
639
  "forDuplicateProcessing": False,
642
640
  "effectiveTime": None,
643
- }
641
+ }
644
642
  url = (
645
643
  f"{self.platform_url}/servers/{view_server}/api/open-metadata/classification-manager/"
646
644
  f"elements/guid-by-unique-name?forLineage=false&forDuplicateProcessing=false"
@@ -649,20 +647,21 @@ class Client2:
649
647
  result = await self._async_make_request("POST", url, body_slimmer(body))
650
648
  return result.json().get("guid", NO_ELEMENTS_FOUND)
651
649
  else:
652
- additional_info = {"reason": "Neither server_guid nor server_name were provided - please provide.",
653
- "parameters": (f"GUID={guid}, display_name={display_name}, property_name={property_name},"
654
- f"qualified_name={qualified_name}, tech_type={tech_type}")
655
- }
650
+ additional_info = {
651
+ "reason": "Neither server_guid nor server_name were provided - please provide.",
652
+ "parameters": (f"GUID={guid}, display_name={display_name}, property_name={property_name},"
653
+ f"qualified_name={qualified_name}, tech_type={tech_type}")
654
+ }
656
655
  raise PyegeriaInvalidParameterException(None, None, additional_info)
657
656
 
658
657
  def __get_guid__(
659
- self,
660
- guid: str = None,
661
- display_name: str = None,
662
- property_name: str = "qualifiedName",
663
- qualified_name: str = None,
664
- tech_type: str = None,
665
- ) -> str:
658
+ self,
659
+ guid: str = None,
660
+ display_name: str = None,
661
+ property_name: str = "qualifiedName",
662
+ qualified_name: str = None,
663
+ tech_type: str = None,
664
+ ) -> str:
666
665
  """Helper function to return a server_guid - one of server_guid, qualified_name or display_name should
667
666
  contain information. If all are None, an exception will be thrown. If all contain
668
667
  values, server_guid will be used first, followed by qualified_name. If the tech_type is supplied and the
@@ -677,8 +676,8 @@ class Client2:
677
676
  result = loop.run_until_complete(
678
677
  self.__async_get_guid__(
679
678
  guid, display_name, property_name, qualified_name, tech_type
679
+ )
680
680
  )
681
- )
682
681
  return result
683
682
 
684
683
  def __create_qualified_name__(self, type: str, display_name: str, local_qualifier: str = None,
@@ -686,9 +685,9 @@ class Client2:
686
685
  """Helper function to create a qualified name for a given type and display name.
687
686
  If present, the local qualifier will be prepended to the qualified name."""
688
687
  EGERIA_LOCAL_QUALIFIER = os.environ.get("EGERIA_LOCAL_QUALIFIER", local_qualifier)
689
- display_name = re.sub(r'\s','-',display_name.strip()) # This changes spaces between words to -; removing
688
+ display_name = re.sub(r'\s', '-', display_name.strip()) # This changes spaces between words to -; removing
690
689
  if display_name is None:
691
- additional_info = {"reason": "Display name is missing - please provide.",}
690
+ additional_info = {"reason": "Display name is missing - please provide.", }
692
691
  raise PyegeriaInvalidParameterException(additional_info=additional_info)
693
692
  q_name = f"{type}::{display_name}"
694
693
  if EGERIA_LOCAL_QUALIFIER:
@@ -697,7 +696,6 @@ class Client2:
697
696
  q_name = f"{q_name}::{version_identifier}"
698
697
  return q_name
699
698
 
700
-
701
699
  async def _async_get_element_by_guid_(self, element_guid: str) -> dict | str:
702
700
  """
703
701
  Simplified, internal version of get_element_by_guid found in Classification Manager.
@@ -726,7 +724,7 @@ class Client2:
726
724
  body = {
727
725
  "class": "EffectiveTimeQueryRequestBody",
728
726
  "effectiveTime": None,
729
- }
727
+ }
730
728
 
731
729
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/classification-manager/elements/"
732
730
  f"{element_guid}?forLineage=false&forDuplicateProcessing=false")
@@ -737,22 +735,318 @@ class Client2:
737
735
 
738
736
  return elements
739
737
 
740
- def validate_new_element_request(self, body: dict | NewElementRequestBody, prop: str)-> NewElementRequestBody
741
- if isinstance(body, NewElementRequestBody):
742
- if body.properties.class_ == prop:
738
+ def validate_new_element_request(self, body: dict | NewElementRequestBody,
739
+ prop: list[str]) -> NewElementRequestBody | None:
740
+ if isinstance(body, NewElementRequestBody):
741
+ # if body.properties.class_ in prop:
743
742
  validated_body = body
744
- else:
745
- raise PyegeriaInvalidParameterException(additional_info=
746
- {"reason": "unexpected property class name"})
743
+ # else:
744
+ # raise PyegeriaInvalidParameterException(additional_info=
745
+ # {"reason": "unexpected property class name"})
747
746
 
748
- elif isinstance(body, dict):
749
- if body.get("properties", {}).get("class", "") == prop:
747
+ elif isinstance(body, dict):
748
+ # if body.get("properties", {}).get("class", "") == prop:
750
749
  validated_body = self._new_element_request_adapter.validate_python(body)
750
+ # else:
751
+ # raise PyegeriaInvalidParameterException(additional_info=
752
+ # {"reason": "unexpected property class name"})
751
753
  else:
752
- raise PyegeriaInvalidParameterException(additional_info=
753
- {"reason": "unexpected property class name"})
754
+ return None
755
+ return validated_body
756
+
757
+ def validate_new_relationship_request(self, body: dict | NewRelationshipRequestBody,
758
+ prop: str = None) -> NewRelationshipRequestBody | None:
759
+ if isinstance(body, NewElementRequestBody):
760
+ if (prop and body.properties.class_ == prop) or (prop is None):
761
+ validated_body = body
762
+ else:
763
+ raise PyegeriaInvalidParameterException(additional_info=
764
+ {"reason": "unexpected property class name"})
765
+
766
+ elif isinstance(body, dict):
767
+ if body.get("properties", {}).get("class", "") == prop:
768
+ validated_body = self._new_relationship_request_adapter.validate_python(body)
769
+ else:
770
+ raise PyegeriaInvalidParameterException(additional_info=
771
+ {"reason": "unexpected property class name"})
772
+ else:
773
+ return None
774
+
775
+ return validated_body
776
+
777
+ def validate_delete_request(self, body: dict | DeleteRequestBody,
778
+ cascade_delete: bool = False) -> DeleteRequestBody | None:
779
+ if isinstance(body, DeleteRequestBody):
780
+ validated_body = body
781
+ elif isinstance(body, dict):
782
+ validated_body = self._delete_request_adapter.validate_python(body)
783
+ else: # handle case where body not provided
784
+ body= {
785
+ "class": "DeleteRequestBody",
786
+ "cascadeDelete": cascade_delete
787
+ }
788
+ validated_body= DeleteRequestBody.model_validate(body)
789
+ return validated_body
790
+
791
+ def validate_update_element_request(self, body: dict | UpdateElementRequestBody,
792
+ prop: list[str]) -> UpdateElementRequestBody | None:
793
+ if isinstance(body, UpdateElementRequestBody):
794
+ if body.properties.class_ in prop:
795
+ validated_body = body
796
+ else:
797
+ raise PyegeriaInvalidParameterException(additional_info=
798
+ {"reason": "unexpected property class name"})
799
+
800
+ elif isinstance(body, dict):
801
+ # if body.get("properties", {}).get("class", "") in prop:
802
+ validated_body = self._update_element_request_adapter.validate_python(body)
803
+ # else:
804
+ # raise PyegeriaInvalidParameterException(additional_info=
805
+ # {"reason": "unexpected property class name"})
806
+ else:
807
+ validated_body = None
808
+ return validated_body
809
+
810
+ def validate_update_status_request(self, status: str = None, body: dict | UpdateStatusRequestBody = None,
811
+ prop: list[str] = None) -> UpdateStatusRequestBody | None:
812
+ if isinstance(body, UpdateStatusRequestBody):
813
+ validated_body = body
814
+
815
+ elif isinstance(body, dict):
816
+ validated_body = self._update_element_request_adapter.validate_python(body)
817
+
818
+ elif status:
819
+ body = {
820
+ "class": "UpdateStatusRequestBody",
821
+ "status": status
822
+ }
823
+ validated_body = UpdateStatusRequestBody.validate_python(body)
824
+ else:
825
+ raise PyegeriaInvalidParameterException(additional_info={"reason": "invalid parameters"})
826
+
827
+ return validated_body
828
+
829
+ def validate_update_relationship_request(self, body: dict | UpdateRelationshipRequestBody,
830
+ prop: [str]) -> UpdateRelationshipRequestBody | None:
831
+ if isinstance(body, UpdateRelationshipRequestBody):
832
+ # if body.properties.class_ == prop:
833
+ validated_body = body
834
+ # else:
835
+ # raise PyegeriaInvalidParameterException(additional_info=
836
+ # {"reason": "unexpected property class name"})
837
+
838
+ elif isinstance(body, dict):
839
+ # if body.get("properties", {}).get("class", "") == prop:
840
+ validated_body = self._update_relationship_request_adapter.validate_python(body)
841
+ # else:
842
+ # raise PyegeriaInvalidParameterException(additional_info=
843
+ # {"reason": "unexpected property class name"})
844
+ else:
845
+ validated_body = None
846
+ return validated_body
847
+
848
+ async def _async_find_request(self, url: str, _type: str, _gen_output: Callable[..., Any],
849
+ search_string: str = '*', classification_names: list[str] = None,
850
+ metadata_element_types: list[str] = None,
851
+ starts_with: bool = True, ends_with: bool = False, ignore_case: bool = False,
852
+ start_from: int = 0, page_size: int = 0, output_format: str = 'JSON',
853
+ output_format_set: str | dict = None,
854
+ body: dict | SearchStringRequestBody = None) -> Any:
855
+
856
+ if isinstance(body, SearchStringRequestBody):
857
+ validated_body = body
858
+ elif isinstance(body, dict):
859
+ validated_body = self._search_string_request_adapter.validate_python(body)
860
+ else:
861
+ search_string = None if search_string is "*" else search_string
862
+ body = {
863
+ "class": "SearchStringRequestBody",
864
+ "search_string": search_string,
865
+ "starts_with": starts_with,
866
+ "ends_with": ends_with,
867
+ "ignore_case": ignore_case,
868
+ "start_from": start_from,
869
+ "page_size": page_size,
870
+ "include_only_classified_elements": classification_names,
871
+ "metadata_element_subtype_names": metadata_element_types,
872
+ }
873
+ validated_body = SearchStringRequestBody.model_validate(body)
874
+
875
+ # classification_names = validated_body.include_only_classified_elements
876
+ # element_type_name = classification_names[0] if classification_names else _type
877
+
878
+ json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
879
+
880
+ response = await self._async_make_request("POST", url, json_body)
881
+ elements = response.json().get("elements", NO_ELEMENTS_FOUND)
882
+ if type(elements) is str:
883
+ logger.info(NO_ELEMENTS_FOUND)
884
+ return NO_ELEMENTS_FOUND
885
+
886
+ if output_format != 'JSON': # return a simplified markdown representation
887
+ # logger.info(f"Found elements, output format: {output_format} and output_format_set: {output_format_set}")
888
+ return _gen_output(elements, search_string, _type,
889
+ output_format, output_format_set)
890
+ return elements
891
+
892
+ async def _async_get_name_request(self, url: str, _type: str, _gen_output: Callable[..., Any],
893
+ filter_string: str, classification_names: list[str] = None,
894
+ start_from: int = 0, page_size: int = 0, output_format: str = 'JSON',
895
+ output_format_set: str | dict = None,
896
+ body: dict | FilterRequestBody = None) -> Any:
897
+
898
+ if isinstance(body, FilterRequestBody):
899
+ validated_body = body
900
+ elif isinstance(body, dict):
901
+ validated_body = self._filter_request_adapter.validate_python(body)
902
+ else:
903
+ filter_string = None if filter_string is "*" else filter_string
904
+ body = {
905
+ "class": "FilterRequestBody",
906
+ "filter": filter_string,
907
+ "start_from": start_from,
908
+ "page_size": page_size,
909
+ "include_only_classified_elements": classification_names,
910
+ }
911
+ validated_body = FilterRequestBody.model_validate(body)
912
+
913
+ # classification_names = validated_body.include_only_classified_elements
914
+ # element_type_name = classification_names[0] if classification_names else _type
915
+
916
+ json_body = validated_body.model_dump_json(indent=2)
917
+
918
+ response = await self._async_make_request("POST", url, json_body)
919
+ elements = response.json().get("elements", NO_ELEMENTS_FOUND)
920
+ if type(elements) is str:
921
+ logger.info(NO_ELEMENTS_FOUND)
922
+ return NO_ELEMENTS_FOUND
923
+
924
+ if output_format != 'JSON': # return a simplified markdown representation
925
+ logger.info(f"Found elements, output format: {output_format} and output_format_set: {output_format_set}")
926
+ return _gen_output(elements, filter_string, _type,
927
+ output_format, output_format_set)
928
+ return elements
929
+
930
+ async def _async_get_guid_request(self, url: str, _type: str, _gen_output: Callable[..., Any],
931
+ output_format: str = 'JSON', output_format_set: str | dict = None,
932
+ body: dict | GetRequestBody = None) -> Any:
933
+
934
+ if isinstance(body, GetRequestBody):
935
+ validated_body = body
936
+ elif isinstance(body, dict):
937
+ validated_body = self._filter_request_adapter.validate_python(body)
938
+ else:
939
+ body = {
940
+ "class": "GetRequestBody",
941
+
942
+ }
943
+ validated_body = GetRequestBody.model_validate(body)
944
+
945
+ json_body = validated_body.model_dump_json(indent=2)
946
+
947
+ response = await self._async_make_request("POST", url, json_body)
948
+ elements = response.json().get("element", NO_ELEMENTS_FOUND)
949
+ if type(elements) is str:
950
+ logger.info(NO_ELEMENTS_FOUND)
951
+ return NO_ELEMENTS_FOUND
952
+
953
+ if output_format != 'JSON': # return a simplified markdown representation
954
+ logger.info(f"Found elements, output format: {output_format} and output_format_set: {output_format_set}")
955
+ return _gen_output(elements, "GUID", _type, output_format, output_format_set)
956
+ return elements
957
+
958
+ async def _async_get_results_body_request(self, url: str, _type: str, _gen_output: Callable[..., Any],
959
+ start_from: int = 0, page_size: int = 0, output_format: str = 'JSON',
960
+ output_format_set: str | dict = None,
961
+ body: dict | ResultsRequestBody = None) -> Any:
962
+ if isinstance(body, ResultsRequestBody):
963
+ validated_body = body
964
+ elif isinstance(body, dict):
965
+ validated_body = self._results_request_adapter.validate_python(body)
966
+ else:
967
+ body = {
968
+ "class": "ResultsRequestBody",
969
+ "start_from": start_from,
970
+ "page_size": page_size,
971
+ }
972
+ validated_body = ResultsRequestBody.model_validate(body)
973
+
974
+ json_body = validated_body.model_dump_json(indent=2)
975
+
976
+ response = await self._async_make_request("POST", url, json_body)
977
+ elements = response.json().get("elements", None)
978
+ if elements is None:
979
+ elements = response.json().get("element", NO_ELEMENTS_FOUND)
980
+
981
+ if type(elements) is str:
982
+ logger.info(NO_ELEMENTS_FOUND)
983
+ return NO_ELEMENTS_FOUND
984
+
985
+ if output_format != 'JSON': # return a simplified markdown representation
986
+ logger.info(f"Found elements, output format: {output_format} and output_format_set: {output_format_set}")
987
+ return _gen_output(elements, "Members", _type,
988
+ output_format, output_format_set)
989
+ return elements
990
+
991
+ async def _async_create_element_body_request(self, url: str, prop: list[str],
992
+ body: dict | NewElementRequestBody = None) -> str:
993
+ validated_body = self.validate_new_element_request(body, prop)
994
+ json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
995
+ logger.info(json_body)
996
+ response = await self._async_make_request("POST", url, json_body)
997
+ logger.info(response.json())
998
+ return response.json().get("guid")
999
+
1000
+ async def _async_update_element_body_request(self, url: str, prop: list[str],
1001
+ body: dict | UpdateElementRequestBody = None) -> None:
1002
+ validated_body = self.validate_update_element_request(body, prop)
1003
+ json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
1004
+ logger.info(json_body)
1005
+ response = await self._async_make_request("POST", url, json_body)
1006
+ logger.info(response.json())
1007
+
1008
+ async def _async_update_status_request(self, url: str, status: str = None,
1009
+ body: dict | UpdateStatusRequestBody = None) -> None:
1010
+ validated_body = self.validate_update_status_request(status, body)
1011
+ json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
1012
+ logger.info(json_body)
1013
+ response = await self._async_make_request("POST", url, json_body)
1014
+ logger.info(response.json())
1015
+
1016
+ async def _async_new_relationship_request(self, url: str, prop: list[str],
1017
+ body: dict | NewRelationshipRequestBody = None) -> None:
1018
+ validated_body = self.validate_new_relationship_request(body, prop)
1019
+ if validated_body:
1020
+ json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
1021
+ logger.info(json_body)
1022
+ await self._async_make_request("POST", url, json_body)
1023
+ else:
1024
+ await self._async_make_request("POST", url)
1025
+
1026
+ async def _async_delete_request(self, url: str, body: dict | DeleteRequestBody = None,
1027
+ cascade_delete: bool = False) -> None:
1028
+ validated_body = self.validate_delete_request(body, cascade_delete)
1029
+ if validated_body:
1030
+ json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
1031
+ logger.info(json_body)
1032
+ await self._async_make_request("POST", url, json_body)
1033
+ else:
1034
+ await self._async_make_request("POST", url)
1035
+
1036
+
1037
+
1038
+
1039
+
1040
+ async def _async_update_relationship_request(self, url: str, prop: str,
1041
+ body: dict | UpdateRelationshipRequestBody = None) -> None:
1042
+ validated_body = self.validate_update_relationship_request(body, prop)
1043
+ if validated_body:
1044
+ json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
1045
+ logger.info(json_body)
1046
+ await self._async_make_request("POST", url, json_body)
1047
+ else:
1048
+ await self._async_make_request("POST", url)
1049
+
754
1050
 
755
- else:
756
- raise TypeError("Invalid parameter type")
757
1051
  if __name__ == "__main__":
758
- print("Main-__client")
1052
+ print("Main-__client")