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.
- cognite/neat/_version.py +1 -1
- cognite/neat/constants.py +6 -3
- cognite/neat/graph/extractors/__init__.py +2 -0
- cognite/neat/graph/extractors/_classic_cdf/_base.py +2 -2
- cognite/neat/graph/extractors/_dms.py +158 -0
- cognite/neat/graph/extractors/_mock_graph_generator.py +50 -9
- cognite/neat/graph/loaders/_rdf2dms.py +16 -13
- cognite/neat/graph/models.py +1 -0
- cognite/neat/graph/queries/_base.py +4 -2
- cognite/neat/issues/_base.py +3 -1
- cognite/neat/issues/errors/__init__.py +2 -1
- cognite/neat/issues/errors/_general.py +7 -0
- cognite/neat/issues/warnings/__init__.py +2 -0
- cognite/neat/issues/warnings/_models.py +1 -1
- cognite/neat/issues/warnings/_properties.py +12 -0
- cognite/neat/issues/warnings/user_modeling.py +1 -1
- cognite/neat/rules/_shared.py +49 -6
- cognite/neat/rules/analysis/_base.py +1 -1
- cognite/neat/rules/exporters/_base.py +7 -18
- cognite/neat/rules/exporters/_rules2dms.py +8 -18
- cognite/neat/rules/exporters/_rules2excel.py +5 -12
- cognite/neat/rules/exporters/_rules2ontology.py +9 -19
- cognite/neat/rules/exporters/_rules2yaml.py +3 -6
- cognite/neat/rules/importers/_base.py +7 -52
- cognite/neat/rules/importers/_dms2rules.py +172 -116
- cognite/neat/rules/importers/_dtdl2rules/dtdl_converter.py +26 -18
- cognite/neat/rules/importers/_dtdl2rules/dtdl_importer.py +14 -30
- cognite/neat/rules/importers/_rdf/_imf2rules/_imf2classes.py +7 -3
- cognite/neat/rules/importers/_rdf/_imf2rules/_imf2metadata.py +3 -3
- cognite/neat/rules/importers/_rdf/_imf2rules/_imf2properties.py +18 -11
- cognite/neat/rules/importers/_rdf/_imf2rules/_imf2rules.py +9 -18
- cognite/neat/rules/importers/_rdf/_inference2rules.py +37 -65
- cognite/neat/rules/importers/_rdf/_owl2rules/_owl2rules.py +9 -20
- cognite/neat/rules/importers/_rdf/_shared.py +1 -1
- cognite/neat/rules/importers/_spreadsheet2rules.py +22 -86
- cognite/neat/rules/importers/_yaml2rules.py +14 -41
- cognite/neat/rules/models/__init__.py +21 -5
- cognite/neat/rules/models/_base_input.py +162 -0
- cognite/neat/rules/models/{_base.py → _base_rules.py} +1 -12
- cognite/neat/rules/models/asset/__init__.py +5 -2
- cognite/neat/rules/models/asset/_rules.py +2 -20
- cognite/neat/rules/models/asset/_rules_input.py +40 -115
- cognite/neat/rules/models/asset/_validation.py +1 -1
- cognite/neat/rules/models/data_types.py +150 -44
- cognite/neat/rules/models/dms/__init__.py +19 -7
- cognite/neat/rules/models/dms/_exporter.py +82 -39
- cognite/neat/rules/models/dms/_rules.py +42 -155
- cognite/neat/rules/models/dms/_rules_input.py +186 -254
- cognite/neat/rules/models/dms/_serializer.py +44 -3
- cognite/neat/rules/models/dms/_validation.py +3 -4
- cognite/neat/rules/models/domain.py +52 -1
- cognite/neat/rules/models/entities/__init__.py +63 -0
- cognite/neat/rules/models/entities/_constants.py +73 -0
- cognite/neat/rules/models/entities/_loaders.py +76 -0
- cognite/neat/rules/models/entities/_multi_value.py +67 -0
- cognite/neat/rules/models/{entities.py → entities/_single_value.py} +74 -232
- cognite/neat/rules/models/entities/_types.py +86 -0
- cognite/neat/rules/models/{wrapped_entities.py → entities/_wrapped.py} +1 -1
- cognite/neat/rules/models/information/__init__.py +10 -2
- cognite/neat/rules/models/information/_rules.py +3 -14
- cognite/neat/rules/models/information/_rules_input.py +57 -204
- cognite/neat/rules/models/information/_validation.py +1 -1
- cognite/neat/rules/transformers/__init__.py +21 -0
- cognite/neat/rules/transformers/_base.py +69 -3
- cognite/neat/rules/{models/information/_converter.py → transformers/_converters.py} +226 -21
- cognite/neat/rules/transformers/_map_onto.py +97 -0
- cognite/neat/rules/transformers/_pipelines.py +61 -0
- cognite/neat/rules/transformers/_verification.py +136 -0
- cognite/neat/store/_base.py +2 -2
- cognite/neat/store/_provenance.py +10 -1
- cognite/neat/utils/cdf/data_classes.py +20 -0
- cognite/neat/utils/regex_patterns.py +6 -0
- cognite/neat/workflows/steps/lib/current/rules_exporter.py +106 -37
- cognite/neat/workflows/steps/lib/current/rules_importer.py +24 -22
- {cognite_neat-0.88.3.dist-info → cognite_neat-0.90.0.dist-info}/METADATA +1 -1
- {cognite_neat-0.88.3.dist-info → cognite_neat-0.90.0.dist-info}/RECORD +80 -74
- cognite/neat/rules/models/_constants.py +0 -2
- cognite/neat/rules/models/_types/__init__.py +0 -19
- cognite/neat/rules/models/asset/_converter.py +0 -4
- cognite/neat/rules/models/dms/_converter.py +0 -143
- /cognite/neat/rules/models/{_types/_field.py → _types.py} +0 -0
- {cognite_neat-0.88.3.dist-info → cognite_neat-0.90.0.dist-info}/LICENSE +0 -0
- {cognite_neat-0.88.3.dist-info → cognite_neat-0.90.0.dist-info}/WHEEL +0 -0
- {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
|
-
|
|
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 ?
|
|
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": "
|
|
23
|
-
"namespace": Namespace("
|
|
22
|
+
"prefix": "pcaimf",
|
|
23
|
+
"namespace": Namespace("https://posccaesar.org/imf/"),
|
|
24
24
|
"version": None,
|
|
25
25
|
"created": None,
|
|
26
26
|
"updated": None,
|
|
27
|
-
"title": "
|
|
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
|
-
|
|
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 ?
|
|
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 ?
|
|
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 ?
|
|
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
|
|
93
|
-
BIND(IF(
|
|
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.
|
|
11
|
-
from cognite.neat.rules.
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
80
|
-
return
|
|
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
|
|
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.
|
|
13
|
-
from cognite.neat.rules.
|
|
14
|
-
from cognite.neat.rules.
|
|
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
|
-
|
|
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
|
|
139
|
+
return ReadRules(None, self.issue_list, {})
|
|
172
140
|
|
|
173
141
|
rules_dict = self._to_rules_components()
|
|
174
142
|
|
|
175
|
-
|
|
176
|
-
|
|
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
|
-
|
|
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
|
-
|
|
242
|
-
|
|
243
|
-
|
|
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) ==
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
76
|
-
return
|
|
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.
|
|
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
|