cognite-neat 0.105.2__py3-none-any.whl → 0.107.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/_config.py +6 -260
- cognite/neat/_graph/extractors/__init__.py +5 -1
- cognite/neat/_graph/extractors/_base.py +32 -0
- cognite/neat/_graph/extractors/_classic_cdf/_base.py +42 -16
- cognite/neat/_graph/extractors/_classic_cdf/_classic.py +78 -8
- cognite/neat/_graph/extractors/_classic_cdf/_relationships.py +2 -0
- cognite/neat/_graph/extractors/_classic_cdf/_sequences.py +10 -3
- cognite/neat/_graph/extractors/_dms.py +48 -14
- cognite/neat/_graph/extractors/_dms_graph.py +149 -0
- cognite/neat/_graph/extractors/_rdf_file.py +32 -5
- cognite/neat/_graph/loaders/_rdf2dms.py +119 -20
- cognite/neat/_graph/queries/_construct.py +1 -1
- cognite/neat/_graph/transformers/__init__.py +5 -0
- cognite/neat/_graph/transformers/_base.py +13 -9
- cognite/neat/_graph/transformers/_classic_cdf.py +141 -44
- cognite/neat/_graph/transformers/_rdfpath.py +4 -4
- cognite/neat/_graph/transformers/_value_type.py +54 -44
- cognite/neat/_issues/warnings/_external.py +1 -1
- cognite/neat/_rules/analysis/_base.py +1 -1
- cognite/neat/_rules/analysis/_information.py +14 -13
- cognite/neat/_rules/catalog/__init__.py +1 -0
- cognite/neat/_rules/catalog/classic_model.xlsx +0 -0
- cognite/neat/_rules/catalog/info-rules-imf.xlsx +0 -0
- cognite/neat/_rules/importers/_dms2rules.py +7 -5
- cognite/neat/_rules/importers/_rdf/_inference2rules.py +5 -3
- cognite/neat/_rules/models/_base_rules.py +0 -12
- cognite/neat/_rules/models/_types.py +5 -0
- cognite/neat/_rules/models/dms/_rules.py +50 -2
- cognite/neat/_rules/models/information/_rules.py +48 -5
- cognite/neat/_rules/models/information/_rules_input.py +1 -1
- cognite/neat/_rules/models/mapping/_classic2core.py +4 -5
- cognite/neat/_rules/models/mapping/_classic2core.yaml +70 -58
- cognite/neat/_rules/transformers/__init__.py +4 -0
- cognite/neat/_rules/transformers/_converters.py +209 -62
- cognite/neat/_rules/transformers/_mapping.py +3 -2
- cognite/neat/_session/_base.py +8 -13
- cognite/neat/_session/_inspect.py +6 -2
- cognite/neat/_session/_mapping.py +22 -13
- cognite/neat/_session/_prepare.py +9 -57
- cognite/neat/_session/_read.py +96 -29
- cognite/neat/_session/_set.py +9 -0
- cognite/neat/_session/_state.py +10 -1
- cognite/neat/_session/_to.py +51 -15
- cognite/neat/_session/exceptions.py +7 -3
- cognite/neat/_store/_graph_store.py +85 -39
- cognite/neat/_store/_rules_store.py +22 -0
- cognite/neat/_utils/auth.py +2 -0
- cognite/neat/_utils/collection_.py +32 -11
- cognite/neat/_version.py +1 -1
- {cognite_neat-0.105.2.dist-info → cognite_neat-0.107.0.dist-info}/METADATA +2 -8
- {cognite_neat-0.105.2.dist-info → cognite_neat-0.107.0.dist-info}/RECORD +54 -52
- {cognite_neat-0.105.2.dist-info → cognite_neat-0.107.0.dist-info}/WHEEL +1 -1
- {cognite_neat-0.105.2.dist-info → cognite_neat-0.107.0.dist-info}/LICENSE +0 -0
- {cognite_neat-0.105.2.dist-info → cognite_neat-0.107.0.dist-info}/entry_points.txt +0 -0
|
@@ -5,7 +5,6 @@ its sub-models and validators.
|
|
|
5
5
|
import math
|
|
6
6
|
import sys
|
|
7
7
|
import types
|
|
8
|
-
import uuid
|
|
9
8
|
from abc import ABC, abstractmethod
|
|
10
9
|
from collections.abc import Callable, Hashable, Iterator, MutableSequence, Sequence
|
|
11
10
|
from datetime import datetime
|
|
@@ -31,7 +30,6 @@ from pydantic import (
|
|
|
31
30
|
PlainSerializer,
|
|
32
31
|
field_validator,
|
|
33
32
|
model_serializer,
|
|
34
|
-
model_validator,
|
|
35
33
|
)
|
|
36
34
|
from pydantic.main import IncEx
|
|
37
35
|
from pydantic_core import core_schema
|
|
@@ -343,10 +341,6 @@ class BaseRules(SchemaModel, ABC):
|
|
|
343
341
|
return output
|
|
344
342
|
|
|
345
343
|
|
|
346
|
-
def make_neat_id() -> URIRef:
|
|
347
|
-
return DEFAULT_NAMESPACE[f"neatId_{str(uuid.uuid4()).replace('-', '_')}"]
|
|
348
|
-
|
|
349
|
-
|
|
350
344
|
class SheetRow(SchemaModel):
|
|
351
345
|
neatId: URIRefType | None = Field(
|
|
352
346
|
alias="Neat ID",
|
|
@@ -354,12 +348,6 @@ class SheetRow(SchemaModel):
|
|
|
354
348
|
default=None,
|
|
355
349
|
)
|
|
356
350
|
|
|
357
|
-
@model_validator(mode="after")
|
|
358
|
-
def set_neat_id(self) -> "SheetRow":
|
|
359
|
-
if self.neatId is None:
|
|
360
|
-
self.neatId = DEFAULT_NAMESPACE[f"neatId_{str(uuid.uuid4()).replace('-', '_')}"]
|
|
361
|
-
return self
|
|
362
|
-
|
|
363
351
|
@abstractmethod
|
|
364
352
|
def _identifier(self) -> tuple[Hashable, ...]:
|
|
365
353
|
raise NotImplementedError()
|
|
@@ -76,6 +76,11 @@ NamespaceType = Annotated[
|
|
|
76
76
|
URIRefType = Annotated[
|
|
77
77
|
rdflib.URIRef,
|
|
78
78
|
BeforeValidator(lambda value: rdflib.URIRef(value)),
|
|
79
|
+
PlainSerializer(
|
|
80
|
+
lambda value: str(value),
|
|
81
|
+
return_type=str,
|
|
82
|
+
when_used="unless-none",
|
|
83
|
+
),
|
|
79
84
|
]
|
|
80
85
|
|
|
81
86
|
PrefixType = Annotated[
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import warnings
|
|
2
2
|
from collections.abc import Hashable
|
|
3
|
-
from typing import Any, ClassVar, Literal
|
|
3
|
+
from typing import TYPE_CHECKING, Any, ClassVar, Literal
|
|
4
4
|
|
|
5
5
|
import pandas as pd
|
|
6
6
|
from cognite.client import data_modeling as dm
|
|
7
|
-
from pydantic import Field, field_serializer, field_validator
|
|
7
|
+
from pydantic import Field, field_serializer, field_validator, model_validator
|
|
8
8
|
from pydantic_core.core_schema import SerializationInfo, ValidationInfo
|
|
9
9
|
|
|
10
10
|
from cognite.neat._client.data_classes.schema import DMSSchema
|
|
@@ -48,6 +48,9 @@ from cognite.neat._rules.models.entities import (
|
|
|
48
48
|
ViewEntityList,
|
|
49
49
|
)
|
|
50
50
|
|
|
51
|
+
if TYPE_CHECKING:
|
|
52
|
+
from cognite.neat._rules.models import InformationRules
|
|
53
|
+
|
|
51
54
|
_DEFAULT_VERSION = "1"
|
|
52
55
|
|
|
53
56
|
|
|
@@ -442,6 +445,51 @@ class DMSRules(BaseRules):
|
|
|
442
445
|
)
|
|
443
446
|
return value
|
|
444
447
|
|
|
448
|
+
@model_validator(mode="after")
|
|
449
|
+
def set_neat_id(self) -> "DMSRules":
|
|
450
|
+
namespace = self.metadata.namespace
|
|
451
|
+
|
|
452
|
+
for view in self.views:
|
|
453
|
+
if not view.neatId:
|
|
454
|
+
view.neatId = namespace[view.view.suffix]
|
|
455
|
+
|
|
456
|
+
for property_ in self.properties:
|
|
457
|
+
if not property_.neatId:
|
|
458
|
+
property_.neatId = namespace[f"{property_.view.suffix}/{property_.view_property}"]
|
|
459
|
+
|
|
460
|
+
return self
|
|
461
|
+
|
|
462
|
+
def update_neat_id(self) -> None:
|
|
463
|
+
"""Update neat ids"""
|
|
464
|
+
|
|
465
|
+
namespace = self.metadata.namespace
|
|
466
|
+
|
|
467
|
+
for view in self.views:
|
|
468
|
+
view.neatId = namespace[view.view.suffix]
|
|
469
|
+
|
|
470
|
+
for property_ in self.properties:
|
|
471
|
+
property_.neatId = namespace[f"{property_.view.suffix}/{property_.view_property}"]
|
|
472
|
+
|
|
473
|
+
def sync_with_info_rules(self, info_rules: "InformationRules") -> None:
|
|
474
|
+
# Sync at the metadata level
|
|
475
|
+
if info_rules.metadata.physical == self.metadata.identifier:
|
|
476
|
+
self.metadata.logical = info_rules.metadata.identifier
|
|
477
|
+
else:
|
|
478
|
+
# if models are not linked to start with, we skip
|
|
479
|
+
return None
|
|
480
|
+
|
|
481
|
+
info_properties_by_neat_id = {prop.neatId: prop for prop in info_rules.properties}
|
|
482
|
+
dms_properties_by_neat_id = {prop.neatId: prop for prop in self.properties}
|
|
483
|
+
for neat_id, prop in info_properties_by_neat_id.items():
|
|
484
|
+
if prop.physical in dms_properties_by_neat_id:
|
|
485
|
+
dms_properties_by_neat_id[prop.physical].logical = neat_id
|
|
486
|
+
|
|
487
|
+
info_classes_by_neat_id = {cls.neatId: cls for cls in info_rules.classes}
|
|
488
|
+
dms_views_by_neat_id = {view.neatId: view for view in self.views}
|
|
489
|
+
for neat_id, class_ in info_classes_by_neat_id.items():
|
|
490
|
+
if class_.physical in dms_views_by_neat_id:
|
|
491
|
+
dms_views_by_neat_id[class_.physical].logical = neat_id
|
|
492
|
+
|
|
445
493
|
def as_schema(self, instance_space: str | None = None, remove_cdf_spaces: bool = False) -> DMSSchema:
|
|
446
494
|
from ._exporter import _DMSExporter
|
|
447
495
|
|
|
@@ -121,7 +121,7 @@ class InformationProperty(SheetRow):
|
|
|
121
121
|
min_count: Minimum count of the property values. Defaults to 0
|
|
122
122
|
max_count: Maximum count of the property values. Defaults to None
|
|
123
123
|
default: Default value of the property
|
|
124
|
-
|
|
124
|
+
instance_source: Actual rule for the transformation from source to target representation of
|
|
125
125
|
knowledge graph. Defaults to None (no transformation)
|
|
126
126
|
"""
|
|
127
127
|
|
|
@@ -153,10 +153,10 @@ class InformationProperty(SheetRow):
|
|
|
153
153
|
"which means that the property can hold any number of values (listable).",
|
|
154
154
|
)
|
|
155
155
|
default: Any | None = Field(alias="Default", default=None, description="Default value of the property.")
|
|
156
|
-
|
|
157
|
-
alias="
|
|
156
|
+
instance_source: RDFPath | None = Field(
|
|
157
|
+
alias="Instance Source",
|
|
158
158
|
default=None,
|
|
159
|
-
description="The
|
|
159
|
+
description="The link to to the instance property for the model. "
|
|
160
160
|
"The rule is provided in a RDFPath query syntax which is converted to downstream solution query (e.g. SPARQL).",
|
|
161
161
|
)
|
|
162
162
|
inherited: bool = Field(
|
|
@@ -181,7 +181,7 @@ class InformationProperty(SheetRow):
|
|
|
181
181
|
return float("inf")
|
|
182
182
|
return value
|
|
183
183
|
|
|
184
|
-
@field_validator("
|
|
184
|
+
@field_validator("instance_source", mode="before")
|
|
185
185
|
def generate_rdfpath(cls, value: str | RDFPath | None) -> RDFPath | None:
|
|
186
186
|
if value is None or isinstance(value, RDFPath):
|
|
187
187
|
return value
|
|
@@ -267,6 +267,49 @@ class InformationRules(BaseRules):
|
|
|
267
267
|
values = get_default_prefixes_and_namespaces()
|
|
268
268
|
return values
|
|
269
269
|
|
|
270
|
+
@model_validator(mode="after")
|
|
271
|
+
def set_neat_id(self) -> "InformationRules":
|
|
272
|
+
namespace = self.metadata.namespace
|
|
273
|
+
|
|
274
|
+
for class_ in self.classes:
|
|
275
|
+
if not class_.neatId:
|
|
276
|
+
class_.neatId = namespace[class_.class_.suffix]
|
|
277
|
+
for property_ in self.properties:
|
|
278
|
+
if not property_.neatId:
|
|
279
|
+
property_.neatId = namespace[f"{property_.class_.suffix}/{property_.property_}"]
|
|
280
|
+
|
|
281
|
+
return self
|
|
282
|
+
|
|
283
|
+
def update_neat_id(self) -> None:
|
|
284
|
+
"""Update neat ids"""
|
|
285
|
+
|
|
286
|
+
namespace = self.metadata.namespace
|
|
287
|
+
|
|
288
|
+
for class_ in self.classes:
|
|
289
|
+
class_.neatId = namespace[class_.class_.suffix]
|
|
290
|
+
for property_ in self.properties:
|
|
291
|
+
property_.neatId = namespace[f"{property_.class_.suffix}/{property_.property_}"]
|
|
292
|
+
|
|
293
|
+
def sync_with_dms_rules(self, dms_rules: "DMSRules") -> None:
|
|
294
|
+
# Sync at the metadata level
|
|
295
|
+
if dms_rules.metadata.logical == self.metadata.identifier:
|
|
296
|
+
self.metadata.physical = dms_rules.metadata.identifier
|
|
297
|
+
else:
|
|
298
|
+
# if models are not linked to start with, we skip
|
|
299
|
+
return None
|
|
300
|
+
|
|
301
|
+
info_properties_by_neat_id = {prop.neatId: prop for prop in self.properties}
|
|
302
|
+
dms_properties_by_neat_id = {prop.neatId: prop for prop in dms_rules.properties}
|
|
303
|
+
for neat_id, prop in dms_properties_by_neat_id.items():
|
|
304
|
+
if prop.logical in info_properties_by_neat_id:
|
|
305
|
+
info_properties_by_neat_id[prop.logical].physical = neat_id
|
|
306
|
+
|
|
307
|
+
info_classes_by_neat_id = {cls.neatId: cls for cls in self.classes}
|
|
308
|
+
dms_views_by_neat_id = {view.neatId: view for view in dms_rules.views}
|
|
309
|
+
for neat_id, view in dms_views_by_neat_id.items():
|
|
310
|
+
if view.logical in info_classes_by_neat_id:
|
|
311
|
+
info_classes_by_neat_id[view.logical].physical = neat_id
|
|
312
|
+
|
|
270
313
|
def as_dms_rules(self) -> "DMSRules":
|
|
271
314
|
from cognite.neat._rules.transformers._converters import _InformationRulesConverter
|
|
272
315
|
|
|
@@ -79,7 +79,7 @@ class InformationInputProperty(InputComponent[InformationProperty]):
|
|
|
79
79
|
min_count: int | None = None
|
|
80
80
|
max_count: int | float | None = None
|
|
81
81
|
default: Any | None = None
|
|
82
|
-
|
|
82
|
+
instance_source: str | None = None
|
|
83
83
|
# Only used internally
|
|
84
84
|
inherited: bool = False
|
|
85
85
|
neatId: str | URIRef | None = None
|
|
@@ -15,14 +15,13 @@ def _read_source_file() -> str:
|
|
|
15
15
|
return _CLASSIC_TO_CORE_MAPPING.read_text()
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
def load_classic_to_core_mapping(org_name: str, source_space: str, source_version: str) -> DMSRules:
|
|
19
|
-
if not org_name:
|
|
20
|
-
raise NeatValueError("Organization name must be provided.")
|
|
21
|
-
|
|
18
|
+
def load_classic_to_core_mapping(org_name: str | None, source_space: str, source_version: str) -> DMSRules:
|
|
22
19
|
from cognite.neat._rules.importers import YAMLImporter
|
|
23
20
|
from cognite.neat._rules.transformers import VerifyDMSRules
|
|
24
21
|
|
|
25
|
-
raw_str = _read_source_file()
|
|
22
|
+
raw_str = _read_source_file()
|
|
23
|
+
if org_name is not None:
|
|
24
|
+
raw_str = raw_str.replace("Classic", org_name)
|
|
26
25
|
|
|
27
26
|
loaded = yaml.safe_load(raw_str)
|
|
28
27
|
loaded["metadata"]["space"] = source_space
|