cognite-neat 0.121.1__py3-none-any.whl → 0.121.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.
- cognite/neat/_version.py +1 -1
- cognite/neat/core/_client/_api/statistics.py +91 -0
- cognite/neat/core/_client/_api_client.py +2 -0
- cognite/neat/core/_client/data_classes/statistics.py +125 -0
- cognite/neat/core/_client/testing.py +4 -0
- cognite/neat/core/_constants.py +6 -7
- cognite/neat/core/_data_model/_constants.py +23 -16
- cognite/neat/core/_data_model/_shared.py +33 -17
- cognite/neat/core/_data_model/analysis/__init__.py +2 -2
- cognite/neat/core/_data_model/analysis/_base.py +186 -183
- cognite/neat/core/_data_model/catalog/__init__.py +1 -1
- cognite/neat/core/_data_model/exporters/__init__.py +5 -5
- cognite/neat/core/_data_model/exporters/_base.py +10 -8
- cognite/neat/core/_data_model/exporters/{_rules2dms.py → _data_model2dms.py} +22 -18
- cognite/neat/core/_data_model/exporters/{_rules2excel.py → _data_model2excel.py} +51 -51
- cognite/neat/core/_data_model/exporters/{_rules2instance_template.py → _data_model2instance_template.py} +4 -4
- cognite/neat/core/_data_model/exporters/{_rules2ontology.py → _data_model2ontology.py} +50 -50
- cognite/neat/core/_data_model/exporters/{_rules2yaml.py → _data_model2yaml.py} +21 -18
- cognite/neat/core/_data_model/importers/__init__.py +6 -6
- cognite/neat/core/_data_model/importers/_base.py +8 -6
- cognite/neat/core/_data_model/importers/_base_file_reader.py +56 -0
- cognite/neat/core/_data_model/importers/{_yaml2rules.py → _dict2data_model.py} +40 -20
- cognite/neat/core/_data_model/importers/{_dms2rules.py → _dms2data_model.py} +58 -49
- cognite/neat/core/_data_model/importers/{_dtdl2rules → _dtdl2data_model}/dtdl_converter.py +22 -22
- cognite/neat/core/_data_model/importers/{_dtdl2rules → _dtdl2data_model}/dtdl_importer.py +7 -7
- cognite/neat/core/_data_model/importers/{_dtdl2rules → _dtdl2data_model}/spec.py +3 -3
- cognite/neat/core/_data_model/importers/_rdf/_base.py +9 -9
- cognite/neat/core/_data_model/importers/_rdf/_imf2rules.py +15 -15
- cognite/neat/core/_data_model/importers/_rdf/_inference2rules.py +36 -36
- cognite/neat/core/_data_model/importers/_rdf/_owl2rules.py +12 -12
- cognite/neat/core/_data_model/importers/_rdf/_shared.py +25 -25
- cognite/neat/core/_data_model/importers/{_spreadsheet2rules.py → _spreadsheet2data_model.py} +72 -12
- cognite/neat/core/_data_model/models/__init__.py +8 -8
- cognite/neat/core/_data_model/models/_base_unverified.py +1 -1
- cognite/neat/core/_data_model/models/_base_verified.py +3 -3
- cognite/neat/core/_data_model/models/_types.py +6 -6
- cognite/neat/core/_data_model/models/conceptual/__init__.py +6 -6
- cognite/neat/core/_data_model/models/conceptual/_unverified.py +20 -20
- cognite/neat/core/_data_model/models/conceptual/_validation.py +87 -77
- cognite/neat/core/_data_model/models/conceptual/_verified.py +53 -51
- cognite/neat/core/_data_model/models/data_types.py +2 -2
- cognite/neat/core/_data_model/models/entities/__init__.py +8 -8
- cognite/neat/core/_data_model/models/entities/_loaders.py +11 -10
- cognite/neat/core/_data_model/models/entities/_multi_value.py +5 -5
- cognite/neat/core/_data_model/models/entities/_single_value.py +44 -38
- cognite/neat/core/_data_model/models/entities/_types.py +9 -3
- cognite/neat/core/_data_model/models/entities/_wrapped.py +3 -3
- cognite/neat/core/_data_model/models/mapping/_classic2core.py +12 -9
- cognite/neat/core/_data_model/models/physical/__init__.py +40 -0
- cognite/neat/core/_data_model/models/{dms → physical}/_exporter.py +71 -52
- cognite/neat/core/_data_model/models/{dms/_rules_input.py → physical/_unverified.py} +48 -39
- cognite/neat/core/_data_model/models/{dms → physical}/_validation.py +13 -11
- cognite/neat/core/_data_model/models/{dms/_rules.py → physical/_verified.py} +68 -60
- cognite/neat/core/_data_model/transformers/__init__.py +27 -23
- cognite/neat/core/_data_model/transformers/_base.py +26 -19
- cognite/neat/core/_data_model/transformers/_converters.py +703 -618
- cognite/neat/core/_data_model/transformers/_mapping.py +74 -55
- cognite/neat/core/_data_model/transformers/_verification.py +63 -54
- cognite/neat/core/_instances/extractors/_base.py +1 -1
- cognite/neat/core/_instances/extractors/_classic_cdf/_classic.py +8 -8
- cognite/neat/core/_instances/extractors/_dms_graph.py +42 -34
- cognite/neat/core/_instances/extractors/_mock_graph_generator.py +98 -95
- cognite/neat/core/_instances/loaders/_base.py +2 -2
- cognite/neat/core/_instances/loaders/_rdf2dms.py +6 -6
- cognite/neat/core/_instances/transformers/_base.py +7 -4
- cognite/neat/core/_instances/transformers/_value_type.py +2 -6
- cognite/neat/core/_issues/_base.py +4 -4
- cognite/neat/core/_issues/errors/__init__.py +2 -2
- cognite/neat/core/_issues/errors/_wrapper.py +2 -2
- cognite/neat/core/_issues/warnings/_models.py +4 -4
- cognite/neat/core/_store/__init__.py +3 -3
- cognite/neat/core/_store/{_rules_store.py → _data_model.py} +119 -112
- cognite/neat/core/_store/{_graph_store.py → _instance.py} +3 -4
- cognite/neat/core/_store/_provenance.py +2 -2
- cognite/neat/core/_store/exceptions.py +2 -2
- cognite/neat/core/_utils/rdf_.py +14 -0
- cognite/neat/core/_utils/text.py +1 -1
- cognite/neat/session/_base.py +22 -20
- cognite/neat/session/_drop.py +2 -2
- cognite/neat/session/_inspect.py +5 -5
- cognite/neat/session/_mapping.py +8 -6
- cognite/neat/session/_read.py +2 -2
- cognite/neat/session/_set.py +3 -3
- cognite/neat/session/_show.py +11 -11
- cognite/neat/session/_state.py +13 -13
- cognite/neat/session/_subset.py +12 -9
- cognite/neat/session/_template.py +13 -13
- cognite/neat/session/_to.py +17 -17
- {cognite_neat-0.121.1.dist-info → cognite_neat-0.121.2.dist-info}/METADATA +1 -1
- {cognite_neat-0.121.1.dist-info → cognite_neat-0.121.2.dist-info}/RECORD +95 -93
- cognite/neat/core/_data_model/exporters/_validation.py +0 -14
- cognite/neat/core/_data_model/models/dms/__init__.py +0 -32
- /cognite/neat/core/_data_model/catalog/{info-rules-imf.xlsx → conceptual-imf-data-model.xlsx} +0 -0
- /cognite/neat/core/_data_model/importers/{_dtdl2rules → _dtdl2data_model}/__init__.py +0 -0
- /cognite/neat/core/_data_model/importers/{_dtdl2rules → _dtdl2data_model}/_unit_lookup.py +0 -0
- {cognite_neat-0.121.1.dist-info → cognite_neat-0.121.2.dist-info}/WHEEL +0 -0
- {cognite_neat-0.121.1.dist-info → cognite_neat-0.121.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
from ._unverified import (
|
|
2
|
-
|
|
2
|
+
UnverifiedConcept,
|
|
3
3
|
UnverifiedConceptualDataModel,
|
|
4
4
|
UnverifiedConceptualMetadata,
|
|
5
5
|
UnverifiedConceptualProperty,
|
|
6
6
|
)
|
|
7
|
-
from ._validation import
|
|
7
|
+
from ._validation import ConceptualValidation
|
|
8
8
|
from ._verified import (
|
|
9
|
-
|
|
9
|
+
Concept,
|
|
10
10
|
ConceptualDataModel,
|
|
11
11
|
ConceptualMetadata,
|
|
12
12
|
ConceptualProperty,
|
|
13
13
|
)
|
|
14
14
|
|
|
15
15
|
__all__ = [
|
|
16
|
-
"
|
|
16
|
+
"Concept",
|
|
17
17
|
"ConceptualDataModel",
|
|
18
18
|
"ConceptualMetadata",
|
|
19
19
|
"ConceptualProperty",
|
|
20
|
-
"
|
|
21
|
-
"
|
|
20
|
+
"ConceptualValidation",
|
|
21
|
+
"UnverifiedConcept",
|
|
22
22
|
"UnverifiedConceptualDataModel",
|
|
23
23
|
"UnverifiedConceptualMetadata",
|
|
24
24
|
"UnverifiedConceptualProperty",
|
|
@@ -13,7 +13,7 @@ from cognite.neat.core._data_model.models._base_unverified import (
|
|
|
13
13
|
)
|
|
14
14
|
from cognite.neat.core._data_model.models.data_types import DataType
|
|
15
15
|
from cognite.neat.core._data_model.models.entities import (
|
|
16
|
-
|
|
16
|
+
ConceptEntity,
|
|
17
17
|
MultiValueTypeInfo,
|
|
18
18
|
UnknownEntity,
|
|
19
19
|
load_value_type,
|
|
@@ -21,7 +21,7 @@ from cognite.neat.core._data_model.models.entities import (
|
|
|
21
21
|
from cognite.neat.core._utils.rdf_ import uri_display_name
|
|
22
22
|
|
|
23
23
|
from ._verified import (
|
|
24
|
-
|
|
24
|
+
Concept,
|
|
25
25
|
ConceptualDataModel,
|
|
26
26
|
ConceptualMetadata,
|
|
27
27
|
ConceptualProperty,
|
|
@@ -68,7 +68,7 @@ class UnverifiedConceptualMetadata(UnverifiedComponent[ConceptualMetadata]):
|
|
|
68
68
|
Unlike namespace, the identifier does not end with "/" or "#".
|
|
69
69
|
|
|
70
70
|
"""
|
|
71
|
-
return DEFAULT_NAMESPACE[f"data-model/unverified/
|
|
71
|
+
return DEFAULT_NAMESPACE[f"data-model/unverified/conceptual/{self.space}/{self.external_id}/{self.version}"]
|
|
72
72
|
|
|
73
73
|
@property
|
|
74
74
|
def namespace(self) -> Namespace:
|
|
@@ -78,9 +78,9 @@ class UnverifiedConceptualMetadata(UnverifiedComponent[ConceptualMetadata]):
|
|
|
78
78
|
|
|
79
79
|
@dataclass
|
|
80
80
|
class UnverifiedConceptualProperty(UnverifiedComponent[ConceptualProperty]):
|
|
81
|
-
|
|
81
|
+
concept: ConceptEntity | str
|
|
82
82
|
property_: str
|
|
83
|
-
value_type: DataType |
|
|
83
|
+
value_type: DataType | ConceptEntity | MultiValueTypeInfo | UnknownEntity | str
|
|
84
84
|
name: str | None = None
|
|
85
85
|
description: str | None = None
|
|
86
86
|
min_count: int | None = None
|
|
@@ -100,7 +100,7 @@ class UnverifiedConceptualProperty(UnverifiedComponent[ConceptualProperty]):
|
|
|
100
100
|
|
|
101
101
|
def dump(self, default_prefix: str, **kwargs) -> dict[str, Any]: # type: ignore
|
|
102
102
|
output = super().dump()
|
|
103
|
-
output["
|
|
103
|
+
output["Concept"] = ConceptEntity.load(self.concept, prefix=default_prefix)
|
|
104
104
|
output["Value Type"] = load_value_type(self.value_type, default_prefix)
|
|
105
105
|
return output
|
|
106
106
|
|
|
@@ -112,33 +112,33 @@ class UnverifiedConceptualProperty(UnverifiedComponent[ConceptualProperty]):
|
|
|
112
112
|
|
|
113
113
|
|
|
114
114
|
@dataclass
|
|
115
|
-
class
|
|
116
|
-
|
|
115
|
+
class UnverifiedConcept(UnverifiedComponent[Concept]):
|
|
116
|
+
concept: ConceptEntity | str
|
|
117
117
|
name: str | None = None
|
|
118
118
|
description: str | None = None
|
|
119
|
-
implements: str | list[
|
|
119
|
+
implements: str | list[ConceptEntity] | None = None
|
|
120
120
|
instance_source: str | None = None
|
|
121
121
|
neatId: str | URIRef | None = None
|
|
122
122
|
# linking
|
|
123
123
|
physical: str | URIRef | None = None
|
|
124
124
|
|
|
125
125
|
@classmethod
|
|
126
|
-
def _get_verified_cls(cls) -> type[
|
|
127
|
-
return
|
|
126
|
+
def _get_verified_cls(cls) -> type[Concept]:
|
|
127
|
+
return Concept
|
|
128
128
|
|
|
129
129
|
@property
|
|
130
|
-
def
|
|
131
|
-
return str(self.
|
|
130
|
+
def concept_str(self) -> str:
|
|
131
|
+
return str(self.concept)
|
|
132
132
|
|
|
133
133
|
def dump(self, default_prefix: str, **kwargs) -> dict[str, Any]: # type: ignore
|
|
134
134
|
output = super().dump()
|
|
135
|
-
parent: list[
|
|
135
|
+
parent: list[ConceptEntity] | None = None
|
|
136
136
|
if isinstance(self.implements, str):
|
|
137
137
|
self.implements = self.implements.strip()
|
|
138
|
-
parent = [
|
|
138
|
+
parent = [ConceptEntity.load(parent, prefix=default_prefix) for parent in self.implements.split(",")]
|
|
139
139
|
elif isinstance(self.implements, list):
|
|
140
|
-
parent = [
|
|
141
|
-
output["
|
|
140
|
+
parent = [ConceptEntity.load(parent_, prefix=default_prefix) for parent_ in self.implements]
|
|
141
|
+
output["Concept"] = ConceptEntity.load(self.concept, prefix=default_prefix)
|
|
142
142
|
output["Implements"] = parent
|
|
143
143
|
return output
|
|
144
144
|
|
|
@@ -147,7 +147,7 @@ class UnverifiedConceptualClass(UnverifiedComponent[ConceptualClass]):
|
|
|
147
147
|
class UnverifiedConceptualDataModel(UnverifiedDataModel[ConceptualDataModel]):
|
|
148
148
|
metadata: UnverifiedConceptualMetadata
|
|
149
149
|
properties: list[UnverifiedConceptualProperty] = field(default_factory=list)
|
|
150
|
-
|
|
150
|
+
concepts: list[UnverifiedConcept] = field(default_factory=list)
|
|
151
151
|
prefixes: dict[str, Namespace] | None = None
|
|
152
152
|
|
|
153
153
|
@classmethod
|
|
@@ -160,7 +160,7 @@ class UnverifiedConceptualDataModel(UnverifiedDataModel[ConceptualDataModel]):
|
|
|
160
160
|
return dict(
|
|
161
161
|
Metadata=self.metadata.dump(),
|
|
162
162
|
Properties=[prop.dump(default_prefix) for prop in self.properties],
|
|
163
|
-
|
|
163
|
+
Concepts=[concept.dump(default_prefix) for concept in self.concepts],
|
|
164
164
|
Prefixes=self.prefixes,
|
|
165
165
|
)
|
|
166
166
|
|
|
@@ -180,7 +180,7 @@ class UnverifiedConceptualDataModel(UnverifiedDataModel[ConceptualDataModel]):
|
|
|
180
180
|
"external_id": self.metadata.external_id,
|
|
181
181
|
"space": self.metadata.space,
|
|
182
182
|
"version": self.metadata.version,
|
|
183
|
-
"
|
|
183
|
+
"concepts": len(self.concepts),
|
|
184
184
|
"properties": len(self.properties),
|
|
185
185
|
}
|
|
186
186
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import itertools
|
|
2
2
|
from collections import Counter, defaultdict
|
|
3
|
+
from collections.abc import Iterable
|
|
3
4
|
|
|
4
5
|
from cognite.neat.core._data_model._constants import PATTERNS, EntityTypes
|
|
5
|
-
from cognite.neat.core._data_model.models.entities import
|
|
6
|
+
from cognite.neat.core._data_model.models.entities import ConceptEntity, UnknownEntity
|
|
6
7
|
from cognite.neat.core._data_model.models.entities._multi_value import MultiValueTypeInfo
|
|
7
8
|
from cognite.neat.core._issues import IssueList
|
|
8
9
|
from cognite.neat.core._issues.errors import NeatValueError
|
|
@@ -10,7 +11,7 @@ from cognite.neat.core._issues.errors._resources import (
|
|
|
10
11
|
ResourceDuplicatedError,
|
|
11
12
|
ResourceNotDefinedError,
|
|
12
13
|
)
|
|
13
|
-
from cognite.neat.core._issues.warnings._models import
|
|
14
|
+
from cognite.neat.core._issues.warnings._models import UndefinedConceptWarning
|
|
14
15
|
from cognite.neat.core._issues.warnings._resources import (
|
|
15
16
|
ResourceNotDefinedWarning,
|
|
16
17
|
ResourceRegexViolationWarning,
|
|
@@ -18,23 +19,23 @@ from cognite.neat.core._issues.warnings._resources import (
|
|
|
18
19
|
from cognite.neat.core._utils.spreadsheet import SpreadsheetRead
|
|
19
20
|
from cognite.neat.core._utils.text import humanize_collection
|
|
20
21
|
|
|
21
|
-
from ._verified import ConceptualDataModel
|
|
22
|
+
from ._verified import ConceptualDataModel, ConceptualProperty
|
|
22
23
|
|
|
23
24
|
|
|
24
|
-
class
|
|
25
|
+
class ConceptualValidation:
|
|
25
26
|
"""This class does all the validation of the Information rules that have dependencies
|
|
26
27
|
between components."""
|
|
27
28
|
|
|
28
29
|
def __init__(
|
|
29
30
|
self,
|
|
30
|
-
|
|
31
|
+
data_model: ConceptualDataModel,
|
|
31
32
|
read_info_by_spreadsheet: dict[str, SpreadsheetRead] | None = None,
|
|
32
33
|
):
|
|
33
|
-
self.
|
|
34
|
+
self.data_model = data_model
|
|
34
35
|
self._read_info_by_spreadsheet = read_info_by_spreadsheet or {}
|
|
35
|
-
self._metadata =
|
|
36
|
-
self._properties =
|
|
37
|
-
self.
|
|
36
|
+
self._metadata = data_model.metadata
|
|
37
|
+
self._properties = data_model.properties
|
|
38
|
+
self._concepts = data_model.concepts
|
|
38
39
|
self.issue_list = IssueList()
|
|
39
40
|
|
|
40
41
|
def validate(self) -> IssueList:
|
|
@@ -42,7 +43,7 @@ class InformationValidation:
|
|
|
42
43
|
self._namespaces_reassigned()
|
|
43
44
|
self._classes_without_properties()
|
|
44
45
|
self._undefined_classes()
|
|
45
|
-
self.
|
|
46
|
+
self._parent_concept_defined()
|
|
46
47
|
self._referenced_classes_exist()
|
|
47
48
|
self._referenced_value_types_exist()
|
|
48
49
|
self._regex_compliance_with_dms()
|
|
@@ -51,7 +52,7 @@ class InformationValidation:
|
|
|
51
52
|
|
|
52
53
|
def _duplicated_resources(self) -> None:
|
|
53
54
|
properties_sheet = self._read_info_by_spreadsheet.get("Properties")
|
|
54
|
-
|
|
55
|
+
concepts_sheet = self._read_info_by_spreadsheet.get("Concepts")
|
|
55
56
|
|
|
56
57
|
visited = defaultdict(list)
|
|
57
58
|
for row_no, property_ in enumerate(self._properties):
|
|
@@ -75,9 +76,9 @@ class InformationValidation:
|
|
|
75
76
|
)
|
|
76
77
|
|
|
77
78
|
visited = defaultdict(list)
|
|
78
|
-
for row_no,
|
|
79
|
-
visited[
|
|
80
|
-
|
|
79
|
+
for row_no, concept in enumerate(self._concepts):
|
|
80
|
+
visited[concept._identifier()].append(
|
|
81
|
+
concepts_sheet.adjusted_row_number(row_no) if concepts_sheet else row_no + 1
|
|
81
82
|
)
|
|
82
83
|
|
|
83
84
|
for identifier, rows in visited.items():
|
|
@@ -86,85 +87,85 @@ class InformationValidation:
|
|
|
86
87
|
self.issue_list.append(
|
|
87
88
|
ResourceDuplicatedError(
|
|
88
89
|
identifier[0],
|
|
89
|
-
"
|
|
90
|
+
"concept",
|
|
90
91
|
(f"the Classes sheet at row {humanize_collection(rows)} if data model is read from a spreadsheet."),
|
|
91
92
|
)
|
|
92
93
|
)
|
|
93
94
|
|
|
94
95
|
def _classes_without_properties(self) -> None:
|
|
95
|
-
|
|
96
|
-
referred_classes = {property_.
|
|
97
|
-
|
|
96
|
+
defined_concepts = {concept.concept for concept in self._concepts}
|
|
97
|
+
referred_classes = {property_.concept for property_ in self._properties}
|
|
98
|
+
concept_parent_pairs = self._concept_parent_pairs()
|
|
98
99
|
|
|
99
|
-
if
|
|
100
|
-
for
|
|
100
|
+
if concepts_without_properties := defined_concepts.difference(referred_classes):
|
|
101
|
+
for concept in concepts_without_properties:
|
|
101
102
|
# USE CASE: class has no direct properties and no parents with properties
|
|
102
103
|
# and it is a class in the prefix of data model, as long as it is in the
|
|
103
104
|
# same prefix, meaning same space
|
|
104
|
-
if not
|
|
105
|
+
if not concept_parent_pairs[concept] and concept.prefix == self._metadata.prefix:
|
|
105
106
|
self.issue_list.append(
|
|
106
107
|
ResourceNotDefinedWarning(
|
|
107
|
-
resource_type="
|
|
108
|
-
identifier=
|
|
108
|
+
resource_type="concept",
|
|
109
|
+
identifier=concept,
|
|
109
110
|
location="Properties sheet",
|
|
110
111
|
)
|
|
111
112
|
)
|
|
112
113
|
|
|
113
114
|
def _undefined_classes(self) -> None:
|
|
114
|
-
|
|
115
|
-
|
|
115
|
+
defined_concept = {concept.concept for concept in self._concepts}
|
|
116
|
+
referred_concepts = {property_.concept for property_ in self._properties}
|
|
116
117
|
|
|
117
|
-
if
|
|
118
|
-
for
|
|
118
|
+
if undefined_concepts := referred_concepts.difference(defined_concept):
|
|
119
|
+
for concept in undefined_concepts:
|
|
119
120
|
self.issue_list.append(
|
|
120
121
|
ResourceNotDefinedError(
|
|
121
|
-
identifier=
|
|
122
|
-
resource_type="
|
|
123
|
-
location="
|
|
122
|
+
identifier=concept,
|
|
123
|
+
resource_type="concept",
|
|
124
|
+
location="Concepts sheet",
|
|
124
125
|
)
|
|
125
126
|
)
|
|
126
127
|
|
|
127
|
-
def
|
|
128
|
-
"""This is a validation to check if the parent
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
parents = set(itertools.chain.from_iterable(
|
|
128
|
+
def _parent_concept_defined(self) -> None:
|
|
129
|
+
"""This is a validation to check if the parent concept is defined."""
|
|
130
|
+
concept_parent_pairs = self._concept_parent_pairs()
|
|
131
|
+
concepts = set(concept_parent_pairs.keys())
|
|
132
|
+
parents = set(itertools.chain.from_iterable(concept_parent_pairs.values()))
|
|
132
133
|
|
|
133
|
-
if undefined_parents := parents.difference(
|
|
134
|
+
if undefined_parents := parents.difference(concepts):
|
|
134
135
|
for parent in undefined_parents:
|
|
135
136
|
if parent.prefix != self._metadata.prefix:
|
|
136
|
-
self.issue_list.append(
|
|
137
|
+
self.issue_list.append(UndefinedConceptWarning(concept_id=str(parent)))
|
|
137
138
|
else:
|
|
138
139
|
self.issue_list.append(
|
|
139
140
|
ResourceNotDefinedWarning(
|
|
140
|
-
resource_type="
|
|
141
|
+
resource_type="concept",
|
|
141
142
|
identifier=parent,
|
|
142
|
-
location="
|
|
143
|
+
location="Concepts sheet",
|
|
143
144
|
)
|
|
144
145
|
)
|
|
145
146
|
|
|
146
147
|
def _referenced_classes_exist(self) -> None:
|
|
147
148
|
# needs to be complete for this validation to pass
|
|
148
|
-
|
|
149
|
-
classes_with_explicit_properties = {property_.
|
|
149
|
+
defined_concept = {concept.concept for concept in self._concepts}
|
|
150
|
+
classes_with_explicit_properties = {property_.concept for property_ in self._properties}
|
|
150
151
|
|
|
151
152
|
# USE CASE: models are complete
|
|
152
|
-
if missing_classes := classes_with_explicit_properties.difference(
|
|
153
|
-
for
|
|
153
|
+
if missing_classes := classes_with_explicit_properties.difference(defined_concept):
|
|
154
|
+
for concept in missing_classes:
|
|
154
155
|
self.issue_list.append(
|
|
155
156
|
ResourceNotDefinedWarning(
|
|
156
|
-
resource_type="
|
|
157
|
-
identifier=
|
|
158
|
-
location="
|
|
157
|
+
resource_type="concept",
|
|
158
|
+
identifier=concept,
|
|
159
|
+
location="Concepts sheet",
|
|
159
160
|
)
|
|
160
161
|
)
|
|
161
162
|
|
|
162
163
|
def _referenced_value_types_exist(self) -> None:
|
|
163
164
|
# adding UnknownEntity to the set of defined classes to handle the case where a property references an unknown
|
|
164
|
-
defined_classes = {
|
|
165
|
+
defined_classes = {concept.concept for concept in self._concepts} | {UnknownEntity()}
|
|
165
166
|
referred_object_types = {
|
|
166
167
|
property_.value_type
|
|
167
|
-
for property_ in self.
|
|
168
|
+
for property_ in self.data_model.properties
|
|
168
169
|
if property_.type_ == EntityTypes.object_property
|
|
169
170
|
}
|
|
170
171
|
|
|
@@ -173,9 +174,9 @@ class InformationValidation:
|
|
|
173
174
|
for missing in missing_value_types:
|
|
174
175
|
self.issue_list.append(
|
|
175
176
|
ResourceNotDefinedWarning(
|
|
176
|
-
resource_type="
|
|
177
|
+
resource_type="concept",
|
|
177
178
|
identifier=missing,
|
|
178
|
-
location="
|
|
179
|
+
location="Concepts sheet",
|
|
179
180
|
)
|
|
180
181
|
)
|
|
181
182
|
|
|
@@ -183,28 +184,28 @@ class InformationValidation:
|
|
|
183
184
|
"""Check regex compliance with DMS of properties, classes and value types."""
|
|
184
185
|
|
|
185
186
|
for prop_ in self._properties:
|
|
186
|
-
if not PATTERNS.
|
|
187
|
+
if not PATTERNS.physical_property_id_compliance.match(prop_.property_):
|
|
187
188
|
self.issue_list.append(
|
|
188
189
|
ResourceRegexViolationWarning(
|
|
189
190
|
prop_.property_,
|
|
190
191
|
"Property",
|
|
191
192
|
"Properties sheet, Property column",
|
|
192
|
-
PATTERNS.
|
|
193
|
+
PATTERNS.physical_property_id_compliance.pattern,
|
|
193
194
|
)
|
|
194
195
|
)
|
|
195
|
-
if not PATTERNS.view_id_compliance.match(prop_.
|
|
196
|
+
if not PATTERNS.view_id_compliance.match(prop_.concept.suffix):
|
|
196
197
|
self.issue_list.append(
|
|
197
198
|
ResourceRegexViolationWarning(
|
|
198
|
-
prop_.
|
|
199
|
-
"
|
|
200
|
-
"Properties sheet,
|
|
199
|
+
prop_.concept,
|
|
200
|
+
"Concept",
|
|
201
|
+
"Properties sheet, Concept column",
|
|
201
202
|
PATTERNS.view_id_compliance.pattern,
|
|
202
203
|
)
|
|
203
204
|
)
|
|
204
205
|
|
|
205
206
|
# Handling Value Type
|
|
206
207
|
if (
|
|
207
|
-
isinstance(prop_.value_type,
|
|
208
|
+
isinstance(prop_.value_type, ConceptEntity)
|
|
208
209
|
and prop_.value_type != UnknownEntity()
|
|
209
210
|
and not PATTERNS.view_id_compliance.match(prop_.value_type.suffix)
|
|
210
211
|
):
|
|
@@ -219,7 +220,7 @@ class InformationValidation:
|
|
|
219
220
|
if isinstance(prop_.value_type, MultiValueTypeInfo):
|
|
220
221
|
for value_type in prop_.value_type.types:
|
|
221
222
|
if (
|
|
222
|
-
isinstance(prop_.value_type,
|
|
223
|
+
isinstance(prop_.value_type, ConceptEntity)
|
|
223
224
|
and prop_.value_type != UnknownEntity()
|
|
224
225
|
and not PATTERNS.view_id_compliance.match(value_type.suffix)
|
|
225
226
|
):
|
|
@@ -232,44 +233,44 @@ class InformationValidation:
|
|
|
232
233
|
)
|
|
233
234
|
)
|
|
234
235
|
|
|
235
|
-
for
|
|
236
|
-
if not PATTERNS.view_id_compliance.match(
|
|
236
|
+
for concepts in self._concepts:
|
|
237
|
+
if not PATTERNS.view_id_compliance.match(concepts.concept.suffix):
|
|
237
238
|
self.issue_list.append(
|
|
238
239
|
ResourceRegexViolationWarning(
|
|
239
|
-
|
|
240
|
-
"
|
|
241
|
-
"
|
|
240
|
+
concepts.concept,
|
|
241
|
+
"Concept",
|
|
242
|
+
"Concepts sheet, Class column",
|
|
242
243
|
PATTERNS.view_id_compliance.pattern,
|
|
243
244
|
)
|
|
244
245
|
)
|
|
245
246
|
|
|
246
|
-
if
|
|
247
|
-
for parent in
|
|
247
|
+
if concepts.implements:
|
|
248
|
+
for parent in concepts.implements:
|
|
248
249
|
if not PATTERNS.view_id_compliance.match(parent.suffix):
|
|
249
250
|
self.issue_list.append(
|
|
250
251
|
ResourceRegexViolationWarning(
|
|
251
252
|
parent,
|
|
252
|
-
"
|
|
253
|
-
"
|
|
253
|
+
"Concept",
|
|
254
|
+
"Concepts sheet, Implements column",
|
|
254
255
|
PATTERNS.view_id_compliance.pattern,
|
|
255
256
|
)
|
|
256
257
|
)
|
|
257
258
|
|
|
258
|
-
def
|
|
259
|
-
|
|
260
|
-
|
|
259
|
+
def _concept_parent_pairs(self) -> dict[ConceptEntity, list[ConceptEntity]]:
|
|
260
|
+
concept_parent_pairs: dict[ConceptEntity, list[ConceptEntity]] = {}
|
|
261
|
+
concepts = self.data_model.model_copy(deep=True).concepts
|
|
261
262
|
|
|
262
|
-
for
|
|
263
|
-
|
|
264
|
-
if
|
|
263
|
+
for concept in concepts:
|
|
264
|
+
concept_parent_pairs[concept.concept] = []
|
|
265
|
+
if concept.implements is None:
|
|
265
266
|
continue
|
|
266
|
-
|
|
267
|
+
concept_parent_pairs[concept.concept].extend(concept.implements)
|
|
267
268
|
|
|
268
|
-
return
|
|
269
|
+
return concept_parent_pairs
|
|
269
270
|
|
|
270
271
|
def _namespaces_reassigned(self) -> None:
|
|
271
|
-
prefixes = self.
|
|
272
|
-
prefixes[self.
|
|
272
|
+
prefixes = self.data_model.prefixes.copy()
|
|
273
|
+
prefixes[self.data_model.metadata.namespace.prefix] = self.data_model.metadata.namespace
|
|
273
274
|
|
|
274
275
|
if len(set(prefixes.values())) != len(prefixes):
|
|
275
276
|
reused_namespaces = [value for value, count in Counter(prefixes.values()).items() if count > 1]
|
|
@@ -282,3 +283,12 @@ class InformationValidation:
|
|
|
282
283
|
"\nMake sure that each unique namespace is assigned to a unique prefix"
|
|
283
284
|
)
|
|
284
285
|
)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def duplicated_properties(
|
|
289
|
+
properties: Iterable[ConceptualProperty],
|
|
290
|
+
) -> dict[tuple[ConceptEntity, str], list[tuple[int, ConceptualProperty]]]:
|
|
291
|
+
concept_properties_by_id: dict[tuple[ConceptEntity, str], list[tuple[int, ConceptualProperty]]] = defaultdict(list)
|
|
292
|
+
for prop_no, prop in enumerate(properties):
|
|
293
|
+
concept_properties_by_id[(prop.concept, prop.property_)].append((prop_no, prop))
|
|
294
|
+
return {k: v for k, v in concept_properties_by_id.items() if len(v) > 1}
|