cognite-neat 0.97.2__py3-none-any.whl → 0.98.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.
- cognite/neat/_graph/loaders/__init__.py +1 -2
- cognite/neat/_graph/queries/_base.py +25 -4
- cognite/neat/_issues/warnings/_models.py +9 -0
- cognite/neat/_rules/_shared.py +3 -8
- cognite/neat/_rules/analysis/__init__.py +1 -2
- cognite/neat/_rules/analysis/_base.py +2 -23
- cognite/neat/_rules/analysis/_dms.py +4 -10
- cognite/neat/_rules/analysis/_information.py +2 -10
- cognite/neat/_rules/catalog/info-rules-imf.xlsx +0 -0
- cognite/neat/_rules/exporters/_rules2excel.py +15 -72
- cognite/neat/_rules/exporters/_rules2ontology.py +4 -4
- cognite/neat/_rules/importers/_base.py +3 -4
- cognite/neat/_rules/importers/_dms2rules.py +17 -40
- cognite/neat/_rules/importers/_dtdl2rules/dtdl_converter.py +1 -7
- cognite/neat/_rules/importers/_dtdl2rules/dtdl_importer.py +7 -10
- cognite/neat/_rules/importers/_rdf/_base.py +17 -29
- cognite/neat/_rules/importers/_rdf/_imf2rules/_imf2classes.py +2 -2
- cognite/neat/_rules/importers/_rdf/_imf2rules/_imf2metadata.py +5 -10
- cognite/neat/_rules/importers/_rdf/_imf2rules/_imf2properties.py +1 -2
- cognite/neat/_rules/importers/_rdf/_inference2rules.py +30 -18
- cognite/neat/_rules/importers/_rdf/_owl2rules/_owl2classes.py +2 -2
- cognite/neat/_rules/importers/_rdf/_owl2rules/_owl2metadata.py +5 -8
- cognite/neat/_rules/importers/_rdf/_owl2rules/_owl2properties.py +1 -2
- cognite/neat/_rules/importers/_rdf/_shared.py +25 -140
- cognite/neat/_rules/importers/_spreadsheet2rules.py +10 -41
- cognite/neat/_rules/models/__init__.py +2 -16
- cognite/neat/_rules/models/_base_rules.py +98 -52
- cognite/neat/_rules/models/dms/_exporter.py +7 -160
- cognite/neat/_rules/models/dms/_rules.py +18 -126
- cognite/neat/_rules/models/dms/_rules_input.py +20 -48
- cognite/neat/_rules/models/dms/_schema.py +11 -0
- cognite/neat/_rules/models/dms/_validation.py +9 -122
- cognite/neat/_rules/models/information/_rules.py +19 -114
- cognite/neat/_rules/models/information/_rules_input.py +32 -41
- cognite/neat/_rules/models/information/_validation.py +34 -102
- cognite/neat/_rules/transformers/__init__.py +1 -4
- cognite/neat/_rules/transformers/_converters.py +18 -195
- cognite/neat/_rules/transformers/_mapping.py +1 -5
- cognite/neat/_rules/transformers/_verification.py +0 -14
- cognite/neat/_session/_base.py +37 -13
- cognite/neat/_session/_collector.py +126 -0
- cognite/neat/_session/_inspect.py +5 -5
- cognite/neat/_session/_prepare.py +37 -11
- cognite/neat/_session/_read.py +62 -9
- cognite/neat/_session/_set.py +2 -2
- cognite/neat/_session/_show.py +11 -11
- cognite/neat/_session/_to.py +24 -11
- cognite/neat/_session/exceptions.py +20 -3
- cognite/neat/_store/_provenance.py +2 -2
- cognite/neat/_utils/auxiliary.py +19 -0
- cognite/neat/_version.py +1 -1
- cognite/neat/_workflows/steps/data_contracts.py +2 -10
- cognite/neat/_workflows/steps/lib/current/rules_exporter.py +6 -46
- cognite/neat/_workflows/steps/lib/current/rules_validator.py +2 -7
- {cognite_neat-0.97.2.dist-info → cognite_neat-0.98.0.dist-info}/METADATA +2 -1
- {cognite_neat-0.97.2.dist-info → cognite_neat-0.98.0.dist-info}/RECORD +59 -65
- cognite/neat/_graph/loaders/_rdf2asset.py +0 -416
- cognite/neat/_rules/analysis/_asset.py +0 -173
- cognite/neat/_rules/models/asset/__init__.py +0 -13
- cognite/neat/_rules/models/asset/_rules.py +0 -109
- cognite/neat/_rules/models/asset/_rules_input.py +0 -101
- cognite/neat/_rules/models/asset/_validation.py +0 -45
- cognite/neat/_rules/models/domain.py +0 -136
- {cognite_neat-0.97.2.dist-info → cognite_neat-0.98.0.dist-info}/LICENSE +0 -0
- {cognite_neat-0.97.2.dist-info → cognite_neat-0.98.0.dist-info}/WHEEL +0 -0
- {cognite_neat-0.97.2.dist-info → cognite_neat-0.98.0.dist-info}/entry_points.txt +0 -0
|
@@ -17,7 +17,7 @@ from cognite.neat._rules._shared import ReadRules
|
|
|
17
17
|
from cognite.neat._rules.importers._base import BaseImporter
|
|
18
18
|
from cognite.neat._rules.importers._dtdl2rules.dtdl_converter import _DTDLConverter
|
|
19
19
|
from cognite.neat._rules.importers._dtdl2rules.spec import DTDL_CLS_BY_TYPE_BY_SPEC, DTDLBase, Interface
|
|
20
|
-
from cognite.neat._rules.models import InformationInputRules
|
|
20
|
+
from cognite.neat._rules.models import InformationInputRules
|
|
21
21
|
from cognite.neat._rules.models.information import InformationInputMetadata
|
|
22
22
|
from cognite.neat._utils.text import humanize_collection, to_pascal
|
|
23
23
|
|
|
@@ -31,7 +31,7 @@ class DTDLImporter(BaseImporter[InformationInputRules]):
|
|
|
31
31
|
|
|
32
32
|
Args:
|
|
33
33
|
items (Sequence[DTDLBase]): A sequence of DTDLBase objects.
|
|
34
|
-
|
|
34
|
+
name (str, optional): Name of the data model. Defaults to None.
|
|
35
35
|
read_issues (list[ValidationIssue], optional): A list of issues that occurred during reading. Defaults to None.
|
|
36
36
|
schema (SchemaCompleteness, optional): Schema completeness. Defaults to SchemaCompleteness.partial.
|
|
37
37
|
|
|
@@ -40,14 +40,12 @@ class DTDLImporter(BaseImporter[InformationInputRules]):
|
|
|
40
40
|
def __init__(
|
|
41
41
|
self,
|
|
42
42
|
items: Sequence[DTDLBase],
|
|
43
|
-
|
|
43
|
+
name: str | None = None,
|
|
44
44
|
read_issues: list[NeatIssue] | None = None,
|
|
45
|
-
schema: SchemaCompleteness = SchemaCompleteness.partial,
|
|
46
45
|
) -> None:
|
|
47
46
|
self._items = items
|
|
48
|
-
self.
|
|
47
|
+
self.name = name
|
|
49
48
|
self._read_issues = IssueList(read_issues)
|
|
50
|
-
self._schema_completeness = schema
|
|
51
49
|
|
|
52
50
|
@classmethod
|
|
53
51
|
def _from_file_content(cls, file_content: str, filepath: Path) -> Iterable[DTDLBase | NeatIssue]:
|
|
@@ -130,17 +128,16 @@ class DTDLImporter(BaseImporter[InformationInputRules]):
|
|
|
130
128
|
converter.convert(self._items)
|
|
131
129
|
|
|
132
130
|
metadata = self._default_metadata()
|
|
133
|
-
metadata["schema"] = self._schema_completeness.value
|
|
134
131
|
|
|
135
|
-
if self.
|
|
136
|
-
metadata["
|
|
132
|
+
if self.name:
|
|
133
|
+
metadata["name"] = to_pascal(self.name)
|
|
137
134
|
try:
|
|
138
135
|
most_common_prefix = converter.get_most_common_prefix()
|
|
139
136
|
except ValueError:
|
|
140
137
|
# No prefixes are defined so we just use the default prefix...
|
|
141
138
|
...
|
|
142
139
|
else:
|
|
143
|
-
metadata["
|
|
140
|
+
metadata["space"] = most_common_prefix
|
|
144
141
|
|
|
145
142
|
rules = InformationInputRules(
|
|
146
143
|
metadata=InformationInputMetadata.load(metadata),
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
2
|
|
|
3
|
+
from cognite.client import data_modeling as dm
|
|
3
4
|
from rdflib import DC, DCTERMS, OWL, RDF, RDFS, SH, SKOS, XSD, Graph, Namespace, URIRef
|
|
4
5
|
|
|
5
6
|
from cognite.neat._issues import IssueList
|
|
6
7
|
from cognite.neat._issues.errors import FileReadError
|
|
8
|
+
from cognite.neat._issues.errors._general import NeatValueError
|
|
7
9
|
from cognite.neat._rules._shared import ReadRules
|
|
8
10
|
from cognite.neat._rules.importers._base import BaseImporter
|
|
9
11
|
from cognite.neat._rules.models.data_types import AnyURI
|
|
@@ -12,31 +14,38 @@ from cognite.neat._rules.models.information import (
|
|
|
12
14
|
InformationInputRules,
|
|
13
15
|
)
|
|
14
16
|
from cognite.neat._store import NeatGraphStore
|
|
15
|
-
from cognite.neat._utils.rdf_ import get_namespace
|
|
17
|
+
from cognite.neat._utils.rdf_ import get_namespace
|
|
16
18
|
|
|
17
19
|
DEFAULT_NON_EXISTING_NODE_TYPE = AnyURI()
|
|
18
20
|
|
|
19
21
|
|
|
22
|
+
DEFAULT_RDF_DATA_MODEL_ID = ("neat_space", "RDFDataModel", "rdf")
|
|
23
|
+
|
|
24
|
+
|
|
20
25
|
class BaseRDFImporter(BaseImporter[InformationInputRules]):
|
|
21
26
|
"""Baser RDF importers used for all rules importers that are using RDF as input.
|
|
22
27
|
|
|
23
28
|
Args:
|
|
24
29
|
issue_list: Issue list to store issues
|
|
25
30
|
graph: Knowledge graph
|
|
26
|
-
|
|
31
|
+
data_model_id: Data model id to be used for the imported rules
|
|
32
|
+
space: CDF Space to be used for the imported rules
|
|
27
33
|
"""
|
|
28
34
|
|
|
29
35
|
def __init__(
|
|
30
36
|
self,
|
|
31
37
|
issue_list: IssueList,
|
|
32
38
|
graph: Graph,
|
|
33
|
-
|
|
39
|
+
data_model_id: dm.DataModelId | tuple[str, str, str],
|
|
34
40
|
max_number_of_instance: int,
|
|
35
41
|
non_existing_node_type: UnknownEntity | AnyURI,
|
|
36
42
|
) -> None:
|
|
37
43
|
self.issue_list = issue_list
|
|
38
44
|
self.graph = graph
|
|
39
|
-
self.
|
|
45
|
+
self.data_model_id = dm.DataModelId.load(data_model_id)
|
|
46
|
+
if self.data_model_id.version is None:
|
|
47
|
+
raise NeatValueError("Version is required when setting a Data Model ID")
|
|
48
|
+
|
|
40
49
|
self.max_number_of_instance = max_number_of_instance
|
|
41
50
|
self.non_existing_node_type = non_existing_node_type
|
|
42
51
|
|
|
@@ -44,14 +53,14 @@ class BaseRDFImporter(BaseImporter[InformationInputRules]):
|
|
|
44
53
|
def from_graph_store(
|
|
45
54
|
cls,
|
|
46
55
|
store: NeatGraphStore,
|
|
47
|
-
|
|
56
|
+
data_model_id: (dm.DataModelId | tuple[str, str, str]) = DEFAULT_RDF_DATA_MODEL_ID,
|
|
48
57
|
max_number_of_instance: int = -1,
|
|
49
58
|
non_existing_node_type: UnknownEntity | AnyURI = DEFAULT_NON_EXISTING_NODE_TYPE,
|
|
50
59
|
):
|
|
51
60
|
return cls(
|
|
52
61
|
IssueList(title=f"{cls.__name__} issues"),
|
|
53
62
|
store.graph,
|
|
54
|
-
|
|
63
|
+
data_model_id=data_model_id,
|
|
55
64
|
max_number_of_instance=max_number_of_instance,
|
|
56
65
|
non_existing_node_type=non_existing_node_type,
|
|
57
66
|
)
|
|
@@ -60,7 +69,7 @@ class BaseRDFImporter(BaseImporter[InformationInputRules]):
|
|
|
60
69
|
def from_file(
|
|
61
70
|
cls,
|
|
62
71
|
filepath: Path,
|
|
63
|
-
|
|
72
|
+
data_model_id: (dm.DataModelId | tuple[str, str, str]) = DEFAULT_RDF_DATA_MODEL_ID,
|
|
64
73
|
max_number_of_instance: int = -1,
|
|
65
74
|
non_existing_node_type: UnknownEntity | AnyURI = DEFAULT_NON_EXISTING_NODE_TYPE,
|
|
66
75
|
):
|
|
@@ -86,7 +95,7 @@ class BaseRDFImporter(BaseImporter[InformationInputRules]):
|
|
|
86
95
|
return cls(
|
|
87
96
|
issue_list,
|
|
88
97
|
graph,
|
|
89
|
-
|
|
98
|
+
data_model_id=data_model_id,
|
|
90
99
|
max_number_of_instance=max_number_of_instance,
|
|
91
100
|
non_existing_node_type=non_existing_node_type,
|
|
92
101
|
)
|
|
@@ -106,32 +115,11 @@ class BaseRDFImporter(BaseImporter[InformationInputRules]):
|
|
|
106
115
|
|
|
107
116
|
rules = InformationInputRules.load(rules_dict)
|
|
108
117
|
|
|
109
|
-
self._add_transformation(rules)
|
|
110
|
-
|
|
111
118
|
return ReadRules(rules, self.issue_list, {})
|
|
112
119
|
|
|
113
120
|
def _to_rules_components(self) -> dict:
|
|
114
121
|
raise NotImplementedError()
|
|
115
122
|
|
|
116
|
-
@classmethod
|
|
117
|
-
def _add_transformation(cls, rules: InformationInputRules) -> None:
|
|
118
|
-
rules.prefixes = {}
|
|
119
|
-
|
|
120
|
-
rules.prefixes[rules.metadata.prefix] = Namespace(rules.metadata.namespace)
|
|
121
|
-
|
|
122
|
-
class_ref_dict = {}
|
|
123
|
-
for class_ in rules.classes:
|
|
124
|
-
if class_.reference:
|
|
125
|
-
cls._add_uri_namespace_to_prefixes(URIRef(class_.reference), rules.prefixes)
|
|
126
|
-
class_ref_dict[class_.class_] = f"{uri_to_short_form(URIRef(class_.reference), rules.prefixes)}"
|
|
127
|
-
|
|
128
|
-
for property_ in rules.properties:
|
|
129
|
-
if property_.reference:
|
|
130
|
-
cls._add_uri_namespace_to_prefixes(URIRef(property_.reference), rules.prefixes)
|
|
131
|
-
if class_id := class_ref_dict.get(property_.class_, None):
|
|
132
|
-
property_id = f"{uri_to_short_form(URIRef(property_.reference), rules.prefixes)}"
|
|
133
|
-
property_.transformation = f"{class_id}({property_id})"
|
|
134
|
-
|
|
135
123
|
@classmethod
|
|
136
124
|
def _add_uri_namespace_to_prefixes(cls, URI: URIRef, prefixes: dict[str, Namespace]):
|
|
137
125
|
"""Add URI to prefixes dict if not already present
|
|
@@ -35,7 +35,7 @@ def parse_imf_to_classes(graph: Graph, language: str = "en") -> list[dict]:
|
|
|
35
35
|
"""
|
|
36
36
|
|
|
37
37
|
query = """
|
|
38
|
-
SELECT ?class ?name ?description ?parentClass
|
|
38
|
+
SELECT ?class ?name ?description ?parentClass
|
|
39
39
|
WHERE {
|
|
40
40
|
# Finding IMF - elements
|
|
41
41
|
VALUES ?type { imf:BlockType imf:TerminalType imf:AttributeType }
|
|
@@ -79,7 +79,7 @@ def parse_imf_to_classes(graph: Graph, language: str = "en") -> list[dict]:
|
|
|
79
79
|
processed_df = make_classes_compliant(processed_df, importer="IMF")
|
|
80
80
|
|
|
81
81
|
# Make Parent Class list elements into string joined with comma
|
|
82
|
-
processed_df["
|
|
82
|
+
processed_df["Implements"] = processed_df["Implements"].apply(
|
|
83
83
|
lambda x: ", ".join(x) if isinstance(x, list) and x else None
|
|
84
84
|
)
|
|
85
85
|
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
from rdflib import Namespace
|
|
2
|
-
|
|
3
1
|
from cognite.neat._rules.importers._rdf._shared import make_metadata_compliant
|
|
4
|
-
from cognite.neat._rules.models import RoleTypes
|
|
2
|
+
from cognite.neat._rules.models import RoleTypes
|
|
5
3
|
|
|
6
4
|
|
|
7
|
-
def parse_imf_metadata(
|
|
5
|
+
def parse_imf_metadata(space: str = "pcaimf") -> dict:
|
|
8
6
|
"""Provide hardcoded IMF metadata to dict.
|
|
9
7
|
|
|
10
8
|
Returns:
|
|
@@ -18,17 +16,14 @@ def parse_imf_metadata(prefix: str = "pcaimf") -> dict:
|
|
|
18
16
|
|
|
19
17
|
raw_metadata = {
|
|
20
18
|
"role": RoleTypes.information,
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"namespace": Namespace("https://posccaesar.org/imf/"),
|
|
19
|
+
"space": space,
|
|
20
|
+
"external_id": "imf_types",
|
|
24
21
|
"version": None,
|
|
25
22
|
"created": None,
|
|
26
23
|
"updated": None,
|
|
27
|
-
"
|
|
24
|
+
"name": "IMF Types",
|
|
28
25
|
"description": "IMF - types",
|
|
29
26
|
"creator": None,
|
|
30
|
-
"rights": None,
|
|
31
|
-
"license": None,
|
|
32
27
|
}
|
|
33
28
|
|
|
34
29
|
return make_metadata_compliant(raw_metadata)
|
|
@@ -36,8 +36,7 @@ def parse_imf_to_properties(graph: Graph, language: str = "en") -> list[dict]:
|
|
|
36
36
|
"""
|
|
37
37
|
|
|
38
38
|
query = """
|
|
39
|
-
SELECT DISTINCT ?class ?property ?name ?description ?valueType ?minCount ?maxCount ?default ?
|
|
40
|
-
?match ?comment ?propertyType
|
|
39
|
+
SELECT DISTINCT ?class ?property ?name ?description ?valueType ?minCount ?maxCount ?default ?propertyType
|
|
41
40
|
WHERE
|
|
42
41
|
{
|
|
43
42
|
# Finding IMF-blocks and terminals
|
|
@@ -4,23 +4,25 @@ from datetime import datetime
|
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
from typing import ClassVar, cast
|
|
6
6
|
|
|
7
|
-
from
|
|
7
|
+
from cognite.client import data_modeling as dm
|
|
8
|
+
from rdflib import RDF, Namespace, URIRef
|
|
8
9
|
from rdflib import Literal as RdfLiteral
|
|
9
10
|
|
|
10
11
|
from cognite.neat._constants import DEFAULT_NAMESPACE
|
|
11
12
|
from cognite.neat._issues.warnings import PropertyValueTypeUndefinedWarning
|
|
12
13
|
from cognite.neat._rules.models import data_types
|
|
13
|
-
from cognite.neat._rules.models._base_rules import MatchType
|
|
14
14
|
from cognite.neat._rules.models.data_types import AnyURI
|
|
15
15
|
from cognite.neat._rules.models.entities._single_value import UnknownEntity
|
|
16
16
|
from cognite.neat._rules.models.information import (
|
|
17
17
|
InformationMetadata,
|
|
18
18
|
)
|
|
19
19
|
from cognite.neat._store import NeatGraphStore
|
|
20
|
-
from cognite.neat._utils.rdf_ import remove_namespace_from_uri
|
|
20
|
+
from cognite.neat._utils.rdf_ import remove_namespace_from_uri, uri_to_short_form
|
|
21
21
|
|
|
22
22
|
from ._base import DEFAULT_NON_EXISTING_NODE_TYPE, BaseRDFImporter
|
|
23
23
|
|
|
24
|
+
DEFAULT_INFERENCE_DATA_MODEL_ID = ("neat_space", "InferredDataModel", "inferred")
|
|
25
|
+
|
|
24
26
|
ORDERED_CLASSES_QUERY = """SELECT ?class (count(?s) as ?instances )
|
|
25
27
|
WHERE { ?s a ?class . }
|
|
26
28
|
group by ?class order by DESC(?instances)"""
|
|
@@ -65,27 +67,27 @@ class InferenceImporter(BaseRDFImporter):
|
|
|
65
67
|
def from_graph_store(
|
|
66
68
|
cls,
|
|
67
69
|
store: NeatGraphStore,
|
|
68
|
-
|
|
70
|
+
data_model_id: (dm.DataModelId | tuple[str, str, str]) = DEFAULT_INFERENCE_DATA_MODEL_ID,
|
|
69
71
|
max_number_of_instance: int = -1,
|
|
70
72
|
non_existing_node_type: UnknownEntity | AnyURI = DEFAULT_NON_EXISTING_NODE_TYPE,
|
|
71
73
|
) -> "InferenceImporter":
|
|
72
|
-
return super().from_graph_store(store,
|
|
74
|
+
return super().from_graph_store(store, data_model_id, max_number_of_instance, non_existing_node_type)
|
|
73
75
|
|
|
74
76
|
@classmethod
|
|
75
77
|
def from_file(
|
|
76
78
|
cls,
|
|
77
79
|
filepath: Path,
|
|
78
|
-
|
|
80
|
+
data_model_id: (dm.DataModelId | tuple[str, str, str]) = DEFAULT_INFERENCE_DATA_MODEL_ID,
|
|
79
81
|
max_number_of_instance: int = -1,
|
|
80
82
|
non_existing_node_type: UnknownEntity | AnyURI = DEFAULT_NON_EXISTING_NODE_TYPE,
|
|
81
83
|
) -> "InferenceImporter":
|
|
82
|
-
return super().from_file(filepath,
|
|
84
|
+
return super().from_file(filepath, data_model_id, max_number_of_instance, non_existing_node_type)
|
|
83
85
|
|
|
84
86
|
@classmethod
|
|
85
87
|
def from_json_file(
|
|
86
88
|
cls,
|
|
87
89
|
filepath: Path,
|
|
88
|
-
|
|
90
|
+
data_model_id: (dm.DataModelId | tuple[str, str, str]) = DEFAULT_INFERENCE_DATA_MODEL_ID,
|
|
89
91
|
max_number_of_instance: int = -1,
|
|
90
92
|
) -> "InferenceImporter":
|
|
91
93
|
raise NotImplementedError("JSON file format is not supported yet.")
|
|
@@ -94,7 +96,7 @@ class InferenceImporter(BaseRDFImporter):
|
|
|
94
96
|
def from_yaml_file(
|
|
95
97
|
cls,
|
|
96
98
|
filepath: Path,
|
|
97
|
-
|
|
99
|
+
data_model_id: (dm.DataModelId | tuple[str, str, str]) = DEFAULT_INFERENCE_DATA_MODEL_ID,
|
|
98
100
|
max_number_of_instance: int = -1,
|
|
99
101
|
) -> "InferenceImporter":
|
|
100
102
|
raise NotImplementedError("YAML file format is not supported yet.")
|
|
@@ -103,7 +105,7 @@ class InferenceImporter(BaseRDFImporter):
|
|
|
103
105
|
def from_xml_file(
|
|
104
106
|
cls,
|
|
105
107
|
filepath: Path,
|
|
106
|
-
|
|
108
|
+
data_model_id: (dm.DataModelId | tuple[str, str, str]) = DEFAULT_INFERENCE_DATA_MODEL_ID,
|
|
107
109
|
max_number_of_instance: int = -1,
|
|
108
110
|
) -> "InferenceImporter":
|
|
109
111
|
raise NotImplementedError("JSON file format is not supported yet.")
|
|
@@ -120,29 +122,32 @@ class InferenceImporter(BaseRDFImporter):
|
|
|
120
122
|
Returns:
|
|
121
123
|
Tuple of data model and prefixes of the graph
|
|
122
124
|
"""
|
|
125
|
+
|
|
123
126
|
classes: dict[str, dict] = {}
|
|
124
127
|
properties: dict[str, dict] = {}
|
|
128
|
+
prefixes: dict[str, Namespace] = {}
|
|
125
129
|
count_by_value_type_by_property: dict[str, dict[str, int]] = defaultdict(Counter)
|
|
126
130
|
|
|
127
131
|
# Infers all the classes in the graph
|
|
128
132
|
for class_uri, no_instances in self.graph.query(ORDERED_CLASSES_QUERY): # type: ignore[misc]
|
|
129
|
-
if (class_id := remove_namespace_from_uri(class_uri)) in classes:
|
|
133
|
+
if (class_id := remove_namespace_from_uri(cast(URIRef, class_uri))) in classes:
|
|
130
134
|
# handles cases when class id is already present in classes
|
|
131
135
|
class_id = f"{class_id}_{len(classes)+1}"
|
|
132
136
|
|
|
133
137
|
classes[class_id] = {
|
|
134
138
|
"class_": class_id,
|
|
135
|
-
"
|
|
136
|
-
"match_type": MatchType.exact,
|
|
139
|
+
"uri": class_uri,
|
|
137
140
|
"comment": f"Inferred from knowledge graph, where this class has <{no_instances}> instances",
|
|
138
141
|
}
|
|
139
142
|
|
|
143
|
+
self._add_uri_namespace_to_prefixes(cast(URIRef, class_uri), prefixes)
|
|
144
|
+
|
|
140
145
|
# Infers all the properties of the class
|
|
141
146
|
for class_id, class_definition in classes.items():
|
|
142
147
|
for (instance,) in self.graph.query( # type: ignore[misc]
|
|
143
|
-
INSTANCES_OF_CLASS_QUERY.replace("class", class_definition["
|
|
148
|
+
INSTANCES_OF_CLASS_QUERY.replace("class", class_definition["uri"])
|
|
144
149
|
if self.max_number_of_instance < 0
|
|
145
|
-
else INSTANCES_OF_CLASS_QUERY.replace("class", class_definition["
|
|
150
|
+
else INSTANCES_OF_CLASS_QUERY.replace("class", class_definition["uri"])
|
|
146
151
|
+ f" LIMIT {self.max_number_of_instance}"
|
|
147
152
|
):
|
|
148
153
|
for property_uri, occurrence, data_type_uri, object_type_uri in self.graph.query( # type: ignore[misc]
|
|
@@ -152,11 +157,13 @@ class InferenceImporter(BaseRDFImporter):
|
|
|
152
157
|
if property_uri == RDF.type:
|
|
153
158
|
continue
|
|
154
159
|
|
|
160
|
+
self._add_uri_namespace_to_prefixes(cast(URIRef, property_uri), prefixes)
|
|
155
161
|
property_id = remove_namespace_from_uri(property_uri)
|
|
156
162
|
if isinstance(data_type_uri, URIRef):
|
|
157
163
|
data_type_uri = self.overwrite_data_types.get(data_type_uri, data_type_uri)
|
|
158
164
|
|
|
159
165
|
if value_type_uri := (data_type_uri or object_type_uri):
|
|
166
|
+
self._add_uri_namespace_to_prefixes(cast(URIRef, value_type_uri), prefixes)
|
|
160
167
|
value_type_id = remove_namespace_from_uri(value_type_uri)
|
|
161
168
|
|
|
162
169
|
# this handles situations when property points to node that is not present in graph
|
|
@@ -181,7 +188,10 @@ class InferenceImporter(BaseRDFImporter):
|
|
|
181
188
|
"property_": property_id,
|
|
182
189
|
"max_count": cast(RdfLiteral, occurrence).value,
|
|
183
190
|
"value_type": value_type_id,
|
|
184
|
-
"
|
|
191
|
+
"transformation": (
|
|
192
|
+
f"{uri_to_short_form(class_definition['uri'], prefixes)}"
|
|
193
|
+
f"({uri_to_short_form(cast(URIRef, property_uri), prefixes)})"
|
|
194
|
+
),
|
|
185
195
|
}
|
|
186
196
|
|
|
187
197
|
count_by_value_type_by_property[id_][value_type_id] += 1
|
|
@@ -233,16 +243,18 @@ class InferenceImporter(BaseRDFImporter):
|
|
|
233
243
|
"metadata": self._default_metadata().model_dump(),
|
|
234
244
|
"classes": list(classes.values()),
|
|
235
245
|
"properties": list(properties.values()),
|
|
246
|
+
"prefixes": prefixes,
|
|
236
247
|
}
|
|
237
248
|
|
|
238
249
|
def _default_metadata(self):
|
|
239
250
|
return InformationMetadata(
|
|
251
|
+
space=self.data_model_id.space,
|
|
252
|
+
external_id=self.data_model_id.external_id,
|
|
253
|
+
version=self.data_model_id.version,
|
|
240
254
|
name="Inferred Model",
|
|
241
255
|
creator="NEAT",
|
|
242
|
-
version="inferred",
|
|
243
256
|
created=datetime.now(),
|
|
244
257
|
updated=datetime.now(),
|
|
245
258
|
description="Inferred model from knowledge graph",
|
|
246
|
-
prefix=self.prefix,
|
|
247
259
|
namespace=DEFAULT_NAMESPACE,
|
|
248
260
|
)
|
|
@@ -24,7 +24,7 @@ def parse_owl_classes(graph: Graph, language: str = "en") -> list[dict]:
|
|
|
24
24
|
"""
|
|
25
25
|
|
|
26
26
|
query = """
|
|
27
|
-
SELECT ?class ?name ?description ?parentClass
|
|
27
|
+
SELECT ?class ?name ?description ?parentClass
|
|
28
28
|
WHERE {
|
|
29
29
|
?class a owl:Class .
|
|
30
30
|
OPTIONAL {?class rdfs:subClassOf ?parentClass }.
|
|
@@ -51,7 +51,7 @@ def parse_owl_classes(graph: Graph, language: str = "en") -> list[dict]:
|
|
|
51
51
|
processed_df = make_classes_compliant(processed_df, importer="OWL")
|
|
52
52
|
|
|
53
53
|
# Make Parent Class list elements into string joined with comma
|
|
54
|
-
processed_df["
|
|
54
|
+
processed_df["Implements"] = processed_df["Implements"].apply(
|
|
55
55
|
lambda x: ", ".join(x) if isinstance(x, list) and x else None
|
|
56
56
|
)
|
|
57
57
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
from rdflib import Graph
|
|
1
|
+
from rdflib import Graph
|
|
2
2
|
|
|
3
3
|
from cognite.neat._constants import DEFAULT_NAMESPACE
|
|
4
4
|
from cognite.neat._rules.importers._rdf._shared import make_metadata_compliant
|
|
5
|
-
from cognite.neat._rules.models import RoleTypes
|
|
5
|
+
from cognite.neat._rules.models import RoleTypes
|
|
6
6
|
from cognite.neat._utils.collection_ import remove_none_elements_from_set
|
|
7
7
|
from cognite.neat._utils.rdf_ import convert_rdflib_content
|
|
8
8
|
|
|
@@ -47,21 +47,18 @@ def parse_owl_metadata(graph: Graph) -> dict:
|
|
|
47
47
|
raw_metadata = convert_rdflib_content(
|
|
48
48
|
{
|
|
49
49
|
"role": RoleTypes.information,
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"namespace": Namespace(results[0].pop()),
|
|
50
|
+
"space": results[1].pop(),
|
|
51
|
+
"external_id": "OntologyBasedDataModel",
|
|
53
52
|
"version": results[2].pop(),
|
|
54
53
|
"created": results[3].pop(),
|
|
55
54
|
"updated": results[4].pop(),
|
|
56
|
-
"
|
|
55
|
+
"name": results[5].pop(),
|
|
57
56
|
"description": results[6].pop(),
|
|
58
57
|
"creator": (
|
|
59
58
|
", ".join(remove_none_elements_from_set(results[7]))
|
|
60
59
|
if remove_none_elements_from_set(results[7])
|
|
61
60
|
else None
|
|
62
61
|
),
|
|
63
|
-
"rights": results[8].pop(),
|
|
64
|
-
"license": results[9].pop(),
|
|
65
62
|
}
|
|
66
63
|
)
|
|
67
64
|
|
|
@@ -22,8 +22,7 @@ def parse_owl_properties(graph: Graph, language: str = "en") -> list[dict]:
|
|
|
22
22
|
|
|
23
23
|
query = """
|
|
24
24
|
|
|
25
|
-
SELECT ?class ?property ?name ?description ?type ?minCount ?maxCount ?default ?
|
|
26
|
-
?match ?comment ?propertyType
|
|
25
|
+
SELECT ?class ?property ?name ?description ?type ?minCount ?maxCount ?default ?propertyType
|
|
27
26
|
WHERE {
|
|
28
27
|
?property a ?propertyType.
|
|
29
28
|
FILTER (?propertyType IN (owl:ObjectProperty, owl:DatatypeProperty ) )
|