pyegeria 5.4.0.28__py3-none-any.whl → 5.5.3.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.

Potentially problematic release.


This version of pyegeria might be problematic. Click here for more details.

Files changed (433) hide show
  1. commands/__init__.py +24 -0
  2. commands/cat/Dr-Egeria_md-orig.py +2 -2
  3. commands/cat/collection_actions.py +197 -0
  4. commands/cat/dr_egeria_command_help.py +137 -38
  5. commands/cat/dr_egeria_jupyter.py +7 -7
  6. commands/cat/dr_egeria_md.py +10 -267
  7. commands/cat/exp_list_glossaries.py +11 -14
  8. commands/cat/get_asset_graph.py +37 -267
  9. commands/cat/{get_collection.py → get_collection_tree.py} +10 -18
  10. commands/cat/get_project_dependencies.py +14 -14
  11. commands/cat/get_project_structure.py +15 -14
  12. commands/cat/get_tech_type_elements.py +16 -116
  13. commands/cat/glossary_actions.py +145 -298
  14. commands/cat/list_assets.py +3 -11
  15. commands/cat/list_cert_types.py +17 -63
  16. commands/cat/list_collections.py +17 -139
  17. commands/cat/list_deployed_catalogs.py +15 -27
  18. commands/cat/list_deployed_database_schemas.py +27 -43
  19. commands/cat/list_deployed_databases.py +16 -31
  20. commands/cat/list_deployed_servers.py +35 -54
  21. commands/cat/list_glossaries.py +18 -17
  22. commands/cat/list_projects.py +10 -12
  23. commands/cat/list_tech_type_elements.py +21 -37
  24. commands/cat/list_tech_types.py +13 -25
  25. commands/cat/list_terms.py +38 -79
  26. commands/cat/list_todos.py +4 -11
  27. commands/cat/list_user_ids.py +3 -10
  28. commands/cat/my_reports.py +559 -0
  29. commands/cat/run_report.py +394 -0
  30. commands/cat/{list_format_set.py → run_report_orig.py} +136 -44
  31. commands/cli/egeria.py +182 -219
  32. commands/cli/egeria_cat.py +32 -59
  33. commands/cli/egeria_my.py +13 -0
  34. commands/cli/egeria_ops.py +69 -74
  35. commands/cli/egeria_tech.py +17 -93
  36. commands/{cat → deprecated}/list_data_designer.py +2 -4
  37. commands/{cat → deprecated}/list_data_structures_full.py +3 -6
  38. commands/deprecated/old_get_asset_graph.py +315 -0
  39. commands/my/__init__.py +0 -2
  40. commands/my/list_my_profile.py +27 -34
  41. commands/my/list_my_roles.py +1 -7
  42. commands/my/monitor_my_todos.py +1 -7
  43. commands/my/monitor_open_todos.py +6 -7
  44. commands/my/todo_actions.py +4 -5
  45. commands/ops/__init__.py +0 -2
  46. commands/ops/gov_server_actions.py +17 -21
  47. commands/ops/list_archives.py +17 -38
  48. commands/ops/list_catalog_targets.py +33 -40
  49. commands/ops/load_archive.py +14 -11
  50. commands/ops/{monitor_engine_activity_c.py → monitor_active_engine_activity.py} +51 -82
  51. commands/ops/{monitor_integ_daemon_status.py → monitor_daemon_status.py} +35 -55
  52. commands/ops/monitor_engine_activity.py +79 -77
  53. commands/ops/{monitor_gov_eng_status.py → monitor_engine_status.py} +10 -7
  54. commands/ops/monitor_platform_status.py +38 -50
  55. commands/ops/monitor_server_startup.py +6 -11
  56. commands/ops/monitor_server_status.py +7 -11
  57. commands/ops/orig_monitor_server_list.py +8 -8
  58. commands/ops/orig_monitor_server_status.py +1 -5
  59. commands/ops/refresh_integration_daemon.py +5 -5
  60. commands/ops/restart_integration_daemon.py +5 -5
  61. commands/ops/table_integ_daemon_status.py +6 -6
  62. commands/ops/x_engine_actions.py +7 -7
  63. commands/tech/__init__.py +0 -2
  64. commands/tech/{generic_actions.py → element_actions.py} +6 -11
  65. commands/tech/get_element_info.py +20 -29
  66. commands/tech/get_guid_info.py +23 -42
  67. commands/tech/get_tech_details.py +20 -35
  68. commands/tech/get_tech_type_template.py +28 -39
  69. commands/tech/list_all_om_type_elements.py +24 -30
  70. commands/tech/list_all_om_type_elements_x.py +22 -28
  71. commands/tech/list_all_related_elements.py +19 -28
  72. commands/tech/list_anchored_elements.py +22 -30
  73. commands/tech/list_asset_types.py +19 -24
  74. commands/tech/list_elements_by_classification_by_property_value.py +26 -32
  75. commands/tech/list_elements_by_property_value.py +19 -25
  76. commands/tech/list_elements_by_property_value_x.py +20 -28
  77. commands/tech/list_elements_for_classification.py +28 -41
  78. commands/tech/list_gov_action_processes.py +16 -27
  79. commands/tech/list_information_supply_chains.py +22 -30
  80. commands/tech/list_registered_services.py +14 -26
  81. commands/tech/list_related_elements_with_prop_value.py +15 -25
  82. commands/tech/list_related_specification.py +1 -4
  83. commands/tech/list_relationship_types.py +15 -25
  84. commands/tech/list_relationships.py +20 -36
  85. commands/tech/list_solution_blueprints.py +28 -33
  86. commands/tech/list_solution_components.py +23 -29
  87. commands/tech/list_solution_roles.py +21 -32
  88. commands/tech/list_tech_templates.py +51 -54
  89. commands/tech/list_valid_metadata_values.py +5 -9
  90. commands/tech/table_tech_templates.py +2 -6
  91. commands/tech/x_list_related_elements.py +1 -4
  92. examples/GeoSpatial Products Example.py +524 -0
  93. examples/Jupyter Notebooks/P-egeria-server-config.ipynb +2137 -0
  94. examples/Jupyter Notebooks/README.md +2 -0
  95. examples/Jupyter Notebooks/common/P-environment-check.ipynb +115 -0
  96. examples/Jupyter Notebooks/common/__init__.py +14 -0
  97. examples/Jupyter Notebooks/common/common-functions.ipynb +4694 -0
  98. examples/Jupyter Notebooks/common/environment-check.ipynb +52 -0
  99. examples/Jupyter Notebooks/common/globals.ipynb +184 -0
  100. examples/Jupyter Notebooks/common/globals.py +154 -0
  101. examples/Jupyter Notebooks/common/orig_globals.py +152 -0
  102. examples/format_sets/all_format_sets.json +910 -0
  103. examples/format_sets/custom_format_sets.json +268 -0
  104. examples/format_sets/subset_format_sets.json +187 -0
  105. examples/format_sets_save_load_example.py +291 -0
  106. examples/jacquard_data_sets.py +129 -0
  107. examples/output_formats_example.py +193 -0
  108. examples/test_jacquard_data_sets.py +54 -0
  109. examples/test_jacquard_data_sets_scenarios.py +94 -0
  110. md_processing/__init__.py +33 -24
  111. md_processing/command_dispatcher.py +33 -0
  112. md_processing/command_mapping.py +221 -0
  113. md_processing/data/commands/commands_data_designer.json +537 -0
  114. md_processing/data/commands/commands_external_reference.json +733 -0
  115. md_processing/data/commands/commands_feedback.json +155 -0
  116. md_processing/data/commands/commands_general.json +204 -0
  117. md_processing/data/commands/commands_glossary.json +218 -0
  118. md_processing/data/commands/commands_governance.json +3678 -0
  119. md_processing/data/commands/commands_product_manager.json +865 -0
  120. md_processing/data/commands/commands_project.json +642 -0
  121. md_processing/data/commands/commands_solution_architect.json +366 -0
  122. md_processing/data/commands.json +6489 -30060
  123. md_processing/data/{commands-working.json → commands_working.json} +9304 -13513
  124. md_processing/data/gened_report_specs.py +6584 -0
  125. md_processing/data/generated_format_sets.json +6533 -0
  126. md_processing/data/generated_format_sets_old.json +4137 -0
  127. md_processing/data/generated_format_sets_old.py +45 -0
  128. md_processing/dr_egeria.py +182 -0
  129. md_processing/md_commands/data_designer_commands.py +195 -583
  130. md_processing/md_commands/ext_ref_commands.py +530 -0
  131. md_processing/md_commands/feedback_commands.py +726 -0
  132. md_processing/md_commands/glossary_commands.py +106 -490
  133. md_processing/md_commands/governance_officer_commands.py +129 -18
  134. md_processing/md_commands/product_manager_commands.py +362 -115
  135. md_processing/md_commands/project_commands.py +351 -134
  136. md_processing/md_commands/solution_architect_commands.py +276 -232
  137. md_processing/md_commands/view_commands.py +295 -0
  138. md_processing/md_processing_utils/common_md_proc_utils.py +258 -166
  139. md_processing/md_processing_utils/common_md_utils.py +138 -43
  140. md_processing/md_processing_utils/determine_width.py +103 -0
  141. md_processing/md_processing_utils/extraction_utils.py +100 -39
  142. md_processing/md_processing_utils/gen_report_specs.py +643 -0
  143. md_processing/md_processing_utils/generate_dr_help.py +61 -33
  144. md_processing/md_processing_utils/generate_md_cmd_templates.py +20 -19
  145. md_processing/md_processing_utils/generate_md_templates.py +3 -12
  146. md_processing/md_processing_utils/md_processing_constants.py +1053 -72
  147. pyegeria/__init__.py +203 -158
  148. pyegeria/core/__init__.py +40 -0
  149. pyegeria/core/_base_platform_client.py +574 -0
  150. pyegeria/core/_base_server_client.py +573 -0
  151. pyegeria/{_exceptions_new.py → core/_exceptions.py} +62 -30
  152. pyegeria/{_globals.py → core/_globals.py} +14 -3
  153. pyegeria/core/_server_client.py +6073 -0
  154. pyegeria/{_validators.py → core/_validators.py} +7 -8
  155. pyegeria/core/config.py +654 -0
  156. pyegeria/{create_tech_guid_lists.py → core/create_tech_guid_lists.py} +0 -1
  157. pyegeria/core/load_config.py +37 -0
  158. pyegeria/{logging_configuration.py → core/logging_configuration.py} +1 -1
  159. pyegeria/core/mcp_adapter.py +144 -0
  160. pyegeria/core/mcp_server.py +212 -0
  161. pyegeria/core/utils.py +405 -0
  162. pyegeria/{_client.py → deprecated/_client.py} +24 -25
  163. pyegeria/{_deprecated_gov_engine.py → deprecated/_deprecated_gov_engine.py} +16 -16
  164. pyegeria/{classification_manager_omvs.py → deprecated/classification_manager_omvs.py} +1987 -1877
  165. pyegeria/{output_formatter.py → deprecated/output_formatter_with_machine_keys.py} +298 -45
  166. pyegeria/{runtime_manager_omvs.py → deprecated/runtime_manager_omvs.py} +155 -171
  167. pyegeria/{valid_metadata_omvs.py → deprecated/valid_metadata_omvs.py} +93 -93
  168. pyegeria/{x_action_author_omvs.py → deprecated/x_action_author_omvs.py} +2 -3
  169. pyegeria/egeria_cat_client.py +26 -70
  170. pyegeria/egeria_client.py +130 -93
  171. pyegeria/egeria_config_client.py +40 -46
  172. pyegeria/egeria_tech_client.py +141 -54
  173. pyegeria/models/__init__.py +150 -0
  174. pyegeria/{models.py → models/models.py} +156 -20
  175. pyegeria/omvs/__init__.py +84 -0
  176. pyegeria/omvs/action_author.py +342 -0
  177. pyegeria/omvs/actor_manager.py +5980 -0
  178. pyegeria/omvs/asset_catalog.py +842 -0
  179. pyegeria/omvs/asset_maker.py +2736 -0
  180. pyegeria/omvs/automated_curation.py +4403 -0
  181. pyegeria/omvs/classification_manager.py +11213 -0
  182. pyegeria/{collection_manager.py → omvs/collection_manager.py} +1334 -1160
  183. pyegeria/omvs/community_matters_omvs.py +468 -0
  184. pyegeria/{core_omag_server_config.py → omvs/core_omag_server_config.py} +157 -157
  185. pyegeria/{data_designer.py → omvs/data_designer.py} +1115 -660
  186. pyegeria/omvs/data_discovery.py +869 -0
  187. pyegeria/omvs/data_engineer.py +372 -0
  188. pyegeria/omvs/digital_business.py +1133 -0
  189. pyegeria/omvs/external_links.py +1752 -0
  190. pyegeria/omvs/feedback_manager.py +834 -0
  191. pyegeria/{full_omag_server_config.py → omvs/full_omag_server_config.py} +73 -69
  192. pyegeria/{glossary_manager.py → omvs/glossary_manager.py} +857 -519
  193. pyegeria/{governance_officer.py → omvs/governance_officer.py} +964 -468
  194. pyegeria/omvs/lineage_linker.py +314 -0
  195. pyegeria/omvs/location_arena.py +1525 -0
  196. pyegeria/omvs/metadata_expert.py +668 -0
  197. pyegeria/omvs/metadata_explorer_omvs.py +2943 -0
  198. pyegeria/omvs/my_profile.py +1042 -0
  199. pyegeria/omvs/notification_manager.py +358 -0
  200. pyegeria/omvs/people_organizer.py +394 -0
  201. pyegeria/{platform_services.py → omvs/platform_services.py} +113 -193
  202. pyegeria/omvs/product_manager.py +1825 -0
  203. pyegeria/omvs/project_manager.py +1907 -0
  204. pyegeria/omvs/reference_data.py +1140 -0
  205. pyegeria/omvs/registered_info.py +334 -0
  206. pyegeria/omvs/runtime_manager.py +2817 -0
  207. pyegeria/omvs/schema_maker.py +446 -0
  208. pyegeria/{server_operations.py → omvs/server_operations.py} +27 -26
  209. pyegeria/{solution_architect_omvs.py → omvs/solution_architect.py} +1886 -1505
  210. pyegeria/omvs/specification_properties.py +37 -0
  211. pyegeria/omvs/subject_area.py +1042 -0
  212. pyegeria/omvs/template_manager_omvs.py +236 -0
  213. pyegeria/omvs/time_keeper.py +1761 -0
  214. pyegeria/omvs/valid_metadata.py +3221 -0
  215. pyegeria/omvs/valid_metadata_lists.py +37 -0
  216. pyegeria/omvs/valid_type_lists.py +37 -0
  217. pyegeria/view/__init__.py +28 -0
  218. pyegeria/{_output_format_models.py → view/_output_format_models.py} +160 -24
  219. pyegeria/view/_output_formats.py +14 -0
  220. pyegeria/view/base_report_formats.py +2719 -0
  221. pyegeria/view/dr_egeria_reports.py +56 -0
  222. pyegeria/view/format_set_executor.py +397 -0
  223. pyegeria/{md_processing_utils.py → view/md_processing_utils.py} +5 -5
  224. pyegeria/{mermaid_utilities.py → view/mermaid_utilities.py} +2 -154
  225. pyegeria/view/output_formatter.py +1297 -0
  226. pyegeria-5.5.3.3.dist-info/METADATA +218 -0
  227. pyegeria-5.5.3.3.dist-info/RECORD +241 -0
  228. {pyegeria-5.4.0.28.dist-info → pyegeria-5.5.3.3.dist-info}/WHEEL +2 -1
  229. pyegeria-5.5.3.3.dist-info/entry_points.txt +103 -0
  230. pyegeria-5.5.3.3.dist-info/top_level.txt +4 -0
  231. commands/cat/.DS_Store +0 -0
  232. commands/cat/.env +0 -8
  233. commands/cat/README.md +0 -16
  234. commands/cat/debug_log +0 -1126
  235. commands/cat/debug_log.2025-08-18_11-34-38_088636.zip +0 -0
  236. commands/cat/list_categories.py +0 -192
  237. commands/cat/logs/pyegeria.log +0 -4
  238. commands/cli/debug_log +0 -0
  239. commands/cli/debug_log.log +0 -0
  240. commands/cli/txt_custom_v2.tcss +0 -19
  241. commands/my/README.md +0 -17
  242. commands/ops/README.md +0 -24
  243. commands/ops/logs/pyegeria.log +0 -0
  244. commands/ops/monitor_asset_events.py +0 -108
  245. commands/tech/README.md +0 -24
  246. md_processing/.DS_Store +0 -0
  247. md_processing/dr-egeria-outbox/Collections-2025-08-12-13-30-37.md +0 -163
  248. md_processing/dr-egeria-outbox/Collections-2025-08-12-13-35-58.md +0 -474
  249. md_processing/dr_egeria_inbox/Derive-Dr-Gov-Defs.md +0 -8
  250. md_processing/dr_egeria_inbox/Dr.Egeria Templates.md +0 -873
  251. md_processing/dr_egeria_inbox/arch_test.md +0 -57
  252. md_processing/dr_egeria_inbox/archive/dr_egeria_intro.md +0 -254
  253. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_more_terms.md +0 -696
  254. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part1.md +0 -254
  255. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part2.md +0 -298
  256. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part3.md +0 -608
  257. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part4.md +0 -94
  258. md_processing/dr_egeria_inbox/archive/freddie_intro.md +0 -284
  259. md_processing/dr_egeria_inbox/archive/freddie_intro_orig.md +0 -275
  260. md_processing/dr_egeria_inbox/archive/test-term.md +0 -110
  261. md_processing/dr_egeria_inbox/cat_test.md +0 -100
  262. md_processing/dr_egeria_inbox/collections.md +0 -39
  263. md_processing/dr_egeria_inbox/data_designer_debug.log +0 -6
  264. md_processing/dr_egeria_inbox/data_designer_out.md +0 -60
  265. md_processing/dr_egeria_inbox/data_designer_search_test.md +0 -11
  266. md_processing/dr_egeria_inbox/data_field.md +0 -54
  267. md_processing/dr_egeria_inbox/data_spec.md +0 -77
  268. md_processing/dr_egeria_inbox/data_spec_test.md +0 -2406
  269. md_processing/dr_egeria_inbox/data_test.md +0 -179
  270. md_processing/dr_egeria_inbox/data_test2.md +0 -429
  271. md_processing/dr_egeria_inbox/data_test3.md +0 -462
  272. md_processing/dr_egeria_inbox/dr_egeria_data_designer_1.md +0 -124
  273. md_processing/dr_egeria_inbox/dr_egeria_intro_categories.md +0 -168
  274. md_processing/dr_egeria_inbox/dr_egeria_intro_part1.md +0 -280
  275. md_processing/dr_egeria_inbox/dr_egeria_intro_part2.md +0 -318
  276. md_processing/dr_egeria_inbox/dr_egeria_intro_part3.md +0 -1073
  277. md_processing/dr_egeria_inbox/dr_egeria_isc1.md +0 -44
  278. md_processing/dr_egeria_inbox/generated_help_report.md +0 -9
  279. md_processing/dr_egeria_inbox/glossary_creation_experiment.ipynb +0 -341
  280. md_processing/dr_egeria_inbox/glossary_list.md +0 -5
  281. md_processing/dr_egeria_inbox/glossary_search_test.md +0 -40
  282. md_processing/dr_egeria_inbox/glossary_test1.md +0 -324
  283. md_processing/dr_egeria_inbox/gov_def.md +0 -482
  284. md_processing/dr_egeria_inbox/gov_def2.md +0 -447
  285. md_processing/dr_egeria_inbox/img.png +0 -0
  286. md_processing/dr_egeria_inbox/product.md +0 -211
  287. md_processing/dr_egeria_inbox/rel.md +0 -8
  288. md_processing/dr_egeria_inbox/sb.md +0 -119
  289. md_processing/dr_egeria_inbox/solution-components.md +0 -136
  290. md_processing/dr_egeria_inbox/solution_blueprints.md +0 -118
  291. md_processing/dr_egeria_inbox/synonym_test.md +0 -42
  292. md_processing/dr_egeria_inbox/t2.md +0 -268
  293. md_processing/dr_egeria_outbox/.obsidian/app.json +0 -1
  294. md_processing/dr_egeria_outbox/.obsidian/appearance.json +0 -1
  295. md_processing/dr_egeria_outbox/.obsidian/community-plugins.json +0 -6
  296. md_processing/dr_egeria_outbox/.obsidian/core-plugins.json +0 -31
  297. md_processing/dr_egeria_outbox/.obsidian/plugins/calendar/data.json +0 -10
  298. md_processing/dr_egeria_outbox/.obsidian/plugins/calendar/main.js +0 -4459
  299. md_processing/dr_egeria_outbox/.obsidian/plugins/calendar/manifest.json +0 -10
  300. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-kanban/data.json +0 -3
  301. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-kanban/main.js +0 -153
  302. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-kanban/manifest.json +0 -11
  303. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-kanban/styles.css +0 -1
  304. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-tasks-plugin/main.js +0 -500
  305. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-tasks-plugin/manifest.json +0 -12
  306. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-tasks-plugin/styles.css +0 -1
  307. md_processing/dr_egeria_outbox/.obsidian/plugins/templater-obsidian/main.js +0 -37
  308. md_processing/dr_egeria_outbox/.obsidian/plugins/templater-obsidian/manifest.json +0 -11
  309. md_processing/dr_egeria_outbox/.obsidian/plugins/templater-obsidian/styles.css +0 -220
  310. md_processing/dr_egeria_outbox/.obsidian/types.json +0 -28
  311. md_processing/dr_egeria_outbox/.obsidian/workspace.json +0 -220
  312. md_processing/dr_egeria_outbox/Untitled.canvas +0 -1
  313. md_processing/dr_egeria_outbox/friday/processed-2025-08-22 21:22-dr_egeria_intro_part1.md +0 -312
  314. md_processing/dr_egeria_outbox/friday/processed-2025-08-22 21:23-dr_egeria_intro_part1.md +0 -265
  315. md_processing/dr_egeria_outbox/friday/processed-2025-08-23 15:06-dr_egeria_intro_part1.md +0 -230
  316. md_processing/dr_egeria_outbox/friday/processed-2025-08-23 15:30-dr_egeria_intro_part1.md +0 -296
  317. md_processing/dr_egeria_outbox/friday/processed-2025-08-23 15:31-dr_egeria_intro_part1.md +0 -253
  318. md_processing/dr_egeria_outbox/friday/processed-2025-08-23 16:08-dr_egeria_intro_part2.md +0 -343
  319. md_processing/dr_egeria_outbox/friday/processed-2025-08-23 16:12-dr_egeria_intro_part2.md +0 -343
  320. md_processing/dr_egeria_outbox/monday/processed-2025-08-19 07:05-product.md +0 -426
  321. md_processing/dr_egeria_outbox/monday/processed-2025-08-19 07:56-product.md +0 -212
  322. md_processing/dr_egeria_outbox/monday/processed-2025-08-19 09:43-product.md +0 -201
  323. md_processing/dr_egeria_outbox/sunday/processed-2025-07-20 14:55-product.md +0 -77
  324. md_processing/dr_egeria_outbox/sunday/processed-2025-07-20 15:05-product.md +0 -75
  325. md_processing/dr_egeria_outbox/sunday/processed-2025-07-20 15:11-product.md +0 -74
  326. md_processing/dr_egeria_outbox/sunday/processed-2025-07-20 20:40-collections.md +0 -49
  327. md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 15:00-Derive-Dr-Gov-Defs.md +0 -719
  328. md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 20:13-Derive-Dr-Gov-Defs.md +0 -41
  329. md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 20:14-Derive-Dr-Gov-Defs.md +0 -33
  330. md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 20:50-Derive-Dr-Gov-Defs.md +0 -192
  331. md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 22:08-gov_def2.md +0 -486
  332. md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 22:10-gov_def2.md +0 -486
  333. md_processing/dr_egeria_outbox/thursday/processed-2025-07-18 08:53-gov_def2.md +0 -486
  334. md_processing/dr_egeria_outbox/thursday/processed-2025-07-18 08:54-gov_def2.md +0 -486
  335. md_processing/dr_egeria_outbox/thursday/processed-2025-07-18 09:03-gov_def2.md +0 -486
  336. md_processing/dr_egeria_outbox/thursday/processed-2025-07-18 09:06-gov_def2.md +0 -486
  337. md_processing/dr_egeria_outbox/thursday/processed-2025-07-18 09:10-gov_def2.md +0 -486
  338. md_processing/dr_egeria_outbox/tuesday/processed-2025-07-16 19:15-gov_def2.md +0 -527
  339. md_processing/dr_egeria_outbox/tuesday/processed-2025-07-17 12:08-gov_def2.md +0 -527
  340. md_processing/dr_egeria_outbox/tuesday/processed-2025-07-17 14:27-gov_def2.md +0 -485
  341. md_processing/dr_egeria_outbox/tuesday/processed-2025-08-19 10:55-product.md +0 -209
  342. md_processing/family_docs/Data Designer/Create_Data_Class.md +0 -164
  343. md_processing/family_docs/Data Designer/Create_Data_Dictionary.md +0 -30
  344. md_processing/family_docs/Data Designer/Create_Data_Field.md +0 -162
  345. md_processing/family_docs/Data Designer/Create_Data_Specification.md +0 -36
  346. md_processing/family_docs/Data Designer/Create_Data_Structure.md +0 -38
  347. md_processing/family_docs/Data Designer/View_Data_Classes.md +0 -78
  348. md_processing/family_docs/Data Designer/View_Data_Dictionaries.md +0 -78
  349. md_processing/family_docs/Data Designer/View_Data_Fields.md +0 -78
  350. md_processing/family_docs/Data Designer/View_Data_Specifications.md +0 -78
  351. md_processing/family_docs/Data Designer/View_Data_Structures.md +0 -78
  352. md_processing/family_docs/Data Designer.md +0 -842
  353. md_processing/family_docs/Digital Product Manager/Add_Member->Collection.md +0 -42
  354. md_processing/family_docs/Digital Product Manager/Attach_Collection->Resource.md +0 -36
  355. md_processing/family_docs/Digital Product Manager/Create_Agreement.md +0 -96
  356. md_processing/family_docs/Digital Product Manager/Create_Data_Sharing_Agreement.md +0 -72
  357. md_processing/family_docs/Digital Product Manager/Create_DigitalSubscription.md +0 -102
  358. md_processing/family_docs/Digital Product Manager/Create_Digital_Product.md +0 -134
  359. md_processing/family_docs/Digital Product Manager/Link_Agreement_Items.md +0 -60
  360. md_processing/family_docs/Digital Product Manager/Link_Contracts.md +0 -26
  361. md_processing/family_docs/Digital Product Manager/Link_Digital_Product_-_Digital_Product.md +0 -30
  362. md_processing/family_docs/Digital Product Manager/Link_Subscribers.md +0 -48
  363. md_processing/family_docs/Digital Product Manager.md +0 -668
  364. md_processing/family_docs/Glossary/Attach_Category_Parent.md +0 -18
  365. md_processing/family_docs/Glossary/Attach_Term-Term_Relationship.md +0 -26
  366. md_processing/family_docs/Glossary/Create_Category.md +0 -38
  367. md_processing/family_docs/Glossary/Create_Glossary.md +0 -42
  368. md_processing/family_docs/Glossary/Create_Term.md +0 -70
  369. md_processing/family_docs/Glossary.md +0 -206
  370. md_processing/family_docs/Governance Officer/Create_Business_Imperative.md +0 -106
  371. md_processing/family_docs/Governance Officer/Create_Certification_Type.md +0 -112
  372. md_processing/family_docs/Governance Officer/Create_Governance_Approach.md +0 -114
  373. md_processing/family_docs/Governance Officer/Create_Governance_Obligation.md +0 -114
  374. md_processing/family_docs/Governance Officer/Create_Governance_Principle.md +0 -114
  375. md_processing/family_docs/Governance Officer/Create_Governance_Procedure.md +0 -128
  376. md_processing/family_docs/Governance Officer/Create_Governance_Process.md +0 -122
  377. md_processing/family_docs/Governance Officer/Create_Governance_Processing_Purpose.md +0 -106
  378. md_processing/family_docs/Governance Officer/Create_Governance_Responsibility.md +0 -122
  379. md_processing/family_docs/Governance Officer/Create_Governance_Rule.md +0 -122
  380. md_processing/family_docs/Governance Officer/Create_Governance_Strategy.md +0 -106
  381. md_processing/family_docs/Governance Officer/Create_License_Type.md +0 -112
  382. md_processing/family_docs/Governance Officer/Create_Naming_Standard_Rule.md +0 -122
  383. md_processing/family_docs/Governance Officer/Create_Regulation_Article.md +0 -106
  384. md_processing/family_docs/Governance Officer/Create_Regulation_Definition.md +0 -118
  385. md_processing/family_docs/Governance Officer/Create_Security_Access_Control.md +0 -114
  386. md_processing/family_docs/Governance Officer/Create_Security_Group.md +0 -120
  387. md_processing/family_docs/Governance Officer/Create_Service_Level_Objectives.md +0 -122
  388. md_processing/family_docs/Governance Officer/Create_Threat_Definition.md +0 -106
  389. md_processing/family_docs/Governance Officer/Link_Governance_Controls.md +0 -32
  390. md_processing/family_docs/Governance Officer/Link_Governance_Drivers.md +0 -32
  391. md_processing/family_docs/Governance Officer/Link_Governance_Policies.md +0 -32
  392. md_processing/family_docs/Governance Officer/View_Governance_Definitions.md +0 -82
  393. md_processing/family_docs/Governance Officer.md +0 -2412
  394. md_processing/family_docs/Solution Architect/Create_Information_Supply_Chain.md +0 -70
  395. md_processing/family_docs/Solution Architect/Create_Solution_Blueprint.md +0 -44
  396. md_processing/family_docs/Solution Architect/Create_Solution_Component.md +0 -96
  397. md_processing/family_docs/Solution Architect/Create_Solution_Role.md +0 -66
  398. md_processing/family_docs/Solution Architect/Link_Information_Supply_Chain_Peers.md +0 -32
  399. md_processing/family_docs/Solution Architect/Link_Solution_Component_Peers.md +0 -32
  400. md_processing/family_docs/Solution Architect/View_Information_Supply_Chains.md +0 -32
  401. md_processing/family_docs/Solution Architect/View_Solution_Blueprints.md +0 -32
  402. md_processing/family_docs/Solution Architect/View_Solution_Components.md +0 -32
  403. md_processing/family_docs/Solution Architect/View_Solution_Roles.md +0 -32
  404. md_processing/family_docs/Solution Architect.md +0 -490
  405. md_processing/md_processing_utils/debug_log +0 -574
  406. md_processing/md_processing_utils/debug_log.log +0 -0
  407. md_processing/md_processing_utils/dr-egeria-help-2025-07-17T17:22:09.md +0 -2065
  408. md_processing/md_processing_utils/generated_help_terms.md +0 -842
  409. pyegeria/.DS_Store +0 -0
  410. pyegeria/README.md +0 -35
  411. pyegeria/_client_new.py +0 -1102
  412. pyegeria/_output_formats.py +0 -730
  413. pyegeria/asset_catalog_omvs.py +0 -864
  414. pyegeria/automated_curation_omvs.py +0 -3765
  415. pyegeria/config.py +0 -523
  416. pyegeria/egeria_my_client.py +0 -91
  417. pyegeria/feedback_manager_omvs.py +0 -4573
  418. pyegeria/load_config_orig.py +0 -218
  419. pyegeria/md_processing_helpers.py +0 -58
  420. pyegeria/md_processing_utils_orig.py +0 -1103
  421. pyegeria/metadata_explorer_omvs.py +0 -2326
  422. pyegeria/my_profile_omvs.py +0 -1022
  423. pyegeria/project_manager.py +0 -1591
  424. pyegeria/registered_info.py +0 -167
  425. pyegeria/template_manager_omvs.py +0 -1414
  426. pyegeria/utils.py +0 -256
  427. pyegeria-5.4.0.28.dist-info/METADATA +0 -77
  428. pyegeria-5.4.0.28.dist-info/RECORD +0 -343
  429. pyegeria-5.4.0.28.dist-info/entry_points.txt +0 -105
  430. /commands/cat/debug_log.log → /pyegeria/deprecated/__init__.py +0 -0
  431. /pyegeria/{_exceptions.py → deprecated/_exceptions.py} +0 -0
  432. /pyegeria/{collection_models.py → models/collection_models.py} +0 -0
  433. {pyegeria-5.4.0.28.dist-info → pyegeria-5.5.3.3.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,643 @@
1
+ """
2
+ Generate report FormatSet specifications for pyegeria from a commands.json file.
3
+
4
+ Overview
5
+ - This utility reads a Dr Egeria style commands.json (aka Command Specifications)
6
+ and converts relevant entries (by default, only those with a display name
7
+ beginning with "Create") into pyegeria FormatSet definitions. These can be:
8
+ - returned in-memory as a FormatSetDict
9
+ - saved to a JSON file that can be loaded by pyegeria.base_report_formats.load_report_specs
10
+ - saved as a Python module that defines a dictionary of FormatSet objects
11
+ - merged directly into the built-in report_specs registry at runtime
12
+
13
+ Typical uses
14
+ - Quickly scaffold report formats for new content types defined in your command
15
+ specifications, without hand-writing every Column/Format block.
16
+ - Keep generated formats alongside your hand-curated ones and iterate as the
17
+ command specifications evolve.
18
+
19
+ What this script extracts
20
+ - Target type: from each command's display_name
21
+ - Columns: only attributes marked with level == "Basic" are included. The
22
+ column name comes from the attribute label; the column key from the
23
+ attribute's variable_name.
24
+ - Action parameter: if a find_method is present on the command, an ActionParameter
25
+ is created with:
26
+ - function = find_method
27
+ - required_params = ["search_string"]
28
+ - optional_params = pyegeria.base_report_formats.OPTIONAL_PARAMS
29
+ - spec_params = parsed find_constraints (see parsing notes below)
30
+
31
+ Constraints parsing
32
+ - find_constraints may be a dict or a JSON string (sometimes double-escaped).
33
+ We try, in order: direct JSON, unquoted JSON, and a simple single-to-double
34
+ quote substitution for dict-like strings. Failures yield an empty dict, and
35
+ a debug message is logged.
36
+
37
+ Naming
38
+ - Each FormatSet key and heading are derived from the command's display_name.
39
+ The key is display_name with spaces replaced by '-' and suffixed with '-DrE'.
40
+ Example: "Create Governance Strategy Definition" -> "Create-Governance-Strategy-Definition-DrE".
41
+
42
+ CLI usage examples
43
+ - Save to JSON (default mode):
44
+ poetry run python -m md_processing.md_processing_utils.gen_report_specs \
45
+ md_processing/data/commands.json md_processing/data/generated_format_sets.json --emit json
46
+
47
+ - Emit Python code to a .py file:
48
+ poetry run python -m md_processing.md_processing_utils.gen_report_specs \
49
+ md_processing/data/commands.json md_processing/data/generated_report_specs.py --emit code
50
+
51
+ - Build in-memory only and list set names:
52
+ poetry run python -m md_processing.md_processing_utils.gen_report_specs \
53
+ md_processing/data/commands.json --emit dict --list
54
+
55
+ - Merge generated sets into the built-in registry (report_specs):
56
+ poetry run python -m md_processing.md_processing_utils.gen_report_specs \
57
+ md_processing/data/commands.json --emit dict --merge --list
58
+
59
+ Programmatic usage
60
+ - Build in memory:
61
+ from md_processing.md_processing_utils.gen_report_specs import generate_format_sets
62
+ sets = generate_format_sets("md_processing/data/commands.json")
63
+
64
+ - Save JSON that can be loaded by pyegeria:
65
+ from md_processing.md_processing_utils.gen_report_specs import save_generated_format_sets
66
+ save_generated_format_sets("md_processing/data/commands.json", "md_processing/data/generated_format_sets.json")
67
+
68
+ - Save as importable Python module:
69
+ from md_processing.md_processing_utils.gen_report_specs import save_generated_format_sets_code
70
+ save_generated_format_sets_code("md_processing/data/commands.json", "md_processing/data/generated_report_specs.py")
71
+
72
+ - Merge directly into built-ins at runtime:
73
+ from md_processing.md_processing_utils.gen_report_specs import merge_generated_report_specs
74
+ merge_generated_format_sets("md_processing/data/commands.json")
75
+
76
+ Notes
77
+ - Only commands whose key or display_name begins with "Create" are included by
78
+ default. Pass include_only_create=False to include all commands.
79
+ - default_types controls the Format.types field, and defaults to ["ALL"].
80
+ - This script logs progress with loguru.
81
+ """
82
+ import json
83
+ import re
84
+ import argparse
85
+ from pathlib import Path
86
+ from typing import Iterable, List, Optional
87
+
88
+ from loguru import logger
89
+ from rich.prompt import Prompt
90
+
91
+ from pyegeria.view._output_format_models import Column, Format, ActionParameter, FormatSet, FormatSetDict
92
+ from pyegeria.view.base_report_formats import OPTIONAL_PARAMS # ["page_size","start_from","starts_with","ends_with","ignore_case"]
93
+
94
+ def _is_create_command(cmd_key: str, cmd_obj: dict) -> bool:
95
+ """Return True if a command should be treated as a "Create" command.
96
+
97
+ A command qualifies if either its dictionary key or its "display_name"
98
+ begins with the word "Create" (case-insensitive). This mirrors how the
99
+ CLI specs tend to name creation operations and is used to filter which
100
+ commands are transformed into report FormatSets by default.
101
+ """
102
+ name = str(cmd_obj.get("display_name", "")).strip()
103
+ return (isinstance(cmd_key, str) and cmd_key.strip().lower().startswith("create")) or \
104
+ (name.lower().startswith("create"))
105
+
106
+ def _derive_set_name_from_display_name(display_name: str) -> str:
107
+ """Derive a compact set name from a command display name.
108
+
109
+ Example: 'Create Governance Strategy Definition' -> 'GovernanceStrategyDefinition-DrE'
110
+ Currently not used in favor of a dash-separated variant, but kept for
111
+ reference and potential future toggles.
112
+ """
113
+ if not display_name:
114
+ return ""
115
+ parts = display_name.strip().split()
116
+ if len(parts) <= 1:
117
+ return re.sub(r"\s+", "", display_name.strip())+"-DrE"
118
+ rest = " ".join(parts[1:]).strip()
119
+ rest = rest+"-DrE"
120
+ return re.sub(r"\s+", "", rest)
121
+
122
+ def _safe_parse_constraints(s) -> dict:
123
+ """Parse a command's `find_constraints` field into a Python dict.
124
+
125
+ Accepts:
126
+ - A dict (returned as-is)
127
+ - A JSON string (possibly surrounded by quotes or single-quoted)
128
+ - A loosely dict-like string using single quotes
129
+
130
+ Returns an empty dict on failure and logs at debug level.
131
+ """
132
+ if not s:
133
+ return {}
134
+ if isinstance(s, dict):
135
+ return s
136
+ txt = str(s).strip()
137
+ # Attempt 1: direct JSON
138
+ try:
139
+ return json.loads(txt)
140
+ except Exception:
141
+ logger.error(f"Error parsing constraints: {s!r}")
142
+ pass
143
+ # Attempt 2: unwrap quotes
144
+ try:
145
+ txt2 = txt.strip('"').strip("'")
146
+ return json.loads(txt2)
147
+ except Exception:
148
+ pass
149
+ # Attempt 3: heuristic single->double quotes for dict-like strings
150
+ if ("{" in txt and "}" in txt) and ("'" in txt and '"' not in txt):
151
+ try:
152
+ return json.loads(txt.replace("'", '"'))
153
+ except Exception:
154
+ pass
155
+ logger.debug(f"Could not parse find_constraints: {s!r} -> {{}}")
156
+ return {}
157
+
158
+ def _extract_basic_columns_from_attributes(attributes: Iterable[dict]) -> List[Column]:
159
+ """Extract Basic-level Columns from a command's Attributes list.
160
+
161
+ Parameters
162
+ - attributes: iterable of dict entries. Each entry is typically a single-key
163
+ mapping of attribute label -> metadata dict with fields like
164
+ {"variable_name": ..., "level": "Basic"|"Advanced"|...}.
165
+
166
+ Behavior
167
+ - Only items with level == "Basic" are included
168
+ - Duplicate variable_name values are de-duplicated
169
+ - Column.name is the label; Column.key is the variable_name
170
+
171
+ Returns
172
+ - List[Column]
173
+ """
174
+
175
+ cols: List[Column] = []
176
+ seen: set[str] = set()
177
+ for entry in attributes or []:
178
+ if not isinstance(entry, dict) or not entry:
179
+ continue
180
+ # Some entries may contain more than one key; scan all items
181
+ for label, details in entry.items():
182
+ if not isinstance(details, dict):
183
+ continue
184
+ if details.get("level") != "Basic":
185
+ continue
186
+ key = details.get("variable_name")
187
+ if not key or key in seen:
188
+ continue
189
+ seen.add(key)
190
+ cols.append(Column(name=str(label), key=str(key)))
191
+ return cols
192
+
193
+ def build_format_sets_from_commands(
194
+ commands_json_path: str | Path,
195
+ *,
196
+ include_only_create: bool = True,
197
+ default_types: Optional[List[str]] = None
198
+ ) -> FormatSetDict:
199
+ """Build a FormatSetDict from a commands.json file.
200
+
201
+ Parameters
202
+ - commands_json_path: path to the Dr Egeria style commands.json file. The
203
+ file may be an object with a "Command Specifications" map, or a list of
204
+ command objects.
205
+ - include_only_create: when True (default), include only commands whose key
206
+ or display_name starts with "Create".
207
+ - default_types: the list used for Format.types for each produced Format
208
+ (defaults to ["ALL"]).
209
+
210
+ Returns
211
+ - FormatSetDict keyed by set names derived from display_name + "-DrE".
212
+
213
+ Notes
214
+ - Columns are derived from Attributes entries whose level == "Basic".
215
+ - If find_method is present, an ActionParameter is created.
216
+ """
217
+ path = Path(commands_json_path)
218
+ data = json.loads(path.read_text(encoding="utf-8"))
219
+
220
+ if isinstance(data, dict):
221
+ items_iter = data.items()
222
+ elif isinstance(data, list):
223
+ # If it’s a list of command objects, synthesize keys from display_name or index
224
+ def _key_for(idx, obj):
225
+ dn = str(obj.get("display_name", "")).strip()
226
+ return dn or f"cmd_{idx}"
227
+
228
+ items_iter = ((_key_for(i, obj), obj) for i, obj in enumerate(data))
229
+ else:
230
+ raise ValueError("commands.json root must be an object/dict or an array of command objects")
231
+ data = dict(items_iter).get("Command Specifications", {})
232
+ logger.info(
233
+ f"Loaded commands.json from {path} with {len(data)} commands"
234
+ )
235
+
236
+
237
+ results = FormatSetDict()
238
+ types = default_types or ["ALL"]
239
+
240
+ for cmd_key, cmd_obj in data.items():
241
+ if not isinstance(cmd_obj, dict):
242
+ continue
243
+ if include_only_create and not _is_create_command(cmd_key, cmd_obj):
244
+ continue
245
+
246
+ display_name = str(cmd_obj.get("display_name", "")).strip()
247
+ if not display_name:
248
+ logger.debug(f"Skip {cmd_key!r}: missing display_name")
249
+ continue
250
+ set_name = re.sub(r"\s+", "-", display_name)
251
+ set_name = set_name.strip() + "-DrE"
252
+ # set_name = _derive_set_name_from_display_name(display_name)
253
+ if not set_name:
254
+ logger.debug(f"Skip {cmd_key!r}: could not derive set name from display_name={display_name!r}")
255
+ continue
256
+
257
+ columns = _extract_basic_columns_from_attributes(cmd_obj.get("Attributes", []))
258
+ if not columns:
259
+ logger.debug(f"Skip {set_name}: no Basic attributes")
260
+ continue
261
+
262
+ find_method = cmd_obj.get("find_method") or ""
263
+ constraints = _safe_parse_constraints(cmd_obj.get("find_constraints"))
264
+ action = None
265
+ if find_method:
266
+ action = ActionParameter(
267
+ function=find_method,
268
+ required_params=["search_string"],
269
+ optional_params=OPTIONAL_PARAMS,
270
+ spec_params=constraints or {},
271
+ )
272
+
273
+ fs = FormatSet(
274
+ target_type=display_name,
275
+ heading=f"{set_name} Attributes",
276
+ description=f"Auto-generated format for {display_name} (Create).",
277
+ family=cmd_obj.get("family"),
278
+ formats=[Format(types=types, columns=columns)],
279
+ action=action
280
+ )
281
+ results[set_name] = fs
282
+
283
+ return results
284
+
285
+ def save_generated_format_sets(
286
+ commands_json_path: str | Path,
287
+ out_file: str | Path,
288
+ *,
289
+ include_only_create: bool = True,
290
+ default_types: Optional[List[str]] = None
291
+ ) -> Path:
292
+ """Build FormatSets from commands.json and save them as JSON.
293
+
294
+ The resulting JSON can be loaded via `pyegeria.base_report_formats.load_report_specs`.
295
+
296
+ Parameters
297
+ - commands_json_path: input commands.json path
298
+ - out_file: where to write the generated JSON
299
+ - include_only_create: filter to only "Create" commands (default True)
300
+ - default_types: list for Format.types (default ["ALL"]).
301
+
302
+ Returns
303
+ - Path to the written JSON file
304
+ """
305
+ sets = build_format_sets_from_commands(
306
+ commands_json_path,
307
+ include_only_create=include_only_create,
308
+ default_types=default_types,
309
+ )
310
+ out = Path(out_file)
311
+ out.parent.mkdir(parents=True, exist_ok=True)
312
+ sets.save_to_json(str(out))
313
+ logger.info(f"Saved {len(sets)} generated format sets to {out}")
314
+ return out
315
+
316
+ # New: expose a simple alias that returns a FormatSetDict directly
317
+ # for callers that want the in-memory object rather than JSON.
318
+ def generate_format_sets(
319
+ commands_json_path: str | Path,
320
+ *,
321
+ include_only_create: bool = True,
322
+ default_types: Optional[List[str]] = None,
323
+ ):
324
+ """Return a FormatSetDict built from commands.json (no file I/O).
325
+
326
+ This is a convenience wrapper around `build_format_sets_from_commands` for
327
+ programmatic use when you don't want to touch the filesystem.
328
+ """
329
+ return build_format_sets_from_commands(
330
+ commands_json_path,
331
+ include_only_create=include_only_create,
332
+ default_types=default_types,
333
+ )
334
+
335
+ # New: merge generated sets into the builtin registry
336
+
337
+ def merge_generated_format_sets(
338
+ commands_json_path: str | Path,
339
+ *,
340
+ include_only_create: bool = True,
341
+ default_types: Optional[List[str]] = None,
342
+ ) -> int:
343
+ """Build and merge generated FormatSets into the built-in registry.
344
+
345
+ Parameters
346
+ - commands_json_path: input commands.json path
347
+ - include_only_create: filter to only "Create" commands (default True)
348
+ - default_types: list for Format.types (default ["ALL"]).
349
+
350
+ Returns
351
+ - int: number of sets merged/added into `pyegeria.base_report_formats.report_specs`.
352
+ """
353
+ from pyegeria.view.base_report_formats import report_specs # local import to avoid cycles on tooling
354
+
355
+ gen = build_format_sets_from_commands(
356
+ commands_json_path,
357
+ include_only_create=include_only_create,
358
+ default_types=default_types,
359
+ )
360
+ count = 0
361
+ for name, fs in gen.items():
362
+ report_specs[name] = fs
363
+ count += 1
364
+ logger.info(f"Merged {count} generated format sets into built-ins")
365
+ return count
366
+
367
+
368
+ def _py_literal(value):
369
+ """Render a value as a valid Python literal string.
370
+
371
+ Supports strings, numbers, bools, None, lists, tuples, dicts. Used when
372
+ emitting Python code for generated FormatSets.
373
+ """
374
+ if isinstance(value, str):
375
+ return repr(value)
376
+ if isinstance(value, (int, float)):
377
+ return str(value)
378
+ if value is True:
379
+ return "True"
380
+ if value is False:
381
+ return "False"
382
+ if value is None:
383
+ return "None"
384
+ if isinstance(value, list):
385
+ return "[" + ", ".join(_py_literal(v) for v in value) + "]"
386
+ if isinstance(value, dict):
387
+ # Render dict with stable key ordering
388
+ items = ", ".join(f"{_py_literal(k)}: {_py_literal(v)}" for k, v in sorted(value.items(), key=lambda kv: str(kv[0]).lower()))
389
+ return "{" + items + "}"
390
+ # Fallback
391
+ return repr(value)
392
+
393
+
394
+ def _format_column(col: Column) -> str:
395
+ """Render a Column instance as Python code.
396
+
397
+ Returns a string like: Column(name='Display Name', key='display_name', ...)
398
+ Only includes optional attributes when present.
399
+ """
400
+ parts = [f"name={_py_literal(getattr(col, 'name', ''))}", f"key={_py_literal(getattr(col, 'key', ''))}"]
401
+ fmt = getattr(col, 'format', None)
402
+ if fmt not in (None, False):
403
+ parts.append(f"format={_py_literal(bool(fmt))}")
404
+ return "Column(" + ", ".join(parts) + ")"
405
+
406
+
407
+ def _format_action(ap: ActionParameter | None) -> str:
408
+ """Render an ActionParameter as Python code for emission.
409
+
410
+ Includes function, required_params, optional_params, and spec_params when present.
411
+ """
412
+ if not ap:
413
+ return "None"
414
+ parts = [
415
+ f"function={_py_literal(getattr(ap, 'function', ''))}",
416
+ ]
417
+ req = getattr(ap, 'required_params', None)
418
+ if req:
419
+ parts.append(f"required_params={_py_literal(list(req))}")
420
+ opt = getattr(ap, 'optional_params', None)
421
+ if opt:
422
+ parts.append(f"optional_params={_py_literal(list(opt))}")
423
+ spec = getattr(ap, 'spec_params', None)
424
+ if spec:
425
+ parts.append(f"spec_params={_py_literal(dict(spec))}")
426
+ return "ActionParameter(" + ", ".join(parts) + ")"
427
+
428
+
429
+ def _format_format(fmt: Format) -> str:
430
+ """Render a Format instance as Python code, including types and columns."""
431
+ cols = getattr(fmt, 'columns', []) or []
432
+ types = getattr(fmt, 'types', []) or []
433
+ col_code = ", ".join(_format_column(c) for c in cols)
434
+ parts = [f"types={_py_literal(list(types))}", f"columns=[{col_code}]"]
435
+ return "Format(" + ", ".join(parts) + ")"
436
+
437
+
438
+ def _format_formatset(fs: FormatSet) -> str:
439
+ """Render a FormatSet as Python code including nested formats and actions."""
440
+ parts = []
441
+ if getattr(fs, 'target_type', None):
442
+ parts.append(f"target_type={_py_literal(fs.target_type)}")
443
+ if getattr(fs, 'heading', None):
444
+ parts.append(f"heading={_py_literal(fs.heading)}")
445
+ if getattr(fs, 'description', None):
446
+ parts.append(f"description={_py_literal(fs.description)}")
447
+ if getattr(fs, 'family', None):
448
+ parts.append(f"family={_py_literal(fs.family)}")
449
+ aliases = getattr(fs, 'aliases', None)
450
+ if aliases:
451
+ parts.append(f"aliases={_py_literal(list(aliases))}")
452
+ ann = getattr(fs, 'annotations', None)
453
+ if ann:
454
+ parts.append(f"annotations={_py_literal(dict(ann))}")
455
+ # formats
456
+ fmts = getattr(fs, 'formats', []) or []
457
+ fmt_code = ", ".join(_format_format(f) for f in fmts)
458
+ parts.append(f"formats=[{fmt_code}]")
459
+ # actions
460
+ action = getattr(fs, 'action', None)
461
+ if action:
462
+ parts.append(f"action={_format_action(action)}")
463
+ get_add = getattr(fs, 'get_additional_props', None)
464
+ if get_add:
465
+ parts.append(f"get_additional_props={_format_action(get_add)}")
466
+ return "FormatSet(" + ", ".join(parts) + ")"
467
+
468
+
469
+ def format_sets_to_python_code(sets: FormatSetDict, var_name: str = "generated_format_sets") -> str:
470
+ """Render a FormatSetDict into the text of a small Python module.
471
+
472
+ Parameters
473
+ - sets: the FormatSetDict to render
474
+ - var_name: the variable name to assign the dict to (default 'generated_format_sets')
475
+
476
+ Returns
477
+ - str: Python source code that, when imported, defines `var_name` as a FormatSetDict
478
+ """
479
+ header = (
480
+ "# Auto-generated by gen_report_specs.py\n"
481
+ "from pyegeria._output_format_models import Column, Format, ActionParameter, FormatSet, FormatSetDict\n\n"
482
+ )
483
+ # Stable ordering by key
484
+ entries = []
485
+ for name in sorted(sets.keys(), key=lambda s: s.lower()):
486
+ fs = sets[name]
487
+ entries.append(f" {_py_literal(name)}: {_format_formatset(fs)}")
488
+ body = f"{var_name} = FormatSetDict({{\n" + ",\n".join(entries) + "\n})\n"
489
+ return header + body
490
+
491
+
492
+ def save_generated_format_sets_code(
493
+ commands_json_path: str | Path,
494
+ out_file: str | Path,
495
+ *,
496
+ include_only_create: bool = True,
497
+ default_types: Optional[List[str]] = None,
498
+ var_name: str = "generated_format_sets",
499
+ ) -> Path:
500
+ """Build FormatSets and save them as an importable Python module.
501
+
502
+ Parameters
503
+ - commands_json_path: input commands.json path
504
+ - out_file: path to write the .py file (module will define `var_name`)
505
+ - include_only_create: filter to only "Create" commands (default True)
506
+ - default_types: list for Format.types (default ["ALL"]).
507
+ - var_name: variable name to bind the resulting FormatSetDict to
508
+
509
+ Returns
510
+ - Path to the written Python file
511
+
512
+ Notes
513
+ - You can import the resulting file dynamically and access the variable
514
+ to merge into `pyegeria.base_report_formats.report_specs`.
515
+ """
516
+ sets = build_format_sets_from_commands(
517
+ commands_json_path,
518
+ include_only_create=include_only_create,
519
+ default_types=default_types,
520
+ )
521
+ code = format_sets_to_python_code(sets, var_name=var_name)
522
+ out = Path(out_file)
523
+ out.parent.mkdir(parents=True, exist_ok=True)
524
+ out.write_text(code, encoding="utf-8")
525
+ logger.info(f"Saved Python code for {len(sets)} generated format sets to {out}")
526
+ return out
527
+
528
+
529
+ def main():
530
+ """CLI entry point for generating report FormatSets from commands.json.
531
+
532
+ Notes
533
+ - If a command object includes a string field `family`, it will be propagated into the generated
534
+ `FormatSet.family`. This applies to both JSON emission and generated Python code.
535
+
536
+ Synopsis
537
+ - Default (emit JSON):
538
+ python -m md_processing.md_processing_utils.gen_report_specs \
539
+ md_processing/data/commands.json md_processing/data/generated_format_sets.json --emit json
540
+ - Emit Python code:
541
+ python -m md_processing.md_processing_utils.gen_report_specs \
542
+ md_processing/data/commands.json md_processing/data/generated_format_sets.py --emit code
543
+ - In-memory only and list:
544
+ python -m md_processing.md_processing_utils.gen_report_specs \
545
+ md_processing/data/commands.json --emit dict --list
546
+
547
+ Flags
548
+ - --emit json|dict|code: controls output mode (default json)
549
+ - --merge: also merge generated sets into built-in report_specs at runtime
550
+ - --list: when emitting dict (or after merge), list set names to stdout
551
+ """
552
+ parser = argparse.ArgumentParser(description="Generate FormatSets from commands.json")
553
+ parser.add_argument("commands_json", nargs="?", help="Path to commands.json")
554
+ parser.add_argument("output_json", nargs="?", help="Path to output JSON file (when --emit json)")
555
+ parser.add_argument("--emit", choices=["json", "dict", "code"], default="json",
556
+ help="Choose output mode: save JSON file, write Python code, or work with in-memory FormatSetDict")
557
+ parser.add_argument("--merge", action="store_true",
558
+ help="Merge generated sets into built-in registry (report_specs)")
559
+ parser.add_argument("--list", action="store_true",
560
+ help="When emitting dict (and/or after merge), list set names to stdout")
561
+ args = parser.parse_args()
562
+
563
+ try:
564
+ input_file = args.commands_json or Prompt.ask(
565
+ "Enter commands.json:", default="md_processing/data/commands.json"
566
+ )
567
+
568
+ if args.emit == "json":
569
+ # JSON output path
570
+ output_file = args.output_json or Prompt.ask(
571
+ "Output File:", default="md_processing/data/generated_format_sets.json"
572
+ )
573
+ save_generated_format_sets(input_file, output_file)
574
+ if args.merge:
575
+ # Also load and merge saved JSON into registry for convenience
576
+ from pyegeria.view.base_report_formats import load_report_specs
577
+ load_report_specs(output_file, merge=True)
578
+ logger.info("Merged saved JSON into built-in registry")
579
+ elif args.emit == "code":
580
+ # Python code output path
581
+ output_file = args.output_json or Prompt.ask(
582
+ "Output Python File:", default="pyegeria/dr_egeria_reports.py" # Changed from config/
583
+ )
584
+ saved_path = save_generated_format_sets_code(input_file, output_file)
585
+ logger.info(f"Generated Python code written to {saved_path}")
586
+
587
+ if args.merge:
588
+ # Dynamically import and merge the generated variable
589
+ try:
590
+ import importlib.util
591
+ import sys as _sys
592
+
593
+ # Convert to absolute path to ensure spec_from_file_location can find it
594
+ abs_output_file = saved_path.resolve()
595
+
596
+ spec = importlib.util.spec_from_file_location("_gen_fs_module", abs_output_file)
597
+ if spec is None or spec.loader is None:
598
+ raise ImportError(f"Could not create module spec from {abs_output_file}")
599
+
600
+ mod = importlib.util.module_from_spec(spec)
601
+ spec.loader.exec_module(mod) # type: ignore
602
+
603
+ generated = getattr(mod, "generated_format_sets", None)
604
+ if generated:
605
+ from pyegeria.view.base_report_formats import report_specs
606
+ merged = 0
607
+ for name, fs in generated.items():
608
+ report_specs[name] = fs
609
+ merged += 1
610
+ logger.info(f"Merged {merged} generated format sets from code into built-ins")
611
+ else:
612
+ logger.warning("No 'generated_format_sets' found in generated code module")
613
+ except Exception as e:
614
+ logger.error(f"Failed to import and merge generated code: {e}")
615
+ else:
616
+ # Emit dict path: build in memory
617
+ sets = generate_format_sets(input_file)
618
+ logger.info(f"Generated {len(sets)} format sets (in-memory FormatSetDict)")
619
+ if args.merge:
620
+ from pyegeria.view.base_report_formats import report_specs
621
+ merged = 0
622
+ for name, fs in sets.items():
623
+ report_specs[name] = fs
624
+ merged += 1
625
+ logger.info(f"Merged {merged} generated format sets into built-ins")
626
+ if args.list:
627
+ # If merged, show names from the global registry that match the generated ones
628
+ names = sorted(list(sets.keys()))
629
+ print("Merged set names:")
630
+ for n in names:
631
+ print(f"- {n}")
632
+ else:
633
+ if args.list:
634
+ names = sorted(list(sets.keys()))
635
+ print(f"Generated set names ({len(names)}):")
636
+ for n in names:
637
+ print(f"- {n}")
638
+ except (KeyboardInterrupt, EOFError):
639
+ # Graceful exit when user cancels or stdin is not interactive
640
+ pass
641
+
642
+ if __name__ == "__main__":
643
+ main()