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,398 +0,0 @@
1
- import time
2
- from pathlib import Path
3
- from typing import ClassVar
4
-
5
- from cognite.client import CogniteClient
6
-
7
- from cognite.neat._client import NeatClient
8
- from cognite.neat._issues.errors import WorkflowStepNotInitializedError
9
- from cognite.neat._issues.formatters import FORMATTER_BY_NAME
10
- from cognite.neat._rules import importers
11
- from cognite.neat._rules._shared import InputRules
12
- from cognite.neat._rules.models import RoleTypes
13
- from cognite.neat._rules.models.entities import DataModelEntity, DMSUnknownEntity
14
- from cognite.neat._rules.transformers import ImporterPipeline
15
- from cognite.neat._workflows.model import FlowMessage, StepExecutionStatus
16
- from cognite.neat._workflows.steps.data_contracts import MultiRuleData
17
- from cognite.neat._workflows.steps.step_model import Configurable, Step
18
-
19
- CATEGORY = __name__.split(".")[-1].replace("_", " ").title()
20
-
21
- __all__ = [
22
- "DMSToRules",
23
- "ExcelToRules",
24
- "IMFToRules",
25
- "OntologyToRules",
26
- "RulesInferenceFromRdfFile",
27
- ]
28
-
29
-
30
- class ExcelToRules(Step):
31
- """This step import rules from the Excel file and validates it."""
32
-
33
- description = "This step imports rules from an excel file "
34
- version = "private-beta"
35
- category = CATEGORY
36
- configurables: ClassVar[list[Configurable]] = [
37
- Configurable(
38
- name="File name",
39
- value="",
40
- label="Full file name of the rules file in the rules folder. \
41
- If not provided, step will attempt to get file name from payload \
42
- of 'File Uploader' step (if exist)",
43
- ),
44
- Configurable(
45
- name="Report formatter",
46
- value=next(iter(FORMATTER_BY_NAME.keys())),
47
- label="The format of the report for the validation of the rules",
48
- options=list(FORMATTER_BY_NAME),
49
- ),
50
- Configurable(
51
- name="Role",
52
- value="infer",
53
- label="For what role Rules are intended?",
54
- options=["infer", *RoleTypes.__members__.keys()],
55
- ),
56
- ]
57
-
58
- def run(self, flow_message: FlowMessage) -> (FlowMessage, MultiRuleData): # type: ignore[syntax, override]
59
- if self.configs is None or self.data_store_path is None:
60
- raise WorkflowStepNotInitializedError(type(self).__name__)
61
-
62
- file_name = self.configs.get("File name", None)
63
- full_path = flow_message.payload.get("full_path", None) if flow_message.payload else None
64
-
65
- if file_name:
66
- rules_file_path = Path(self.data_store_path) / "rules" / file_name
67
- elif full_path:
68
- rules_file_path = full_path
69
- else:
70
- error_text = "Expected either 'File name' in the step config or 'File uploader' step uploading Excel Rules."
71
- return FlowMessage(error_text=error_text, step_execution_status=StepExecutionStatus.ABORT_AND_FAIL)
72
-
73
- # if role is None, it will be inferred from the rules file
74
- role = self.configs.get("Role")
75
- role_enum: RoleTypes | None = None
76
- if role != "infer" and role is not None:
77
- role_enum = RoleTypes[role]
78
-
79
- excel_importer = importers.ExcelImporter[InputRules](rules_file_path)
80
- result = ImporterPipeline.try_verify(excel_importer, role_enum)
81
-
82
- if result.rules is None:
83
- output_dir = self.config.staging_path
84
- report_writer = FORMATTER_BY_NAME[self.configs["Report formatter"]]()
85
- report_writer.write_to_file(result.issues, file_or_dir_path=output_dir)
86
- report_file = report_writer.default_file_name
87
- error_text = (
88
- "<p></p>"
89
- f'<a href="/data/staging/{report_file}?{time.time()}" '
90
- f'target="_blank">Failed to validate rules, click here for report</a>'
91
- )
92
- return FlowMessage(error_text=error_text, step_execution_status=StepExecutionStatus.ABORT_AND_FAIL)
93
-
94
- output_text = "Rules validation passed successfully!"
95
-
96
- return FlowMessage(output_text=output_text), MultiRuleData.from_rules(result.rules)
97
-
98
-
99
- class OntologyToRules(Step):
100
- """This step import rules from the ontology file (owl) and validates it."""
101
-
102
- description = "This step imports rules from an ontology file "
103
- version = "private-beta"
104
- category = CATEGORY
105
- configurables: ClassVar[list[Configurable]] = [
106
- Configurable(
107
- name="File name",
108
- value="",
109
- label="Full file name of the ontology file in the rules folder. \
110
- If not provided, step will attempt to get file name from payload \
111
- of 'File Uploader' step (if exist)",
112
- ),
113
- Configurable(
114
- name="Report formatter",
115
- value=next(iter(FORMATTER_BY_NAME.keys())),
116
- label="The format of the report for the validation of the rules",
117
- options=list(FORMATTER_BY_NAME),
118
- ),
119
- Configurable(
120
- name="Role",
121
- value="infer",
122
- label="For what role Rules are intended?",
123
- options=["infer", *RoleTypes.__members__.keys()],
124
- ),
125
- ]
126
-
127
- def run(self, flow_message: FlowMessage) -> (FlowMessage, MultiRuleData): # type: ignore[syntax, override]
128
- if self.configs is None or self.data_store_path is None:
129
- raise WorkflowStepNotInitializedError(type(self).__name__)
130
-
131
- file_name = self.configs.get("File name", None)
132
- full_path = flow_message.payload.get("full_path", None) if flow_message.payload else None
133
-
134
- if file_name:
135
- rules_file_path = self.config.rules_store_path / file_name
136
- elif full_path:
137
- rules_file_path = full_path
138
- else:
139
- error_text = "Expected either 'File name' in the step config or 'File uploader' step uploading Excel Rules."
140
- return FlowMessage(error_text=error_text, step_execution_status=StepExecutionStatus.ABORT_AND_FAIL)
141
-
142
- # if role is None, it will be inferred from the rules file
143
- role = self.configs.get("Role")
144
- role_enum = None
145
- if role != "infer" and role is not None:
146
- role_enum = RoleTypes[role]
147
-
148
- ontology_importer = importers.OWLImporter.from_file(filepath=rules_file_path)
149
- result = ImporterPipeline.try_verify(ontology_importer, role_enum)
150
-
151
- if result.rules is None:
152
- output_dir = self.config.staging_path
153
- report_writer = FORMATTER_BY_NAME[self.configs["Report formatter"]]()
154
- report_writer.write_to_file(result.issues, file_or_dir_path=output_dir)
155
- report_file = report_writer.default_file_name
156
- error_text = (
157
- "<p></p>"
158
- f'<a href="/data/staging/{report_file}?{time.time()}" '
159
- f'target="_blank">Failed to validate rules, click here for report</a>'
160
- )
161
- return FlowMessage(error_text=error_text, step_execution_status=StepExecutionStatus.ABORT_AND_FAIL)
162
-
163
- output_text = "Rules validation passed successfully!"
164
-
165
- return FlowMessage(output_text=output_text), MultiRuleData.from_rules(result.rules)
166
-
167
-
168
- class IMFToRules(Step):
169
- """This step import rules from the IMF-types and validates them."""
170
-
171
- description = "This step imports rules from an RDF file "
172
- version = "private-beta"
173
- category = CATEGORY
174
- configurables: ClassVar[list[Configurable]] = [
175
- Configurable(
176
- name="File name",
177
- value="",
178
- label="""Full file name of the RDF-file containing the IMF-types in the rules folder.
179
- If not provided, step will attempt to get file name from payload
180
- of 'File Uploader' step (if exist)""",
181
- ),
182
- Configurable(
183
- name="Report formatter",
184
- value=next(iter(FORMATTER_BY_NAME.keys())),
185
- label="The format of the report for the validation of the rules",
186
- options=list(FORMATTER_BY_NAME),
187
- ),
188
- Configurable(
189
- name="Role",
190
- value="infer",
191
- label="For what role Rules are intended?",
192
- options=["infer", *RoleTypes.__members__.keys()],
193
- ),
194
- ]
195
-
196
- def run(self, flow_message: FlowMessage) -> (FlowMessage, MultiRuleData): # type: ignore[syntax, override]
197
- if self.configs is None or self.data_store_path is None:
198
- raise WorkflowStepNotInitializedError(type(self).__name__)
199
-
200
- file_name = self.configs.get("File name", None)
201
-
202
- full_path = flow_message.payload.get("full_path", None) if flow_message.payload else None
203
-
204
- if file_name:
205
- rules_file_path = self.config.rules_store_path / file_name
206
-
207
- elif full_path:
208
- rules_file_path = full_path
209
- else:
210
- error_text = "Expected either 'File name' in the step config or 'File uploader' step uploading Excel Rules."
211
- return FlowMessage(error_text=error_text, step_execution_status=StepExecutionStatus.ABORT_AND_FAIL)
212
-
213
- # if role is None, it will be inferred from the rules file
214
- role = self.configs.get("Role")
215
- role_enum = None
216
- if role != "infer" and role is not None:
217
- role_enum = RoleTypes[role]
218
-
219
- ontology_importer = importers.IMFImporter.from_file(rules_file_path)
220
- result = ImporterPipeline.try_verify(ontology_importer, role_enum)
221
-
222
- if result.rules is None:
223
- output_dir = self.config.staging_path
224
- report_writer = FORMATTER_BY_NAME[self.configs["Report formatter"]]()
225
- report_writer.write_to_file(result.issues, file_or_dir_path=output_dir)
226
- report_file = report_writer.default_file_name
227
- error_text = (
228
- "<p></p>"
229
- f'<a href="/data/staging/{report_file}?{time.time()}" '
230
- f'target="_blank">Failed to validate rules, click here for report</a>'
231
- )
232
- return FlowMessage(error_text=error_text, step_execution_status=StepExecutionStatus.ABORT_AND_FAIL)
233
-
234
- output_text = "Rules validation passed successfully!"
235
-
236
- return FlowMessage(output_text=output_text), MultiRuleData.from_rules(result.rules)
237
-
238
-
239
- class DMSToRules(Step):
240
- """This step imports rules from CDF Data Model"""
241
-
242
- description = "This step imports rules from CDF Data Model"
243
- version = "private-beta"
244
- category = CATEGORY
245
- configurables: ClassVar[list[Configurable]] = [
246
- Configurable(
247
- name="Data model id",
248
- value="",
249
- label="The ID of the Data Model to import. Written at 'my_space:my_data_model(version=1)'",
250
- type="string",
251
- required=True,
252
- ),
253
- Configurable(
254
- name="Reference data model id",
255
- value="",
256
- label="The ID of the Reference Data Model to import. Written at 'my_space:my_data_model(version=1)'. "
257
- "This is typically an enterprise data model when you want to import a solution model",
258
- type="string",
259
- ),
260
- Configurable(
261
- name="Report formatter",
262
- value=next(iter(FORMATTER_BY_NAME.keys())),
263
- label="The format of the report for the validation of the rules",
264
- options=list(FORMATTER_BY_NAME),
265
- ),
266
- Configurable(
267
- name="Role",
268
- value="infer",
269
- label="For what role Rules are intended?",
270
- options=["infer", *RoleTypes.__members__.keys()],
271
- ),
272
- ]
273
-
274
- def run(self, cdf_client: CogniteClient) -> (FlowMessage, MultiRuleData): # type: ignore[syntax, override]
275
- if self.configs is None or self.data_store_path is None:
276
- raise WorkflowStepNotInitializedError(type(self).__name__)
277
-
278
- datamodel_id_str = self.configs.get("Data model id")
279
- if datamodel_id_str is None:
280
- error_text = "Expected input payload to contain 'Data model id' key."
281
- return FlowMessage(error_text=error_text, step_execution_status=StepExecutionStatus.ABORT_AND_FAIL)
282
-
283
- datamodel_entity = DataModelEntity.load(datamodel_id_str)
284
- if isinstance(datamodel_entity, DMSUnknownEntity):
285
- error_text = (
286
- f"Data model id should be in the format 'my_space:my_data_model(version=1)' "
287
- f"or 'my_space:my_data_model', failed to parse space from {datamodel_id_str}"
288
- )
289
- return FlowMessage(error_text=error_text, step_execution_status=StepExecutionStatus.ABORT_AND_FAIL)
290
-
291
- dms_importer = importers.DMSImporter.from_data_model_id(NeatClient(cdf_client), datamodel_entity.as_id())
292
-
293
- # if role is None, it will be inferred from the rules file
294
- role = self.configs.get("Role")
295
- role_enum = None
296
- if role != "infer" and role is not None:
297
- role_enum = RoleTypes[role]
298
-
299
- result = ImporterPipeline.try_verify(dms_importer, role_enum)
300
-
301
- if result.rules is None:
302
- output_dir = self.config.staging_path
303
- report_writer = FORMATTER_BY_NAME[self.configs["Report formatter"]]()
304
- report_writer.write_to_file(result.issues, file_or_dir_path=output_dir)
305
- report_file = report_writer.default_file_name
306
- error_text = (
307
- "<p></p>"
308
- f'<a href="/data/staging/{report_file}?{time.time()}" '
309
- f'target="_blank">Failed to validate rules, click here for report</a>'
310
- )
311
- return FlowMessage(error_text=error_text, step_execution_status=StepExecutionStatus.ABORT_AND_FAIL)
312
-
313
- output_text = "Rules import and validation passed successfully!"
314
-
315
- return FlowMessage(output_text=output_text), MultiRuleData.from_rules(result.rules)
316
-
317
-
318
- class RulesInferenceFromRdfFile(Step):
319
- """This step infers rules from the RDF file which contains knowledge graph."""
320
-
321
- description = "This step infers rules from the RDF file which contains knowledge graph"
322
- version = "private-beta"
323
- category = CATEGORY
324
- configurables: ClassVar[list[Configurable]] = [
325
- Configurable(
326
- name="File path",
327
- value="staging/knowledge_graph.ttl",
328
- label=("Relative path to the RDF file to be used for inference"),
329
- ),
330
- Configurable(
331
- name="Report formatter",
332
- value=next(iter(FORMATTER_BY_NAME.keys())),
333
- label="The format of the report for the validation of the rules",
334
- options=list(FORMATTER_BY_NAME),
335
- ),
336
- Configurable(
337
- name="Role",
338
- value="infer",
339
- label="For what role Rules are intended?",
340
- options=["infer", *RoleTypes.__members__.keys()],
341
- ),
342
- Configurable(
343
- name="Maximum number of instances to process",
344
- value="-1",
345
- label=(
346
- "Maximum number of instances to process"
347
- " to infer rules from the RDF file. Default -1 means all instances."
348
- ),
349
- ),
350
- ]
351
-
352
- def run(self, flow_message: FlowMessage) -> (FlowMessage, MultiRuleData): # type: ignore[syntax, override]
353
- if self.configs is None or self.data_store_path is None:
354
- raise WorkflowStepNotInitializedError(type(self).__name__)
355
-
356
- file_path = self.configs.get("File path", None)
357
- full_path = flow_message.payload.get("full_path", None) if flow_message.payload else None
358
-
359
- try:
360
- max_number_of_instance = int(self.configs.get("Maximum number of instances to process", -1))
361
- except ValueError:
362
- error_text = "Maximum number of instances to process should be an integer value"
363
- return FlowMessage(error_text=error_text, step_execution_status=StepExecutionStatus.ABORT_AND_FAIL)
364
-
365
- if file_path:
366
- rdf_file_path = self.data_store_path / Path(file_path)
367
- elif full_path:
368
- rdf_file_path = full_path
369
- else:
370
- error_text = "Expected either 'File name' in the step config or 'File uploader' step uploading Excel Rules."
371
- return FlowMessage(error_text=error_text, step_execution_status=StepExecutionStatus.ABORT_AND_FAIL)
372
-
373
- # if role is None, it will be inferred from the rules file
374
- role = self.configs.get("Role")
375
- role_enum = None
376
- if role != "infer" and role is not None:
377
- role_enum = RoleTypes[role]
378
-
379
- inference_importer = importers.InferenceImporter.from_file(
380
- rdf_file_path, max_number_of_instance=max_number_of_instance
381
- )
382
- result = ImporterPipeline.try_verify(inference_importer, role_enum)
383
-
384
- if result.rules is None:
385
- output_dir = self.config.staging_path
386
- report_writer = FORMATTER_BY_NAME[self.configs["Report formatter"]]()
387
- report_writer.write_to_file(result.issues, file_or_dir_path=output_dir)
388
- report_file = report_writer.default_file_name
389
- error_text = (
390
- "<p></p>"
391
- f'<a href="/data/staging/{report_file}?{time.time()}" '
392
- f'target="_blank">Failed to validate rules, click here for report</a>'
393
- )
394
- return FlowMessage(error_text=error_text, step_execution_status=StepExecutionStatus.ABORT_AND_FAIL)
395
-
396
- output_text = "Rules validation passed successfully!"
397
-
398
- return FlowMessage(output_text=output_text), MultiRuleData.from_rules(result.rules)
@@ -1,106 +0,0 @@
1
- import logging
2
- import time
3
- from pathlib import Path
4
- from typing import ClassVar
5
-
6
- from cognite.client import CogniteClient
7
-
8
- from cognite.neat._client import NeatClient
9
- from cognite.neat._client._api.data_modeling_loaders import ViewLoader
10
- from cognite.neat._issues import NeatIssueList
11
- from cognite.neat._issues.errors import ResourceNotFoundError, WorkflowStepNotInitializedError
12
- from cognite.neat._issues.formatters import FORMATTER_BY_NAME
13
- from cognite.neat._rules.models import DMSRules
14
- from cognite.neat._rules.models.dms import DMSValidation
15
- from cognite.neat._workflows.model import FlowMessage, StepExecutionStatus
16
- from cognite.neat._workflows.steps.data_contracts import MultiRuleData
17
- from cognite.neat._workflows.steps.step_model import Configurable, Step
18
-
19
- CATEGORY = __name__.split(".")[-1].replace("_", " ").title()
20
-
21
- __all__ = [
22
- "ValidateRulesAgainstCDF",
23
- ]
24
-
25
-
26
- class ValidateRulesAgainstCDF(Step):
27
- """This steps downloads views and containers from CDF and validates the rules against them
28
-
29
- Note that this only applies to DMSRules
30
- """
31
-
32
- description = "This steps downloads views and containers from CDF and validates the rules against them."
33
- category = CATEGORY
34
- version = "private-beta"
35
- configurables: ClassVar[list[Configurable]] = [
36
- Configurable(
37
- name="Report Formatter",
38
- value=next(iter(FORMATTER_BY_NAME.keys())),
39
- label="The format of the report for the validation of the rules",
40
- options=list(FORMATTER_BY_NAME),
41
- ),
42
- ]
43
-
44
- def run(self, rules: MultiRuleData, cdf_client: CogniteClient) -> FlowMessage: # type: ignore[override, syntax]
45
- if self.configs is None or self.data_store_path is None:
46
- raise WorkflowStepNotInitializedError(type(self).__name__)
47
-
48
- if not isinstance(rules.dms, DMSRules):
49
- return FlowMessage(
50
- error_text="DMS rules are missing. This step requires DMS rules to be present.",
51
- step_execution_status=StepExecutionStatus.ABORT_AND_FAIL,
52
- )
53
- dms_rules = rules.dms
54
-
55
- errors = DMSValidation(dms_rules, NeatClient(cdf_client)).validate()
56
-
57
- missing_spaces = [
58
- error.identifier
59
- for error in errors
60
- if isinstance(error, ResourceNotFoundError) and error.resource_type == "Space"
61
- ]
62
- missing_views = [
63
- error.identifier
64
- for error in errors
65
- if isinstance(error, ResourceNotFoundError) and error.resource_type == "View"
66
- ]
67
- missing_containers = [
68
- error.identifier
69
- for error in errors
70
- if isinstance(error, ResourceNotFoundError) and error.resource_type == "Container"
71
- ]
72
-
73
- retrieved_spaces = cdf_client.data_modeling.spaces.retrieve(missing_spaces).as_write()
74
- retrieved_containers = cdf_client.data_modeling.containers.retrieve(missing_containers).as_write()
75
- # Converting read format of views to write format requires to account for parents (implements)
76
- # Thus we use the loader to convert the views to write format.
77
- view_loader = ViewLoader(NeatClient(cdf_client))
78
- retrieved_views = [
79
- view_loader.as_write(view) for view in cdf_client.data_modeling.views.retrieve(missing_views)
80
- ]
81
- logging.info(
82
- f"Retrieved {len(retrieved_spaces)} spaces, {len(retrieved_containers)} containers, "
83
- f"and {len(retrieved_views)} views from CDF."
84
- )
85
-
86
- schema = dms_rules.as_schema()
87
- schema.spaces.update({space.space: space for space in retrieved_spaces})
88
- schema.containers.update({container.as_id(): container for container in retrieved_containers})
89
- schema.views.update({view.as_id(): view for view in retrieved_views})
90
-
91
- if errors:
92
- output_dir = self.data_store_path / Path("staging")
93
- report_writer = FORMATTER_BY_NAME[self.configs["Report Formatter"]]()
94
- report_writer.write_to_file(
95
- NeatIssueList(errors, title=dms_rules.metadata.name or dms_rules.metadata.external_id),
96
- file_or_dir_path=output_dir,
97
- )
98
- report_file = report_writer.default_file_name
99
- error_text = (
100
- "<p></p>"
101
- f'<a href="/data/staging/{report_file}?{time.time()}" '
102
- f'target="_blank">The rules failed validation against CDF, click here for report</a>'
103
- )
104
- return FlowMessage(error_text=error_text, step_execution_status=StepExecutionStatus.ABORT_AND_FAIL)
105
-
106
- return FlowMessage(output_text="Rules validated successfully against CDF")
@@ -1 +0,0 @@
1
- from .io_steps import * # noqa