cognite-neat 0.88.3__py3-none-any.whl → 0.90.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 (84) hide show
  1. cognite/neat/_version.py +1 -1
  2. cognite/neat/constants.py +6 -3
  3. cognite/neat/graph/extractors/__init__.py +2 -0
  4. cognite/neat/graph/extractors/_classic_cdf/_base.py +2 -2
  5. cognite/neat/graph/extractors/_dms.py +158 -0
  6. cognite/neat/graph/extractors/_mock_graph_generator.py +50 -9
  7. cognite/neat/graph/loaders/_rdf2dms.py +16 -13
  8. cognite/neat/graph/models.py +1 -0
  9. cognite/neat/graph/queries/_base.py +4 -2
  10. cognite/neat/issues/_base.py +3 -1
  11. cognite/neat/issues/errors/__init__.py +2 -1
  12. cognite/neat/issues/errors/_general.py +7 -0
  13. cognite/neat/issues/warnings/__init__.py +2 -0
  14. cognite/neat/issues/warnings/_models.py +1 -1
  15. cognite/neat/issues/warnings/_properties.py +12 -0
  16. cognite/neat/issues/warnings/user_modeling.py +1 -1
  17. cognite/neat/rules/_shared.py +49 -6
  18. cognite/neat/rules/analysis/_base.py +1 -1
  19. cognite/neat/rules/exporters/_base.py +7 -18
  20. cognite/neat/rules/exporters/_rules2dms.py +8 -18
  21. cognite/neat/rules/exporters/_rules2excel.py +5 -12
  22. cognite/neat/rules/exporters/_rules2ontology.py +9 -19
  23. cognite/neat/rules/exporters/_rules2yaml.py +3 -6
  24. cognite/neat/rules/importers/_base.py +7 -52
  25. cognite/neat/rules/importers/_dms2rules.py +172 -116
  26. cognite/neat/rules/importers/_dtdl2rules/dtdl_converter.py +26 -18
  27. cognite/neat/rules/importers/_dtdl2rules/dtdl_importer.py +14 -30
  28. cognite/neat/rules/importers/_rdf/_imf2rules/_imf2classes.py +7 -3
  29. cognite/neat/rules/importers/_rdf/_imf2rules/_imf2metadata.py +3 -3
  30. cognite/neat/rules/importers/_rdf/_imf2rules/_imf2properties.py +18 -11
  31. cognite/neat/rules/importers/_rdf/_imf2rules/_imf2rules.py +9 -18
  32. cognite/neat/rules/importers/_rdf/_inference2rules.py +37 -65
  33. cognite/neat/rules/importers/_rdf/_owl2rules/_owl2rules.py +9 -20
  34. cognite/neat/rules/importers/_rdf/_shared.py +1 -1
  35. cognite/neat/rules/importers/_spreadsheet2rules.py +22 -86
  36. cognite/neat/rules/importers/_yaml2rules.py +14 -41
  37. cognite/neat/rules/models/__init__.py +21 -5
  38. cognite/neat/rules/models/_base_input.py +162 -0
  39. cognite/neat/rules/models/{_base.py → _base_rules.py} +1 -12
  40. cognite/neat/rules/models/asset/__init__.py +5 -2
  41. cognite/neat/rules/models/asset/_rules.py +2 -20
  42. cognite/neat/rules/models/asset/_rules_input.py +40 -115
  43. cognite/neat/rules/models/asset/_validation.py +1 -1
  44. cognite/neat/rules/models/data_types.py +150 -44
  45. cognite/neat/rules/models/dms/__init__.py +19 -7
  46. cognite/neat/rules/models/dms/_exporter.py +82 -39
  47. cognite/neat/rules/models/dms/_rules.py +42 -155
  48. cognite/neat/rules/models/dms/_rules_input.py +186 -254
  49. cognite/neat/rules/models/dms/_serializer.py +44 -3
  50. cognite/neat/rules/models/dms/_validation.py +3 -4
  51. cognite/neat/rules/models/domain.py +52 -1
  52. cognite/neat/rules/models/entities/__init__.py +63 -0
  53. cognite/neat/rules/models/entities/_constants.py +73 -0
  54. cognite/neat/rules/models/entities/_loaders.py +76 -0
  55. cognite/neat/rules/models/entities/_multi_value.py +67 -0
  56. cognite/neat/rules/models/{entities.py → entities/_single_value.py} +74 -232
  57. cognite/neat/rules/models/entities/_types.py +86 -0
  58. cognite/neat/rules/models/{wrapped_entities.py → entities/_wrapped.py} +1 -1
  59. cognite/neat/rules/models/information/__init__.py +10 -2
  60. cognite/neat/rules/models/information/_rules.py +3 -14
  61. cognite/neat/rules/models/information/_rules_input.py +57 -204
  62. cognite/neat/rules/models/information/_validation.py +1 -1
  63. cognite/neat/rules/transformers/__init__.py +21 -0
  64. cognite/neat/rules/transformers/_base.py +69 -3
  65. cognite/neat/rules/{models/information/_converter.py → transformers/_converters.py} +226 -21
  66. cognite/neat/rules/transformers/_map_onto.py +97 -0
  67. cognite/neat/rules/transformers/_pipelines.py +61 -0
  68. cognite/neat/rules/transformers/_verification.py +136 -0
  69. cognite/neat/store/_base.py +2 -2
  70. cognite/neat/store/_provenance.py +10 -1
  71. cognite/neat/utils/cdf/data_classes.py +20 -0
  72. cognite/neat/utils/regex_patterns.py +6 -0
  73. cognite/neat/workflows/steps/lib/current/rules_exporter.py +106 -37
  74. cognite/neat/workflows/steps/lib/current/rules_importer.py +24 -22
  75. {cognite_neat-0.88.3.dist-info → cognite_neat-0.90.0.dist-info}/METADATA +1 -1
  76. {cognite_neat-0.88.3.dist-info → cognite_neat-0.90.0.dist-info}/RECORD +80 -74
  77. cognite/neat/rules/models/_constants.py +0 -2
  78. cognite/neat/rules/models/_types/__init__.py +0 -19
  79. cognite/neat/rules/models/asset/_converter.py +0 -4
  80. cognite/neat/rules/models/dms/_converter.py +0 -143
  81. /cognite/neat/rules/models/{_types/_field.py → _types.py} +0 -0
  82. {cognite_neat-0.88.3.dist-info → cognite_neat-0.90.0.dist-info}/LICENSE +0 -0
  83. {cognite_neat-0.88.3.dist-info → cognite_neat-0.90.0.dist-info}/WHEEL +0 -0
  84. {cognite_neat-0.88.3.dist-info → cognite_neat-0.90.0.dist-info}/entry_points.txt +0 -0
@@ -37,16 +37,20 @@ def parse_imf_to_classes(graph: Graph, language: str = "en") -> list[dict]:
37
37
  query = """
38
38
  SELECT ?class ?name ?description ?parentClass ?reference ?match ?comment
39
39
  WHERE {
40
- #Finding IMF - elements
40
+ # Finding IMF - elements
41
41
  VALUES ?type { imf:BlockType imf:TerminalType imf:AttributeType }
42
42
  ?imfClass a ?type .
43
43
  OPTIONAL {?imfClass rdfs:subClassOf ?parent }.
44
44
  OPTIONAL {?imfClass rdfs:label | skos:prefLabel ?name }.
45
- OPTIONAL {?imfClass rdfs:comment | skos:description ?description} .
45
+
46
+ # Note: Bug in PCA has lead to the use non-existing term skos:description. This will be replaced
47
+ # with the correct skos:definition in the near future, so both terms are included here.
48
+ OPTIONAL {?imfClass rdfs:comment | skos:definition | skos:description ?description} .
46
49
 
47
50
  # Finding the last segment of the class IRI
48
51
  BIND(STR(?imfClass) AS ?classString)
49
- BIND(REPLACE(?classString, "^.*[/#]([^/#]*)$", "$1") AS ?classSegment)
52
+ BIND(REPLACE(?classString, "^.*[/#]([^/#]*)$", "$1") AS ?tempSegment)
53
+ BIND(REPLACE(?tempSegment, "-", "_") AS ?classSegment)
50
54
  BIND(IF(CONTAINS(?classString, "imf/"), CONCAT("IMF_", ?classSegment) , ?classSegment) AS ?class)
51
55
 
52
56
  # Add imf:Attribute as parent class
@@ -19,12 +19,12 @@ def parse_imf_metadata() -> dict:
19
19
  raw_metadata = {
20
20
  "role": RoleTypes.information,
21
21
  "schema": SchemaCompleteness.partial,
22
- "prefix": "pca-imf",
23
- "namespace": Namespace("http://posccaesar.org/imf/"),
22
+ "prefix": "pcaimf",
23
+ "namespace": Namespace("https://posccaesar.org/imf/"),
24
24
  "version": None,
25
25
  "created": None,
26
26
  "updated": None,
27
- "title": "IMF - types",
27
+ "title": "IMF_types",
28
28
  "description": "IMF - types",
29
29
  "creator": None,
30
30
  "rights": None,
@@ -36,7 +36,7 @@ def parse_imf_to_properties(graph: Graph, language: str = "en") -> list[dict]:
36
36
  """
37
37
 
38
38
  query = """
39
- SELECT ?class ?property ?name ?description ?valueType ?minCount ?maxCount ?default ?reference
39
+ SELECT DISTINCT ?class ?property ?name ?description ?valueType ?minCount ?maxCount ?default ?reference
40
40
  ?match ?comment ?propertyType
41
41
  WHERE
42
42
  {
@@ -48,7 +48,7 @@ def parse_imf_to_properties(graph: Graph, language: str = "en") -> list[dict]:
48
48
  ?propertyShape sh:path ?imfProperty .
49
49
 
50
50
  OPTIONAL { ?imfProperty skos:prefLabel ?name . }
51
- OPTIONAL { ?imfProperty skos:description ?description . }
51
+ OPTIONAL { ?imfProperty skos:definition | skos:description ?description . }
52
52
  OPTIONAL { ?imfProperty rdfs:range ?range . }
53
53
  OPTIONAL { ?imfProperty a ?type . }
54
54
  OPTIONAL { ?propertyShape sh:minCount ?minCardinality} .
@@ -62,22 +62,24 @@ def parse_imf_to_properties(graph: Graph, language: str = "en") -> list[dict]:
62
62
  ?imfClass a imf:AttributeType ;
63
63
  ?imfProperty ?default .
64
64
 
65
- # imf:predicate is required
66
- BIND(IF(?imfProperty = <http://ns.imfid.org/imf#predicate>, 1, 0) AS ?minCardinality)
67
-
68
65
  # The following information is used to describe the attribute when it is connected to a block or a terminal
69
66
  # and not duplicated here.
70
- FILTER(?imfProperty != rdf:type && ?imfProperty != skos:prefLabel && ?imfProperty != skos:description)
67
+ # Note: Bug in PCA has lead to the use non-existing term skos:description. This will be replaced
68
+ # with the correct skos:definition in the near future, so both terms are included here.
69
+ FILTER(?imfProperty != rdf:type && ?imfProperty != skos:prefLabel &&
70
+ ?imfProperty != skos:defintion && ?imfProperty != skos:description)
71
71
  }
72
72
 
73
73
  # Finding the last segment of the class IRI
74
74
  BIND(STR(?imfClass) AS ?classString)
75
- BIND(REPLACE(?classString, "^.*[/#]([^/#]*)$", "$1") AS ?classSegment)
75
+ BIND(REPLACE(?classString, "^.*[/#]([^/#]*)$", "$1") AS ?tempClassSegment)
76
+ BIND(REPLACE(?tempClassSegment, "-", "_") AS ?classSegment)
76
77
  BIND(IF(CONTAINS(?classString, "imf/"), CONCAT("IMF_", ?classSegment) , ?classSegment) AS ?class)
77
78
 
78
79
  # Finding the last segment of the property IRI
79
80
  BIND(STR(?imfProperty) AS ?propertyString)
80
- BIND(REPLACE(?propertyString, "^.*[/#]([^/#]*)$", "$1") AS ?propertySegment)
81
+ BIND(REPLACE(?propertyString, "^.*[/#]([^/#]*)$", "$1") AS ?tempPropertySegment)
82
+ BIND(REPLACE(?tempPropertySegment, "-", "_") AS ?propertySegment)
81
83
  BIND(IF(CONTAINS(?propertyString, "imf/"), CONCAT("IMF_", ?propertySegment) , ?propertySegment) AS ?property)
82
84
 
83
85
  # Set the value type for the property based on sh:class, sh:qualifiedValueType or rdfs:range
@@ -85,12 +87,17 @@ def parse_imf_to_properties(graph: Graph, language: str = "en") -> list[dict]:
85
87
 
86
88
  # Finding the last segment of value types
87
89
  BIND(STR(?valueIriType) AS ?valueTypeString)
88
- BIND(REPLACE(?valueTypeString, "^.*[/#]([^/#]*)$", "$1") AS ?valueTypeSegment)
90
+ BIND(REPLACE(?valueTypeString, "^.*[/#]([^/#]*)$", "$1") AS ?tempValueTypeSegment)
91
+ BIND(REPLACE(?tempValueTypeSegment, "-", "_") AS ?valueTypeSegment)
89
92
  BIND(IF(CONTAINS(?valueTypeString, "imf/"), CONCAT("IMF_", ?valueTypeSegment) , ?valueTypeSegment)
90
93
  AS ?valueType)
91
94
 
92
- # Helper variable to set property type if value type is not already set.
93
- BIND(IF(BOUND(?type) && ?type = owl:DatatypeProperty, ?type , owl:ObjectProperty) AS ?propertyType)
95
+ # Helper variable to set owl datatype- or object-property if this is not already set.
96
+ BIND(IF( EXISTS {?imfProperty a ?tempPropertyType . FILTER(?tempPropertyType = owl:DatatypeProperty) },
97
+ owl:DatatypeProperty,
98
+ owl:ObjectProperty
99
+ )
100
+ AS ?propertyType)
94
101
 
95
102
  # Assert cardinality values if they do not exist
96
103
  BIND(IF(BOUND(?minCardinality), ?minCardinality, 0) AS ?minCount)
@@ -2,13 +2,14 @@
2
2
  there are loaders to TransformationRules pydantic class."""
3
3
 
4
4
  from pathlib import Path
5
- from typing import Literal, overload
6
5
 
7
6
  from rdflib import DC, DCTERMS, OWL, RDF, RDFS, SH, SKOS, Graph
8
7
 
9
8
  from cognite.neat.issues import IssueList
10
- from cognite.neat.rules.importers._base import BaseImporter, VerifiedRules
11
- from cognite.neat.rules.models import InformationRules, RoleTypes
9
+ from cognite.neat.issues.errors import FileReadError
10
+ from cognite.neat.rules._shared import ReadRules
11
+ from cognite.neat.rules.importers._base import BaseImporter
12
+ from cognite.neat.rules.models import InformationInputRules
12
13
  from cognite.neat.rules.models.data_types import _XSD_TYPES
13
14
 
14
15
  from ._imf2classes import parse_imf_to_classes
@@ -16,7 +17,7 @@ from ._imf2metadata import parse_imf_metadata
16
17
  from ._imf2properties import parse_imf_to_properties
17
18
 
18
19
 
19
- class IMFImporter(BaseImporter):
20
+ class IMFImporter(BaseImporter[InformationInputRules]):
20
21
  """Convert SHACL shapes to tables/ transformation rules / Excel file.
21
22
 
22
23
  Args:
@@ -38,24 +39,14 @@ class IMFImporter(BaseImporter):
38
39
  def __init__(self, filepath: Path):
39
40
  self.filepath = filepath
40
41
 
41
- @overload
42
- def to_rules(self, errors: Literal["raise"], role: RoleTypes | None = None) -> VerifiedRules: ...
43
-
44
- @overload
45
- def to_rules(
46
- self, errors: Literal["continue"] = "continue", role: RoleTypes | None = None
47
- ) -> tuple[VerifiedRules | None, IssueList]: ...
48
-
49
42
  def to_rules(
50
43
  self,
51
- errors: Literal["raise", "continue"] = "continue",
52
- role: RoleTypes | None = None,
53
- ) -> tuple[VerifiedRules | None, IssueList] | VerifiedRules:
44
+ ) -> ReadRules[InformationInputRules]:
54
45
  graph = Graph()
55
46
  try:
56
47
  graph.parse(self.filepath)
57
48
  except Exception as e:
58
- raise Exception(f"Could not parse owl file: {e}") from e
49
+ return ReadRules(None, IssueList([FileReadError(self.filepath, f"Could not parse owl file: {e}")]), {})
59
50
 
60
51
  # bind key namespaces
61
52
  graph.bind("owl", OWL)
@@ -76,8 +67,8 @@ class IMFImporter(BaseImporter):
76
67
 
77
68
  components = make_components_compliant(components)
78
69
 
79
- rules = InformationRules.model_validate(components)
80
- return self._to_output(rules, IssueList(), errors, role)
70
+ rules = InformationInputRules.load(components)
71
+ return ReadRules(rules, IssueList(), {})
81
72
 
82
73
 
83
74
  def make_components_compliant(components: dict) -> dict:
@@ -1,20 +1,22 @@
1
1
  from collections import Counter, defaultdict
2
2
  from datetime import datetime
3
3
  from pathlib import Path
4
- from typing import Literal, cast, overload
4
+ from typing import cast
5
5
 
6
- from rdflib import Graph, Namespace, URIRef
6
+ from rdflib import RDF, Graph, Namespace, URIRef
7
7
  from rdflib import Literal as RdfLiteral
8
8
 
9
9
  from cognite.neat.constants import DEFAULT_NAMESPACE, get_default_prefixes
10
10
  from cognite.neat.issues import IssueList
11
11
  from cognite.neat.issues.errors import FileReadError
12
- from cognite.neat.rules.importers._base import BaseImporter, VerifiedRules, _handle_issues
13
- from cognite.neat.rules.models import InformationRules, RoleTypes
14
- from cognite.neat.rules.models._base import MatchType
12
+ from cognite.neat.issues.warnings import PropertyValueTypeUndefinedWarning
13
+ from cognite.neat.rules._shared import ReadRules
14
+ from cognite.neat.rules.importers._base import BaseImporter
15
+ from cognite.neat.rules.models._base_rules import MatchType
16
+ from cognite.neat.rules.models.entities._single_value import UnknownEntity
15
17
  from cognite.neat.rules.models.information import (
18
+ InformationInputRules,
16
19
  InformationMetadata,
17
- InformationRulesInput,
18
20
  )
19
21
  from cognite.neat.store import NeatGraphStore
20
22
  from cognite.neat.utils.rdf_ import get_namespace, remove_namespace_from_uri, uri_to_short_form
@@ -25,16 +27,6 @@ ORDERED_CLASSES_QUERY = """SELECT ?class (count(?s) as ?instances )
25
27
 
26
28
  INSTANCES_OF_CLASS_QUERY = """SELECT ?s WHERE { ?s a <class> . }"""
27
29
 
28
- INSTANCE_PROPERTIES_JSON_DEFINITION = """SELECT ?property (count(?property) as ?occurrence) ?dataType ?objectType
29
- WHERE {<instance_id> ?property ?value .
30
-
31
- BIND(IF(REGEX(?value, "^\u007b(.*)\u007d$"),
32
- <http://www.w3.org/2001/XMLSchema#json>,
33
- datatype(?value)) AS ?dataType)
34
-
35
- OPTIONAL {?value rdf:type ?objectType .}}
36
- GROUP BY ?property ?dataType ?objectType"""
37
-
38
30
  INSTANCE_PROPERTIES_DEFINITION = """SELECT ?property (count(?property) as ?occurrence) ?dataType ?objectType
39
31
  WHERE {<instance_id> ?property ?value .
40
32
 
@@ -44,7 +36,7 @@ INSTANCE_PROPERTIES_DEFINITION = """SELECT ?property (count(?property) as ?occur
44
36
  GROUP BY ?property ?dataType ?objectType"""
45
37
 
46
38
 
47
- class InferenceImporter(BaseImporter):
39
+ class InferenceImporter(BaseImporter[InformationInputRules]):
48
40
  """Infers rules from a triple store.
49
41
 
50
42
  Rules inference through analysis of knowledge graph provided in various formats.
@@ -56,7 +48,6 @@ class InferenceImporter(BaseImporter):
56
48
  graph: Knowledge graph
57
49
  max_number_of_instance: Maximum number of instances to be used in inference
58
50
  prefix: Prefix to be used for the inferred model
59
- check_for_json_string: Check if values are JSON strings
60
51
  """
61
52
 
62
53
  def __init__(
@@ -65,15 +56,11 @@ class InferenceImporter(BaseImporter):
65
56
  graph: Graph,
66
57
  max_number_of_instance: int = -1,
67
58
  prefix: str = "inferred",
68
- check_for_json_string: bool = False,
69
59
  ) -> None:
70
60
  self.issue_list = issue_list
71
61
  self.graph = graph
72
62
  self.max_number_of_instance = max_number_of_instance
73
63
  self.prefix = prefix
74
- self.check_for_json_string = (
75
- check_for_json_string if graph.store.__class__.__name__ != "OxigraphStore" else False
76
- )
77
64
 
78
65
  @classmethod
79
66
  def from_graph_store(
@@ -81,7 +68,6 @@ class InferenceImporter(BaseImporter):
81
68
  store: NeatGraphStore,
82
69
  max_number_of_instance: int = -1,
83
70
  prefix: str = "inferred",
84
- check_for_json_string: bool = False,
85
71
  ) -> "InferenceImporter":
86
72
  issue_list = IssueList(title="Inferred from graph store")
87
73
 
@@ -90,7 +76,6 @@ class InferenceImporter(BaseImporter):
90
76
  store.graph,
91
77
  max_number_of_instance=max_number_of_instance,
92
78
  prefix=prefix,
93
- check_for_json_string=check_for_json_string,
94
79
  )
95
80
 
96
81
  @classmethod
@@ -99,7 +84,6 @@ class InferenceImporter(BaseImporter):
99
84
  filepath: Path,
100
85
  max_number_of_instance: int = -1,
101
86
  prefix: str = "inferred",
102
- check_for_json_string: bool = False,
103
87
  ) -> "InferenceImporter":
104
88
  issue_list = IssueList(title=f"'{filepath.name}'")
105
89
 
@@ -114,7 +98,6 @@ class InferenceImporter(BaseImporter):
114
98
  graph,
115
99
  max_number_of_instance=max_number_of_instance,
116
100
  prefix=prefix,
117
- check_for_json_string=check_for_json_string,
118
101
  )
119
102
 
120
103
  @classmethod
@@ -123,7 +106,6 @@ class InferenceImporter(BaseImporter):
123
106
  filepath: Path,
124
107
  max_number_of_instance: int = -1,
125
108
  prefix: str = "inferred",
126
- check_for_json_string: bool = False,
127
109
  ) -> "InferenceImporter":
128
110
  raise NotImplementedError("JSON file format is not supported yet.")
129
111
 
@@ -133,7 +115,6 @@ class InferenceImporter(BaseImporter):
133
115
  filepath: Path,
134
116
  max_number_of_instance: int = -1,
135
117
  prefix: str = "inferred",
136
- check_for_json_string: bool = False,
137
118
  ) -> "InferenceImporter":
138
119
  raise NotImplementedError("YAML file format is not supported yet.")
139
120
 
@@ -143,48 +124,24 @@ class InferenceImporter(BaseImporter):
143
124
  filepath: Path,
144
125
  max_number_of_instance: int = -1,
145
126
  prefix: str = "inferred",
146
- check_for_json_string: bool = False,
147
127
  ) -> "InferenceImporter":
148
128
  raise NotImplementedError("JSON file format is not supported yet.")
149
129
 
150
- @overload
151
- def to_rules(self, errors: Literal["raise"], role: RoleTypes | None = None) -> VerifiedRules: ...
152
-
153
- @overload
154
- def to_rules(
155
- self,
156
- errors: Literal["continue"] = "continue",
157
- role: RoleTypes | None = None,
158
- ) -> tuple[VerifiedRules | None, IssueList]: ...
159
-
160
130
  def to_rules(
161
131
  self,
162
- errors: Literal["raise", "continue"] = "continue",
163
- role: RoleTypes | None = None,
164
- ) -> tuple[VerifiedRules | None, IssueList] | VerifiedRules:
132
+ ) -> ReadRules[InformationInputRules]:
165
133
  """
166
134
  Creates `Rules` object from the data for target role.
167
135
  """
168
136
 
169
137
  if self.issue_list.has_errors:
170
138
  # In case there were errors during the import, the to_rules method will return None
171
- return self._return_or_raise(self.issue_list, errors)
139
+ return ReadRules(None, self.issue_list, {})
172
140
 
173
141
  rules_dict = self._to_rules_components()
174
142
 
175
- with _handle_issues(self.issue_list) as future:
176
- rules: InformationRules
177
- rules = InformationRulesInput.load(rules_dict).as_rules()
178
-
179
- if future.result == "failure" or self.issue_list.has_errors:
180
- return self._return_or_raise(self.issue_list, errors)
181
-
182
- return self._to_output(
183
- rules,
184
- self.issue_list,
185
- errors=errors,
186
- role=role,
187
- )
143
+ rules = InformationInputRules.load(rules_dict)
144
+ return ReadRules(rules, self.issue_list, {})
188
145
 
189
146
  def _to_rules_components(
190
147
  self,
@@ -203,7 +160,6 @@ class InferenceImporter(BaseImporter):
203
160
  prefixes: dict[str, Namespace] = get_default_prefixes()
204
161
  count_by_value_type_by_property: dict[str, dict[str, int]] = defaultdict(Counter)
205
162
 
206
- query = INSTANCE_PROPERTIES_JSON_DEFINITION if self.check_for_json_string else INSTANCE_PROPERTIES_DEFINITION
207
163
  # Adds default namespace to prefixes
208
164
  prefixes[self._default_metadata().prefix] = self._default_metadata().namespace
209
165
 
@@ -231,19 +187,35 @@ class InferenceImporter(BaseImporter):
231
187
  + f" LIMIT {self.max_number_of_instance}"
232
188
  ):
233
189
  for property_uri, occurrence, data_type_uri, object_type_uri in self.graph.query( # type: ignore[misc]
234
- query.replace("instance_id", instance)
190
+ INSTANCE_PROPERTIES_DEFINITION.replace("instance_id", instance)
235
191
  ): # type: ignore[misc]
192
+ # this is to skip rdf:type property
193
+ if property_uri == RDF.type:
194
+ continue
195
+
236
196
  property_id = remove_namespace_from_uri(property_uri)
237
197
 
238
198
  self._add_uri_namespace_to_prefixes(cast(URIRef, property_uri), prefixes)
239
- value_type_uri = data_type_uri if data_type_uri else object_type_uri
240
199
 
241
- # this is to skip rdf:type property
242
- if not value_type_uri:
243
- continue
200
+ if value_type_uri := (data_type_uri or object_type_uri):
201
+ self._add_uri_namespace_to_prefixes(cast(URIRef, value_type_uri), prefixes)
202
+
203
+ value_type_id = remove_namespace_from_uri(value_type_uri)
204
+
205
+ # this handles situations when property points to node that is not present in graph
206
+ else:
207
+ value_type_id = str(UnknownEntity())
208
+
209
+ self.issue_list.append(
210
+ PropertyValueTypeUndefinedWarning(
211
+ resource_type="Property",
212
+ identifier=f"{class_id}{property_id}",
213
+ property_name=property_id,
214
+ default_action="Remove the property from the rules",
215
+ recommended_action="Make sure that graph is complete",
216
+ )
217
+ )
244
218
 
245
- self._add_uri_namespace_to_prefixes(cast(URIRef, value_type_uri), prefixes)
246
- value_type_id = remove_namespace_from_uri(value_type_uri)
247
219
  id_ = f"{class_id}:{property_id}"
248
220
 
249
221
  definition = {
@@ -288,7 +260,7 @@ class InferenceImporter(BaseImporter):
288
260
  if len(count_list) == 1:
289
261
  type_, count = count_list[0]
290
262
  counts_str = f"with value type {base_string.format(value_type=type_, count=count)} in the graph"
291
- elif len(count_list) == 1:
263
+ elif len(count_list) == 2:
292
264
  first = base_string.format(value_type=count_list[0][0], count=count_list[0][1])
293
265
  second = base_string.format(value_type=count_list[1][0], count=count_list[1][1])
294
266
  counts_str = f"with value types {first} and {second} in the graph"
@@ -2,21 +2,22 @@
2
2
  there are loaders to TransformationRules pydantic class."""
3
3
 
4
4
  from pathlib import Path
5
- from typing import Literal, overload
6
5
 
7
6
  from rdflib import DC, DCTERMS, OWL, RDF, RDFS, SKOS, Graph
8
7
 
9
8
  from cognite.neat.issues import IssueList
10
- from cognite.neat.rules.importers._base import BaseImporter, VerifiedRules
9
+ from cognite.neat.issues.errors import FileReadError
10
+ from cognite.neat.rules._shared import ReadRules
11
+ from cognite.neat.rules.importers._base import BaseImporter
11
12
  from cognite.neat.rules.importers._rdf._shared import make_components_compliant
12
- from cognite.neat.rules.models import InformationRules, RoleTypes
13
+ from cognite.neat.rules.models import InformationInputRules
13
14
 
14
15
  from ._owl2classes import parse_owl_classes
15
16
  from ._owl2metadata import parse_owl_metadata
16
17
  from ._owl2properties import parse_owl_properties
17
18
 
18
19
 
19
- class OWLImporter(BaseImporter):
20
+ class OWLImporter(BaseImporter[InformationInputRules]):
20
21
  """Convert OWL ontology to tables/ transformation rules / Excel file.
21
22
 
22
23
  Args:
@@ -37,24 +38,12 @@ class OWLImporter(BaseImporter):
37
38
  def __init__(self, filepath: Path):
38
39
  self.owl_filepath = filepath
39
40
 
40
- @overload
41
- def to_rules(self, errors: Literal["raise"], role: RoleTypes | None = None) -> VerifiedRules: ...
42
-
43
- @overload
44
- def to_rules(
45
- self, errors: Literal["continue"] = "continue", role: RoleTypes | None = None
46
- ) -> tuple[VerifiedRules | None, IssueList]: ...
47
-
48
- def to_rules(
49
- self,
50
- errors: Literal["raise", "continue"] = "continue",
51
- role: RoleTypes | None = None,
52
- ) -> tuple[VerifiedRules | None, IssueList] | VerifiedRules:
41
+ def to_rules(self) -> ReadRules[InformationInputRules]:
53
42
  graph = Graph()
54
43
  try:
55
44
  graph.parse(self.owl_filepath)
56
45
  except Exception as e:
57
- raise Exception(f"Could not parse owl file: {e}") from e
46
+ return ReadRules(None, IssueList([FileReadError(self.owl_filepath, f"Could not parse owl file: {e}")]), {})
58
47
 
59
48
  # bind key namespaces
60
49
  graph.bind("owl", OWL)
@@ -72,5 +61,5 @@ class OWLImporter(BaseImporter):
72
61
 
73
62
  components = make_components_compliant(components)
74
63
 
75
- rules = InformationRules.model_validate(components)
76
- return self._to_output(rules, IssueList(), errors, role)
64
+ rules = InformationInputRules.load(components)
65
+ return ReadRules(rules, IssueList(), {})
@@ -4,7 +4,7 @@ import numpy as np
4
4
  import pandas as pd
5
5
  from rdflib import OWL, Literal, Namespace
6
6
 
7
- from cognite.neat.rules.models._base import MatchType
7
+ from cognite.neat.rules.models._base_rules import MatchType
8
8
  from cognite.neat.rules.models.data_types import _XSD_TYPES
9
9
  from cognite.neat.utils.rdf_ import remove_namespace_from_uri
10
10
  from cognite.neat.utils.regex_patterns import PATTERNS