cognite-neat 0.88.1__py3-none-any.whl → 0.88.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of cognite-neat might be problematic. Click here for more details.

Files changed (62) hide show
  1. cognite/neat/_version.py +1 -1
  2. cognite/neat/exceptions.py +2 -2
  3. cognite/neat/graph/loaders/_base.py +4 -4
  4. cognite/neat/graph/loaders/_rdf2asset.py +12 -14
  5. cognite/neat/graph/loaders/_rdf2dms.py +14 -10
  6. cognite/neat/issues/__init__.py +16 -0
  7. cognite/neat/{issues.py → issues/_base.py} +73 -5
  8. cognite/neat/issues/errors/external.py +21 -0
  9. cognite/neat/issues/errors/properties.py +75 -0
  10. cognite/neat/issues/errors/resources.py +123 -0
  11. cognite/neat/issues/errors/schema.py +0 -0
  12. cognite/neat/{rules/issues → issues}/formatters.py +9 -9
  13. cognite/neat/issues/neat_warnings/__init__.py +2 -0
  14. cognite/neat/issues/neat_warnings/identifier.py +27 -0
  15. cognite/neat/issues/neat_warnings/models.py +22 -0
  16. cognite/neat/issues/neat_warnings/properties.py +77 -0
  17. cognite/neat/issues/neat_warnings/resources.py +125 -0
  18. cognite/neat/rules/exporters/_rules2dms.py +3 -2
  19. cognite/neat/rules/exporters/_validation.py +2 -2
  20. cognite/neat/rules/importers/__init__.py +7 -3
  21. cognite/neat/rules/importers/_base.py +3 -3
  22. cognite/neat/rules/importers/_dms2rules.py +39 -18
  23. cognite/neat/rules/importers/_dtdl2rules/dtdl_converter.py +44 -53
  24. cognite/neat/rules/importers/_dtdl2rules/dtdl_importer.py +6 -5
  25. cognite/neat/rules/importers/_rdf/__init__.py +0 -0
  26. cognite/neat/rules/importers/_rdf/_imf2rules/__init__.py +3 -0
  27. cognite/neat/rules/importers/_rdf/_imf2rules/_imf2classes.py +82 -0
  28. cognite/neat/rules/importers/_rdf/_imf2rules/_imf2metadata.py +34 -0
  29. cognite/neat/rules/importers/_rdf/_imf2rules/_imf2properties.py +123 -0
  30. cognite/neat/rules/importers/{_owl2rules/_owl2rules.py → _rdf/_imf2rules/_imf2rules.py} +15 -11
  31. cognite/neat/rules/importers/{_inference2rules.py → _rdf/_inference2rules.py} +1 -1
  32. cognite/neat/rules/importers/_rdf/_owl2rules/_owl2classes.py +57 -0
  33. cognite/neat/rules/importers/_rdf/_owl2rules/_owl2metadata.py +68 -0
  34. cognite/neat/rules/importers/_rdf/_owl2rules/_owl2properties.py +59 -0
  35. cognite/neat/rules/importers/_rdf/_owl2rules/_owl2rules.py +76 -0
  36. cognite/neat/rules/importers/_rdf/_shared.py +586 -0
  37. cognite/neat/rules/importers/_spreadsheet2rules.py +1 -1
  38. cognite/neat/rules/importers/_yaml2rules.py +2 -1
  39. cognite/neat/rules/issues/__init__.py +1 -5
  40. cognite/neat/rules/issues/base.py +2 -21
  41. cognite/neat/rules/issues/dms.py +0 -134
  42. cognite/neat/rules/issues/spreadsheet.py +3 -3
  43. cognite/neat/rules/models/_types/_field.py +5 -2
  44. cognite/neat/rules/models/asset/_validation.py +1 -1
  45. cognite/neat/rules/models/dms/_schema.py +53 -30
  46. cognite/neat/rules/models/dms/_validation.py +2 -2
  47. cognite/neat/rules/models/entities.py +3 -0
  48. cognite/neat/rules/models/information/_validation.py +1 -1
  49. cognite/neat/workflows/steps/lib/current/rules_importer.py +73 -1
  50. cognite/neat/workflows/steps/lib/current/rules_validator.py +19 -7
  51. {cognite_neat-0.88.1.dist-info → cognite_neat-0.88.2.dist-info}/METADATA +1 -1
  52. {cognite_neat-0.88.1.dist-info → cognite_neat-0.88.2.dist-info}/RECORD +57 -42
  53. cognite/neat/graph/issues/loader.py +0 -104
  54. cognite/neat/rules/importers/_owl2rules/_owl2classes.py +0 -215
  55. cognite/neat/rules/importers/_owl2rules/_owl2metadata.py +0 -209
  56. cognite/neat/rules/importers/_owl2rules/_owl2properties.py +0 -203
  57. cognite/neat/rules/issues/importing.py +0 -423
  58. /cognite/neat/{graph/issues → issues/errors}/__init__.py +0 -0
  59. /cognite/neat/rules/importers/{_owl2rules → _rdf/_owl2rules}/__init__.py +0 -0
  60. {cognite_neat-0.88.1.dist-info → cognite_neat-0.88.2.dist-info}/LICENSE +0 -0
  61. {cognite_neat-0.88.1.dist-info → cognite_neat-0.88.2.dist-info}/WHEEL +0 -0
  62. {cognite_neat-0.88.1.dist-info → cognite_neat-0.88.2.dist-info}/entry_points.txt +0 -0
@@ -10,13 +10,6 @@ __all__ = [
10
10
  "DMSSchemaError",
11
11
  "DMSSchemaWarning",
12
12
  "IncompleteSchemaError",
13
- "MissingSpaceError",
14
- "MissingContainerError",
15
- "MissingContainerPropertyError",
16
- "MissingViewError",
17
- "MissingParentViewError",
18
- "MissingSourceViewError",
19
- "MissingEdgeViewError",
20
13
  "DirectRelationMissingSourceWarning",
21
14
  "ViewModelVersionNotMatchingWarning",
22
15
  "ViewModelSpaceNotMatchingWarning",
@@ -87,133 +80,6 @@ class IncompleteSchemaError(DMSSchemaError):
87
80
  return output
88
81
 
89
82
 
90
- @dataclass(frozen=True)
91
- class MissingSpaceError(DMSSchemaError):
92
- description = "The spaced referred to by the Container/View/Node/Edge/DataModel does not exist"
93
- fix = "Create the space"
94
- space: str
95
- referred_by: dm.ContainerId | dm.ViewId | dm.NodeId | dm.EdgeId | dm.DataModelId
96
-
97
- def message(self) -> str:
98
- return f"The space {self.space} referred to by {self.referred_by} does not exist"
99
-
100
- def dump(self) -> dict[str, Any]:
101
- output = super().dump()
102
- output["space"] = self.space
103
- output["referred_by"] = self.referred_by
104
- return output
105
-
106
-
107
- @dataclass(frozen=True)
108
- class MissingContainerError(DMSSchemaError):
109
- description = "The container referred to by the View does not exist"
110
- fix = "Create the container"
111
- error_name: ClassVar[str] = "MissingContainer"
112
- container: dm.ContainerId
113
- referred_by: dm.ViewId | dm.ContainerId
114
-
115
- def message(self) -> str:
116
- return f"The container {self.container} referred to by {self.referred_by} does not exist"
117
-
118
- def dump(self) -> dict[str, Any]:
119
- output = super().dump()
120
- output["container"] = self.container
121
- output["referred_by"] = self.referred_by
122
- return output
123
-
124
-
125
- @dataclass(frozen=True)
126
- class MissingContainerPropertyError(DMSSchemaError):
127
- description = "The property referred to by the View does not exist in the container"
128
- fix = "Create the property"
129
- error_name: ClassVar[str] = "MissingContainerProperty"
130
- container: dm.ContainerId
131
- property: str
132
- referred_by: dm.ViewId
133
-
134
- def message(self) -> str:
135
- return (
136
- f"The property {self.property} referred to by the container {self.container} "
137
- f"does not exist in {self.referred_by}"
138
- )
139
-
140
- def dump(self) -> dict[str, Any]:
141
- output = super().dump()
142
- output["container"] = self.container
143
- output["property"] = self.property
144
- output["referred_by"] = self.referred_by
145
- return output
146
-
147
-
148
- @dataclass(frozen=True)
149
- class MissingViewError(DMSSchemaError):
150
- description = "The view referred to by the View/DataModel does not exist"
151
- fix = "Create the view"
152
- error_name: ClassVar[str] = "MissingView"
153
- view: dm.ViewId
154
- referred_by: dm.DataModelId | dm.ViewId
155
-
156
- def message(self) -> str:
157
- return f"The view {self.view} referred to by {self.referred_by} does not exist"
158
-
159
- def dump(self) -> dict[str, Any]:
160
- output = super().dump()
161
- output["view"] = self.view
162
- output["referred_by"] = self.referred_by
163
- return output
164
-
165
-
166
- @dataclass(frozen=True)
167
- class MissingParentViewError(MissingViewError):
168
- description = "The parent view referred to by the View does not exist"
169
- fix = "Create the parent view"
170
- error_name: ClassVar[str] = "MissingParentView"
171
- referred_by: dm.ViewId
172
-
173
- def message(self) -> str:
174
- return f"The parent view {self.view} referred to by {self.referred_by} does not exist"
175
-
176
- def dump(self) -> dict[str, Any]:
177
- output = super().dump()
178
- output["referred_by"] = self.referred_by
179
- return output
180
-
181
-
182
- @dataclass(frozen=True)
183
- class MissingSourceViewError(MissingViewError):
184
- description = "The source view referred to by the View does not exist"
185
- fix = "Create the source view"
186
- error_name: ClassVar[str] = "MissingSourceView"
187
- property: str
188
- referred_by: dm.ViewId
189
-
190
- def message(self) -> str:
191
- return f"The source view {self.view} referred to by {self.referred_by}.{self.property} does not exist"
192
-
193
- def dump(self) -> dict[str, Any]:
194
- output = super().dump()
195
- output["property"] = self.property
196
- return output
197
-
198
-
199
- @dataclass(frozen=True)
200
- class MissingEdgeViewError(MissingViewError):
201
- description = "The edge view referred to by the View does not exist"
202
- fix = "Create the edge view"
203
- error_name: ClassVar[str] = "MissingEdgeView"
204
- property: str
205
- referred_by: dm.ViewId
206
-
207
- def message(self) -> str:
208
- return f"The edge view {self.view} referred to by {self.referred_by}.{self.property} does not exist"
209
-
210
- def dump(self) -> dict[str, Any]:
211
- output = super().dump()
212
- output["property"] = self.property
213
- output["referred_by"] = self.referred_by
214
- return output
215
-
216
-
217
83
  @dataclass(frozen=True)
218
84
  class DuplicatedViewInDataModelError(DMSSchemaError):
219
85
  description = "The view is duplicated in the DataModel"
@@ -9,7 +9,7 @@ from cognite.client.data_classes.data_modeling import ContainerId, ViewId
9
9
  from pydantic_core import ErrorDetails
10
10
  from rdflib import Namespace
11
11
 
12
- from cognite.neat.issues import MultiValueError
12
+ from cognite.neat.issues import MultiValueError, NeatError
13
13
  from cognite.neat.utils.spreadsheet import SpreadsheetRead
14
14
 
15
15
  from .base import DefaultPydanticError, NeatValidationError
@@ -59,8 +59,8 @@ class InvalidSheetError(NeatValidationError, ABC):
59
59
  errors: list[ErrorDetails],
60
60
  read_info_by_sheet: dict[str, SpreadsheetRead] | None = None,
61
61
  **kwargs: Any,
62
- ) -> "list[NeatValidationError]":
63
- output: list[NeatValidationError] = []
62
+ ) -> "list[NeatError]":
63
+ output: list[NeatError] = []
64
64
  for error in errors:
65
65
  if raised_error := error.get("ctx", {}).get("error"):
66
66
  if isinstance(raised_error, MultiValueError):
@@ -16,7 +16,7 @@ from pydantic import (
16
16
  from pydantic.functional_serializers import PlainSerializer
17
17
  from pydantic_core import PydanticCustomError
18
18
 
19
- from cognite.neat.rules.issues.importing import MoreThanOneNonAlphanumericCharacterWarning
19
+ from cognite.neat.issues.neat_warnings.identifier import RegexViolationWarning
20
20
  from cognite.neat.rules.issues.spreadsheet import RegexViolationError
21
21
  from cognite.neat.utils.regex_patterns import (
22
22
  PATTERNS,
@@ -91,7 +91,10 @@ def _property_validation(value: str) -> str:
91
91
  if not PATTERNS.property_id_compliance.match(value):
92
92
  _raise(RegexViolationError(value, PROPERTY_ID_COMPLIANCE_REGEX).as_pydantic_exception())
93
93
  if PATTERNS.more_than_one_alphanumeric.search(value):
94
- warnings.warn(MoreThanOneNonAlphanumericCharacterWarning("property", value), stacklevel=2)
94
+ warnings.warn(
95
+ RegexViolationWarning(value, PROPERTY_ID_COMPLIANCE_REGEX, "property", "MoreThanOneNonAlphanumeric"),
96
+ stacklevel=2,
97
+ )
95
98
  return value
96
99
 
97
100
 
@@ -1,8 +1,8 @@
1
1
  from graphlib import CycleError
2
2
  from typing import cast
3
3
 
4
+ from cognite.neat.issues import IssueList
4
5
  from cognite.neat.rules import issues
5
- from cognite.neat.rules.issues.base import IssueList
6
6
  from cognite.neat.rules.models._base import SheetList
7
7
  from cognite.neat.rules.models.asset._rules import AssetProperty, AssetRules
8
8
  from cognite.neat.rules.models.entities import AssetEntity, AssetFields, ClassEntity
@@ -25,20 +25,16 @@ from cognite.client.data_classes.data_modeling.views import (
25
25
  )
26
26
  from cognite.client.data_classes.transformations.common import Edges, EdgeType, Nodes, ViewInfo
27
27
 
28
+ from cognite.neat.issues import NeatError
29
+ from cognite.neat.issues.errors.properties import ReferredPropertyNotFoundError
30
+ from cognite.neat.issues.errors.resources import ReferredResourceNotFoundError
31
+ from cognite.neat.issues.neat_warnings.resources import FailedLoadingResourcesWarning, MultipleResourcesWarning
28
32
  from cognite.neat.rules import issues
29
33
  from cognite.neat.rules.issues.dms import (
30
34
  ContainerPropertyUsedMultipleTimesError,
31
35
  DirectRelationMissingSourceWarning,
32
- DMSSchemaError,
33
36
  DuplicatedViewInDataModelError,
34
37
  IncompleteSchemaError,
35
- MissingContainerError,
36
- MissingContainerPropertyError,
37
- MissingEdgeViewError,
38
- MissingParentViewError,
39
- MissingSourceViewError,
40
- MissingSpaceError,
41
- MissingViewError,
42
38
  MissingViewInModelWarning,
43
39
  )
44
40
  from cognite.neat.rules.models.data_types import _DATA_TYPE_BY_DMS_TYPE
@@ -168,14 +164,10 @@ class DMSSchema:
168
164
  connection_referenced_view_ids |= cls._connection_references(view)
169
165
  connection_referenced_view_ids = connection_referenced_view_ids - existing_view_ids
170
166
  if connection_referenced_view_ids:
171
- warnings.warn(
172
- MissingViewInModelWarning(data_model.as_id(), connection_referenced_view_ids), UserWarning, stacklevel=2
173
- )
167
+ warnings.warn(MissingViewInModelWarning(data_model.as_id(), connection_referenced_view_ids), stacklevel=2)
174
168
  connection_referenced_views = view_loader.retrieve(list(connection_referenced_view_ids))
175
169
  if failed := connection_referenced_view_ids - set(connection_referenced_views.as_ids()):
176
- warnings.warn(
177
- issues.importing.FailedImportWarning({repr(v) for v in failed}), UserWarning, stacklevel=2
178
- )
170
+ warnings.warn(FailedLoadingResourcesWarning[dm.ViewId](frozenset(failed), "View"), stacklevel=2)
179
171
  views.extend(connection_referenced_views)
180
172
 
181
173
  # We need to include parent views in the schema to make sure that the schema is valid.
@@ -432,8 +424,9 @@ class DMSSchema:
432
424
  if attr.name == "data_model":
433
425
  if isinstance(items, list) and len(items) > 1:
434
426
  warnings.warn(
435
- issues.importing.MultipleDataModelsWarning(
436
- [item.get("externalId", "Unknown") for item in items]
427
+ MultipleResourcesWarning[str](
428
+ frozenset([item.get("externalId", "Unknown") for item in items]),
429
+ "DataModel",
437
430
  ),
438
431
  stacklevel=2,
439
432
  )
@@ -522,8 +515,8 @@ class DMSSchema:
522
515
  else:
523
516
  raise ValueError(f"Cannot sort item of type {type(item)}")
524
517
 
525
- def validate(self) -> list[DMSSchemaError]:
526
- errors: set[DMSSchemaError] = set()
518
+ def validate(self) -> list[NeatError]:
519
+ errors: set[NeatError] = set()
527
520
  defined_spaces = self.spaces.copy()
528
521
  defined_containers = self.containers.copy()
529
522
  defined_views = self.views.copy()
@@ -535,28 +528,42 @@ class DMSSchema:
535
528
 
536
529
  for container in self.containers.values():
537
530
  if container.space not in defined_spaces:
538
- errors.add(MissingSpaceError(space=container.space, referred_by=container.as_id()))
531
+ errors.add(
532
+ ReferredResourceNotFoundError[str, dm.ContainerId](
533
+ container.space, "Space", container.as_id(), "Container"
534
+ )
535
+ )
539
536
 
540
537
  for view in self.views.values():
541
538
  view_id = view.as_id()
542
539
  if view.space not in defined_spaces:
543
- errors.add(MissingSpaceError(space=view.space, referred_by=view_id))
540
+ errors.add(ReferredResourceNotFoundError[str, dm.ViewId](view.space, "Space", view_id, "View"))
544
541
 
545
542
  for parent in view.implements or []:
546
543
  if parent not in defined_views:
547
- errors.add(MissingParentViewError(view=parent, referred_by=view_id))
544
+ errors.add(
545
+ ReferredPropertyNotFoundError[dm.ViewId, dm.ViewId](
546
+ parent, "View", view_id, "View", property_name="implements"
547
+ )
548
+ )
548
549
 
549
550
  for prop_name, prop in (view.properties or {}).items():
550
551
  if isinstance(prop, dm.MappedPropertyApply):
551
552
  ref_container = defined_containers.get(prop.container)
552
553
  if ref_container is None:
553
- errors.add(MissingContainerError(container=prop.container, referred_by=view_id))
554
+ errors.add(
555
+ ReferredResourceNotFoundError[dm.ContainerId, dm.ViewId](
556
+ prop.container, "Container", view_id, "View"
557
+ )
558
+ )
554
559
  elif prop.container_property_identifier not in ref_container.properties:
555
560
  errors.add(
556
- MissingContainerPropertyError(
557
- container=prop.container,
558
- property=prop.container_property_identifier,
559
- referred_by=view_id,
561
+ ReferredPropertyNotFoundError[dm.ContainerId, dm.ViewId](
562
+ prop.container,
563
+ "Container",
564
+ view_id,
565
+ "View",
566
+ property_name=prop.container_property_identifier,
560
567
  )
561
568
  )
562
569
  else:
@@ -568,14 +575,22 @@ class DMSSchema:
568
575
  )
569
576
 
570
577
  if isinstance(prop, dm.EdgeConnectionApply) and prop.source not in defined_views:
571
- errors.add(MissingSourceViewError(view=prop.source, property=prop_name, referred_by=view_id))
578
+ errors.add(
579
+ ReferredPropertyNotFoundError[dm.ViewId, dm.ViewId](
580
+ prop.source, "View", view_id, "View", property_name=prop_name
581
+ )
582
+ )
572
583
 
573
584
  if (
574
585
  isinstance(prop, dm.EdgeConnectionApply)
575
586
  and prop.edge_source is not None
576
587
  and prop.edge_source not in defined_views
577
588
  ):
578
- errors.add(MissingEdgeViewError(view=prop.edge_source, property=prop_name, referred_by=view_id))
589
+ errors.add(
590
+ ReferredPropertyNotFoundError[dm.ViewId, dm.ViewId](
591
+ prop.edge_source, "View", view_id, "View", property_name=prop_name
592
+ )
593
+ )
579
594
 
580
595
  # This allows for multiple view properties to be mapped to the same container property,
581
596
  # as long as they have different external_id, otherwise this will lead to raising
@@ -610,13 +625,21 @@ class DMSSchema:
610
625
  if self.data_model:
611
626
  model = self.data_model
612
627
  if model.space not in defined_spaces:
613
- errors.add(MissingSpaceError(space=model.space, referred_by=model.as_id()))
628
+ errors.add(
629
+ ReferredResourceNotFoundError[str, dm.DataModelId](
630
+ model.space, "Space", model.as_id(), "Data Model"
631
+ )
632
+ )
614
633
 
615
634
  view_counts: dict[dm.ViewId, int] = defaultdict(int)
616
635
  for view_id_or_class in model.views or []:
617
636
  view_id = view_id_or_class if isinstance(view_id_or_class, dm.ViewId) else view_id_or_class.as_id()
618
637
  if view_id not in defined_views:
619
- errors.add(MissingViewError(referred_by=model.as_id(), view=view_id))
638
+ errors.add(
639
+ ReferredResourceNotFoundError[dm.ViewId, dm.DataModelId](
640
+ view_id, "View", model.as_id(), "DataModel"
641
+ )
642
+ )
620
643
  view_counts[view_id] += 1
621
644
 
622
645
  for view_id, count in view_counts.items():
@@ -3,8 +3,8 @@ from typing import Any, ClassVar
3
3
 
4
4
  from cognite.client import data_modeling as dm
5
5
 
6
+ from cognite.neat.issues import IssueList, NeatIssueList
6
7
  from cognite.neat.rules import issues
7
- from cognite.neat.rules.issues import IssueList
8
8
  from cognite.neat.rules.models._base import DataModelType, ExtensionCategory, SchemaCompleteness
9
9
  from cognite.neat.rules.models._constants import DMS_CONTAINER_SIZE_LIMIT
10
10
  from cognite.neat.rules.models.data_types import DataType
@@ -31,7 +31,7 @@ class DMSPostValidation:
31
31
  self.views = rules.views
32
32
  self.issue_list = IssueList()
33
33
 
34
- def validate(self) -> IssueList:
34
+ def validate(self) -> NeatIssueList:
35
35
  self._validate_raw_filter()
36
36
  self._consistent_container_properties()
37
37
 
@@ -418,6 +418,9 @@ class ViewEntity(DMSVersionedEntity[ViewId]):
418
418
  ) -> ViewId:
419
419
  return ViewId(space=self.space, external_id=self.external_id, version=self.version)
420
420
 
421
+ def to_property_id(self, property_id: str) -> PropertyId:
422
+ return PropertyId(source=self.as_id(), property=property_id)
423
+
421
424
  @classmethod
422
425
  def from_id(cls, id: ViewId, default_version: str | None = None) -> "ViewEntity":
423
426
  if id.version is not None:
@@ -2,8 +2,8 @@ import itertools
2
2
  from collections import Counter
3
3
  from typing import cast
4
4
 
5
+ from cognite.neat.issues import IssueList
5
6
  from cognite.neat.rules import issues
6
- from cognite.neat.rules.issues import IssueList
7
7
  from cognite.neat.rules.models._base import DataModelType, SchemaCompleteness
8
8
  from cognite.neat.rules.models.entities import ClassEntity, EntityTypes, UnknownEntity
9
9
  from cognite.neat.utils.rdf_ import get_inheritance_path
@@ -5,8 +5,8 @@ from typing import ClassVar
5
5
  from cognite.client import CogniteClient
6
6
  from cognite.client.data_classes.data_modeling import DataModelId
7
7
 
8
+ from cognite.neat.issues.formatters import FORMATTER_BY_NAME
8
9
  from cognite.neat.rules import importers
9
- from cognite.neat.rules.issues.formatters import FORMATTER_BY_NAME
10
10
  from cognite.neat.rules.models import RoleTypes
11
11
  from cognite.neat.rules.models.entities import DataModelEntity, DMSUnknownEntity
12
12
  from cognite.neat.workflows._exceptions import StepNotInitialized
@@ -19,6 +19,7 @@ CATEGORY = __name__.split(".")[-1].replace("_", " ").title()
19
19
  __all__ = [
20
20
  "ExcelToRules",
21
21
  "OntologyToRules",
22
+ "IMFToRules",
22
23
  "DMSToRules",
23
24
  "RulesInferenceFromRdfFile",
24
25
  ]
@@ -162,6 +163,77 @@ class OntologyToRules(Step):
162
163
  return FlowMessage(output_text=output_text), MultiRuleData.from_rules(rules)
163
164
 
164
165
 
166
+ class IMFToRules(Step):
167
+ """This step import rules from the IMF-types and validates them."""
168
+
169
+ description = "This step imports rules from an RDF file "
170
+ version = "private-beta"
171
+ category = CATEGORY
172
+ configurables: ClassVar[list[Configurable]] = [
173
+ Configurable(
174
+ name="File name",
175
+ value="",
176
+ label="""Full file name of the RDF-file containing the IMF-types in the rules folder.
177
+ If not provided, step will attempt to get file name from payload
178
+ of 'File Uploader' step (if exist)""",
179
+ ),
180
+ Configurable(
181
+ name="Report formatter",
182
+ value=next(iter(FORMATTER_BY_NAME.keys())),
183
+ label="The format of the report for the validation of the rules",
184
+ options=list(FORMATTER_BY_NAME),
185
+ ),
186
+ Configurable(
187
+ name="Role",
188
+ value="infer",
189
+ label="For what role Rules are intended?",
190
+ options=["infer", *RoleTypes.__members__.keys()],
191
+ ),
192
+ ]
193
+
194
+ def run(self, flow_message: FlowMessage) -> (FlowMessage, MultiRuleData): # type: ignore[syntax, override]
195
+ if self.configs is None or self.data_store_path is None:
196
+ raise StepNotInitialized(type(self).__name__)
197
+
198
+ file_name = self.configs.get("File name", None)
199
+
200
+ full_path = flow_message.payload.get("full_path", None) if flow_message.payload else None
201
+
202
+ if file_name:
203
+ rules_file_path = self.config.rules_store_path / file_name
204
+
205
+ elif full_path:
206
+ rules_file_path = full_path
207
+ else:
208
+ error_text = "Expected either 'File name' in the step config or 'File uploader' step uploading Excel Rules."
209
+ return FlowMessage(error_text=error_text, step_execution_status=StepExecutionStatus.ABORT_AND_FAIL)
210
+
211
+ # if role is None, it will be inferred from the rules file
212
+ role = self.configs.get("Role")
213
+ role_enum = None
214
+ if role != "infer" and role is not None:
215
+ role_enum = RoleTypes[role]
216
+
217
+ ontology_importer = importers.IMFImporter(filepath=rules_file_path)
218
+ rules, issues = ontology_importer.to_rules(errors="continue", role=role_enum)
219
+
220
+ if rules is None:
221
+ output_dir = self.config.staging_path
222
+ report_writer = FORMATTER_BY_NAME[self.configs["Report formatter"]]()
223
+ report_writer.write_to_file(issues, file_or_dir_path=output_dir)
224
+ report_file = report_writer.default_file_name
225
+ error_text = (
226
+ "<p></p>"
227
+ f'<a href="/data/staging/{report_file}?{time.time()}" '
228
+ f'target="_blank">Failed to validate rules, click here for report</a>'
229
+ )
230
+ return FlowMessage(error_text=error_text, step_execution_status=StepExecutionStatus.ABORT_AND_FAIL)
231
+
232
+ output_text = "Rules validation passed successfully!"
233
+
234
+ return FlowMessage(output_text=output_text), MultiRuleData.from_rules(rules)
235
+
236
+
165
237
  class DMSToRules(Step):
166
238
  """This step imports rules from CDF Data Model"""
167
239
 
@@ -5,9 +5,9 @@ from typing import ClassVar
5
5
 
6
6
  from cognite.client import CogniteClient
7
7
 
8
- from cognite.neat.rules.issues import IssueList
9
- from cognite.neat.rules.issues.dms import MissingContainerError, MissingSpaceError, MissingViewError
10
- from cognite.neat.rules.issues.formatters import FORMATTER_BY_NAME
8
+ from cognite.neat.issues import NeatIssueList
9
+ from cognite.neat.issues.errors.resources import ReferredResourceNotFoundError
10
+ from cognite.neat.issues.formatters import FORMATTER_BY_NAME
11
11
  from cognite.neat.rules.models import DMSRules, SchemaCompleteness
12
12
  from cognite.neat.utils.cdf.loaders import ViewLoader
13
13
  from cognite.neat.workflows._exceptions import StepNotInitialized
@@ -61,9 +61,21 @@ class ValidateRulesAgainstCDF(Step):
61
61
  if not errors:
62
62
  return FlowMessage(output_text="Rules are complete and valid. No need to fetch from CDF.")
63
63
 
64
- missing_spaces = [error.space for error in errors if isinstance(error, MissingSpaceError)]
65
- missing_views = [error.view for error in errors if isinstance(error, MissingViewError)]
66
- missing_containers = [error.container for error in errors if isinstance(error, MissingContainerError)]
64
+ missing_spaces = [
65
+ error.identifier
66
+ for error in errors
67
+ if isinstance(error, ReferredResourceNotFoundError) and error.resource_type == "Space"
68
+ ]
69
+ missing_views = [
70
+ error.identifier
71
+ for error in errors
72
+ if isinstance(error, ReferredResourceNotFoundError) and error.resource_type == "View"
73
+ ]
74
+ missing_containers = [
75
+ error.identifier
76
+ for error in errors
77
+ if isinstance(error, ReferredResourceNotFoundError) and error.resource_type == "Container"
78
+ ]
67
79
 
68
80
  retrieved_spaces = cdf_client.data_modeling.spaces.retrieve(missing_spaces).as_write()
69
81
  retrieved_containers = cdf_client.data_modeling.containers.retrieve(missing_containers).as_write()
@@ -87,7 +99,7 @@ class ValidateRulesAgainstCDF(Step):
87
99
  output_dir = self.data_store_path / Path("staging")
88
100
  report_writer = FORMATTER_BY_NAME[self.configs["Report Formatter"]]()
89
101
  report_writer.write_to_file(
90
- IssueList(errors, title=dms_rules.metadata.name or dms_rules.metadata.external_id),
102
+ NeatIssueList(errors, title=dms_rules.metadata.name or dms_rules.metadata.external_id),
91
103
  file_or_dir_path=output_dir,
92
104
  )
93
105
  report_file = report_writer.default_file_name
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cognite-neat
3
- Version: 0.88.1
3
+ Version: 0.88.2
4
4
  Summary: Knowledge graph transformation
5
5
  Home-page: https://cognite-neat.readthedocs-hosted.com/
6
6
  License: Apache-2.0