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,64 +0,0 @@
1
- configs: []
2
- description: null
3
- implementation_module: null
4
- name: Validate Solution Model
5
- steps:
6
- - complex_configs: {}
7
- configs: {}
8
- description: null
9
- enabled: true
10
- id: step_769298
11
- label: Upload File
12
- max_retries: 0
13
- method: null
14
- params:
15
- file_type: rules
16
- retry_delay: 3
17
- stype: file_uploader
18
- system_component_id: null
19
- transition_to:
20
- - step_399494
21
- trigger: true
22
- ui_config:
23
- pos_x: 627
24
- pos_y: -19
25
- - complex_configs: {}
26
- configs:
27
- File name: ''
28
- Report formatter: BasicHTML
29
- Role: infer
30
- description: null
31
- enabled: true
32
- id: step_399494
33
- label: Import Excel
34
- max_retries: 0
35
- method: ExcelToRules
36
- params: {}
37
- retry_delay: 3
38
- stype: stdstep
39
- system_component_id: null
40
- transition_to:
41
- - step_273233
42
- trigger: false
43
- ui_config:
44
- pos_x: 627
45
- pos_y: 66
46
- - complex_configs: {}
47
- configs:
48
- Report Formatter: BasicHTML
49
- description: null
50
- enabled: true
51
- id: step_273233
52
- label: Validate Against CDF
53
- max_retries: 0
54
- method: ValidateRulesAgainstCDF
55
- params: {}
56
- retry_delay: 3
57
- stype: stdstep
58
- system_component_id: null
59
- transition_to: []
60
- trigger: false
61
- ui_config:
62
- pos_x: 627
63
- pos_y: 154
64
- system_components: []
@@ -1,292 +0,0 @@
1
- import logging
2
- import os
3
- import shutil
4
- import sys
5
- import time
6
- import traceback
7
-
8
- from cognite.client import CogniteClient
9
- from prometheus_client import Gauge
10
- from pydantic import BaseModel
11
-
12
- from cognite.neat._config import Config
13
- from cognite.neat._workflows import BaseWorkflow
14
- from cognite.neat._workflows.base import WorkflowDefinition
15
- from cognite.neat._workflows.model import FlowMessage, InstanceStartMethod, WorkflowState, WorkflowStepDefinition
16
- from cognite.neat._workflows.steps_registry import StepsRegistry
17
- from cognite.neat._workflows.tasks import WorkflowTaskBuilder
18
-
19
- live_workflow_instances = Gauge("neat_workflow_live_instances", "Count of live workflow instances", ["itype"])
20
-
21
-
22
- class WorkflowStartStatus(BaseModel, arbitrary_types_allowed=True):
23
- workflow_instance: BaseWorkflow | None = None
24
- is_success: bool = True
25
- status_text: str | None = None
26
-
27
-
28
- class WorkflowManager:
29
- """Workflow manager is responsible for loading, saving and managing workflows
30
- client: CogniteClient
31
- config: Config
32
- """
33
-
34
- def __init__(self, client: CogniteClient, config: Config):
35
- self.client = client
36
- self.data_set_id = config.cdf_default_dataset_id
37
- self.data_store_path = config.data_store_path
38
- self.workflow_registry: dict[str, BaseWorkflow] = {}
39
- self.ephemeral_instance_registry: dict[str, BaseWorkflow] = {}
40
- self.workflows_storage_type = config.workflows_store_type
41
- self.config = config
42
- self.workflows_storage_path = config.workflows_store_path
43
- self.rules_storage_path = config.rules_store_path
44
- self.task_builder = WorkflowTaskBuilder(client, self)
45
- self.steps_registry = StepsRegistry(self.config)
46
- self.steps_registry.load_step_classes()
47
-
48
- def update_cdf_client(self, client: CogniteClient):
49
- self.client = client
50
- self.task_builder = WorkflowTaskBuilder(client, self)
51
- self.workflow_registry = {}
52
- self.load_workflows_from_storage()
53
-
54
- def get_list_of_workflows(self):
55
- return list(self.workflow_registry.keys())
56
-
57
- def get_steps_registry(self):
58
- return self.steps_registry
59
-
60
- def get_workflow(self, name: str) -> BaseWorkflow | None:
61
- try:
62
- return self.workflow_registry[name]
63
- except KeyError:
64
- return None
65
-
66
- def full_reset(self):
67
- self.workflow_registry = {}
68
- self.ephemeral_instance_registry = {}
69
-
70
- def start_workflow(self, name: str, sync=False, **kwargs):
71
- workflow = self.get_workflow(name)
72
- if workflow is None:
73
- raise ValueError(f"Workflow {name} not found")
74
- workflow.start(sync, kwargs=kwargs)
75
- return workflow
76
-
77
- def delete_workflow(self, name: str):
78
- workflow = self.get_workflow(name)
79
- if workflow is not None:
80
- workflow.cleanup_workflow_context()
81
- del self.workflow_registry[name]
82
- full_path = self.workflows_storage_path / name
83
- shutil.rmtree(full_path)
84
-
85
- def update_workflow(self, name: str, workflow: WorkflowDefinition):
86
- self.workflow_registry[name].workflow_steps = workflow.steps
87
- self.workflow_registry[name].configs = workflow.configs
88
- self.workflow_registry[name].workflow_system_components = workflow.system_components
89
-
90
- def save_workflow_to_storage(self, name: str, custom_implementation_module: str | None = None):
91
- """Save workflow from memory to storage"""
92
- if self.workflows_storage_type == "file":
93
- full_path = self.workflows_storage_path / name / "workflow.yaml"
94
- full_path.parent.mkdir(parents=True, exist_ok=True)
95
- wf = self.workflow_registry[name]
96
- full_path.write_text(
97
- wf.serialize_workflow(output_format="yaml", custom_implementation_module=custom_implementation_module)
98
- )
99
-
100
- def create_new_workflow(self, name: str, description=None, mode: str = "manifest") -> WorkflowDefinition:
101
- """Create new workflow in memory"""
102
- workflow_definition = WorkflowDefinition(
103
- name=name, description=description, steps=[], system_components=[], configs=[]
104
- )
105
- self.register_workflow(BaseWorkflow, name, workflow_definition)
106
- self.save_workflow_to_storage(name)
107
- return workflow_definition
108
-
109
- def load_single_workflow_from_storage(self, workflow_name: str):
110
- """Load single workflow from storage into memory"""
111
-
112
- # check if workflow is already loaded. If so, perform context cleanup first
113
- if workflow_name in self.workflow_registry:
114
- self.workflow_registry[workflow_name].cleanup_workflow_context()
115
- del self.workflow_registry[workflow_name]
116
-
117
- workflow_path = self.workflows_storage_path / workflow_name
118
- # THIS IS WHERE WE LOAD THE WORKFLOW MODULES
119
- if workflow_path.is_dir():
120
- logging.info(f"Loading workflow {workflow_name} from {workflow_path}")
121
- try:
122
- if (workflow_definition_path := workflow_path / "workflow.yaml").exists():
123
- with workflow_definition_path.open() as workflow_definition_file:
124
- workflow_definition: WorkflowDefinition = BaseWorkflow.deserialize_definition(
125
- workflow_definition_file.read(), output_format="yaml"
126
- )
127
- else:
128
- logging.info(f"Definition file {workflow_definition_path} not found, skipping")
129
- return
130
-
131
- # This is convinience feature when user wants to share self contained workflow
132
- # folder as single zip file.
133
- if (workflow_path / "rules").exists():
134
- logging.info(f"Copying rules from {workflow_path / 'rules'} to {self.rules_storage_path} ")
135
- for rule_file in os.listdir(workflow_path / "rules"):
136
- shutil.copy(workflow_path / "rules" / rule_file, self.rules_storage_path)
137
-
138
- self.steps_registry.load_custom_step_classes(workflow_path, workflow_name)
139
- self.register_workflow(BaseWorkflow, workflow_name, workflow_definition)
140
-
141
- except Exception as e:
142
- trace = traceback.format_exc()
143
- logging.error(f"Error loading workflow {workflow_name}: error: {e} trace : {trace}")
144
-
145
- def load_workflows_from_storage(self):
146
- """Loads workflows from disk/storage into memory, initializes and register them in the workflow registry"""
147
-
148
- # set workflow storage path
149
- workflows_storage_path = self.workflows_storage_path
150
-
151
- # set system path to be used when importing individual workflows as python modules
152
- # via importlib.import_module(...)
153
- sys.path.append(str(workflows_storage_path))
154
-
155
- for workflow_name in os.listdir(workflows_storage_path):
156
- self.load_single_workflow_from_storage(workflow_name)
157
-
158
- def register_workflow(self, obj, workflow_name, workflow_definition):
159
- """Register workflow in the workflow registry
160
-
161
- Parameters
162
- ----------
163
- obj : BaseWorkflow
164
- Class of the workflow to be registered
165
- workflow_name : _type_
166
- Name of the workflow to be registered
167
- workflow_definition : _type_
168
- Definition of the workflow to be registered originating from workflow.yaml
169
- """
170
- self.workflow_registry[workflow_name] = obj(workflow_name, self.client, steps_registry=self.steps_registry)
171
- self.workflow_registry[workflow_name].set_definition(workflow_definition)
172
- # Comment: Not entirely sure what is task_builder meant for
173
- # as at first glance it looks like circular import ???
174
- self.workflow_registry[workflow_name].set_task_builder(self.task_builder)
175
- self.workflow_registry[workflow_name].set_default_dataset_id(self.data_set_id)
176
- self.workflow_registry[workflow_name].set_storage_path("transformation_rules", self.rules_storage_path)
177
- self.workflow_registry[workflow_name].set_storage_path("data_store", self.data_store_path)
178
-
179
- def create_workflow_instance(self, template_name: str, add_to_registry: bool = True) -> BaseWorkflow:
180
- new_instance = self.workflow_registry[template_name].copy()
181
- if add_to_registry:
182
- self.ephemeral_instance_registry[new_instance.instance_id] = new_instance
183
- live_workflow_instances.labels(itype="ephemeral").set(len(self.ephemeral_instance_registry))
184
- return new_instance
185
-
186
- def get_workflow_instance(self, instance_id: str) -> BaseWorkflow:
187
- return self.ephemeral_instance_registry[instance_id]
188
-
189
- def delete_workflow_instance(self, instance_id: str):
190
- del self.ephemeral_instance_registry[instance_id]
191
- live_workflow_instances.labels(itype="ephemeral").set(len(self.ephemeral_instance_registry))
192
- return
193
-
194
- def start_workflow_instance(
195
- self, workflow_name: str, step_id: str = "", flow_msg: FlowMessage | None = None, sync: bool | None = None
196
- ) -> WorkflowStartStatus:
197
- retrieved = self.get_workflow(workflow_name)
198
-
199
- if retrieved is None:
200
- return WorkflowStartStatus(
201
- workflow_instance=None, is_success=False, status_text="Workflow not found in registry"
202
- )
203
-
204
- if self._is_workflow_made_of_mixed_steps(retrieved.workflow_steps):
205
- retrieved.state = WorkflowState.FAILED
206
- return WorkflowStartStatus(
207
- workflow_instance=None,
208
- is_success=False,
209
- status_text="Workflow consists of both legacy and current steps. "
210
- "Please update the workflow to use only current steps.",
211
- )
212
-
213
- workflow = retrieved
214
- retrieved_step = workflow.get_trigger_step(step_id)
215
- if retrieved_step is None:
216
- return WorkflowStartStatus(
217
- workflow_instance=None, is_success=False, status_text="Step not found in workflow"
218
- )
219
- trigger_step = retrieved_step
220
- if not trigger_step.trigger:
221
- logging.info(f"Step {step_id} is not a trigger step")
222
- return WorkflowStartStatus(
223
- workflow_instance=None, is_success=False, status_text="Step is not a trigger step"
224
- )
225
- if sync is None:
226
- sync = trigger_step.params.get("sync", "true").lower() == "true"
227
-
228
- max_wait_time = int(trigger_step.params.get("max_wait_time", "30"))
229
- instance_start_method = trigger_step.params.get(
230
- "workflow_start_method", InstanceStartMethod.PERSISTENT_INSTANCE_BLOCKING
231
- )
232
-
233
- logging.info(
234
- f"""----- Starting workflow {workflow_name} , step_id = {step_id} , sync = {sync},
235
- max_wait_time = {max_wait_time}, instance_start_method = {instance_start_method} -----"""
236
- )
237
-
238
- if instance_start_method == InstanceStartMethod.PERSISTENT_INSTANCE_BLOCKING:
239
- live_workflow_instances.labels(itype="persistent").set(len(self.workflow_registry))
240
- # wait until workflow transition to RUNNING state and then start , set max wait time to 30 seconds
241
- start_time = time.perf_counter()
242
- # wait until workflow transition to RUNNING state and then start , set max wait time to 30 seconds.
243
- # The operation is executed in callers thread
244
- while workflow.state == WorkflowState.RUNNING:
245
- logging.info("Existing workflow instance already running , waiting for RUNNING state")
246
- elapsed_time = time.perf_counter() - start_time
247
- if elapsed_time > max_wait_time:
248
- logging.info(
249
- f"Workflow {workflow_name} wait time exceeded . "
250
- f"elapsed time = {elapsed_time}, max wait time = {max_wait_time}"
251
- )
252
- return WorkflowStartStatus(
253
- workflow_instance=None,
254
- is_success=False,
255
- status_text="Workflow instance already running.Wait time exceeded",
256
- )
257
- time.sleep(0.5)
258
- workflow.start(sync=sync, flow_message=flow_msg, start_step_id=step_id)
259
- return WorkflowStartStatus(workflow_instance=workflow, is_success=True, status_text="")
260
-
261
- elif instance_start_method == InstanceStartMethod.PERSISTENT_INSTANCE_NON_BLOCKING:
262
- live_workflow_instances.labels(itype="persistent").set(len(self.workflow_registry))
263
- # start workflow if not already running, skip if already running
264
- if workflow.state == WorkflowState.RUNNING:
265
- return WorkflowStartStatus(
266
- workflow_instance=None, is_success=False, status_text="Workflow instance already running"
267
- )
268
-
269
- workflow.start(sync=sync, flow_message=flow_msg, start_step_id=step_id)
270
- return WorkflowStartStatus(workflow_instance=workflow, is_success=True, status_text="")
271
-
272
- elif instance_start_method == InstanceStartMethod.EPHEMERAL_INSTANCE:
273
- # start new workflow instance in new thread
274
- workflow = self.create_workflow_instance(workflow_name, add_to_registry=True)
275
- workflow.start(sync=sync, delete_after_completion=True, flow_message=flow_msg, start_step_id=step_id)
276
- if sync:
277
- self.delete_workflow_instance(workflow.instance_id)
278
- return WorkflowStartStatus(workflow_instance=workflow, is_success=True, status_text="")
279
-
280
- return WorkflowStartStatus(
281
- workflow_instance=None, is_success=False, status_text="Unsupported workflow start method"
282
- )
283
-
284
- def _is_workflow_made_of_mixed_steps(self, steps: list[WorkflowStepDefinition]):
285
- legacy_steps = 0
286
- current_steps = 0
287
- for step in steps:
288
- if step.method in self.steps_registry.categorized_steps["legacy"]:
289
- legacy_steps += 1
290
- if step.method in self.steps_registry.categorized_steps["current"]:
291
- current_steps += 1
292
- return legacy_steps > 0 and current_steps > 0
@@ -1,203 +0,0 @@
1
- import sys
2
- from typing import Any
3
-
4
- if sys.version_info >= (3, 11):
5
- from enum import StrEnum
6
- else:
7
- from backports.strenum import StrEnum
8
-
9
- from pydantic import BaseModel, Field, field_validator
10
-
11
-
12
- class WorkflowState(StrEnum):
13
- CREATED = "CREATED"
14
- RUNNING = "RUNNING"
15
- RUNNING_WAITING = "RUNNING_WAITING"
16
- COMPLETED = "COMPLETED"
17
- FAILED = "FAILED"
18
- EXPIRED = "EXPIRED"
19
- UNKNOWN = "UNKNOWN"
20
-
21
-
22
- class StepExecutionStatus(StrEnum):
23
- SUCCESS = "COMPLETED"
24
- FAILED = "FAILED"
25
- SKIPPED = "SKIPPED"
26
- STARTED = "STARTED"
27
- UNKNOWN = "UNKNOWN"
28
- ABORT_AND_FAIL = "ABORT_AND_FAIL"
29
-
30
-
31
- class InstanceStartMethod(StrEnum):
32
- PERSISTENT_INSTANCE_NON_BLOCKING = "persistent_non_blocking"
33
- PERSISTENT_INSTANCE_BLOCKING = "persistent_blocking"
34
- EPHEMERAL_INSTANCE = "ephemeral_instance"
35
-
36
-
37
- class WorkflowStartException(Exception):
38
- pass
39
-
40
-
41
- class FlowMessage(BaseModel):
42
- """A message that can be sent between steps in a workflow.It's the only parameter step takes as input."""
43
-
44
- payload: Any = None # The payload of the message
45
- headers: dict[str, str] | None = None # The headers of the message
46
- output_text: str | None = None # The output text of the step that is captured in the execution log
47
- error_text: str | None = None # The error text of the step that is captured in the execution log
48
- next_step_ids: list[str] | None = (
49
- None # If set, the workflow will skip default route and go to the next step in the list
50
- )
51
- step_execution_status: StepExecutionStatus = StepExecutionStatus.UNKNOWN # The status of the step execution
52
-
53
-
54
- class StepType(StrEnum):
55
- PYSTEP = "pystep"
56
- STD_STEP = "stdstep"
57
- START_WORKFLOW_TASK_STEP = "start_workflow_task_step" # Call a workflow from another workflow
58
- CONTAINER_TASK_STEP = "container_step" # TODO: implement
59
- CLI_TASK_STEP = "cli_step" # TODO: implement
60
- HTTP_TRIGGER = "http_trigger"
61
- TIME_TRIGGER = "time_trigger"
62
- WAIT_FOR_EVENT = "wait_for_event" # TODO: implement
63
- EVENT_TRIGGER = "event_trigger" # TODO: implement
64
-
65
-
66
- class UIConfig(BaseModel):
67
- pos_x: int = 0
68
- pos_y: int = 0
69
-
70
-
71
- class WorkflowConfigItem(BaseModel):
72
- name: str
73
- value: str | None = None
74
- label: str | None = None
75
- type: str | None = None
76
- required: bool = False
77
- options: list[str] | None = None
78
- group: str | None = None
79
-
80
-
81
- class WorkflowStepDefinition(BaseModel):
82
- id: str
83
- label: str | None = None
84
- stype: str = StepType.PYSTEP
85
- description: str | None = None
86
- method: str | None = None
87
- enabled: bool = True
88
- system_component_id: str | None = None
89
- trigger: bool = False
90
- transition_to: list[str] | None = None
91
- ui_config: UIConfig = UIConfig()
92
- params: dict[str, str] = Field(default_factory=dict) # System parameters
93
- configs: dict[str, Any] = Field(default_factory=dict) # Step configurations
94
- complex_configs: dict[str, Any] = Field(default_factory=dict) # Complex step configurations
95
- max_retries: int = 0
96
- retry_delay: int = 3
97
- auto_workflow_cleanup: bool = False
98
-
99
- @field_validator("configs", "params", mode="before")
100
- def none_as_empty_dict(cls, value):
101
- if value is None:
102
- return {}
103
- return value
104
-
105
-
106
- class WorkflowSystemComponent(BaseModel):
107
- # Container for steps
108
- id: str
109
- label: str
110
- transition_to: list[str] | None = None
111
- description: str | None = None
112
- ui_config: UIConfig = UIConfig()
113
-
114
-
115
- class WorkflowDefinition(BaseModel):
116
- """Workflow definition"""
117
-
118
- name: str
119
- description: str | None = None
120
- implementation_module: str | None = None
121
- steps: list[WorkflowStepDefinition] = Field(default_factory=list)
122
- system_components: list[WorkflowSystemComponent] = Field(default_factory=list)
123
- configs: list[WorkflowConfigItem] = Field(default_factory=list)
124
-
125
- def get_config_item(self, name: str) -> WorkflowConfigItem | None:
126
- for config in self.configs:
127
- if config.name == name:
128
- return config
129
- return None
130
-
131
- def upsert_config_item(self, config_item: WorkflowConfigItem) -> None:
132
- for config in self.configs:
133
- if config.name == config_item.name:
134
- config.value = config_item.value
135
- config.label = config_item.label
136
- config.type = config_item.type
137
- config.required = config_item.required
138
- config.options = config_item.options
139
- config.group = config_item.group
140
- return
141
- self.configs.append(config_item)
142
-
143
-
144
- class WorkflowStepEvent(BaseModel):
145
- """Workflow step event represent a single step execution"""
146
-
147
- id: str
148
- system_component_id: str | None = None
149
- state: StepExecutionStatus
150
- elapsed_time: float
151
- timestamp: str
152
- error: str | None = None
153
- output_text: str | None = None
154
- data: Any = None
155
-
156
-
157
- class WorkflowFullStateReport(BaseModel):
158
- """Workflow state report is complete log of workflow execution"""
159
-
160
- workflow_name: str | None = None
161
- workflow_version: str | None = None
162
- run_id: str | None = None
163
- state: WorkflowState
164
- start_time: int | None = None
165
- end_time: int | None = None
166
- elapsed_time: float = 0
167
- last_error: str | None = None
168
- execution_log: list[WorkflowStepEvent]
169
- last_updated_time: int | None = None
170
-
171
- @field_validator("start_time", "end_time", mode="before")
172
- def float_to_int(cls, value):
173
- if isinstance(value, float):
174
- return int(value)
175
- return value
176
-
177
-
178
- class WorkflowConfigs(BaseModel):
179
- """Workflow configs"""
180
-
181
- configs: list[WorkflowConfigItem] = []
182
-
183
- def get_config_item(self, config_name: str) -> WorkflowConfigItem | None:
184
- return next((item for item in self.configs if item.name == config_name), None)
185
-
186
- def set_config_item(self, config_item: WorkflowConfigItem):
187
- for item in self.configs:
188
- if item.name == config_item.name:
189
- item.value = config_item.value
190
- return
191
- self.configs.append(config_item)
192
-
193
- def get_config_group_values_by_name(
194
- self, group_name: str, remove_group_prefix: bool = True
195
- ) -> dict[str, str | None]:
196
- return {
197
- (item.name.removeprefix(item.group) if remove_group_prefix else item.name): item.value
198
- for item in self.configs
199
- if item.group == group_name
200
- }
201
-
202
- def get_config_item_value(self, config_name: str, default_value=None) -> str | None:
203
- return config.value if (config := self.get_config_item(config_name)) else default_value
File without changes
@@ -1,109 +0,0 @@
1
- from pathlib import Path
2
-
3
- from cognite.client import CogniteClient
4
- from cognite.client.data_classes import (
5
- Asset,
6
- AssetUpdate,
7
- Relationship,
8
- RelationshipUpdate,
9
- )
10
- from cognite.client.data_classes.data_modeling import EdgeApply, NodeApply
11
-
12
- from cognite.neat._rules.models import (
13
- DMSRules,
14
- InformationRules,
15
- )
16
- from cognite.neat._store import NeatGraphStore
17
- from cognite.neat._workflows.steps.step_model import DataContract
18
-
19
-
20
- class MultiRuleData(DataContract):
21
- information: InformationRules | None = None
22
- dms: DMSRules | None = None
23
-
24
- @classmethod
25
- def from_rules(cls, rules: InformationRules | DMSRules):
26
- if isinstance(rules, InformationRules):
27
- return cls(information=rules)
28
- elif isinstance(rules, DMSRules):
29
- return cls(dms=rules)
30
- else:
31
- raise ValueError(f"Unsupported rules type {type(rules)}")
32
-
33
-
34
- class PathData(DataContract):
35
- """
36
- This represents the path to the excel file.
37
-
38
- Args:
39
- excel_file_path: The path to the excel file.
40
- """
41
-
42
- excel_file_path: Path
43
-
44
-
45
- class NeatGraph(DataContract):
46
- """
47
- This represents the neat graph.
48
-
49
- Args:
50
- graph: The neat graph store.
51
- """
52
-
53
- graph: NeatGraphStore
54
-
55
-
56
- class ClientData(DataContract):
57
- """
58
- This represents an instantiated CogniteClient object.
59
-
60
- Args:
61
- client: The CogniteClient object.
62
- """
63
-
64
- client: CogniteClient
65
-
66
-
67
- class CategorizedAssets(DataContract):
68
- """ "
69
- This represents the categorized assets.
70
-
71
- Args:
72
- assets: The categorized assets.
73
- """
74
-
75
- assets: dict[str, list[Asset | AssetUpdate]]
76
-
77
-
78
- class CategorizedRelationships(DataContract):
79
- """
80
- This represents the categorized relationships.
81
-
82
- Args:
83
- relationships: The categorized relationships.
84
-
85
- """
86
-
87
- relationships: dict[str, list[Relationship] | list[RelationshipUpdate]]
88
-
89
-
90
- class Nodes(DataContract):
91
- """
92
- This represents nodes.
93
-
94
- Args:
95
- nodes: list of nodes.
96
- """
97
-
98
- nodes: list[NodeApply]
99
-
100
-
101
- class Edges(DataContract):
102
- """
103
- This represents edges.
104
-
105
- Args:
106
- edges: list of edges.
107
- """
108
-
109
- edges: list[EdgeApply]
File without changes
@@ -1,6 +0,0 @@
1
- from .rules_importer import * # noqa
2
- from .rules_validator import * # noqa
3
- from .rules_exporter import * # noqa
4
- from .graph_store import * # noqa
5
- from .graph_loader import * # noqa
6
- from .graph_extractor import * # noqa