pyegeria 5.4.0.dev14__py3-none-any.whl → 5.4.0.2__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 (43) hide show
  1. commands/cat/__init__.py +1 -17
  2. commands/cat/dr_egeria_md.py +6 -4
  3. commands/cat/list_collections.py +46 -36
  4. md_processing/__init__.py +5 -2
  5. md_processing/data/commands-working.json +34850 -0
  6. md_processing/data/commands.json +1750 -530
  7. md_processing/md_commands/product_manager_commands.py +171 -220
  8. md_processing/md_processing_utils/common_md_proc_utils.py +9 -0
  9. md_processing/md_processing_utils/common_md_utils.py +15 -2
  10. md_processing/md_processing_utils/md_processing_constants.py +44 -6
  11. pyegeria/__init__.py +8 -4
  12. pyegeria/_client.py +2 -1
  13. pyegeria/_client_new.py +688 -0
  14. pyegeria/_exceptions_new.py +364 -0
  15. pyegeria/_globals.py +3 -1
  16. pyegeria/_output_formats.py +196 -0
  17. pyegeria/_validators.py +72 -199
  18. pyegeria/collection_manager_omvs.py +602 -324
  19. pyegeria/data_designer_omvs.py +251 -203
  20. pyegeria/load_config.py +206 -0
  21. pyegeria/logging_configuration.py +204 -0
  22. pyegeria/output_formatter.py +162 -31
  23. pyegeria/utils.py +99 -61
  24. {pyegeria-5.4.0.dev14.dist-info → pyegeria-5.4.0.2.dist-info}/METADATA +4 -1
  25. {pyegeria-5.4.0.dev14.dist-info → pyegeria-5.4.0.2.dist-info}/RECORD +28 -37
  26. commands/cat/debug_log +0 -2806
  27. commands/cat/debug_log.2025-07-15_14-28-38_087378.zip +0 -0
  28. commands/cat/debug_log.2025-07-16_15-48-50_037087.zip +0 -0
  29. md_processing/dr_egeria_outbox-pycharm/.obsidian/app.json +0 -1
  30. md_processing/dr_egeria_outbox-pycharm/.obsidian/appearance.json +0 -1
  31. md_processing/dr_egeria_outbox-pycharm/.obsidian/core-plugins.json +0 -31
  32. md_processing/dr_egeria_outbox-pycharm/.obsidian/workspace.json +0 -177
  33. md_processing/dr_egeria_outbox-pycharm/monday/processed-2025-07-14 12:38-data_designer_out.md +0 -663
  34. md_processing/dr_egeria_outbox-pycharm/thursday/processed-2025-07-17 15:00-Derive-Dr-Gov-Defs.md +0 -719
  35. md_processing/dr_egeria_outbox-pycharm/thursday/processed-2025-07-17 20:13-Derive-Dr-Gov-Defs.md +0 -41
  36. md_processing/dr_egeria_outbox-pycharm/thursday/processed-2025-07-17 20:14-Derive-Dr-Gov-Defs.md +0 -33
  37. md_processing/dr_egeria_outbox-pycharm/thursday/processed-2025-07-17 20:50-Derive-Dr-Gov-Defs.md +0 -192
  38. md_processing/dr_egeria_outbox-pycharm/tuesday/processed-2025-07-16 19:15-gov_def2.md +0 -527
  39. md_processing/dr_egeria_outbox-pycharm/tuesday/processed-2025-07-17 12:08-gov_def2.md +0 -527
  40. md_processing/dr_egeria_outbox-pycharm/tuesday/processed-2025-07-17 14:27-gov_def2.md +0 -474
  41. {pyegeria-5.4.0.dev14.dist-info → pyegeria-5.4.0.2.dist-info}/LICENSE +0 -0
  42. {pyegeria-5.4.0.dev14.dist-info → pyegeria-5.4.0.2.dist-info}/WHEEL +0 -0
  43. {pyegeria-5.4.0.dev14.dist-info → pyegeria-5.4.0.2.dist-info}/entry_points.txt +0 -0
@@ -11,6 +11,60 @@ console = Console(width= 250)
11
11
  # Constants
12
12
  MD_SEPARATOR = "\n---\n\n"
13
13
 
14
+
15
+ def _extract_referenceable_properties(element: dict[str, Any]) -> dict[str, Any]:
16
+ # Get general header attributes
17
+ guid = element['elementHeader'].get("guid", None)
18
+ metadata_collection_id = element['elementHeader']['origin'].get("homeMetadataCollectionId", None)
19
+ metadata_collection_name = element['elementHeader']['origin'].get("homeMetadataCollectionName", None)
20
+ origin_category = element['elementHeader'].get("origin_category", None)
21
+ created_by = element['elementHeader']["versions"].get("createdBy", None)
22
+ create_time = element['elementHeader']["versions"].get("createTime", None)
23
+ updated_by = element['elementHeader']["versions"].get("updatedBy", None)
24
+ version = element['elementHeader']["versions"].get("version", None)
25
+ type_name = element['elementHeader']["type"].get("typeName", None)
26
+ classifications = element['elementHeader'].get("classifications", [])
27
+
28
+ # Get attributes from properties
29
+ properties = element['properties']
30
+ display_name = properties.get("name", "") or ""
31
+ description = properties.get("description", "") or ""
32
+ qualified_name = properties.get("qualifiedName", "") or ""
33
+ category = properties.get("category", "") or ""
34
+ version_identifier = properties.get("versionIdentifier", "") or ""
35
+ additional_properties = properties.get("additionalProperties", {}) or {}
36
+ extended_properties = properties.get("extendedProperties", {}) or {}
37
+ effective_from = element['elementHeader'].get("effectiveFrom", None)
38
+ effective_to = element['elementHeader'].get("effectiveTo", None)
39
+
40
+ return {
41
+ "GUID": guid,
42
+ "metadata_collection_id": metadata_collection_id,
43
+ "metadata_collection_name": metadata_collection_name,
44
+ "origin_category": origin_category,
45
+ "created_by": created_by,
46
+ "create_time": create_time,
47
+ "updated_by": updated_by,
48
+ "version": version,
49
+ "type_name": type_name,
50
+ "classifications": classifications,
51
+
52
+ "display_name": display_name,
53
+ "description": description,
54
+ "qualified_name": qualified_name,
55
+ "category": category,
56
+ "version_identifier": version_identifier,
57
+ "additional_properties": additional_properties,
58
+ "extended_properties": extended_properties,
59
+ "effective_from": effective_from,
60
+ "effective_to": effective_to,
61
+ }
62
+
63
+
64
+
65
+
66
+
67
+
14
68
  def markdown_to_html(markdown_text: str) -> str:
15
69
  """
16
70
  Convert markdown text to HTML, with special handling for mermaid code blocks.
@@ -120,7 +174,7 @@ def make_md_attribute(attribute_name: str, attribute_value: str, output_type: st
120
174
  output = ""
121
175
  if isinstance(attribute_value,str):
122
176
  attribute_value = attribute_value.strip() if attribute_value else ""
123
- elif isinstance(attribute_value,list):
177
+ elif isinstance(attribute_value,list) and len(attribute_value) > 0:
124
178
  attribute_value = ",\n".join(attribute_value)
125
179
  if attribute_name:
126
180
  if attribute_name.upper() == "GUID":
@@ -170,7 +224,8 @@ def generate_entity_md(elements: List[Dict],
170
224
  output_format: str,
171
225
  entity_type: str,
172
226
  extract_properties_func: Callable,
173
- get_additional_props_func: Optional[Callable] = None) -> str:
227
+ get_additional_props_func: Optional[Callable] = None,
228
+ columns_struct: [dict] = None) -> str:
174
229
  """
175
230
  Generic method to generate markdown for entities.
176
231
 
@@ -181,11 +236,13 @@ def generate_entity_md(elements: List[Dict],
181
236
  entity_type (str): Type of entity (Glossary, Term, Category, etc.)
182
237
  extract_properties_func: Function to extract properties from an element
183
238
  get_additional_props_func: Optional function to get additional properties
239
+ columns (list): List of column name structures
184
240
 
185
241
  Returns:
186
242
  str: Markdown representation
187
243
  """
188
244
  elements_md = ""
245
+ columns = columns_struct['formats'].get('columns') if columns_struct else None
189
246
 
190
247
  for element in elements:
191
248
  if element is None:
@@ -197,7 +254,7 @@ def generate_entity_md(elements: List[Dict],
197
254
  if get_additional_props_func:
198
255
  additional_props = get_additional_props_func(element,props['GUID'], output_format)
199
256
 
200
- display_name = props.get('displayName', None)
257
+ display_name = props.get('display_name', None)
201
258
  if display_name is None:
202
259
  display_name = props.get('title', None)
203
260
  if display_name is None:
@@ -208,25 +265,45 @@ def generate_entity_md(elements: List[Dict],
208
265
  elements_md += f"# {elements_action}\n\n"
209
266
  elements_md += f"## {entity_type} Name \n\n{display_name}\n\n"
210
267
  elif output_format == 'REPORT':
211
- elements_md += f'<a id="{props["GUID"]}"></a>\n\n# {entity_type} Name: {display_name}\n\n'
268
+ elements_md += f'<a id="{props.get("GUID","No GUID")}"></a>\n# {entity_type} Name: {display_name}\n\n'
212
269
  else:
213
270
  elements_md += f"## {entity_type} Name \n\n{display_name}\n\n"
214
271
 
215
- # Add common attributes
216
- for key, value in props.items():
217
- if output_format in ['FORM', 'MD', 'DICT'] and key == 'mermaid':
218
- continue
272
+ # Add attributes based on column spec if available, otherwise, add all
273
+ if columns:
274
+ for column in columns:
275
+ key = column['key']
276
+ name = column['name']
277
+ value = ""
278
+
279
+ # Check if the key is in props or additional_props
280
+ if key in props:
281
+ value = props[key]
282
+ elif key in additional_props:
283
+ value = additional_props[key]
284
+ # Format the value if needed
285
+ if 'format' in column and column['format']:
286
+ value = format_for_markdown_table(value, props['GUID'])
287
+ # elements_md += make_md_attribute(key.replace('_', ' '), value, output_format)
288
+ elements_md += make_md_attribute(name, value, output_format)
219
289
 
220
- if key not in [ 'properties', 'display_name']:
290
+ else:
291
+ for key, value in props.items():
292
+ if output_format in ['FORM', 'MD', 'DICT'] and key == 'mermaid':
293
+ continue
294
+ if key not in [ 'properties', 'display_name']:
295
+ if key == "mermaid" and value == '':
296
+ continue
297
+ elements_md += make_md_attribute(key.replace('_', ' '), value, output_format)
298
+ # Add additional properties
299
+ for key, value in additional_props.items():
221
300
  elements_md += make_md_attribute(key.replace('_', ' '), value, output_format)
222
301
 
223
- # Add additional properties
224
- for key, value in additional_props.items():
225
- elements_md += make_md_attribute(key.replace('_', ' '), value, output_format)
226
-
227
302
  # # Add GUID
228
303
  # elements_md += make_md_attribute("GUID",props['GUID'], output_format)
229
304
 
305
+ if wk := columns_struct.get("annotations", {}).get("wikilinks", None):
306
+ elements_md += ", ".join(wk)
230
307
  # Add separator if not the last element
231
308
  if element != elements[-1]:
232
309
  elements_md += MD_SEPARATOR
@@ -237,7 +314,7 @@ def generate_entity_md_table(elements: List[Dict],
237
314
  search_string: str,
238
315
  entity_type: str,
239
316
  extract_properties_func: Callable,
240
- columns: List[Dict],
317
+ columns_struct: dict,
241
318
  get_additional_props_func: Optional[Callable] = None,
242
319
  output_format: str = 'LIST') -> str:
243
320
  """
@@ -257,6 +334,7 @@ def generate_entity_md_table(elements: List[Dict],
257
334
  """
258
335
  # Handle pluralization - if entity_type ends with 'y', use 'ies' instead of 's'
259
336
  entity_type_plural = f"{entity_type[:-1]}ies" if entity_type.endswith('y') else f"{entity_type}s"
337
+ columns = columns_struct['formats'].get('columns', [])
260
338
 
261
339
  elements_md = ""
262
340
  if output_format == "LIST":
@@ -304,14 +382,16 @@ def generate_entity_md_table(elements: List[Dict],
304
382
  row += f"{value} | "
305
383
 
306
384
  elements_md += row + "\n"
307
-
385
+ if wk := columns_struct.get("annotations",{}).get("wikilinks", None):
386
+ elements_md += ", ".join(wk)
308
387
  return elements_md
309
388
 
310
389
  def generate_entity_dict(elements: List[Dict],
311
390
  extract_properties_func: Callable,
312
391
  get_additional_props_func: Optional[Callable] = None,
313
392
  include_keys: Optional[List[str]] = None,
314
- exclude_keys: Optional[List[str]] = None,
393
+ exclude_keys: Optional[List[str]] = None,
394
+ columns_struct: dict = None,
315
395
  output_format: str = 'DICT') -> List[Dict]:
316
396
  """
317
397
  Generic method to generate a dictionary representation of entities.
@@ -322,6 +402,7 @@ def generate_entity_dict(elements: List[Dict],
322
402
  get_additional_props_func: Optional function to get additional properties
323
403
  include_keys: Optional list of keys to include in the result (if None, include all)
324
404
  exclude_keys: Optional list of keys to exclude from the result (if None, exclude none)
405
+ columns_struct: Optional dict of columns to include (if None, include all)
325
406
  output_format (str): Output format (FORM, REPORT, DICT, etc.)
326
407
 
327
408
  Returns:
@@ -329,11 +410,12 @@ def generate_entity_dict(elements: List[Dict],
329
410
  """
330
411
  result = []
331
412
 
413
+ #####
414
+ # Add attributes based on column spec if available, otherwise, add all
332
415
  for element in elements:
333
416
  if element is None:
334
417
  continue
335
418
  props = extract_properties_func(element)
336
-
337
419
  # Get additional properties if function is provided
338
420
  additional_props = {}
339
421
  if get_additional_props_func:
@@ -342,19 +424,64 @@ def generate_entity_dict(elements: List[Dict],
342
424
  # Create entity dictionary
343
425
  entity_dict = {}
344
426
 
345
- # Add properties based on include/exclude lists
346
- for key, value in props.items():
347
- if key not in [ 'properties', 'mermaid']: # Skip the raw properties object
348
- if (include_keys is None or key in include_keys) and (
349
- exclude_keys is None or key not in exclude_keys):
350
- entity_dict[key] = value
427
+ columns = columns_struct['formats'].get('columns', None) if columns_struct else None
428
+ if columns:
429
+ for column in columns:
430
+ key = column['key']
431
+ name = column['name']
432
+ value = ""
433
+
434
+ # Check if the key is in props or additional_props
435
+ if key in props:
436
+ value = props[key]
437
+ elif key in additional_props:
438
+ value = additional_props[key]
439
+ # Format the value if needed
440
+ if column.get('format', None):
441
+ value = format_for_markdown_table(value, props['GUID'])
442
+ entity_dict[name] = value
351
443
 
352
- # Add additional properties
353
- for key, value in additional_props.items():
354
- if (include_keys is None or key in include_keys) and (exclude_keys is None or key not in exclude_keys):
355
- entity_dict[key] = value
444
+ else:
445
+ # Add properties based on include/exclude lists
446
+ for key, value in props.items():
447
+ if key not in ['properties', 'mermaid']: # Skip the raw properties object
448
+ if (include_keys is None or key in include_keys) and (
449
+ exclude_keys is None or key not in exclude_keys):
450
+ entity_dict[key] = value
451
+
452
+ # Add additional properties
453
+ for key, value in additional_props.items():
454
+ if (include_keys is None or key in include_keys) and (exclude_keys is None or key not in exclude_keys):
455
+ entity_dict[key] = value
356
456
 
357
457
  result.append(entity_dict)
458
+ #####
459
+ # for element in elements:
460
+ # if element is None:
461
+ # continue
462
+ # props = extract_properties_func(element)
463
+ #
464
+ # # Get additional properties if function is provided
465
+ # additional_props = {}
466
+ # if get_additional_props_func:
467
+ # additional_props = get_additional_props_func(element,props['GUID'], output_format)
468
+ #
469
+ # # Create entity dictionary
470
+ # entity_dict = {}
471
+ #
472
+ # # Add properties based on include/exclude lists
473
+ # for key, value in props.items():
474
+ # if key not in [ 'properties', 'mermaid']: # Skip the raw properties object
475
+ # if (include_keys is None or key in include_keys) and (
476
+ # exclude_keys is None or key not in exclude_keys):
477
+ # entity_dict[key] = value
478
+ #
479
+ # # Add additional properties
480
+ # for key, value in additional_props.items():
481
+ # if (include_keys is None or key in include_keys) and (exclude_keys is None or key not in exclude_keys):
482
+ # entity_dict[key] = value
483
+ #
484
+ # result.append(entity_dict)
358
485
 
359
486
  return result
360
487
 
@@ -430,7 +557,7 @@ def generate_output(elements: Union[Dict, List[Dict]],
430
557
  output_format: str,
431
558
  extract_properties_func: Callable,
432
559
  get_additional_props_func: Optional[Callable] = None,
433
- columns: Optional[List[Dict]] = None) -> Union[str, List[Dict]]:
560
+ columns_struct: dict = None) -> Union[str, list[dict]]:
434
561
  """
435
562
  Generate output in the specified format for the given elements.
436
563
 
@@ -446,6 +573,7 @@ def generate_output(elements: Union[Dict, List[Dict]],
446
573
  Returns:
447
574
  Formatted output as string or list of dictionaries
448
575
  """
576
+ columns = columns_struct['formats'].get('columns',None) if columns_struct else None
449
577
  # Ensure elements is a list
450
578
  if isinstance(elements, dict):
451
579
  elements = [elements]
@@ -466,7 +594,8 @@ def generate_output(elements: Union[Dict, List[Dict]],
466
594
  entity_type=entity_type,
467
595
  output_format="REPORT",
468
596
  extract_properties_func=extract_properties_func,
469
- get_additional_props_func=get_additional_props_func
597
+ get_additional_props_func=get_additional_props_func,
598
+ columns_struct=columns_struct
470
599
  )
471
600
 
472
601
  # Convert the markdown to HTML
@@ -478,6 +607,7 @@ def generate_output(elements: Union[Dict, List[Dict]],
478
607
  extract_properties_func=extract_properties_func,
479
608
  get_additional_props_func=get_additional_props_func,
480
609
  exclude_keys=['properties'],
610
+ columns_struct=columns_struct,
481
611
  output_format=output_format
482
612
  )
483
613
 
@@ -490,7 +620,7 @@ def generate_output(elements: Union[Dict, List[Dict]],
490
620
  search_string=search_string,
491
621
  entity_type=entity_type,
492
622
  extract_properties_func=extract_properties_func,
493
- columns=columns,
623
+ columns_struct=columns_struct,
494
624
  get_additional_props_func=get_additional_props_func,
495
625
  output_format=output_format
496
626
  )
@@ -508,7 +638,8 @@ def generate_output(elements: Union[Dict, List[Dict]],
508
638
  output_format=output_format,
509
639
  entity_type=entity_type,
510
640
  extract_properties_func=extract_properties_func,
511
- get_additional_props_func=get_additional_props_func
641
+ get_additional_props_func=get_additional_props_func,
642
+ columns_struct = columns_struct
512
643
  )
513
644
 
514
645
  return elements_md
pyegeria/utils.py CHANGED
@@ -8,72 +8,17 @@ General utility functions in support of the Egeria Python Client package.
8
8
 
9
9
  import json
10
10
  from datetime import datetime
11
-
11
+ from loguru import logger
12
12
  from rich import print, print_json
13
13
  from rich.console import Console
14
+ from pyegeria.load_config import get_app_config
14
15
 
15
- console = Console(width=200)
16
+ app_settings = get_app_config()
16
17
 
17
- # def wrap_text(df: pd.DataFrame, wrap_len: int = 30) -> pd.DataFrame:
18
- # """ Wrap the text in a dataframe
19
- # Parameters
20
- # ----------
21
- # df : pandas.DataFrame
22
- # The DataFrame to wrap the text in.
23
- # wrap_len : int, optional
24
- # The maximum length of each cell's contents to wrap. Defaults to 30.
25
- #
26
- # Returns
27
- # -------
28
- # pandas.DataFrame
29
- # A new DataFrame with the wrapped text.
30
- #
31
- # """
32
- #
33
- # # Helper function to wrap text in a particular cell
34
- # def wrap_cell_contents(cell_contents: str, wrap: int = 30) -> str:
35
- # """ Wrap the text in a cell
36
- # Parameters
37
- # ----------
38
- # cell_contents : str or any
39
- # The contents of a cell in a dataframe.
40
- # wrap : int, optional
41
- # The maximum width at which to wrap the cell contents. Default is 30.
42
- #
43
- # Returns
44
- # -------
45
- # str or any
46
- # If the cell_contents is a string and its length is greater than wrap_len,
47
- # the contents are wrapped at wrap_len width using textwrap.
48
- # Otherwise, the original cell_contents are returned as is.
49
- # """
50
- # if isinstance(cell_contents, str) and len(cell_contents) > wrap:
51
- # return textwrap.fill(cell_contents, width=wrap)
52
- # else:
53
- # return cell_contents
54
- #
55
- # # Apply the helper function to each element in the DataFrame
56
- # return df.map(lambda x: wrap_cell_contents(x, wrap_len))
57
- #
58
- #
59
- # def print_nice_table(df, wrap_len: int = 20, tablefmt: str = "grid") -> None:
60
- # """ Print a nice table from the data frame"""
61
- # print(tabulate(wrap_text(df, wrap_len), headers="keys", tablefmt=tablefmt))
62
- #
63
- #
64
- # def get_json_as_table(input_json, wrap_len: int = 30, tablefmt: str = "grid") -> str:
65
- # """ return the input json as a table"""
66
- # data = json.loads(json.dumps(input_json))
67
- # df = pd.json_normalize(data)
68
- # return tabulate(wrap_text(df, wrap_len), headers="keys", tablefmt=tablefmt)
69
- #
70
- #
71
- # def print_json_list_as_table(input_json, wrap_len: int = 30, tablefmt: str = "grid") -> None:
72
- # """ print a json list as a table"""
73
- # data = json.loads(json.dumps(input_json))
74
- # df = pd.json_normalize(data)
75
- # print(tabulate(wrap_text(df, wrap_len), headers="keys", tablefmt=tablefmt))
18
+ console = Console(width=200)
76
19
 
20
+ def init_log():
21
+ pass
77
22
 
78
23
  def print_rest_request_body(body):
79
24
  """
@@ -213,5 +158,98 @@ def camel_to_title_case(input_string):
213
158
  return result
214
159
 
215
160
 
161
+ def to_camel_case(input_string):
162
+ """Convert an input string to camelCase, singularizing if plural.
163
+
164
+ This function takes an input string, converts it to singular form if it's plural,
165
+ and then transforms it to camelCase format (first word lowercase, subsequent words
166
+ capitalized with no spaces).
167
+
168
+ Parameters
169
+ ----------
170
+ input_string : str
171
+ The string to convert to camelCase
172
+
173
+ Returns
174
+ -------
175
+ str:
176
+ The input string converted to camelCase, after singularization if needed
177
+
178
+ Examples
179
+ --------
180
+ >>> to_camel_case("data categories")
181
+ 'dataCategory'
182
+ >>> to_camel_case("business terms")
183
+ 'businessTerm'
184
+ >>> to_camel_case("glossary categories")
185
+ 'glossaryCategory'
186
+ """
187
+ if not input_string:
188
+ return ""
189
+
190
+ # Convert to lowercase for consistent processing
191
+ lowercase_input = input_string.lower()
192
+
193
+ # First, convert to singular if plural
194
+ singular = lowercase_input
195
+
196
+ # Handle common plural endings
197
+ if singular.endswith('ies'):
198
+ singular = singular[:-3] + 'y'
199
+ elif singular.endswith('es'):
200
+ # Special cases like 'classes' -> 'class'
201
+ if singular.endswith('sses') or singular.endswith('ches') or singular.endswith('shes') or singular.endswith('xes'):
202
+ singular = singular[:-2]
203
+ else:
204
+ singular = singular[:-1]
205
+ elif singular.endswith('s') and not singular.endswith('ss'):
206
+ singular = singular[:-1]
207
+
208
+ # Split the string into words and convert to camelCase
209
+ words = singular.split()
210
+ if not words:
211
+ return ""
212
+
213
+ # First word is lowercase, rest are capitalized
214
+ result = words[0]
215
+ for word in words[1:]:
216
+ result += word.capitalize()
217
+
218
+ return result
219
+
220
+ def to_pascal_case(input_string)->str:
221
+ """
222
+ Convert input string to PascalCase, singularizing if plural.
223
+ Args:
224
+ input_string ():
225
+
226
+ Returns:
227
+ transformed string
228
+ """
229
+ result = to_camel_case(input_string)
230
+ output_string = result[0].upper() + result[1:]
231
+ return output_string
232
+
233
+ def flatten_dict_to_string(d: dict) -> str:
234
+ """Flatten a dictionary into a string and replace quotes with backticks."""
235
+ try:
236
+ flat_string = ", ".join(
237
+ # Change replace(\"'\", '`') to replace("'", '`')
238
+ f"{key}=`{str(value).replace('\"', '`').replace("'", '`')}`"
239
+ for key, value in d.items()
240
+ )
241
+ return flat_string
242
+ except Exception as e:
243
+ # Corrected syntax for exception chaining
244
+ raise Exception("Error flattening dictionary") from e
245
+ # The decorator logic, which applies @logger.catch dynamically
246
+
247
+
248
+ def dynamic_catch(func):
249
+ if app_settings.get("enable_logger_catchh", False):
250
+ return logger.catch(func) # Apply the logger.catch decorator
251
+ else:
252
+ return func # Return the function unwrapped
253
+
216
254
  if __name__ == "__main__":
217
255
  print("Main-Utils")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pyegeria
3
- Version: 5.4.0.dev14
3
+ Version: 5.4.0.2
4
4
  Summary: A python client for Egeria
5
5
  License: Apache 2.0
6
6
  Keywords: egeria,metadata,governance
@@ -14,11 +14,14 @@ Classifier: Programming Language :: Python :: 3
14
14
  Classifier: Programming Language :: Python :: 3.13
15
15
  Requires-Dist: click
16
16
  Requires-Dist: httpx
17
+ Requires-Dist: inflect (>=7.5.0,<8.0.0)
17
18
  Requires-Dist: jupyter
18
19
  Requires-Dist: jupyter-notebook-parser (>=0.1.4,<0.2.0)
19
20
  Requires-Dist: loguru (>=0.7.3,<0.8.0)
20
21
  Requires-Dist: mermaid-py
22
+ Requires-Dist: poetry-core (>=2.1.3,<3.0.0)
21
23
  Requires-Dist: psycopg2-binary (>=2.9.9,<3.0.0)
24
+ Requires-Dist: pydantic (>=2.11.7,<3.0.0)
22
25
  Requires-Dist: pytest (>=8.3.5,<9.0.0)
23
26
  Requires-Dist: requests
24
27
  Requires-Dist: rich