pyegeria 5.4.8.2__py3-none-any.whl → 5.4.8.3__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.
pyegeria/_client_new.py CHANGED
@@ -12,6 +12,7 @@ import os
12
12
  import re
13
13
  import time
14
14
  from collections.abc import Callable
15
+ from datetime import datetime
15
16
  from typing import Any
16
17
 
17
18
  from httpx import Response
@@ -536,7 +537,7 @@ class Client2(BaseClient):
536
537
 
537
538
  async def _async_get_guid_for_name(
538
539
  self, name: str, property_name: list[str] = ["qualifiedName", "displayName"],
539
- type_name: str = "ValidMetadataValue"
540
+ type_name: str = None
540
541
 
541
542
  ) -> list | str:
542
543
  """
@@ -570,6 +571,8 @@ class Client2(BaseClient):
570
571
  raise PyegeriaException(context={"issue": "Multiple elements found for supplied name!"})
571
572
  elif len(elements) == 1:
572
573
  return elements[0]["elementHeader"]["guid"]
574
+ else:
575
+ return NO_ELEMENTS_FOUND
573
576
  return elements
574
577
 
575
578
  def get_guid_for_name(
@@ -1687,7 +1690,7 @@ class Client2(BaseClient):
1687
1690
  @dynamic_catch
1688
1691
  async def _async_create_note_log(
1689
1692
  self,
1690
- element_guid: str,
1693
+ element_guid: str = None,
1691
1694
  display_name: str = None,
1692
1695
  description: str = None,
1693
1696
  body: dict = None,
@@ -1697,8 +1700,8 @@ class Client2(BaseClient):
1697
1700
 
1698
1701
  Parameters
1699
1702
  ----------
1700
- element_guid: str
1701
- - unique identifier of the element where the note log is located
1703
+ element_guid: str, optional
1704
+ - unique identifier of the element where the note log is attached
1702
1705
  display_name: str, optional
1703
1706
  - name of the note log
1704
1707
  description: str, optional
@@ -1752,14 +1755,17 @@ class Client2(BaseClient):
1752
1755
  context = {"issue": "Invalid display name and body not provided"}
1753
1756
  raise PyegeriaInvalidParameterException(context=context)
1754
1757
 
1755
- url = f"{self.command_root}feedback-manager/elements/{element_guid}/note-logs"
1758
+ if element_guid:
1759
+ url = f"{self.command_root}feedback-manager/elements/{element_guid}/note-logs"
1760
+ else:
1761
+ url = f"{self.command_root}feedback-manager/elements/note-logs"
1756
1762
  response = await self._async_make_request("POST", url, body_slimmer(body))
1757
1763
  return response.json()
1758
1764
 
1759
1765
  @dynamic_catch
1760
1766
  def create_note_log(
1761
1767
  self,
1762
- element_guid: str,
1768
+ element_guid: str = None,
1763
1769
  display_name: str = None,
1764
1770
  description: str = None,
1765
1771
  body: dict = None,
@@ -1769,8 +1775,8 @@ class Client2(BaseClient):
1769
1775
 
1770
1776
  Parameters
1771
1777
  ----------
1772
- element_guid
1773
- - unique identifier of the element where the note log is located
1778
+ element_guid, str, optional
1779
+ - unique identifier of the element where the note log is attached
1774
1780
  display_name: str, optional
1775
1781
  - name of the note log
1776
1782
  description: str, optional
@@ -1981,7 +1987,7 @@ class Client2(BaseClient):
1981
1987
 
1982
1988
  """
1983
1989
 
1984
- url = f"{self.command_root}feedback-manager/elements/{note_log_guid}/remove"
1990
+ url = f"{self.command_root}feedback-manager/note-logs/{note_log_guid}/remove"
1985
1991
  await self._async_delete_element_request(url, body, cascade_delete)
1986
1992
 
1987
1993
  @dynamic_catch
@@ -2090,7 +2096,7 @@ class Client2(BaseClient):
2090
2096
 
2091
2097
  url = f"{self.command_root}feedback-manager/note-logs/by-search-string"
2092
2098
  response = await self._async_find_request(url, _type="NoteLog",
2093
- _gen_output=self._generate_note_log_output,
2099
+ _gen_output=self._generate_feedback_output,
2094
2100
  search_string=search_string,
2095
2101
  classification_names=classification_names,
2096
2102
  metadata_element_types=metadata_element_types,
@@ -2162,7 +2168,7 @@ class Client2(BaseClient):
2162
2168
  return resp
2163
2169
 
2164
2170
  @dynamic_catch
2165
- async def _async_get_note_logs_by_gname(
2171
+ async def _async_get_note_logs_by_name(
2166
2172
  self, filter: str,
2167
2173
  element_type: str = "NoteLog",
2168
2174
  body: dict | FilterRequestBody = None,
@@ -2194,7 +2200,7 @@ class Client2(BaseClient):
2194
2200
 
2195
2201
  url = f"{self.command_root}feedback-manager/note-logs/by-name"
2196
2202
  response = await self._async_get_name_request(url, _type=element_type,
2197
- _gen_output=self._generate_note_log_output, start_from=start_from,
2203
+ _gen_output=self._generate_feedback_output, start_from=start_from,
2198
2204
  page_size=page_size, output_format=output_format,
2199
2205
  report_spec=report_spec,
2200
2206
  body=body)
@@ -2233,7 +2239,7 @@ class Client2(BaseClient):
2233
2239
  """
2234
2240
  loop = asyncio.get_event_loop()
2235
2241
  response = loop.run_until_complete(
2236
- self._async_get_note_log_by_name(filter, element_type, body, output_format, report_spec, start_from,
2242
+ self._async_get_note_logs_by_name(filter, element_type, body, output_format, report_spec, start_from,
2237
2243
  page_size)
2238
2244
  )
2239
2245
  return response
@@ -2281,7 +2287,7 @@ class Client2(BaseClient):
2281
2287
  if element == NO_ELEMENTS_FOUND:
2282
2288
  return NO_ELEMENTS_FOUND
2283
2289
  if output_format != 'JSON': # return a simplified markdown representation
2284
- return self._generate_note_log_output(element, None, output_format, report_spec)
2290
+ return self._generate_feedback_output(element, None, output_format, report_spec)
2285
2291
  return response.json().get("elements", NO_ELEMENTS_FOUND)
2286
2292
 
2287
2293
  @dynamic_catch
@@ -2498,6 +2504,183 @@ class Client2(BaseClient):
2498
2504
  )
2499
2505
  return response
2500
2506
 
2507
+ @dynamic_catch
2508
+ async def _async_add_journal_entry(self, note_log_qn: str = None, element_qn: str = None, note_log_display_name: str = None, journal_entry_display_name: str = None, journal_entry_description: str = None,
2509
+ body: dict | NewElementRequestBody = None ) -> str:
2510
+ """
2511
+ Creates a new journal entry for a note log and returns the unique identifier for it. The note_log will be
2512
+ created if it does not exist. Async version.
2513
+
2514
+ Parameters
2515
+ ----------
2516
+ note_log_qn: str = None
2517
+ - If provided, the journal entry will be attached to this note log. If not provided, a new note_log will be created.
2518
+ element_qn: str = None
2519
+ - If provided, and note log needs to be created, this will be used to define the new note log and attach it
2520
+ to the specified element.
2521
+ note_log_display_name: str = None
2522
+ - optional note log display name
2523
+ journal_entry_display_name: str = None
2524
+ - optional journal entry display name
2525
+ journal_entry_description: str = None
2526
+ - the journal entry text
2527
+
2528
+ body
2529
+ - optional body for the note - if provided, details here will supercede other parameters.
2530
+
2531
+ Returns
2532
+ -------
2533
+ GUID for the journal entry (note).
2534
+
2535
+ Raises
2536
+ ------
2537
+ PyegeriaException
2538
+
2539
+ Notes
2540
+ _____
2541
+
2542
+ Sample body (a note is an asset)
2543
+ {
2544
+ "class" : "NewElementRequestBody",
2545
+ "anchorGUID" : "{{noteLogGUID}}",
2546
+ "isOwnAnchor": false,
2547
+ "parentGUID": "{{noteLogGUID}}",
2548
+ "parentRelationshipTypeName": "AttachedNoteLogEntry",
2549
+ "parentAtEnd1": true,
2550
+ "properties": {
2551
+ "class" : "NotificationProperties",
2552
+ "typeName" : "Notification",
2553
+ "qualifiedName": "add unique name here",
2554
+ "displayName": "add short name here",
2555
+ "description": "add description here",
2556
+ "systemAction" : "add optional system action that occurred as part of this notification processing",
2557
+ "userResponse" : "add optional action that the reader should take",
2558
+ "priority" : 1,
2559
+ "activityStatus" : "FOR_INFO",
2560
+ "additionalProperties": {
2561
+ "property1" : "propertyValue1",
2562
+ "property2" : "propertyValue2"
2563
+ },
2564
+ "extendedProperties": {
2565
+ "property1" : "propertyValue1",
2566
+ "property2" : "propertyValue2"
2567
+ },
2568
+ "effectiveFrom": "{{$isoTimestamp}}",
2569
+ "effectiveTo": "{{$isoTimestamp}}"
2570
+ },
2571
+ "externalSourceGUID": "add guid here",
2572
+ "externalSourceName": "add qualified name here",
2573
+ "effectiveTime" : "{{$isoTimestamp}}",
2574
+ "forLineage" : false,
2575
+ "forDuplicateProcessing" : false
2576
+ }
2577
+
2578
+ """
2579
+ note_log_guid = None
2580
+ element_guid = None
2581
+ # If a note_log_qn has been provided, look up its GUID
2582
+ if note_log_qn:
2583
+ note_log_guid = await self._async_get_guid_for_name(note_log_qn, ["qualifiedName"],'NoteLog' ) if note_log_qn else None
2584
+
2585
+ # If we need to create a new note_log, then use the qualified name from the element_qn parameter, if provided.
2586
+ if note_log_guid is None or note_log_guid == NO_ELEMENTS_FOUND:
2587
+ if element_qn is None:
2588
+ if note_log_display_name is None:
2589
+ note_log_display_name = f"NoName-{datetime.now().strftime('%Y-%m-%d %H:%M')}"
2590
+
2591
+ else:
2592
+ element_guid = await self._async_get_guid_for_name(element_qn, ["qualifiedName"])
2593
+
2594
+ note_log = await self._async_create_note_log(element_guid = element_guid, display_name = note_log_display_name)
2595
+ note_log_guid = note_log["guid"]
2596
+
2597
+ # Create the Journal Entry (Note)
2598
+ journal_entry_guid = await self._async_create_note(note_log_guid, journal_entry_display_name,
2599
+ journal_entry_description, body)
2600
+
2601
+ return journal_entry_guid
2602
+
2603
+ @dynamic_catch
2604
+ def add_journal_entry(self, note_log_qn: str = None, element_qn: str = None,
2605
+ note_log_display_name: str = None, journal_entry_display_name: str = None,
2606
+ journal_entry_description: str = None,
2607
+ body: dict | NewElementRequestBody = None) -> str:
2608
+ """
2609
+ Creates a new journal entry for a note log and returns the unique identifier for it. The note_log will be
2610
+ created if it does not exist.
2611
+
2612
+ Parameters
2613
+ ----------
2614
+ note_log_qn: str = None
2615
+ - If provided, the journal entry will be attached to this note log. If not provided, a new note_log will be created.
2616
+ element_qn: str = None
2617
+ - If provided, and note log needs to be created, this will be used to define the new note log and attach it
2618
+ to the specified element.
2619
+ note_log_display_name: str = None
2620
+ - optional note log display name
2621
+ journal_entry_display_name: str = None
2622
+ - optional journal entry display name
2623
+ journal_entry_description: str = None
2624
+ - the journal entry text
2625
+
2626
+ body
2627
+ - optional body for the note - if provided, details here will supercede other parameters.
2628
+
2629
+ Returns
2630
+ -------
2631
+ GUID for the journal entry (note).
2632
+
2633
+ Raises
2634
+ ------
2635
+ PyegeriaException
2636
+
2637
+ Notes
2638
+ _____
2639
+
2640
+ Sample body (a note is an asset)
2641
+ {
2642
+ "class" : "NewElementRequestBody",
2643
+ "anchorGUID" : "{{noteLogGUID}}",
2644
+ "isOwnAnchor": false,
2645
+ "parentGUID": "{{noteLogGUID}}",
2646
+ "parentRelationshipTypeName": "AttachedNoteLogEntry",
2647
+ "parentAtEnd1": true,
2648
+ "properties": {
2649
+ "class" : "NotificationProperties",
2650
+ "typeName" : "Notification",
2651
+ "qualifiedName": "add unique name here",
2652
+ "displayName": "add short name here",
2653
+ "description": "add description here",
2654
+ "systemAction" : "add optional system action that occurred as part of this notification processing",
2655
+ "userResponse" : "add optional action that the reader should take",
2656
+ "priority" : 1,
2657
+ "activityStatus" : "FOR_INFO",
2658
+ "additionalProperties": {
2659
+ "property1" : "propertyValue1",
2660
+ "property2" : "propertyValue2"
2661
+ },
2662
+ "extendedProperties": {
2663
+ "property1" : "propertyValue1",
2664
+ "property2" : "propertyValue2"
2665
+ },
2666
+ "effectiveFrom": "{{$isoTimestamp}}",
2667
+ "effectiveTo": "{{$isoTimestamp}}"
2668
+ },
2669
+ "externalSourceGUID": "add guid here",
2670
+ "externalSourceName": "add qualified name here",
2671
+ "effectiveTime" : "{{$isoTimestamp}}",
2672
+ "forLineage" : false,
2673
+ "forDuplicateProcessing" : false
2674
+ }
2675
+
2676
+ """
2677
+ loop = asyncio.get_event_loop()
2678
+ response = loop.run_until_complete(
2679
+ self._async_add_journal_entry(note_log_qn, element_qn, note_log_display_name, journal_entry_display_name, journal_entry_description, body)
2680
+ )
2681
+ return response
2682
+
2683
+
2501
2684
  @dynamic_catch
2502
2685
  async def _async_update_note(self, note_guid: str, display_name: str = None, description: str = None,
2503
2686
  body: dict | UpdateElementRequestBody = None, merge_update: bool = True) -> None:
@@ -2767,19 +2950,19 @@ class Client2(BaseClient):
2767
2950
 
2768
2951
  url = f"{self.command_root}feedback-manager/assets/by-search-string"
2769
2952
  response = await self._async_find_request(url, "Notification", self._generate_feedback_output,
2770
- search_string, [], ["Notification"],
2953
+ search_string, None, ["Notification"] ,
2771
2954
  starts_with, ends_with, ignore_case,
2772
2955
  start_from, page_size, output_format, report_spec,
2773
- body, )
2956
+ body )
2774
2957
  return response
2775
2958
 
2776
2959
  @dynamic_catch
2777
2960
  def find_notes(
2778
2961
  self, search_string: str = None,
2779
2962
  body: dict | SearchStringRequestBody = None,
2780
- starts_with: bool = None,
2781
- ends_with: bool = None,
2782
- ignore_case: bool = None,
2963
+ starts_with: bool = True,
2964
+ ends_with: bool = False,
2965
+ ignore_case: bool = False,
2783
2966
  start_from: int = 0,
2784
2967
  page_size: int = 0,
2785
2968
  output_format: str = "JSON",
@@ -2929,7 +3112,7 @@ class Client2(BaseClient):
2929
3112
 
2930
3113
  """
2931
3114
 
2932
- url = f"{self.command_root}feedback-manager/note-logs/by-name"
3115
+ url = f"{self.command_root}feedback-manager/note-logs/{note_log_guid}/retrieve"
2933
3116
  response = await self._async_get_results_body_request(url, "Notification", self._generate_feedback_output,
2934
3117
  0, 0, output_format, report_spec, body)
2935
3118
  return response
@@ -3873,6 +4056,7 @@ class Client2(BaseClient):
3873
4056
  #
3874
4057
  # Search Tags
3875
4058
  #
4059
+ @dynamic_catch
3876
4060
  async def _async_add_search_keyword_to_element(
3877
4061
  self,
3878
4062
  element_guid: str,
@@ -3929,6 +4113,7 @@ class Client2(BaseClient):
3929
4113
  response = await self._async_make_request("POST", url, body_slimmer(body))
3930
4114
  return response.json().get('guid', 'Search keyword was not created')
3931
4115
 
4116
+ @dynamic_catch
3932
4117
  def add_search_keyword_to_element(
3933
4118
  self,
3934
4119
  element_guid: str,
@@ -3976,6 +4161,8 @@ class Client2(BaseClient):
3976
4161
  )
3977
4162
  return response
3978
4163
 
4164
+
4165
+ @dynamic_catch
3979
4166
  async def _async_update_search_keyword(
3980
4167
  self,
3981
4168
  keyword_guid: str,
@@ -4017,6 +4204,7 @@ class Client2(BaseClient):
4017
4204
  url = f"{self.command_root}classification-manager/search-keywords/{keyword_guid}/update"
4018
4205
  await self._async_update_relationship_request(url, None, body_slimmer(body))
4019
4206
 
4207
+ @dynamic_catch
4020
4208
  def update_search_keyword(
4021
4209
  self,
4022
4210
  keyword_guid: str,
@@ -4060,6 +4248,7 @@ class Client2(BaseClient):
4060
4248
  self._async_update_search_keyword(keyword_guid, body)
4061
4249
  )
4062
4250
 
4251
+ @dynamic_catch
4063
4252
  async def _async_remove_search_keyword(
4064
4253
  self,
4065
4254
  keyword_guid: str
@@ -4083,16 +4272,15 @@ class Client2(BaseClient):
4083
4272
  """
4084
4273
 
4085
4274
  url = f"{self.command_root}classification-manager/search-keywords/{keyword_guid}/remove"
4086
- await self._async_delete_relationship_request(url)
4275
+ await self._async_delete_relationship_request(url = url, body = None, cascade_delete = False)
4087
4276
 
4277
+ @dynamic_catch
4088
4278
  def remove_search_keyword(
4089
4279
  self,
4090
4280
  keyword_guid,
4091
4281
  ) -> None:
4092
4282
  """
4093
- Remove the licensed for an element.
4094
-
4095
- licenses: https://egeria-project.org/types/1/0120-Assignment-licenses/
4283
+ Remove the search keyword for an element.
4096
4284
 
4097
4285
  Parameters
4098
4286
  ----------
@@ -4111,7 +4299,7 @@ class Client2(BaseClient):
4111
4299
 
4112
4300
  loop = asyncio.get_event_loop()
4113
4301
  loop.run_until_complete(
4114
- self._async_remove_search_keyword(keyword_guid, )
4302
+ self._async_remove_search_keyword(keyword_guid )
4115
4303
  )
4116
4304
 
4117
4305
  @dynamic_catch
@@ -4423,7 +4611,9 @@ class Client2(BaseClient):
4423
4611
  col_data = populate_common_columns(element, columns_struct)
4424
4612
  columns_list = col_data.get('formats', {}).get('attributes', [])
4425
4613
  # Overlay extras (project roles) only where empty
4426
- if isinstance(element['keywordElements'], list):
4614
+ keyword_elements = element.get("keywordElements", [])
4615
+
4616
+ if keyword_elements != [] and isinstance(element['keywordElements'], list):
4427
4617
  extra = self._extract_element_properties_for_keyword(element, columns_struct)
4428
4618
  col_data = overlay_additional_values(col_data, extra)
4429
4619
 
@@ -4456,6 +4646,7 @@ class Client2(BaseClient):
4456
4646
  columns_struct=output_formats,
4457
4647
  )
4458
4648
 
4649
+
4459
4650
  #
4460
4651
  # Helper functions for requests
4461
4652
  #
@@ -4556,11 +4747,12 @@ class Client2(BaseClient):
4556
4747
  elif isinstance(body, dict):
4557
4748
  validated_body = self._delete_relationship_request_adapter.validate_python(body)
4558
4749
  else: # handle case where body not provided
4559
- body = {
4560
- "class": "DeleteRelationshipRequestBody",
4561
- "cascadeDelete": cascade_delete
4562
- }
4563
- validated_body = DeleteRelationshipRequestBody.model_validate(body)
4750
+ # body = {
4751
+ # "class": "DeleteRelationshipRequestBody",
4752
+ # "cascadeDelete": cascade_delete
4753
+ # }
4754
+ # validated_body = DeleteRelationshipRequestBody.model_validate(body)
4755
+ return None
4564
4756
  return validated_body
4565
4757
 
4566
4758
  @dynamic_catch
@@ -4888,7 +5080,7 @@ class Client2(BaseClient):
4888
5080
  @dynamic_catch
4889
5081
  async def _async_delete_relationship_request(self, url: str, body: dict | DeleteRelationshipRequestBody = None,
4890
5082
  cascade_delete: bool = False) -> None:
4891
- validated_body = self.validate_delete_relationshp_request(body, cascade_delete)
5083
+ validated_body = self.validate_delete_relationship_request(body, cascade_delete)
4892
5084
  if validated_body:
4893
5085
  json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
4894
5086
  logger.info(json_body)
@@ -379,7 +379,12 @@ def print_basic_exception(e: PyegeriaException):
379
379
  table.caption = e.pyegeria_code
380
380
  table.add_column("Facet", justify="center")
381
381
  table.add_column("Item", justify="left", width=80)
382
- related_response = e.response.json() if e.response else ""
382
+ if e.response:
383
+ related_response = e.response.json() if isinstance(e, PyegeriaException) else None
384
+ exception_msg_id = related_response.get("exceptionErrorMessageId", None)
385
+ else:
386
+ exception_msg_id = ""
387
+
383
388
  table = Table(title=f"Exception: {e.__class__.__name__}", show_lines=True, header_style="bold", box=box.HEAVY_HEAD)
384
389
  table.caption = e.pyegeria_code
385
390
  table.add_column("Facet", justify="center")
@@ -307,6 +307,7 @@ base_report_specs = FormatSetDict({
307
307
  Format(
308
308
  types=["ALL"],
309
309
  attributes= [
310
+ Column(name='Search Keyword', key='keyword'),
310
311
  Column(name="Search Keyword GUID", key='guid'),
311
312
  Column(name="Element Display Name", key='element_display_name'),
312
313
  Column(name="Element GUID", key='element_guid'),
pyegeria/config.py CHANGED
@@ -150,6 +150,7 @@ class UserProfileConfig(BaseModel):
150
150
  egeria_home_collection: str = Field(default="MyHome", alias="Egeria Home Collection")
151
151
  egeria_home_glossary_name: str = Field(default="Egeria-Markdown", alias="Egeria Home Glossary Name")
152
152
  egeria_local_qualifier: str = Field(default="PDR", alias="Egeria Local Qualifier")
153
+ egeria_usage_level: str = Field(default="Advanced", alias="Egeria Usage Level")
153
154
  user_name: Optional[str] = "erinoverview"
154
155
  user_pwd: Optional[str] = "secret"
155
156