cognite-neat 0.103.1__py3-none-any.whl → 0.105.0__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 cognite-neat might be problematic. Click here for more details.

Files changed (175) hide show
  1. cognite/neat/_client/_api/data_modeling_loaders.py +83 -23
  2. cognite/neat/_client/_api/schema.py +2 -1
  3. cognite/neat/_client/data_classes/neat_sequence.py +261 -0
  4. cognite/neat/_client/data_classes/schema.py +5 -1
  5. cognite/neat/_client/testing.py +33 -0
  6. cognite/neat/_constants.py +56 -0
  7. cognite/neat/_graph/extractors/_classic_cdf/_base.py +6 -5
  8. cognite/neat/_graph/extractors/_classic_cdf/_sequences.py +225 -11
  9. cognite/neat/_graph/extractors/_mock_graph_generator.py +2 -2
  10. cognite/neat/_graph/loaders/_rdf2dms.py +13 -2
  11. cognite/neat/_graph/transformers/__init__.py +3 -1
  12. cognite/neat/_graph/transformers/_base.py +109 -1
  13. cognite/neat/_graph/transformers/_classic_cdf.py +6 -1
  14. cognite/neat/_graph/transformers/_prune_graph.py +103 -47
  15. cognite/neat/_graph/transformers/_rdfpath.py +41 -17
  16. cognite/neat/_graph/transformers/_value_type.py +188 -151
  17. cognite/neat/_issues/__init__.py +0 -2
  18. cognite/neat/_issues/_base.py +54 -43
  19. cognite/neat/_issues/warnings/__init__.py +4 -1
  20. cognite/neat/_issues/warnings/_general.py +7 -0
  21. cognite/neat/_issues/warnings/_resources.py +12 -1
  22. cognite/neat/_rules/_shared.py +18 -34
  23. cognite/neat/_rules/exporters/_base.py +28 -2
  24. cognite/neat/_rules/exporters/_rules2dms.py +39 -1
  25. cognite/neat/_rules/exporters/_rules2excel.py +13 -2
  26. cognite/neat/_rules/exporters/_rules2instance_template.py +4 -0
  27. cognite/neat/_rules/exporters/_rules2ontology.py +13 -1
  28. cognite/neat/_rules/exporters/_rules2yaml.py +4 -0
  29. cognite/neat/_rules/importers/_base.py +9 -0
  30. cognite/neat/_rules/importers/_dms2rules.py +80 -57
  31. cognite/neat/_rules/importers/_dtdl2rules/dtdl_importer.py +5 -2
  32. cognite/neat/_rules/importers/_rdf/_base.py +10 -8
  33. cognite/neat/_rules/importers/_rdf/_imf2rules.py +4 -0
  34. cognite/neat/_rules/importers/_rdf/_inference2rules.py +7 -0
  35. cognite/neat/_rules/importers/_rdf/_owl2rules.py +4 -0
  36. cognite/neat/_rules/importers/_spreadsheet2rules.py +17 -8
  37. cognite/neat/_rules/importers/_yaml2rules.py +21 -7
  38. cognite/neat/_rules/models/_base_input.py +1 -1
  39. cognite/neat/_rules/models/_base_rules.py +9 -1
  40. cognite/neat/_rules/models/dms/_rules.py +4 -0
  41. cognite/neat/_rules/models/dms/_rules_input.py +9 -0
  42. cognite/neat/_rules/models/entities/_wrapped.py +10 -5
  43. cognite/neat/_rules/models/information/_rules.py +4 -0
  44. cognite/neat/_rules/models/information/_rules_input.py +9 -0
  45. cognite/neat/_rules/models/mapping/_classic2core.py +2 -5
  46. cognite/neat/_rules/models/mapping/_classic2core.yaml +239 -38
  47. cognite/neat/_rules/transformers/__init__.py +13 -6
  48. cognite/neat/_rules/transformers/_base.py +41 -65
  49. cognite/neat/_rules/transformers/_converters.py +404 -234
  50. cognite/neat/_rules/transformers/_mapping.py +93 -72
  51. cognite/neat/_rules/transformers/_verification.py +50 -38
  52. cognite/neat/_session/_base.py +32 -121
  53. cognite/neat/_session/_inspect.py +5 -3
  54. cognite/neat/_session/_mapping.py +17 -105
  55. cognite/neat/_session/_prepare.py +138 -268
  56. cognite/neat/_session/_read.py +39 -195
  57. cognite/neat/_session/_set.py +6 -30
  58. cognite/neat/_session/_show.py +40 -21
  59. cognite/neat/_session/_state.py +49 -107
  60. cognite/neat/_session/_to.py +44 -33
  61. cognite/neat/_shared.py +23 -2
  62. cognite/neat/_store/_provenance.py +3 -82
  63. cognite/neat/_store/_rules_store.py +368 -10
  64. cognite/neat/_store/exceptions.py +23 -0
  65. cognite/neat/_utils/graph_transformations_report.py +36 -0
  66. cognite/neat/_utils/rdf_.py +8 -0
  67. cognite/neat/_utils/reader/_base.py +27 -0
  68. cognite/neat/_utils/spreadsheet.py +5 -4
  69. cognite/neat/_version.py +1 -1
  70. {cognite_neat-0.103.1.dist-info → cognite_neat-0.105.0.dist-info}/METADATA +3 -2
  71. cognite_neat-0.105.0.dist-info/RECORD +179 -0
  72. {cognite_neat-0.103.1.dist-info → cognite_neat-0.105.0.dist-info}/WHEEL +1 -1
  73. cognite/neat/_app/api/__init__.py +0 -0
  74. cognite/neat/_app/api/asgi/metrics.py +0 -4
  75. cognite/neat/_app/api/configuration.py +0 -98
  76. cognite/neat/_app/api/context_manager/__init__.py +0 -3
  77. cognite/neat/_app/api/context_manager/manager.py +0 -16
  78. cognite/neat/_app/api/data_classes/__init__.py +0 -0
  79. cognite/neat/_app/api/data_classes/rest.py +0 -59
  80. cognite/neat/_app/api/explorer.py +0 -66
  81. cognite/neat/_app/api/routers/configuration.py +0 -25
  82. cognite/neat/_app/api/routers/crud.py +0 -102
  83. cognite/neat/_app/api/routers/metrics.py +0 -10
  84. cognite/neat/_app/api/routers/workflows.py +0 -224
  85. cognite/neat/_app/api/utils/__init__.py +0 -0
  86. cognite/neat/_app/api/utils/data_mapping.py +0 -17
  87. cognite/neat/_app/api/utils/logging.py +0 -26
  88. cognite/neat/_app/api/utils/query_templates.py +0 -92
  89. cognite/neat/_app/main.py +0 -17
  90. cognite/neat/_app/monitoring/__init__.py +0 -0
  91. cognite/neat/_app/monitoring/metrics.py +0 -69
  92. cognite/neat/_app/ui/index.html +0 -1
  93. cognite/neat/_app/ui/neat-app/.gitignore +0 -23
  94. cognite/neat/_app/ui/neat-app/README.md +0 -70
  95. cognite/neat/_app/ui/neat-app/build/asset-manifest.json +0 -14
  96. cognite/neat/_app/ui/neat-app/build/favicon.ico +0 -0
  97. cognite/neat/_app/ui/neat-app/build/img/architect-icon.svg +0 -116
  98. cognite/neat/_app/ui/neat-app/build/img/developer-icon.svg +0 -112
  99. cognite/neat/_app/ui/neat-app/build/img/sme-icon.svg +0 -34
  100. cognite/neat/_app/ui/neat-app/build/index.html +0 -1
  101. cognite/neat/_app/ui/neat-app/build/logo192.png +0 -0
  102. cognite/neat/_app/ui/neat-app/build/manifest.json +0 -25
  103. cognite/neat/_app/ui/neat-app/build/robots.txt +0 -3
  104. cognite/neat/_app/ui/neat-app/build/static/css/main.72e3d92e.css +0 -2
  105. cognite/neat/_app/ui/neat-app/build/static/css/main.72e3d92e.css.map +0 -1
  106. cognite/neat/_app/ui/neat-app/build/static/js/main.5a52cf09.js +0 -3
  107. cognite/neat/_app/ui/neat-app/build/static/js/main.5a52cf09.js.LICENSE.txt +0 -88
  108. cognite/neat/_app/ui/neat-app/build/static/js/main.5a52cf09.js.map +0 -1
  109. cognite/neat/_app/ui/neat-app/build/static/media/logo.8093b84df9ed36a174c629d6fe0b730d.svg +0 -1
  110. cognite/neat/_app/ui/neat-app/package-lock.json +0 -18306
  111. cognite/neat/_app/ui/neat-app/package.json +0 -62
  112. cognite/neat/_app/ui/neat-app/public/favicon.ico +0 -0
  113. cognite/neat/_app/ui/neat-app/public/img/architect-icon.svg +0 -116
  114. cognite/neat/_app/ui/neat-app/public/img/developer-icon.svg +0 -112
  115. cognite/neat/_app/ui/neat-app/public/img/sme-icon.svg +0 -34
  116. cognite/neat/_app/ui/neat-app/public/index.html +0 -43
  117. cognite/neat/_app/ui/neat-app/public/logo192.png +0 -0
  118. cognite/neat/_app/ui/neat-app/public/manifest.json +0 -25
  119. cognite/neat/_app/ui/neat-app/public/robots.txt +0 -3
  120. cognite/neat/_app/ui/neat-app/src/App.css +0 -38
  121. cognite/neat/_app/ui/neat-app/src/App.js +0 -17
  122. cognite/neat/_app/ui/neat-app/src/App.test.js +0 -8
  123. cognite/neat/_app/ui/neat-app/src/MainContainer.tsx +0 -70
  124. cognite/neat/_app/ui/neat-app/src/components/JsonViewer.tsx +0 -43
  125. cognite/neat/_app/ui/neat-app/src/components/LocalUploader.tsx +0 -124
  126. cognite/neat/_app/ui/neat-app/src/components/OverviewComponentEditorDialog.tsx +0 -63
  127. cognite/neat/_app/ui/neat-app/src/components/StepEditorDialog.tsx +0 -511
  128. cognite/neat/_app/ui/neat-app/src/components/TabPanel.tsx +0 -36
  129. cognite/neat/_app/ui/neat-app/src/components/Utils.tsx +0 -56
  130. cognite/neat/_app/ui/neat-app/src/components/WorkflowDeleteDialog.tsx +0 -60
  131. cognite/neat/_app/ui/neat-app/src/components/WorkflowExecutionReport.tsx +0 -112
  132. cognite/neat/_app/ui/neat-app/src/components/WorkflowImportExportDialog.tsx +0 -67
  133. cognite/neat/_app/ui/neat-app/src/components/WorkflowMetadataDialog.tsx +0 -79
  134. cognite/neat/_app/ui/neat-app/src/index.css +0 -13
  135. cognite/neat/_app/ui/neat-app/src/index.js +0 -13
  136. cognite/neat/_app/ui/neat-app/src/logo.svg +0 -1
  137. cognite/neat/_app/ui/neat-app/src/reportWebVitals.js +0 -13
  138. cognite/neat/_app/ui/neat-app/src/setupTests.js +0 -5
  139. cognite/neat/_app/ui/neat-app/src/types/WorkflowTypes.ts +0 -388
  140. cognite/neat/_app/ui/neat-app/src/views/AboutView.tsx +0 -61
  141. cognite/neat/_app/ui/neat-app/src/views/ConfigView.tsx +0 -184
  142. cognite/neat/_app/ui/neat-app/src/views/GlobalConfigView.tsx +0 -180
  143. cognite/neat/_app/ui/neat-app/src/views/WorkflowView.tsx +0 -570
  144. cognite/neat/_app/ui/neat-app/tsconfig.json +0 -27
  145. cognite/neat/_rules/transformers/_pipelines.py +0 -70
  146. cognite/neat/_workflows/__init__.py +0 -17
  147. cognite/neat/_workflows/base.py +0 -590
  148. cognite/neat/_workflows/cdf_store.py +0 -393
  149. cognite/neat/_workflows/examples/Export_DMS/workflow.yaml +0 -89
  150. cognite/neat/_workflows/examples/Export_Semantic_Data_Model/workflow.yaml +0 -66
  151. cognite/neat/_workflows/examples/Import_DMS/workflow.yaml +0 -65
  152. cognite/neat/_workflows/examples/Validate_Rules/workflow.yaml +0 -67
  153. cognite/neat/_workflows/examples/Validate_Solution_Model/workflow.yaml +0 -64
  154. cognite/neat/_workflows/manager.py +0 -292
  155. cognite/neat/_workflows/model.py +0 -203
  156. cognite/neat/_workflows/steps/__init__.py +0 -0
  157. cognite/neat/_workflows/steps/data_contracts.py +0 -109
  158. cognite/neat/_workflows/steps/lib/__init__.py +0 -0
  159. cognite/neat/_workflows/steps/lib/current/__init__.py +0 -6
  160. cognite/neat/_workflows/steps/lib/current/graph_extractor.py +0 -100
  161. cognite/neat/_workflows/steps/lib/current/graph_loader.py +0 -51
  162. cognite/neat/_workflows/steps/lib/current/graph_store.py +0 -48
  163. cognite/neat/_workflows/steps/lib/current/rules_exporter.py +0 -537
  164. cognite/neat/_workflows/steps/lib/current/rules_importer.py +0 -398
  165. cognite/neat/_workflows/steps/lib/current/rules_validator.py +0 -106
  166. cognite/neat/_workflows/steps/lib/io/__init__.py +0 -1
  167. cognite/neat/_workflows/steps/lib/io/io_steps.py +0 -393
  168. cognite/neat/_workflows/steps/step_model.py +0 -79
  169. cognite/neat/_workflows/steps_registry.py +0 -218
  170. cognite/neat/_workflows/tasks.py +0 -18
  171. cognite/neat/_workflows/triggers.py +0 -169
  172. cognite/neat/_workflows/utils.py +0 -19
  173. cognite_neat-0.103.1.dist-info/RECORD +0 -275
  174. {cognite_neat-0.103.1.dist-info → cognite_neat-0.105.0.dist-info}/LICENSE +0 -0
  175. {cognite_neat-0.103.1.dist-info → cognite_neat-0.105.0.dist-info}/entry_points.txt +0 -0
@@ -1,537 +0,0 @@
1
- import time
2
- from pathlib import Path
3
- from typing import ClassVar, Literal, cast
4
-
5
- from cognite.neat._client import NeatClient
6
- from cognite.neat._issues.errors import WorkflowStepNotInitializedError
7
- from cognite.neat._rules import exporters
8
- from cognite.neat._rules._shared import DMSRules, InformationRules, VerifiedRules
9
- from cognite.neat._rules.models import RoleTypes
10
- from cognite.neat._rules.transformers import (
11
- DMSToInformation,
12
- InformationToDMS,
13
- )
14
- from cognite.neat._workflows.model import FlowMessage, StepExecutionStatus
15
- from cognite.neat._workflows.steps.data_contracts import CogniteClient, MultiRuleData
16
- from cognite.neat._workflows.steps.step_model import Configurable, Step
17
-
18
- __all__ = [
19
- "DeleteDataModelFromCDF",
20
- "RulesToDMS",
21
- "RulesToExcel",
22
- "RulesToOntology",
23
- "RulesToSHACL",
24
- "RulesToSemanticDataModel",
25
- ]
26
-
27
-
28
- CATEGORY = __name__.split(".")[-1].replace("_", " ").title()
29
-
30
-
31
- class DeleteDataModelFromCDF(Step):
32
- """
33
- This step deletes data model and its components from CDF
34
- """
35
-
36
- description = "This step deletes data model and its components from CDF."
37
- version = "private-beta"
38
- category = CATEGORY
39
-
40
- configurables: ClassVar[list[Configurable]] = [
41
- Configurable(
42
- name="Dry run",
43
- value="False",
44
- label=("Whether to perform a dry run of the deleter. "),
45
- options=["True", "False"],
46
- ),
47
- Configurable(
48
- name="Components",
49
- type="multi_select",
50
- value="",
51
- label="Select which DMS schema component(s) to be deleted from CDF",
52
- options=["spaces", "containers", "views", "data_models"],
53
- ),
54
- Configurable(
55
- name="Multi-space components deletion",
56
- value="False",
57
- label=(
58
- "Whether to delete only components belonging to the data model space"
59
- " (i.e. space define under Metadata sheet of Rules), "
60
- "or also additionally delete components outside of the data model space."
61
- ),
62
- options=["True", "False"],
63
- ),
64
- ]
65
-
66
- def run(self, rules: MultiRuleData, cdf_client: CogniteClient) -> FlowMessage: # type: ignore[override]
67
- if self.configs is None or self.data_store_path is None:
68
- raise WorkflowStepNotInitializedError(type(self).__name__)
69
- components_to_delete = {
70
- cast(Literal["spaces", "data_models", "views", "containers"], key)
71
- for key, value in self.complex_configs["Components"].items()
72
- if value
73
- }
74
- dry_run = self.configs["Dry run"] == "True"
75
- multi_space_components_delete: bool = self.configs["Multi-space components deletion"] == "True"
76
-
77
- if not components_to_delete:
78
- return FlowMessage(
79
- error_text="No DMS Schema components selected for removal! Please select minimum one!",
80
- step_execution_status=StepExecutionStatus.ABORT_AND_FAIL,
81
- )
82
- input_rules = rules.dms or rules.information
83
- if input_rules is None:
84
- return FlowMessage(
85
- error_text="Missing DMS or Information rules in the input data! "
86
- "Please ensure that a DMS or Information rules is provided!",
87
- step_execution_status=StepExecutionStatus.ABORT_AND_FAIL,
88
- )
89
- if isinstance(input_rules, DMSRules):
90
- dms_rules = input_rules
91
- elif isinstance(input_rules, InformationRules):
92
- dms_rules = InformationToDMS().transform(input_rules).rules
93
- else:
94
- raise NotImplementedError(f"Unsupported rules type {type(input_rules)}")
95
-
96
- dms_exporter = exporters.DMSExporter(
97
- export_components=frozenset(components_to_delete),
98
- include_space=(None if multi_space_components_delete else {dms_rules.metadata.space}),
99
- )
100
-
101
- report_lines = ["# Data Model Deletion from CDF\n\n"]
102
- errors = []
103
- for result in dms_exporter.delete_from_cdf(rules=dms_rules, client=NeatClient(cdf_client), dry_run=dry_run):
104
- report_lines.append(str(result))
105
- errors.extend(result.error_messages)
106
-
107
- report_lines.append("\n\n# ERRORS\n\n")
108
- report_lines.extend(errors)
109
-
110
- output_dir = self.config.staging_path
111
- output_dir.mkdir(parents=True, exist_ok=True)
112
- report_file = "dms_component_creation_report.txt"
113
- report_full_path = output_dir / report_file
114
- report_full_path.write_text("\n".join(report_lines))
115
-
116
- output_text = (
117
- "<p></p>"
118
- "Download Data Model Deletion "
119
- f'<a href="/data/staging/{report_file}?{time.time()}" '
120
- f'target="_blank">Report</a>'
121
- )
122
-
123
- if errors:
124
- return FlowMessage(error_text=output_text, step_execution_status=StepExecutionStatus.ABORT_AND_FAIL)
125
- else:
126
- return FlowMessage(output_text=output_text)
127
-
128
-
129
- class RulesToDMS(Step):
130
- """
131
- This step exports Rules to DMS Schema components in CDF
132
- """
133
-
134
- description = "This step exports Rules to DMS Schema components in CDF."
135
- version = "private-beta"
136
- category = CATEGORY
137
-
138
- configurables: ClassVar[list[Configurable]] = [
139
- Configurable(
140
- name="Dry run",
141
- value="False",
142
- label=("Whether to perform a dry run of the export. "),
143
- options=["True", "False"],
144
- ),
145
- Configurable(
146
- name="Components",
147
- type="multi_select",
148
- value="",
149
- label="Select which DMS schema component(s) to export to CDF",
150
- options=["spaces", "containers", "views", "data_models"],
151
- ),
152
- Configurable(
153
- name="Existing component handling",
154
- value="fail",
155
- label=(
156
- "How to handle situation when components being exported in CDF already exist."
157
- "Fail the step if any component already exists, "
158
- "Skip the component if it already exists, "
159
- " or Update the component try to update the component."
160
- ),
161
- options=["fail", "skip", "update", "force"],
162
- ),
163
- Configurable(
164
- name="Multi-space components create",
165
- value="False",
166
- label=(
167
- "Whether to create only components belonging to the data model space"
168
- " (i.e. space define under Metadata sheet of Rules), "
169
- "or also additionally components outside of the data model space."
170
- ),
171
- options=["True", "False"],
172
- ),
173
- ]
174
-
175
- def run(self, rules: MultiRuleData, cdf_client: CogniteClient) -> FlowMessage: # type: ignore[override]
176
- if self.configs is None or self.data_store_path is None:
177
- raise WorkflowStepNotInitializedError(type(self).__name__)
178
- existing_components_handling = cast(
179
- Literal["fail", "update", "skip", "force"], self.configs["Existing component handling"]
180
- )
181
- multi_space_components_create: bool = self.configs["Multi-space components create"] == "True"
182
- components_to_create = {
183
- cast(Literal["spaces", "data_models", "views", "containers"], key)
184
- for key, value in self.complex_configs["Components"].items()
185
- if value
186
- }
187
- dry_run = self.configs["Dry run"] == "True"
188
-
189
- if not components_to_create:
190
- return FlowMessage(
191
- error_text="No DMS Schema components selected for upload! Please select minimum one!",
192
- step_execution_status=StepExecutionStatus.ABORT_AND_FAIL,
193
- )
194
- input_rules = rules.dms or rules.information
195
- if input_rules is None:
196
- return FlowMessage(
197
- error_text="Missing DMS or Information rules in the input data! "
198
- "Please ensure that a DMS or Information rules is provided!",
199
- step_execution_status=StepExecutionStatus.ABORT_AND_FAIL,
200
- )
201
- if isinstance(input_rules, DMSRules):
202
- dms_rules = input_rules
203
- elif isinstance(input_rules, InformationRules):
204
- dms_rules = InformationToDMS().transform(input_rules).rules
205
- else:
206
- raise NotImplementedError(f"Unsupported rules type {type(input_rules)}")
207
-
208
- dms_exporter = exporters.DMSExporter(
209
- export_components=frozenset(components_to_create),
210
- include_space=(None if multi_space_components_create else {dms_rules.metadata.space}),
211
- existing=existing_components_handling,
212
- )
213
-
214
- output_dir = self.config.staging_path
215
- output_dir.mkdir(parents=True, exist_ok=True)
216
- file_name = input_rules.metadata.external_id
217
- schema_zip = f"{file_name}.zip"
218
- schema_full_path = output_dir / schema_zip
219
- dms_exporter.export_to_file(dms_rules, schema_full_path)
220
-
221
- report_lines = ["# DMS Schema Export to CDF\n\n"]
222
- errors = []
223
- for result in dms_exporter.export_to_cdf_iterable(
224
- rules=dms_rules, client=NeatClient(cdf_client), dry_run=dry_run
225
- ):
226
- report_lines.append(str(result))
227
- errors.extend(result.error_messages)
228
-
229
- report_lines.append("\n\n# ERRORS\n\n")
230
- report_lines.extend(errors)
231
-
232
- output_dir = self.config.staging_path
233
- output_dir.mkdir(parents=True, exist_ok=True)
234
- report_file = "dms_component_creation_report.txt"
235
- report_full_path = output_dir / report_file
236
- report_full_path.write_text("\n".join(report_lines))
237
-
238
- output_text = (
239
- "<p></p>"
240
- "Download DMS Export "
241
- f'<a href="/data/staging/{report_file}?{time.time()}" '
242
- f'target="_blank">Report</a>'
243
- "<p></p>"
244
- "Download DMS exported schema"
245
- f'- <a href="/data/staging/{schema_zip}?{time.time()}" '
246
- f'target="_blank">{schema_zip}</a>'
247
- )
248
-
249
- if errors:
250
- return FlowMessage(error_text=output_text, step_execution_status=StepExecutionStatus.ABORT_AND_FAIL)
251
- else:
252
- return FlowMessage(output_text=output_text)
253
-
254
-
255
- class RulesToExcel(Step):
256
- """This step exports Rules to Excel serialization"""
257
-
258
- description = "This step exports Rules to Excel serialization."
259
- version = "private-beta"
260
- category = CATEGORY
261
-
262
- configurables: ClassVar[list[Configurable]] = [
263
- Configurable(
264
- name="Styling",
265
- value="default",
266
- label="Styling of the Excel file",
267
- options=list(exporters.ExcelExporter.style_options),
268
- ),
269
- Configurable(
270
- name="Output role format",
271
- value="input",
272
- label="The role to use for the exported spreadsheet. If provided, the rules will be converted to "
273
- "this role format before being written to excel. If not provided, the role from the input "
274
- "rules will be used.",
275
- options=["input", *RoleTypes.__members__.keys()],
276
- ),
277
- Configurable(
278
- name="New Data Model ID",
279
- value="",
280
- label="If you chose Dump Format 'reference', the provided ID will be use in the new medata sheet. "
281
- "Expected format 'sp_space:my_external_id'.",
282
- ),
283
- Configurable(
284
- name="File path",
285
- value="",
286
- label="File path to the generated Excel file.For example: 'staging/exported-rules.xlsx'",
287
- ),
288
- ]
289
-
290
- def run(self, rules: MultiRuleData) -> FlowMessage: # type: ignore[override, syntax]
291
- if self.configs is None or self.data_store_path is None:
292
- raise WorkflowStepNotInitializedError(type(self).__name__)
293
-
294
- styling = cast(exporters.ExcelExporter.Style, self.configs.get("Styling", "default"))
295
- role = self.configs.get("Output role format")
296
- output_role: RoleTypes | None = None
297
- if role != "input" and role is not None:
298
- output_role = RoleTypes[role]
299
-
300
- new_model_str = self.configs.get("New Data Model ID")
301
- new_model_id: tuple[str, str] | None = None
302
- if new_model_str and ":" in new_model_str:
303
- new_model_id = tuple(new_model_str.split(":", 1)) # type: ignore[assignment]
304
- elif new_model_str:
305
- return FlowMessage(
306
- error_text="New Data Model ID must be in the format 'sp_space:my_external_id'!",
307
- step_execution_status=StepExecutionStatus.ABORT_AND_FAIL,
308
- )
309
-
310
- excel_exporter = exporters.ExcelExporter(styling=styling, new_model_id=new_model_id) # type: ignore[arg-type]
311
-
312
- # Todo - Move the conversion to a separate workflow step.
313
- rule_instance: VerifiedRules
314
-
315
- if rules.information:
316
- rule_instance = rules.information
317
- elif rules.dms:
318
- rule_instance = rules.dms
319
- else:
320
- output_errors = "No rules provided for export!"
321
- return FlowMessage(error_text=output_errors, step_execution_status=StepExecutionStatus.ABORT_AND_FAIL)
322
-
323
- if rule_instance.metadata.role is output_role or output_role is None:
324
- ...
325
- elif output_role is RoleTypes.dms:
326
- if isinstance(rule_instance, InformationRules):
327
- rule_instance = InformationToDMS().transform(rule_instance).rules
328
- else:
329
- raise NotImplementedError(f"Role {output_role} is not supported for {type(rules).__name__} rules")
330
- elif output_role is RoleTypes.information:
331
- if isinstance(rule_instance, DMSRules):
332
- rule_instance = DMSToInformation().transform(rule_instance).rules
333
- else:
334
- raise NotImplementedError(f"Role {output_role} is not supported for {type(rules).__name__} rules")
335
- else:
336
- raise NotImplementedError(f"Role {output_role} is not supported for {type(rules).__name__} rules")
337
-
338
- if output_role is None:
339
- output_role = rule_instance.metadata.role
340
- output_dir = self.data_store_path / Path("staging")
341
- output_dir.mkdir(parents=True, exist_ok=True)
342
- file_name = f"exported_rules_{output_role.value}.xlsx"
343
- filepath = output_dir / file_name
344
- if self.configs.get("File path", ""):
345
- file_name = self.configs["File path"]
346
- filepath = Path(self.data_store_path) / Path(file_name)
347
- else:
348
- file_name = f"staging/{file_name}"
349
-
350
- excel_exporter.export_to_file(rule_instance, filepath)
351
-
352
- output_text = (
353
- "<p></p>"
354
- f"Download Excel Exported {output_role.value} rules: "
355
- f'- <a href="/data/{file_name}?{time.time()}" '
356
- f'target="_blank">{file_name}</a>'
357
- )
358
-
359
- return FlowMessage(output_text=output_text)
360
-
361
-
362
- class RulesToOntology(Step):
363
- """
364
- This step exports Rules to OWL ontology
365
- """
366
-
367
- description = "This step exports Rules to OWL ontology"
368
- version = "private-beta"
369
- category = CATEGORY
370
- configurables: ClassVar[list[Configurable]] = [
371
- Configurable(
372
- name="File path",
373
- value="staging/ontology.ttl",
374
- label=("Relative path for the ontology file storage, " " It will be auto-created if not provided ! "),
375
- )
376
- ]
377
-
378
- def run(self, rules: MultiRuleData) -> FlowMessage: # type: ignore[override, syntax]
379
- if self.configs is None or self.data_store_path is None:
380
- raise WorkflowStepNotInitializedError(type(self).__name__)
381
-
382
- if not rules.information and not rules.dms:
383
- return FlowMessage(
384
- error_text="Rules must be made either by Information Architect or DMS Architect!",
385
- step_execution_status=StepExecutionStatus.ABORT_AND_FAIL,
386
- )
387
-
388
- default_path = self.config.staging_path / _get_default_file_name(rules, "ontology", "ttl")
389
-
390
- storage_path = (
391
- self.data_store_path / Path(self.configs["File path"]) if self.configs["File path"] else default_path
392
- )
393
- storage_path.parent.mkdir(parents=True, exist_ok=True)
394
-
395
- input_rules = rules.information or rules.dms
396
- if isinstance(input_rules, DMSRules):
397
- info_rules = DMSToInformation().transform(input_rules).rules
398
- elif isinstance(input_rules, InformationRules):
399
- info_rules = input_rules
400
- else:
401
- raise NotImplementedError(f"Unsupported rules type {type(input_rules)}")
402
-
403
- exporter = exporters.OWLExporter()
404
- exporter.export_to_file(info_rules, storage_path)
405
-
406
- relative_file_path = "/".join(storage_path.relative_to(self.data_store_path).parts)
407
-
408
- output_text = (
409
- "<p></p>"
410
- "Rules exported as OWL ontology can be downloaded here : "
411
- f'<a href="/data/{relative_file_path}?{time.time()}" '
412
- f'target="_blank">{storage_path.stem}.ttl</a>'
413
- )
414
-
415
- return FlowMessage(output_text=output_text)
416
-
417
-
418
- class RulesToSHACL(Step):
419
- """
420
- This step exports Rules to SHACL
421
- """
422
-
423
- description = "This step exports Rules to SHACL"
424
- version = "private-beta"
425
- category = CATEGORY
426
- configurables: ClassVar[list[Configurable]] = [
427
- Configurable(
428
- name="File path",
429
- value="staging/shacl.ttl",
430
- label=(
431
- "Relative path for the shacl file storage, "
432
- "must end with .ttl ! It will be auto-created if not provided !"
433
- ),
434
- )
435
- ]
436
-
437
- def run(self, rules: MultiRuleData) -> FlowMessage: # type: ignore[override, syntax]
438
- if self.configs is None or self.data_store_path is None:
439
- raise WorkflowStepNotInitializedError(type(self).__name__)
440
-
441
- if not rules.information and not rules.dms:
442
- return FlowMessage(
443
- error_text="Rules must be made either by Information Architect or DMS Architect!",
444
- step_execution_status=StepExecutionStatus.ABORT_AND_FAIL,
445
- )
446
-
447
- default_path = self.config.staging_path / _get_default_file_name(rules, "shacl", "ttl")
448
-
449
- storage_path = (
450
- self.data_store_path / Path(self.configs["File path"]) if self.configs["File path"] else default_path
451
- )
452
- storage_path.parent.mkdir(parents=True, exist_ok=True)
453
-
454
- input_rules = rules.information or rules.dms
455
- if isinstance(input_rules, DMSRules):
456
- info_rules = DMSToInformation().transform(input_rules).rules
457
- elif isinstance(input_rules, InformationRules):
458
- info_rules = input_rules
459
- else:
460
- raise NotImplementedError(f"Unsupported rules type {type(input_rules)}")
461
-
462
- exporter = exporters.SHACLExporter()
463
- exporter.export_to_file(info_rules, storage_path)
464
-
465
- relative_file_path = "/".join(storage_path.relative_to(self.data_store_path).parts)
466
-
467
- output_text = (
468
- "<p></p>"
469
- "Rules exported as SHACL shapes can be downloaded here : "
470
- f'<a href="/data/{relative_file_path}?{time.time()}" '
471
- f'target="_blank">{storage_path.stem}.ttl</a>'
472
- )
473
-
474
- return FlowMessage(output_text=output_text)
475
-
476
-
477
- class RulesToSemanticDataModel(Step):
478
- """
479
- This step exports Rules to semantic data model
480
- """
481
-
482
- description = "This step exports Rules to semantic data model (ontology + SHACL)"
483
- version = "private-beta"
484
- category = CATEGORY
485
- configurables: ClassVar[list[Configurable]] = [
486
- Configurable(
487
- name="File path",
488
- value="staging/semantic-data-model.ttl",
489
- label=(
490
- "Relative path for the semantic data model file storage, "
491
- "must end with .ttl ! It will be auto-created if not provided !"
492
- ),
493
- )
494
- ]
495
-
496
- def run(self, rules: MultiRuleData) -> FlowMessage: # type: ignore[override, syntax]
497
- if self.configs is None or self.data_store_path is None:
498
- raise WorkflowStepNotInitializedError(type(self).__name__)
499
-
500
- if not rules.information and not rules.dms:
501
- return FlowMessage(
502
- error_text="Rules must be made either by Information Architect or DMS Architect!",
503
- step_execution_status=StepExecutionStatus.ABORT_AND_FAIL,
504
- )
505
-
506
- default_path = self.config.staging_path / _get_default_file_name(rules, "semantic-data-model", "ttl")
507
-
508
- storage_path = (
509
- self.data_store_path / Path(self.configs["File path"]) if self.configs["File path"] else default_path
510
- )
511
- storage_path.parent.mkdir(parents=True, exist_ok=True)
512
- input_rules = rules.information or rules.dms
513
- if isinstance(input_rules, DMSRules):
514
- info_rules = DMSToInformation().transform(input_rules).rules
515
- elif isinstance(input_rules, InformationRules):
516
- info_rules = input_rules
517
- else:
518
- raise NotImplementedError(f"Unsupported rules type {type(input_rules)}")
519
- exporter = exporters.SemanticDataModelExporter()
520
- exporter.export_to_file(info_rules, storage_path)
521
-
522
- relative_file_path = "/".join(storage_path.relative_to(self.data_store_path).parts)
523
-
524
- output_text = (
525
- "<p></p>"
526
- "Rules exported as semantic data model (OWL + SHACL) can be downloaded here : "
527
- f'<a href="/data/{relative_file_path}?{time.time()}" '
528
- f'target="_blank">{storage_path.stem}.ttl</a>'
529
- )
530
-
531
- return FlowMessage(output_text=output_text)
532
-
533
-
534
- def _get_default_file_name(rules: MultiRuleData, file_category: str = "ontology", extension: str = "ttl") -> str:
535
- name = rules.information.metadata.prefix if rules.information else cast(DMSRules, rules.dms).metadata.space
536
- version = rules.information.metadata.version if rules.information else cast(DMSRules, rules.dms).metadata.version
537
- return f"{name}-v{version.strip().replace('.', '_')}-{file_category}.{extension}"