cognite-neat 0.84.1__py3-none-any.whl → 0.85.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.
- cognite/neat/__init__.py +2 -1
- cognite/neat/_shared.py +17 -1
- cognite/neat/_version.py +1 -1
- cognite/neat/graph/extractors/__init__.py +22 -0
- cognite/neat/graph/extractors/_base.py +5 -0
- cognite/neat/graph/extractors/_classic_cdf/_assets.py +7 -0
- cognite/neat/graph/extractors/_classic_cdf/_events.py +7 -0
- cognite/neat/graph/extractors/_classic_cdf/_labels.py +7 -0
- cognite/neat/graph/extractors/_classic_cdf/_relationships.py +7 -0
- cognite/neat/graph/extractors/_classic_cdf/_sequences.py +7 -0
- cognite/neat/graph/extractors/_classic_cdf/_timeseries.py +7 -0
- cognite/neat/graph/extractors/_dexpi.py +1 -1
- cognite/neat/graph/extractors/_rdf_file.py +8 -0
- cognite/neat/graph/loaders/__init__.py +19 -0
- cognite/neat/graph/loaders/_base.py +22 -45
- cognite/neat/graph/loaders/_rdf2dms.py +21 -9
- cognite/neat/graph/stores/_base.py +10 -0
- cognite/neat/graph/stores/_provenance.py +11 -3
- cognite/neat/rules/exporters/__init__.py +23 -1
- cognite/neat/rules/exporters/_base.py +5 -0
- cognite/neat/rules/exporters/_rules2dms.py +1 -1
- cognite/neat/rules/exporters/_rules2ontology.py +6 -0
- cognite/neat/rules/importers/__init__.py +20 -0
- cognite/neat/rules/importers/_base.py +5 -0
- cognite/neat/rules/importers/_dms2rules.py +10 -0
- cognite/neat/rules/importers/_dtdl2rules/dtdl_importer.py +1 -1
- cognite/neat/rules/importers/_inference2rules.py +5 -1
- cognite/neat/rules/importers/_spreadsheet2rules.py +17 -0
- cognite/neat/utils/auth.py +298 -0
- cognite/neat/utils/auxiliary.py +24 -0
- cognite/neat/utils/upload.py +5 -42
- {cognite_neat-0.84.1.dist-info → cognite_neat-0.85.0.dist-info}/METADATA +3 -1
- {cognite_neat-0.84.1.dist-info → cognite_neat-0.85.0.dist-info}/RECORD +37 -36
- /cognite/neat/utils/{xml.py → xml_.py} +0 -0
- {cognite_neat-0.84.1.dist-info → cognite_neat-0.85.0.dist-info}/LICENSE +0 -0
- {cognite_neat-0.84.1.dist-info → cognite_neat-0.85.0.dist-info}/WHEEL +0 -0
- {cognite_neat-0.84.1.dist-info → cognite_neat-0.85.0.dist-info}/entry_points.txt +0 -0
cognite/neat/__init__.py
CHANGED
cognite/neat/_shared.py
CHANGED
|
@@ -17,8 +17,24 @@ class NeatObject:
|
|
|
17
17
|
"""Return a dictionary representation of the object."""
|
|
18
18
|
raise NotImplementedError()
|
|
19
19
|
|
|
20
|
+
def _repr_html_(self) -> str:
|
|
21
|
+
return pd.Series(self.dump(aggregate=True)).to_frame(name="value")._repr_html_()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass(frozen=True)
|
|
25
|
+
class FrozenNeatObject:
|
|
26
|
+
"""A frozen neat object can be dumped to a dictionary."""
|
|
27
|
+
|
|
28
|
+
@abstractmethod
|
|
29
|
+
def dump(self, aggregate: bool = True) -> dict[str, Any]:
|
|
30
|
+
"""Return a dictionary representation of the object."""
|
|
31
|
+
raise NotImplementedError()
|
|
32
|
+
|
|
33
|
+
def _repr_html_(self) -> str:
|
|
34
|
+
return pd.Series(self.dump(aggregate=True)).to_frame(name="value")._repr_html_()
|
|
35
|
+
|
|
20
36
|
|
|
21
|
-
T_NeatObject = TypeVar("T_NeatObject", bound=NeatObject)
|
|
37
|
+
T_NeatObject = TypeVar("T_NeatObject", bound=NeatObject | FrozenNeatObject)
|
|
22
38
|
|
|
23
39
|
|
|
24
40
|
class NeatList(list, Sequence[T_NeatObject]):
|
cognite/neat/_version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.
|
|
1
|
+
__version__ = "0.85.0"
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from ._base import BaseExtractor
|
|
1
2
|
from ._classic_cdf._assets import AssetsExtractor
|
|
2
3
|
from ._classic_cdf._events import EventsExtractor
|
|
3
4
|
from ._classic_cdf._files import FilesExtractor
|
|
@@ -10,6 +11,7 @@ from ._mock_graph_generator import MockGraphGenerator
|
|
|
10
11
|
from ._rdf_file import RdfFileExtractor
|
|
11
12
|
|
|
12
13
|
__all__ = [
|
|
14
|
+
"BaseExtractor",
|
|
13
15
|
"AssetsExtractor",
|
|
14
16
|
"MockGraphGenerator",
|
|
15
17
|
"RelationshipsExtractor",
|
|
@@ -35,3 +37,23 @@ TripleExtractors = (
|
|
|
35
37
|
| RdfFileExtractor
|
|
36
38
|
| DexpiExtractor
|
|
37
39
|
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _repr_html_() -> str:
|
|
43
|
+
import pandas as pd
|
|
44
|
+
|
|
45
|
+
table = pd.DataFrame( # type: ignore[operator]
|
|
46
|
+
[
|
|
47
|
+
{
|
|
48
|
+
"Extractor": name,
|
|
49
|
+
"Description": globals()[name].__doc__.strip().split("\n")[0] if globals()[name].__doc__ else "Missing",
|
|
50
|
+
}
|
|
51
|
+
for name in __all__
|
|
52
|
+
if name != "BaseExtractor"
|
|
53
|
+
]
|
|
54
|
+
)._repr_html_()
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
"<strong>Extractor</strong> An extractor is used to read data from "
|
|
58
|
+
f"a source into Neat's internal triple storage. <br />{table}"
|
|
59
|
+
)
|
|
@@ -2,6 +2,7 @@ from abc import abstractmethod
|
|
|
2
2
|
from collections.abc import Iterable
|
|
3
3
|
|
|
4
4
|
from cognite.neat.graph.models import Triple
|
|
5
|
+
from cognite.neat.utils.auxiliary import class_html_doc
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
class BaseExtractor:
|
|
@@ -12,3 +13,7 @@ class BaseExtractor:
|
|
|
12
13
|
@abstractmethod
|
|
13
14
|
def extract(self) -> Iterable[Triple]:
|
|
14
15
|
raise NotImplementedError()
|
|
16
|
+
|
|
17
|
+
@classmethod
|
|
18
|
+
def _repr_html_(cls) -> str:
|
|
19
|
+
return class_html_doc(cls)
|
|
@@ -14,6 +14,13 @@ from cognite.neat.utils.utils import create_sha256_hash, string_to_ideal_type
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class AssetsExtractor(BaseExtractor):
|
|
17
|
+
"""Extract data from Cognite Data Fusions Assets into Neat.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
assets (Iterable[Asset]): An iterable of assets.
|
|
21
|
+
namespace (Namespace, optional): The namespace to use. Defaults to DEFAULT_NAMESPACE.
|
|
22
|
+
"""
|
|
23
|
+
|
|
17
24
|
def __init__(
|
|
18
25
|
self,
|
|
19
26
|
assets: Iterable[Asset],
|
|
@@ -15,6 +15,13 @@ from cognite.neat.utils.utils import string_to_ideal_type
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class EventsExtractor(BaseExtractor):
|
|
18
|
+
"""Extract data from Cognite Data Fusions Events into Neat.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
events (Iterable[Event]): An iterable of events.
|
|
22
|
+
namespace (Namespace, optional): The namespace to use. Defaults to DEFAULT_NAMESPACE.
|
|
23
|
+
"""
|
|
24
|
+
|
|
18
25
|
def __init__(
|
|
19
26
|
self,
|
|
20
27
|
events: Iterable[Event],
|
|
@@ -14,6 +14,13 @@ from cognite.neat.utils.utils import create_sha256_hash
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class LabelsExtractor(BaseExtractor):
|
|
17
|
+
"""Extract data from Cognite Data Fusions Labels into Neat.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
labels (Iterable[LabelDefinition]): An iterable of labels.
|
|
21
|
+
namespace (Namespace, optional): The namespace to use. Defaults to DEFAULT_NAMESPACE.
|
|
22
|
+
"""
|
|
23
|
+
|
|
17
24
|
def __init__(
|
|
18
25
|
self,
|
|
19
26
|
labels: Iterable[LabelDefinition],
|
|
@@ -15,6 +15,13 @@ from cognite.neat.utils.utils import create_sha256_hash
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class RelationshipsExtractor(BaseExtractor):
|
|
18
|
+
"""Extract data from Cognite Data Fusions Relationships into Neat.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
relationships (Iterable[Asset]): An iterable of relationships.
|
|
22
|
+
namespace (Namespace, optional): The namespace to use. Defaults to DEFAULT_NAMESPACE.
|
|
23
|
+
"""
|
|
24
|
+
|
|
18
25
|
def __init__(
|
|
19
26
|
self,
|
|
20
27
|
relationships: Iterable[Relationship],
|
|
@@ -15,6 +15,13 @@ from cognite.neat.utils.utils import string_to_ideal_type
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class SequencesExtractor(BaseExtractor):
|
|
18
|
+
"""Extract data from Cognite Data Fusions Sequences into Neat.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
sequence (Iterable[Sequence]): An iterable of sequences.
|
|
22
|
+
namespace (Namespace, optional): The namespace to use. Defaults to DEFAULT_NAMESPACE.
|
|
23
|
+
"""
|
|
24
|
+
|
|
18
25
|
def __init__(
|
|
19
26
|
self,
|
|
20
27
|
sequence: Iterable[Sequence],
|
|
@@ -15,6 +15,13 @@ from cognite.neat.utils.utils import string_to_ideal_type
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class TimeSeriesExtractor(BaseExtractor):
|
|
18
|
+
"""Extract data from Cognite Data Fusions TimeSeries into Neat.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
timeseries (Iterable[TimeSeries]): An iterable of timeseries.
|
|
22
|
+
namespace (Namespace, optional): The namespace to use. Defaults to DEFAULT_NAMESPACE.
|
|
23
|
+
"""
|
|
24
|
+
|
|
18
25
|
def __init__(
|
|
19
26
|
self,
|
|
20
27
|
timeseries: Iterable[TimeSeries],
|
|
@@ -10,7 +10,7 @@ from cognite.neat.constants import DEFAULT_NAMESPACE
|
|
|
10
10
|
from cognite.neat.graph.extractors._base import BaseExtractor
|
|
11
11
|
from cognite.neat.graph.models import Triple
|
|
12
12
|
from cognite.neat.utils.utils import as_neat_compliant_uri
|
|
13
|
-
from cognite.neat.utils.
|
|
13
|
+
from cognite.neat.utils.xml_ import get_children, iterate_tree
|
|
14
14
|
|
|
15
15
|
DEXPI = Namespace("http://sandbox.dexpi.org/rdl/")
|
|
16
16
|
QUDT = Namespace("https://qudt.org/vocab/unit/")
|
|
@@ -7,6 +7,14 @@ from cognite.neat.graph.extractors._base import BaseExtractor
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class RdfFileExtractor(BaseExtractor):
|
|
10
|
+
"""Extract data from RDF files into Neat.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
filepath (Path): The path to the RDF file.
|
|
14
|
+
mime_type (MIMETypes, optional): The MIME type of the RDF file. Defaults to "application/rdf+xml".
|
|
15
|
+
base_uri (URIRef, optional): The base URI to use. Defaults to None.
|
|
16
|
+
"""
|
|
17
|
+
|
|
10
18
|
def __init__(
|
|
11
19
|
self,
|
|
12
20
|
filepath: Path,
|
|
@@ -2,3 +2,22 @@ from ._base import BaseLoader, CDFLoader
|
|
|
2
2
|
from ._rdf2dms import DMSLoader
|
|
3
3
|
|
|
4
4
|
__all__ = ["BaseLoader", "CDFLoader", "DMSLoader"]
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _repr_html_() -> str:
|
|
8
|
+
import pandas as pd
|
|
9
|
+
|
|
10
|
+
table = pd.DataFrame( # type: ignore[operator]
|
|
11
|
+
[
|
|
12
|
+
{
|
|
13
|
+
"Loader": name,
|
|
14
|
+
"Description": globals()[name].__doc__.strip().split("\n")[0] if globals()[name].__doc__ else "Missing",
|
|
15
|
+
}
|
|
16
|
+
for name in __all__
|
|
17
|
+
if name not in ("BaseLoader", "CDFLoader")
|
|
18
|
+
]
|
|
19
|
+
)._repr_html_()
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
"<strong>Loader</strong> A loader writes data from Neat's triple storage into a target system" f"<br />{table}"
|
|
23
|
+
)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
|
-
from collections.abc import Iterable
|
|
2
|
+
from collections.abc import Hashable, Iterable
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from typing import ClassVar, Generic,
|
|
4
|
+
from typing import ClassVar, Generic, TypeVar
|
|
5
5
|
|
|
6
6
|
from cognite.client import CogniteClient
|
|
7
7
|
from cognite.client.data_classes.capabilities import Capability
|
|
@@ -9,7 +9,8 @@ from cognite.client.data_classes.capabilities import Capability
|
|
|
9
9
|
from cognite.neat.graph import NeatGraphStore
|
|
10
10
|
from cognite.neat.graph.issues.loader import FailedAuthorizationError
|
|
11
11
|
from cognite.neat.issues import NeatIssue, NeatIssueList
|
|
12
|
-
from cognite.neat.utils.
|
|
12
|
+
from cognite.neat.utils.auxiliary import class_html_doc
|
|
13
|
+
from cognite.neat.utils.upload import UploadResult, UploadResultList
|
|
13
14
|
|
|
14
15
|
T_Output = TypeVar("T_Output")
|
|
15
16
|
|
|
@@ -34,49 +35,25 @@ class BaseLoader(ABC, Generic[T_Output]):
|
|
|
34
35
|
"""Load the graph with data."""
|
|
35
36
|
pass
|
|
36
37
|
|
|
38
|
+
@classmethod
|
|
39
|
+
def _repr_html_(cls) -> str:
|
|
40
|
+
return class_html_doc(cls)
|
|
41
|
+
|
|
37
42
|
|
|
38
43
|
class CDFLoader(BaseLoader[T_Output]):
|
|
39
44
|
_UPLOAD_BATCH_SIZE: ClassVar[int] = 1000
|
|
40
45
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
) -> Iterable[
|
|
45
|
-
|
|
46
|
-
@overload
|
|
47
|
-
def load_into_cdf_iterable(
|
|
48
|
-
self, client: CogniteClient, return_diffs: Literal[True], dry_run: bool = False
|
|
49
|
-
) -> Iterable[UploadDiffsID]: ...
|
|
50
|
-
|
|
51
|
-
def load_into_cdf_iterable(
|
|
52
|
-
self, client: CogniteClient, return_diffs: bool = False, dry_run: bool = False
|
|
53
|
-
) -> Iterable[UploadResultIDs] | Iterable[UploadDiffsID]:
|
|
54
|
-
yield from self._load_into_cdf_iterable(client, return_diffs, dry_run)
|
|
55
|
-
|
|
56
|
-
@overload
|
|
57
|
-
def load_into_cdf(
|
|
58
|
-
self, client: CogniteClient, return_diffs: Literal[False] = False, dry_run: bool = False
|
|
59
|
-
) -> list[UploadResultIDs]: ...
|
|
60
|
-
|
|
61
|
-
@overload
|
|
62
|
-
def load_into_cdf(
|
|
63
|
-
self, client: CogniteClient, return_diffs: Literal[True], dry_run: bool = False
|
|
64
|
-
) -> list[UploadDiffsID]: ...
|
|
65
|
-
|
|
66
|
-
def load_into_cdf(
|
|
67
|
-
self, client: CogniteClient, return_diffs: bool = False, dry_run: bool = False
|
|
68
|
-
) -> list[UploadResultIDs] | list[UploadDiffsID]:
|
|
69
|
-
return list(self._load_into_cdf_iterable(client, return_diffs, dry_run)) # type: ignore[return-value]
|
|
70
|
-
|
|
71
|
-
def _load_into_cdf_iterable(
|
|
72
|
-
self, client: CogniteClient, return_diffs: bool = False, dry_run: bool = False
|
|
73
|
-
) -> Iterable[UploadResultIDs] | Iterable[UploadDiffsID]:
|
|
46
|
+
def load_into_cdf(self, client: CogniteClient, dry_run: bool = False) -> UploadResultList:
|
|
47
|
+
return UploadResultList(self.load_into_cdf_iterable(client, dry_run))
|
|
48
|
+
|
|
49
|
+
def load_into_cdf_iterable(self, client: CogniteClient, dry_run: bool = False) -> Iterable[UploadResult]:
|
|
74
50
|
missing_capabilities = client.iam.verify_capabilities(self._get_required_capabilities())
|
|
75
|
-
result_cls = UploadDiffsID if return_diffs else UploadResultIDs
|
|
76
51
|
if missing_capabilities:
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
52
|
+
upload_result = UploadResult[Hashable](name=type(self).__name__)
|
|
53
|
+
upload_result.issues.append(
|
|
54
|
+
FailedAuthorizationError(action="Upload to CDF", reason=str(missing_capabilities))
|
|
55
|
+
)
|
|
56
|
+
yield upload_result
|
|
80
57
|
return
|
|
81
58
|
|
|
82
59
|
issues = NeatIssueList[NeatIssue]()
|
|
@@ -88,10 +65,11 @@ class CDFLoader(BaseLoader[T_Output]):
|
|
|
88
65
|
items.append(result)
|
|
89
66
|
|
|
90
67
|
if len(items) >= self._UPLOAD_BATCH_SIZE:
|
|
91
|
-
yield self._upload_to_cdf(client, items,
|
|
92
|
-
|
|
68
|
+
yield self._upload_to_cdf(client, items, dry_run, issues)
|
|
69
|
+
issues = NeatIssueList[NeatIssue]()
|
|
70
|
+
items = []
|
|
93
71
|
if items:
|
|
94
|
-
yield self._upload_to_cdf(client, items,
|
|
72
|
+
yield self._upload_to_cdf(client, items, dry_run, issues)
|
|
95
73
|
|
|
96
74
|
@abstractmethod
|
|
97
75
|
def _get_required_capabilities(self) -> list[Capability]:
|
|
@@ -102,8 +80,7 @@ class CDFLoader(BaseLoader[T_Output]):
|
|
|
102
80
|
self,
|
|
103
81
|
client: CogniteClient,
|
|
104
82
|
items: list[T_Output],
|
|
105
|
-
return_diffs: bool,
|
|
106
83
|
dry_run: bool,
|
|
107
84
|
read_issues: NeatIssueList,
|
|
108
|
-
) ->
|
|
85
|
+
) -> UploadResult:
|
|
109
86
|
raise NotImplementedError
|
|
@@ -10,6 +10,7 @@ from cognite.client import CogniteClient
|
|
|
10
10
|
from cognite.client import data_modeling as dm
|
|
11
11
|
from cognite.client.data_classes.capabilities import Capability, DataModelInstancesAcl
|
|
12
12
|
from cognite.client.data_classes.data_modeling import ViewId
|
|
13
|
+
from cognite.client.data_classes.data_modeling.ids import InstanceId
|
|
13
14
|
from cognite.client.data_classes.data_modeling.views import SingleEdgeConnection
|
|
14
15
|
from cognite.client.exceptions import CogniteAPIError
|
|
15
16
|
from pydantic import ValidationInfo, create_model, field_validator
|
|
@@ -21,13 +22,24 @@ from cognite.neat.graph.stores import NeatGraphStore
|
|
|
21
22
|
from cognite.neat.issues import NeatIssue, NeatIssueList
|
|
22
23
|
from cognite.neat.rules.models import DMSRules
|
|
23
24
|
from cognite.neat.rules.models.data_types import _DATA_TYPE_BY_DMS_TYPE
|
|
24
|
-
from cognite.neat.utils.upload import
|
|
25
|
+
from cognite.neat.utils.upload import UploadResult
|
|
25
26
|
from cognite.neat.utils.utils import create_sha256_hash
|
|
26
27
|
|
|
27
28
|
from ._base import CDFLoader
|
|
28
29
|
|
|
29
30
|
|
|
30
31
|
class DMSLoader(CDFLoader[dm.InstanceApply]):
|
|
32
|
+
"""Load data from Cognite Data Fusions Data Modeling Service (DMS) into Neat.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
graph_store (NeatGraphStore): The graph store to load the data into.
|
|
36
|
+
data_model (dm.DataModel[dm.View] | None): The data model to load.
|
|
37
|
+
instance_space (str): The instance space to load the data into.
|
|
38
|
+
class_by_view_id (dict[ViewId, str] | None): A mapping from view id to class name. Defaults to None.
|
|
39
|
+
creat_issues (Sequence[NeatIssue] | None): A list of issues that occurred during reading. Defaults to None.
|
|
40
|
+
tracker (type[Tracker] | None): The tracker to use. Defaults to None.
|
|
41
|
+
"""
|
|
42
|
+
|
|
31
43
|
def __init__(
|
|
32
44
|
self,
|
|
33
45
|
graph_store: NeatGraphStore,
|
|
@@ -243,11 +255,10 @@ class DMSLoader(CDFLoader[dm.InstanceApply]):
|
|
|
243
255
|
self,
|
|
244
256
|
client: CogniteClient,
|
|
245
257
|
items: list[dm.InstanceApply],
|
|
246
|
-
return_diffs: bool,
|
|
247
258
|
dry_run: bool,
|
|
248
259
|
read_issues: NeatIssueList,
|
|
249
|
-
) ->
|
|
250
|
-
result =
|
|
260
|
+
) -> UploadResult:
|
|
261
|
+
result = UploadResult[InstanceId](name=type(self).__name__, issues=read_issues)
|
|
251
262
|
try:
|
|
252
263
|
nodes = [item for item in items if isinstance(item, dm.NodeApply)]
|
|
253
264
|
edges = [item for item in items if isinstance(item, dm.EdgeApply)]
|
|
@@ -260,16 +271,17 @@ class DMSLoader(CDFLoader[dm.InstanceApply]):
|
|
|
260
271
|
)
|
|
261
272
|
except CogniteAPIError as e:
|
|
262
273
|
result.error_messages.append(str(e))
|
|
263
|
-
result.
|
|
274
|
+
result.failed_upserted.update(item.as_id() for item in e.failed + e.unknown)
|
|
275
|
+
result.created.update(item.as_id() for item in e.successful)
|
|
264
276
|
else:
|
|
265
277
|
for instance in itertools.chain(upserted.nodes, upserted.edges):
|
|
266
278
|
if instance.was_modified and instance.created_time == instance.last_updated_time:
|
|
267
|
-
result.created.
|
|
279
|
+
result.created.add(instance.as_id())
|
|
268
280
|
elif instance.was_modified:
|
|
269
|
-
result.changed.
|
|
281
|
+
result.changed.add(instance.as_id())
|
|
270
282
|
else:
|
|
271
|
-
result.unchanged.
|
|
272
|
-
return result
|
|
283
|
+
result.unchanged.add(instance.as_id())
|
|
284
|
+
return result
|
|
273
285
|
|
|
274
286
|
|
|
275
287
|
def _triples2dictionary(
|
|
@@ -282,3 +282,13 @@ class NeatGraphStore:
|
|
|
282
282
|
description=transformer.description,
|
|
283
283
|
)
|
|
284
284
|
)
|
|
285
|
+
|
|
286
|
+
def _repr_html_(self) -> str:
|
|
287
|
+
provenance = self.provenance._repr_html_()
|
|
288
|
+
|
|
289
|
+
return (
|
|
290
|
+
f"<strong>{type(self).__name__}</strong> A graph store is a container for storing triples. "
|
|
291
|
+
"It can be queried and transformed to extract information.<br />"
|
|
292
|
+
"<strong>Provenance</strong> Provenance is a record of changes that have occurred in the graph store.<br />"
|
|
293
|
+
f"{provenance}"
|
|
294
|
+
)
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
import uuid
|
|
11
|
-
from collections import UserList
|
|
12
11
|
from collections.abc import Sequence
|
|
13
12
|
from dataclasses import dataclass
|
|
14
13
|
from datetime import datetime
|
|
@@ -16,6 +15,7 @@ from typing import TypeVar
|
|
|
16
15
|
|
|
17
16
|
from rdflib import PROV, RDF, Literal, URIRef
|
|
18
17
|
|
|
18
|
+
from cognite.neat._shared import FrozenNeatObject, NeatList
|
|
19
19
|
from cognite.neat.constants import DEFAULT_NAMESPACE
|
|
20
20
|
|
|
21
21
|
|
|
@@ -64,7 +64,7 @@ class Entity:
|
|
|
64
64
|
|
|
65
65
|
|
|
66
66
|
@dataclass(frozen=True)
|
|
67
|
-
class Change:
|
|
67
|
+
class Change(FrozenNeatObject):
|
|
68
68
|
agent: Agent
|
|
69
69
|
activity: Activity
|
|
70
70
|
entity: Entity
|
|
@@ -81,11 +81,19 @@ class Change:
|
|
|
81
81
|
entity = Entity(was_generated_by=activity, was_attributed_to=agent)
|
|
82
82
|
return cls(agent, activity, entity, description)
|
|
83
83
|
|
|
84
|
+
def dump(self, aggregate: bool = True) -> dict[str, str]:
|
|
85
|
+
return {
|
|
86
|
+
"Agent": self.agent.id_,
|
|
87
|
+
"Activity": self.activity.id_,
|
|
88
|
+
"Entity": self.entity.id_,
|
|
89
|
+
"Description": self.description,
|
|
90
|
+
}
|
|
91
|
+
|
|
84
92
|
|
|
85
93
|
T_Change = TypeVar("T_Change", bound=Change)
|
|
86
94
|
|
|
87
95
|
|
|
88
|
-
class Provenance(
|
|
96
|
+
class Provenance(NeatList[Change]):
|
|
89
97
|
def __init__(self, changes: Sequence[T_Change] | None = None):
|
|
90
98
|
super().__init__(changes or [])
|
|
91
99
|
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
from .
|
|
1
|
+
from ._base import BaseExporter, CDFExporter
|
|
2
|
+
from ._rules2dms import DMSExporter
|
|
2
3
|
from ._rules2excel import ExcelExporter
|
|
3
4
|
from ._rules2ontology import GraphExporter, OWLExporter, SemanticDataModelExporter, SHACLExporter
|
|
4
5
|
from ._rules2yaml import YAMLExporter
|
|
5
6
|
|
|
6
7
|
__all__ = [
|
|
8
|
+
"BaseExporter",
|
|
7
9
|
"DMSExporter",
|
|
8
10
|
"CDFExporter",
|
|
9
11
|
"SemanticDataModelExporter",
|
|
@@ -13,3 +15,23 @@ __all__ = [
|
|
|
13
15
|
"ExcelExporter",
|
|
14
16
|
"YAMLExporter",
|
|
15
17
|
]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _repr_html_() -> str:
|
|
21
|
+
import pandas as pd
|
|
22
|
+
|
|
23
|
+
table = pd.DataFrame( # type: ignore[operator]
|
|
24
|
+
[
|
|
25
|
+
{
|
|
26
|
+
"Exporter": name,
|
|
27
|
+
"Description": globals()[name].__doc__.strip().split("\n")[0] if globals()[name].__doc__ else "Missing",
|
|
28
|
+
}
|
|
29
|
+
for name in __all__
|
|
30
|
+
if name not in ("BaseExporter", "CDFExporter", "GraphExporter")
|
|
31
|
+
]
|
|
32
|
+
)._repr_html_()
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
"<strong>Exporter</strong> An exporter converts Neat's representation of a data model called <em>Rules</em>"
|
|
36
|
+
f" into a schema/data model for a target format.<br />{table}"
|
|
37
|
+
)
|
|
@@ -7,6 +7,7 @@ from cognite.client import CogniteClient
|
|
|
7
7
|
|
|
8
8
|
from cognite.neat.rules._shared import Rules
|
|
9
9
|
from cognite.neat.rules.models import DMSRules, InformationRules, RoleTypes
|
|
10
|
+
from cognite.neat.utils.auxiliary import class_html_doc
|
|
10
11
|
from cognite.neat.utils.upload import UploadResult, UploadResultList
|
|
11
12
|
|
|
12
13
|
T_Export = TypeVar("T_Export")
|
|
@@ -34,6 +35,10 @@ class BaseExporter(ABC, Generic[T_Export]):
|
|
|
34
35
|
else:
|
|
35
36
|
raise NotImplementedError(f"Role {output_role} is not supported for {type(rules).__name__} rules")
|
|
36
37
|
|
|
38
|
+
@classmethod
|
|
39
|
+
def _repr_html_(cls) -> str:
|
|
40
|
+
return class_html_doc(cls, include_factory_methods=False)
|
|
41
|
+
|
|
37
42
|
|
|
38
43
|
class CDFExporter(BaseExporter[T_Export]):
|
|
39
44
|
@abstractmethod
|
|
@@ -39,7 +39,7 @@ Component: TypeAlias = Literal["all", "spaces", "data_models", "views", "contain
|
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
class DMSExporter(CDFExporter[DMSSchema]):
|
|
42
|
-
"""
|
|
42
|
+
"""Export rules to Cognite Data Fusion's Data Model Storage (DMS) service.
|
|
43
43
|
|
|
44
44
|
Args:
|
|
45
45
|
export_components (frozenset[Literal["all", "spaces", "data_models", "views", "containers"]], optional):
|
|
@@ -39,16 +39,22 @@ class GraphExporter(BaseExporter[Graph], ABC):
|
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
class OWLExporter(GraphExporter):
|
|
42
|
+
"""Exports rules to an OWL ontology."""
|
|
43
|
+
|
|
42
44
|
def export(self, rules: Rules) -> Graph:
|
|
43
45
|
return Ontology.from_rules(rules).as_owl()
|
|
44
46
|
|
|
45
47
|
|
|
46
48
|
class SHACLExporter(GraphExporter):
|
|
49
|
+
"""Exports rules to a SHACL graph."""
|
|
50
|
+
|
|
47
51
|
def export(self, rules: Rules) -> Graph:
|
|
48
52
|
return Ontology.from_rules(rules).as_shacl()
|
|
49
53
|
|
|
50
54
|
|
|
51
55
|
class SemanticDataModelExporter(GraphExporter):
|
|
56
|
+
"""Exports rules to a semantic data model."""
|
|
57
|
+
|
|
52
58
|
def export(self, rules: Rules) -> Graph:
|
|
53
59
|
return Ontology.from_rules(rules).as_semantic_data_model()
|
|
54
60
|
|
|
@@ -16,3 +16,23 @@ __all__ = [
|
|
|
16
16
|
"YAMLImporter",
|
|
17
17
|
"InferenceImporter",
|
|
18
18
|
]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _repr_html_() -> str:
|
|
22
|
+
import pandas as pd
|
|
23
|
+
|
|
24
|
+
table = pd.DataFrame( # type: ignore[operator]
|
|
25
|
+
[
|
|
26
|
+
{
|
|
27
|
+
"Importer": name,
|
|
28
|
+
"Description": globals()[name].__doc__.strip().split("\n")[0] if globals()[name].__doc__ else "Missing",
|
|
29
|
+
}
|
|
30
|
+
for name in __all__
|
|
31
|
+
if name != "BaseImporter"
|
|
32
|
+
]
|
|
33
|
+
)._repr_html_()
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
"<strong>Importer</strong> An importer reads data/schema/data model from a source"
|
|
37
|
+
f" and converts it into Neat's representation of a data model called <em>Rules</em>.<br />{table}"
|
|
38
|
+
)
|
|
@@ -12,6 +12,7 @@ from rdflib import Namespace
|
|
|
12
12
|
from cognite.neat.rules._shared import Rules
|
|
13
13
|
from cognite.neat.rules.issues.base import IssueList, NeatValidationError, ValidationWarning
|
|
14
14
|
from cognite.neat.rules.models import AssetRules, DMSRules, InformationRules, RoleTypes
|
|
15
|
+
from cognite.neat.utils.auxiliary import class_html_doc
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
class BaseImporter(ABC):
|
|
@@ -79,6 +80,10 @@ class BaseImporter(ABC):
|
|
|
79
80
|
"description": f"Imported using {type(self).__name__}",
|
|
80
81
|
}
|
|
81
82
|
|
|
83
|
+
@classmethod
|
|
84
|
+
def _repr_html_(cls) -> str:
|
|
85
|
+
return class_html_doc(cls)
|
|
86
|
+
|
|
82
87
|
|
|
83
88
|
class _FutureResult:
|
|
84
89
|
def __init__(self) -> None:
|
|
@@ -46,6 +46,16 @@ from cognite.neat.rules.models.entities import (
|
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
class DMSImporter(BaseImporter):
|
|
49
|
+
"""Imports a Data Model from Cognite Data Fusion.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
schema: The schema containing the data model.
|
|
53
|
+
read_issues: A list of issues that occurred during the import.
|
|
54
|
+
metadata: Metadata for the data model.
|
|
55
|
+
ref_metadata: Metadata for the reference data model.
|
|
56
|
+
|
|
57
|
+
"""
|
|
58
|
+
|
|
49
59
|
def __init__(
|
|
50
60
|
self,
|
|
51
61
|
schema: DMSSchema,
|
|
@@ -18,7 +18,7 @@ from cognite.neat.utils.text import to_pascal
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
class DTDLImporter(BaseImporter):
|
|
21
|
-
"""Importer
|
|
21
|
+
"""Importer from Azure Digital Twin - DTDL (Digital Twin Definition Language).
|
|
22
22
|
|
|
23
23
|
This importer supports DTDL v2.0 and v3.0.
|
|
24
24
|
|
|
@@ -33,7 +33,11 @@ INSTANCE_PROPERTIES_DEFINITION = """SELECT ?property (count(?property) as ?occur
|
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
class InferenceImporter(BaseImporter):
|
|
36
|
-
"""
|
|
36
|
+
"""Infers rules from a triple store.
|
|
37
|
+
|
|
38
|
+
Rules inference through analysis of knowledge graph provided in various formats.
|
|
39
|
+
Use the factory methods to create an triples store from sources such as
|
|
40
|
+
RDF files, JSON files, YAML files, XML files, or directly from a graph store.
|
|
37
41
|
|
|
38
42
|
Args:
|
|
39
43
|
issue_list: Issue list to store issues
|
|
@@ -205,6 +205,12 @@ class SpreadsheetReader:
|
|
|
205
205
|
|
|
206
206
|
|
|
207
207
|
class ExcelImporter(BaseImporter):
|
|
208
|
+
"""Import rules from an Excel file.
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
filepath (Path): The path to the Excel file.
|
|
212
|
+
"""
|
|
213
|
+
|
|
208
214
|
def __init__(self, filepath: Path):
|
|
209
215
|
self.filepath = filepath
|
|
210
216
|
|
|
@@ -286,6 +292,17 @@ class ExcelImporter(BaseImporter):
|
|
|
286
292
|
|
|
287
293
|
|
|
288
294
|
class GoogleSheetImporter(BaseImporter):
|
|
295
|
+
"""Import rules from a Google Sheet.
|
|
296
|
+
|
|
297
|
+
.. warning::
|
|
298
|
+
|
|
299
|
+
This importer is experimental and may not work as expected.
|
|
300
|
+
|
|
301
|
+
Args:
|
|
302
|
+
sheet_id (str): The Google Sheet ID.
|
|
303
|
+
skiprows (int): The number of rows to skip when reading the Google Sheet.
|
|
304
|
+
"""
|
|
305
|
+
|
|
289
306
|
def __init__(self, sheet_id: str, skiprows: int = 1):
|
|
290
307
|
self.sheet_id = sheet_id
|
|
291
308
|
self.skiprows = skiprows
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import subprocess
|
|
3
|
+
from contextlib import suppress
|
|
4
|
+
from dataclasses import dataclass, fields
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Literal, TypeAlias, get_args
|
|
7
|
+
|
|
8
|
+
from cognite.client import CogniteClient
|
|
9
|
+
from cognite.client.credentials import CredentialProvider, OAuthClientCredentials, OAuthInteractive, Token
|
|
10
|
+
|
|
11
|
+
from cognite.neat import _version
|
|
12
|
+
from cognite.neat.utils.auxiliary import local_import
|
|
13
|
+
|
|
14
|
+
__all__ = ["get_cognite_client"]
|
|
15
|
+
|
|
16
|
+
_LOGIN_FLOW: TypeAlias = Literal["infer", "client_credentials", "interactive", "token"]
|
|
17
|
+
_VALID_LOGIN_FLOWS = get_args(_LOGIN_FLOW)
|
|
18
|
+
_CLIENT_NAME = f"CogniteNeat:{_version.__version__}"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_cognite_client() -> CogniteClient:
|
|
22
|
+
with suppress(KeyError):
|
|
23
|
+
variables = _EnvironmentVariables.create_from_environ()
|
|
24
|
+
return variables.get_client()
|
|
25
|
+
|
|
26
|
+
repo_root = _repo_root()
|
|
27
|
+
if repo_root:
|
|
28
|
+
with suppress(KeyError, FileNotFoundError, TypeError):
|
|
29
|
+
variables = _from_dotenv(repo_root / ".env")
|
|
30
|
+
client = variables.get_client()
|
|
31
|
+
print("Found .env file in repository root. Loaded variables from .env file.")
|
|
32
|
+
return client
|
|
33
|
+
variables = _prompt_user()
|
|
34
|
+
if repo_root and _env_in_gitignore(repo_root):
|
|
35
|
+
local_import("rich", "jupyter")
|
|
36
|
+
from rich.prompt import Prompt
|
|
37
|
+
|
|
38
|
+
env_file = repo_root / ".env"
|
|
39
|
+
answer = Prompt.ask(
|
|
40
|
+
"Do you store the variables in an .env file in the repository root for easy reuse?", choices=["y", "n"]
|
|
41
|
+
)
|
|
42
|
+
if env_file.exists():
|
|
43
|
+
answer = Prompt.ask(f"{env_file} already exists. Overwrite?", choices=["y", "n"])
|
|
44
|
+
if answer == "y":
|
|
45
|
+
env_file.write_text(variables.create_env_file())
|
|
46
|
+
print("Created .env file in repository root.")
|
|
47
|
+
|
|
48
|
+
return variables.get_client()
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass
|
|
52
|
+
class _EnvironmentVariables:
|
|
53
|
+
CDF_CLUSTER: str
|
|
54
|
+
CDF_PROJECT: str
|
|
55
|
+
LOGIN_FLOW: _LOGIN_FLOW = "infer"
|
|
56
|
+
IDP_CLIENT_ID: str | None = None
|
|
57
|
+
IDP_CLIENT_SECRET: str | None = None
|
|
58
|
+
TOKEN: str | None = None
|
|
59
|
+
|
|
60
|
+
IDP_TENANT_ID: str | None = None
|
|
61
|
+
IDP_TOKEN_URL: str | None = None
|
|
62
|
+
|
|
63
|
+
CDF_URL: str | None = None
|
|
64
|
+
IDP_AUDIENCE: str | None = None
|
|
65
|
+
IDP_SCOPES: str | None = None
|
|
66
|
+
IDP_AUTHORITY_URL: str | None = None
|
|
67
|
+
|
|
68
|
+
def __post_init__(self):
|
|
69
|
+
if self.LOGIN_FLOW.lower() not in _VALID_LOGIN_FLOWS:
|
|
70
|
+
raise ValueError(f"LOGIN_FLOW must be one of {_VALID_LOGIN_FLOWS}")
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def cdf_url(self) -> str:
|
|
74
|
+
return self.CDF_URL or f"https://{self.CDF_CLUSTER}.cognitedata.com"
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def idp_token_url(self) -> str:
|
|
78
|
+
if self.IDP_TOKEN_URL:
|
|
79
|
+
return self.IDP_TOKEN_URL
|
|
80
|
+
if not self.IDP_TENANT_ID:
|
|
81
|
+
raise KeyError("IDP_TENANT_ID or IDP_TOKEN_URL must be set in the environment.")
|
|
82
|
+
return f"https://login.microsoftonline.com/{self.IDP_TENANT_ID}/oauth2/v2.0/token"
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def idp_audience(self) -> str:
|
|
86
|
+
return self.IDP_AUDIENCE or f"https://{self.CDF_CLUSTER}.cognitedata.com"
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def idp_scopes(self) -> list[str]:
|
|
90
|
+
if self.IDP_SCOPES:
|
|
91
|
+
return self.IDP_SCOPES.split()
|
|
92
|
+
return [f"https://{self.CDF_CLUSTER}.cognitedata.com/.default"]
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def idp_authority_url(self) -> str:
|
|
96
|
+
if self.IDP_AUTHORITY_URL:
|
|
97
|
+
return self.IDP_AUTHORITY_URL
|
|
98
|
+
if not self.IDP_TENANT_ID:
|
|
99
|
+
raise KeyError("IDP_TENANT_ID or IDP_AUTHORITY_URL must be set in the environment.")
|
|
100
|
+
return f"https://login.microsoftonline.com/{self.IDP_TENANT_ID}"
|
|
101
|
+
|
|
102
|
+
@classmethod
|
|
103
|
+
def create_from_environ(cls) -> "_EnvironmentVariables":
|
|
104
|
+
if "CDF_CLUSTER" not in os.environ or "CDF_PROJECT" not in os.environ:
|
|
105
|
+
raise KeyError("CDF_CLUSTER and CDF_PROJECT must be set in the environment.", "CDF_CLUSTER", "CDF_PROJECT")
|
|
106
|
+
|
|
107
|
+
return cls(
|
|
108
|
+
CDF_CLUSTER=os.environ["CDF_CLUSTER"],
|
|
109
|
+
CDF_PROJECT=os.environ["CDF_PROJECT"],
|
|
110
|
+
LOGIN_FLOW=os.environ.get("LOGIN_FLOW", "infer"), # type: ignore[arg-type]
|
|
111
|
+
IDP_CLIENT_ID=os.environ.get("IDP_CLIENT_ID"),
|
|
112
|
+
IDP_CLIENT_SECRET=os.environ.get("IDP_CLIENT_SECRET"),
|
|
113
|
+
TOKEN=os.environ.get("TOKEN"),
|
|
114
|
+
CDF_URL=os.environ.get("CDF_URL"),
|
|
115
|
+
IDP_TOKEN_URL=os.environ.get("IDP_TOKEN_URL"),
|
|
116
|
+
IDP_TENANT_ID=os.environ.get("IDP_TENANT_ID"),
|
|
117
|
+
IDP_AUDIENCE=os.environ.get("IDP_AUDIENCE"),
|
|
118
|
+
IDP_SCOPES=os.environ.get("IDP_SCOPES"),
|
|
119
|
+
IDP_AUTHORITY_URL=os.environ.get("IDP_AUTHORITY_URL"),
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
def get_credentials(self) -> CredentialProvider:
|
|
123
|
+
method_by_flow = {
|
|
124
|
+
"client_credentials": self.get_oauth_client_credentials,
|
|
125
|
+
"interactive": self.get_oauth_interactive,
|
|
126
|
+
"token": self.get_token,
|
|
127
|
+
}
|
|
128
|
+
if self.LOGIN_FLOW in method_by_flow:
|
|
129
|
+
return method_by_flow[self.LOGIN_FLOW]()
|
|
130
|
+
key_options: list[tuple[str, ...]] = []
|
|
131
|
+
for method in method_by_flow.values():
|
|
132
|
+
try:
|
|
133
|
+
return method()
|
|
134
|
+
except KeyError as e:
|
|
135
|
+
key_options += e.args[1:]
|
|
136
|
+
raise KeyError(
|
|
137
|
+
f"LOGIN_FLOW={self.LOGIN_FLOW} requires one of the following environment set variables to be set.",
|
|
138
|
+
*key_options,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
def get_oauth_client_credentials(self) -> OAuthClientCredentials:
|
|
142
|
+
if not self.IDP_CLIENT_ID or not self.IDP_CLIENT_SECRET:
|
|
143
|
+
raise KeyError(
|
|
144
|
+
"IDP_CLIENT_ID and IDP_CLIENT_SECRET must be set in the environment.",
|
|
145
|
+
"IDP_CLIENT_ID",
|
|
146
|
+
"IDP_CLIENT_SECRET",
|
|
147
|
+
)
|
|
148
|
+
return OAuthClientCredentials(
|
|
149
|
+
client_id=self.IDP_CLIENT_ID,
|
|
150
|
+
client_secret=self.IDP_CLIENT_SECRET,
|
|
151
|
+
token_url=self.idp_token_url,
|
|
152
|
+
audience=self.idp_audience,
|
|
153
|
+
scopes=self.idp_scopes,
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
def get_oauth_interactive(self) -> OAuthInteractive:
|
|
157
|
+
if not self.IDP_CLIENT_ID:
|
|
158
|
+
raise KeyError("IDP_CLIENT_ID must be set in the environment.", "IDP_CLIENT_ID")
|
|
159
|
+
return OAuthInteractive(
|
|
160
|
+
client_id=self.IDP_CLIENT_ID,
|
|
161
|
+
authority_url=self.idp_authority_url,
|
|
162
|
+
redirect_port=53_000,
|
|
163
|
+
scopes=self.idp_scopes,
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
def get_token(self) -> Token:
|
|
167
|
+
if not self.TOKEN:
|
|
168
|
+
raise KeyError("TOKEN must be set in the environment", "TOKEN")
|
|
169
|
+
return Token(self.TOKEN)
|
|
170
|
+
|
|
171
|
+
def get_client(self) -> CogniteClient:
|
|
172
|
+
return CogniteClient.default(
|
|
173
|
+
self.CDF_PROJECT, self.CDF_CLUSTER, credentials=self.get_credentials(), client_name=_CLIENT_NAME
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
def create_env_file(self) -> str:
|
|
177
|
+
lines: list[str] = []
|
|
178
|
+
first_optional = True
|
|
179
|
+
for field in fields(self):
|
|
180
|
+
is_optional = hasattr(self, field.name.lower())
|
|
181
|
+
if is_optional and first_optional:
|
|
182
|
+
lines.append(
|
|
183
|
+
"# The below variables are the defaults, they are automatically " "constructed unless they are set."
|
|
184
|
+
)
|
|
185
|
+
first_optional = False
|
|
186
|
+
name = field.name.lower() if is_optional else field.name
|
|
187
|
+
value = getattr(self, name)
|
|
188
|
+
if value is not None:
|
|
189
|
+
if isinstance(value, list):
|
|
190
|
+
value = " ".join(value)
|
|
191
|
+
lines.append(f"{field.name}={value}")
|
|
192
|
+
return "\n".join(lines)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def _from_dotenv(evn_file: Path) -> _EnvironmentVariables:
|
|
196
|
+
if not evn_file.exists():
|
|
197
|
+
raise FileNotFoundError(f"{evn_file} does not exist.")
|
|
198
|
+
content = evn_file.read_text()
|
|
199
|
+
valid_variables = {f.name for f in fields(_EnvironmentVariables)}
|
|
200
|
+
variables: dict[str, str] = {}
|
|
201
|
+
for line in content.splitlines():
|
|
202
|
+
if line.startswith("#") or not line:
|
|
203
|
+
continue
|
|
204
|
+
key, value = line.split("=", 1)
|
|
205
|
+
if key in valid_variables:
|
|
206
|
+
variables[key] = value
|
|
207
|
+
return _EnvironmentVariables(**variables) # type: ignore[arg-type]
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def _prompt_user() -> _EnvironmentVariables:
|
|
211
|
+
local_import("rich", "jupyter")
|
|
212
|
+
from rich.prompt import Prompt
|
|
213
|
+
|
|
214
|
+
try:
|
|
215
|
+
variables = _EnvironmentVariables.create_from_environ()
|
|
216
|
+
continue_ = Prompt.ask(
|
|
217
|
+
f"Use environment variables for CDF Cluster '{variables.CDF_CLUSTER}' "
|
|
218
|
+
f"and Project '{variables.CDF_PROJECT}'? [y/n]",
|
|
219
|
+
choices=["y", "n"],
|
|
220
|
+
default="y",
|
|
221
|
+
)
|
|
222
|
+
if continue_ == "n":
|
|
223
|
+
variables = _prompt_cluster_and_project()
|
|
224
|
+
except KeyError:
|
|
225
|
+
variables = _prompt_cluster_and_project()
|
|
226
|
+
|
|
227
|
+
login_flow = Prompt.ask("Login flow", choices=[f for f in _VALID_LOGIN_FLOWS if f != "infer"])
|
|
228
|
+
variables.LOGIN_FLOW = login_flow # type: ignore[assignment]
|
|
229
|
+
if login_flow == "token":
|
|
230
|
+
token = Prompt.ask("Enter token")
|
|
231
|
+
variables.TOKEN = token
|
|
232
|
+
return variables
|
|
233
|
+
|
|
234
|
+
variables.IDP_CLIENT_ID = Prompt.ask("Enter IDP Client ID")
|
|
235
|
+
if login_flow == "client_credentials":
|
|
236
|
+
variables.IDP_CLIENT_SECRET = Prompt.ask("Enter IDP Client Secret", password=True)
|
|
237
|
+
tenant_id = Prompt.ask("Enter IDP_TENANT_ID (leave empty to enter IDP_TOKEN_URL instead)")
|
|
238
|
+
if tenant_id:
|
|
239
|
+
variables.IDP_TENANT_ID = tenant_id
|
|
240
|
+
else:
|
|
241
|
+
token_url = Prompt.ask("Enter IDP_TOKEN_URL")
|
|
242
|
+
variables.IDP_TOKEN_URL = token_url
|
|
243
|
+
optional = ["IDP_AUDIENCE", "IDP_SCOPES"]
|
|
244
|
+
else:
|
|
245
|
+
optional = ["IDP_TENANT_ID", "IDP_SCOPES"]
|
|
246
|
+
|
|
247
|
+
defaults = "".join(f"\n - {name}: {getattr(variables, name.lower())}" for name in optional)
|
|
248
|
+
use_defaults = Prompt.ask(
|
|
249
|
+
f"Use default values for the following variables?{defaults}", choices=["y", "n"], default="y"
|
|
250
|
+
)
|
|
251
|
+
if use_defaults:
|
|
252
|
+
return variables
|
|
253
|
+
for name in optional:
|
|
254
|
+
value = Prompt.ask(f"Enter {name}")
|
|
255
|
+
setattr(variables, name, value)
|
|
256
|
+
return variables
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def _prompt_cluster_and_project() -> _EnvironmentVariables:
|
|
260
|
+
from rich.prompt import Prompt
|
|
261
|
+
|
|
262
|
+
cluster = Prompt.ask("Enter CDF Cluster (example 'greenfield', 'bluefield', 'westeurope-1)")
|
|
263
|
+
project = Prompt.ask("Enter CDF Project")
|
|
264
|
+
return _EnvironmentVariables(cluster, project)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def _is_notebook() -> bool:
|
|
268
|
+
try:
|
|
269
|
+
shell = get_ipython().__class__.__name__ # type: ignore[name-defined]
|
|
270
|
+
if shell == "ZMQInteractiveShell":
|
|
271
|
+
return True # Jupyter notebook or qtconsole
|
|
272
|
+
elif shell == "TerminalInteractiveShell":
|
|
273
|
+
return False # Terminal running IPython
|
|
274
|
+
else:
|
|
275
|
+
return False # Other type (?)
|
|
276
|
+
except NameError:
|
|
277
|
+
return False # Probably standard Python interpreter
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def _repo_root() -> Path | None:
|
|
281
|
+
with suppress(Exception):
|
|
282
|
+
result = subprocess.run("git rev-parse --show-toplevel".split(), stdout=subprocess.PIPE)
|
|
283
|
+
return Path(result.stdout.decode().strip())
|
|
284
|
+
return None
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def _env_in_gitignore(repo_root: Path) -> bool:
|
|
288
|
+
ignore_file = repo_root / ".gitignore"
|
|
289
|
+
if not ignore_file.exists():
|
|
290
|
+
return False
|
|
291
|
+
else:
|
|
292
|
+
ignored = {line.strip() for line in ignore_file.read_text().splitlines()}
|
|
293
|
+
return ".env" in ignored or "*.env" in ignored
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
if __name__ == "__main__":
|
|
297
|
+
c = _prompt_user().get_client()
|
|
298
|
+
print(c.iam.token.inspect())
|
cognite/neat/utils/auxiliary.py
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import importlib
|
|
2
|
+
import inspect
|
|
3
|
+
from collections.abc import Callable
|
|
2
4
|
from types import ModuleType
|
|
3
5
|
|
|
4
6
|
from cognite.neat.exceptions import NeatImportError
|
|
@@ -9,3 +11,25 @@ def local_import(module: str, extra: str) -> ModuleType:
|
|
|
9
11
|
return importlib.import_module(module)
|
|
10
12
|
except ImportError as e:
|
|
11
13
|
raise NeatImportError(module.split(".")[0], extra) from e
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def get_classmethods(cls: type) -> list[Callable]:
|
|
17
|
+
return [
|
|
18
|
+
func for _, func in inspect.getmembers(cls, lambda x: inspect.ismethod(x) and not x.__name__.startswith("_"))
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def class_html_doc(cls: type, include_factory_methods: bool = True) -> str:
|
|
23
|
+
if cls.__doc__:
|
|
24
|
+
docstring = cls.__doc__.split("Args:")[0].strip().replace("\n", "<br />")
|
|
25
|
+
else:
|
|
26
|
+
docstring = "Missing Description"
|
|
27
|
+
if include_factory_methods:
|
|
28
|
+
factory_methods = get_classmethods(cls)
|
|
29
|
+
if factory_methods:
|
|
30
|
+
factory_methods_str = "".join(f"<li><em>.{m.__name__}</em></li>" for m in factory_methods)
|
|
31
|
+
docstring += (
|
|
32
|
+
f"<br /><strong>Available factory methods:</strong><br />"
|
|
33
|
+
f'<ul style="list-style-type:circle;">{factory_methods_str}</ul>'
|
|
34
|
+
)
|
|
35
|
+
return f"<h3>{cls.__name__}</h3><p>{docstring}</p>"
|
cognite/neat/utils/upload.py
CHANGED
|
@@ -41,15 +41,18 @@ class UploadResult(UploadResultCore, Generic[T_ID]):
|
|
|
41
41
|
unchanged: set[T_ID] = field(default_factory=set)
|
|
42
42
|
skipped: set[T_ID] = field(default_factory=set)
|
|
43
43
|
failed_created: set[T_ID] = field(default_factory=set)
|
|
44
|
+
failed_upserted: set[T_ID] = field(default_factory=set)
|
|
44
45
|
failed_changed: set[T_ID] = field(default_factory=set)
|
|
45
46
|
failed_deleted: set[T_ID] = field(default_factory=set)
|
|
46
47
|
|
|
47
48
|
@property
|
|
48
49
|
def failed(self) -> int:
|
|
49
|
-
return
|
|
50
|
+
return (
|
|
51
|
+
len(self.failed_created) + len(self.failed_changed) + len(self.failed_deleted) + len(self.failed_upserted)
|
|
52
|
+
)
|
|
50
53
|
|
|
51
54
|
@property
|
|
52
|
-
def
|
|
55
|
+
def success(self) -> int:
|
|
53
56
|
return len(self.created) + len(self.deleted) + len(self.changed) + len(self.unchanged) + len(self.skipped)
|
|
54
57
|
|
|
55
58
|
def dump(self, aggregate: bool = True) -> dict[str, Any]:
|
|
@@ -84,43 +87,3 @@ class UploadResult(UploadResultCore, Generic[T_ID]):
|
|
|
84
87
|
continue
|
|
85
88
|
lines.append(f"{key}: {value}")
|
|
86
89
|
return f"{self.name.title()}: {', '.join(lines)}"
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
@dataclass
|
|
90
|
-
class UploadResultIDs(UploadResultCore):
|
|
91
|
-
success: list[str] = field(default_factory=list)
|
|
92
|
-
failed: list[str] = field(default_factory=list)
|
|
93
|
-
|
|
94
|
-
def dump(self, aggregate: bool = True) -> dict[str, Any]:
|
|
95
|
-
output = super().dump(aggregate)
|
|
96
|
-
if self.success:
|
|
97
|
-
output["success"] = len(self.success) if aggregate else self.success
|
|
98
|
-
if self.failed:
|
|
99
|
-
output["failed"] = len(self.failed) if aggregate else self.failed
|
|
100
|
-
return output
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
@dataclass
|
|
104
|
-
class UploadDiffsID(UploadResultCore):
|
|
105
|
-
created: list[str] = field(default_factory=list)
|
|
106
|
-
changed: list[str] = field(default_factory=list)
|
|
107
|
-
unchanged: list[str] = field(default_factory=list)
|
|
108
|
-
failed: list[str] = field(default_factory=list)
|
|
109
|
-
|
|
110
|
-
def as_upload_result_ids(self) -> UploadResultIDs:
|
|
111
|
-
result = UploadResultIDs(name=self.name, error_messages=self.error_messages, issues=self.issues)
|
|
112
|
-
result.success = self.created + self.changed + self.unchanged
|
|
113
|
-
result.failed = self.failed
|
|
114
|
-
return result
|
|
115
|
-
|
|
116
|
-
def dump(self, aggregate: bool = True) -> dict[str, Any]:
|
|
117
|
-
output = super().dump(aggregate)
|
|
118
|
-
if self.created:
|
|
119
|
-
output["created"] = len(self.created) if aggregate else self.created
|
|
120
|
-
if self.changed:
|
|
121
|
-
output["changed"] = len(self.changed) if aggregate else self.changed
|
|
122
|
-
if self.unchanged:
|
|
123
|
-
output["unchanged"] = len(self.unchanged) if aggregate else self.unchanged
|
|
124
|
-
if self.failed:
|
|
125
|
-
output["failed"] = len(self.failed) if aggregate else self.failed
|
|
126
|
-
return output
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: cognite-neat
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.85.0
|
|
4
4
|
Summary: Knowledge graph transformation
|
|
5
5
|
Home-page: https://cognite-neat.readthedocs-hosted.com/
|
|
6
6
|
License: Apache-2.0
|
|
@@ -16,6 +16,7 @@ Provides-Extra: all
|
|
|
16
16
|
Provides-Extra: docs
|
|
17
17
|
Provides-Extra: google
|
|
18
18
|
Provides-Extra: graphql
|
|
19
|
+
Provides-Extra: jupyter
|
|
19
20
|
Provides-Extra: oxi
|
|
20
21
|
Provides-Extra: service
|
|
21
22
|
Requires-Dist: PyYAML
|
|
@@ -46,6 +47,7 @@ Requires-Dist: pymdown-extensions ; extra == "docs"
|
|
|
46
47
|
Requires-Dist: pyoxigraph (==0.3.19) ; extra == "oxi" or extra == "all"
|
|
47
48
|
Requires-Dist: rdflib
|
|
48
49
|
Requires-Dist: requests
|
|
50
|
+
Requires-Dist: rich[jupyter] (>=13.7.1,<14.0.0) ; extra == "jupyter"
|
|
49
51
|
Requires-Dist: schedule (>=1,<2) ; extra == "service" or extra == "all"
|
|
50
52
|
Requires-Dist: tomli (>=2.0.1,<3.0.0) ; python_version < "3.11"
|
|
51
53
|
Requires-Dist: typing_extensions (>=4.8,<5.0) ; python_version < "3.11"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
cognite/neat/__init__.py,sha256=
|
|
2
|
-
cognite/neat/_shared.py,sha256=
|
|
3
|
-
cognite/neat/_version.py,sha256=
|
|
1
|
+
cognite/neat/__init__.py,sha256=AiexNcHdAHFbrrbo9c65gtil1dqx_SGraDH1PSsXjKE,126
|
|
2
|
+
cognite/neat/_shared.py,sha256=RSaHm2eJceTlvb-hMMe4nHgoHdPYDfN3XcxDXo24k3A,1530
|
|
3
|
+
cognite/neat/_version.py,sha256=oS_t2ihHSRa_TQs1XBgfsFFpaFOEDZAndDmjccnIF4g,23
|
|
4
4
|
cognite/neat/app/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
cognite/neat/app/api/asgi/metrics.py,sha256=nxFy7L5cChTI0a-zkCiJ59Aq8yLuIJp5c9Dg0wRXtV0,152
|
|
6
6
|
cognite/neat/app/api/configuration.py,sha256=2U5M6M252swvQPQyooA1EBzFUZNtcTmuSaywfJDgckM,4232
|
|
@@ -54,34 +54,34 @@ cognite/neat/graph/examples/Knowledge-Graph-Nordic44.xml,sha256=U2Ns-M4LRjT1fBkh
|
|
|
54
54
|
cognite/neat/graph/examples/__init__.py,sha256=yAjHVY3b5jOjmbW-iLbhvu7BG014TpGi3K4igkDqW5I,368
|
|
55
55
|
cognite/neat/graph/examples/skos-capturing-sheet-wind-topics.xlsx,sha256=CV_yK5ZSbYS_ktfIZUPD8Sevs47zpswLXQUDFkGE4Gw,45798
|
|
56
56
|
cognite/neat/graph/exceptions.py,sha256=R6pyOH774n9w2x_X_nrUr8OMAdjJMf_XPIqAvxIQaWo,3401
|
|
57
|
-
cognite/neat/graph/extractors/__init__.py,sha256=
|
|
58
|
-
cognite/neat/graph/extractors/_base.py,sha256=
|
|
57
|
+
cognite/neat/graph/extractors/__init__.py,sha256=nXcNp6i3-1HteIkr8Ujxk4b09W5jk27Q3eWuwjcnGnM,1647
|
|
58
|
+
cognite/neat/graph/extractors/_base.py,sha256=8IWygpkQTwo0UOmbbwWVI7540_klTVdUVX2JjVPFRIs,498
|
|
59
59
|
cognite/neat/graph/extractors/_classic_cdf/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
60
|
-
cognite/neat/graph/extractors/_classic_cdf/_assets.py,sha256=
|
|
61
|
-
cognite/neat/graph/extractors/_classic_cdf/_events.py,sha256=
|
|
60
|
+
cognite/neat/graph/extractors/_classic_cdf/_assets.py,sha256=Hu-RoTBhn4LFm38G51L5tc0MVy4-zr1POHWyrIB-vUc,4130
|
|
61
|
+
cognite/neat/graph/extractors/_classic_cdf/_events.py,sha256=SGZWKCxppECIQkwQs5M2e_SoF-eGilCW2KiyXk2PmzM,4230
|
|
62
62
|
cognite/neat/graph/extractors/_classic_cdf/_files.py,sha256=-6nCkXUCAnDsv4eDFDEiQ-U4SGhmW1VLxZJFUcszqjU,4831
|
|
63
|
-
cognite/neat/graph/extractors/_classic_cdf/_labels.py,sha256=
|
|
64
|
-
cognite/neat/graph/extractors/_classic_cdf/_relationships.py,sha256=
|
|
65
|
-
cognite/neat/graph/extractors/_classic_cdf/_sequences.py,sha256=
|
|
66
|
-
cognite/neat/graph/extractors/_classic_cdf/_timeseries.py,sha256=
|
|
67
|
-
cognite/neat/graph/extractors/_dexpi.py,sha256=
|
|
63
|
+
cognite/neat/graph/extractors/_classic_cdf/_labels.py,sha256=4JxQHPDciMjbk7F6GxMa-HfhOgAv8LT3VO3mRfEgQ0E,2832
|
|
64
|
+
cognite/neat/graph/extractors/_classic_cdf/_relationships.py,sha256=jgIN__nztlhLwoIJw59s2-Blc9gxIm7YDha5qEoXBSg,5654
|
|
65
|
+
cognite/neat/graph/extractors/_classic_cdf/_sequences.py,sha256=5FuhwpgDiGG51C0bQacQ4LD6KkutUaU1cX2NSy_krhU,3652
|
|
66
|
+
cognite/neat/graph/extractors/_classic_cdf/_timeseries.py,sha256=Ui7WRAvot3KJFwpzqmEYvRs3cN0qh93ocJjYaNLfH30,4811
|
|
67
|
+
cognite/neat/graph/extractors/_dexpi.py,sha256=xIw3kSaQ17k_bAuecvrVRic70PUhFHtcyy-ReLt36Q4,9385
|
|
68
68
|
cognite/neat/graph/extractors/_mock_graph_generator.py,sha256=1TjgbxDVwgZjivIqx1lLKwggn_zHqWLiYM26esgDAMs,14694
|
|
69
|
-
cognite/neat/graph/extractors/_rdf_file.py,sha256=
|
|
69
|
+
cognite/neat/graph/extractors/_rdf_file.py,sha256=ialMCLv9WH5k6v1YMfozfcmAYhz8OVo9jVhsKMyQkDA,763
|
|
70
70
|
cognite/neat/graph/issues/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
71
71
|
cognite/neat/graph/issues/loader.py,sha256=v8YDsehkUT1QUG61JM9BDV_lqowMUnDmGmbay0aFzN4,3085
|
|
72
|
-
cognite/neat/graph/loaders/__init__.py,sha256=
|
|
73
|
-
cognite/neat/graph/loaders/_base.py,sha256=
|
|
72
|
+
cognite/neat/graph/loaders/__init__.py,sha256=BteVkTklPVUB2W-bbzZug-cEUrx8ZFA-YcQPSxWVpTI,678
|
|
73
|
+
cognite/neat/graph/loaders/_base.py,sha256=t33I-Olw0xYz3Icf2RJZq9cs5_dEKeY87npxsA597Sw,3012
|
|
74
74
|
cognite/neat/graph/loaders/_rdf2asset.py,sha256=aFby7BwIrW253LEJ4XqGeUuf4jG9VUe8Lg7OlUnXMlM,4493
|
|
75
|
-
cognite/neat/graph/loaders/_rdf2dms.py,sha256=
|
|
75
|
+
cognite/neat/graph/loaders/_rdf2dms.py,sha256=xyr0SfIusfjYjlAXZcIGS1-IQ6LoVWeOB3_q6D304oo,13603
|
|
76
76
|
cognite/neat/graph/models.py,sha256=AtLgZh2qyRP6NRetjQCy9qLMuTQB0CH52Zsev-qa2sk,149
|
|
77
77
|
cognite/neat/graph/queries/__init__.py,sha256=BgDd-037kvtWwAoGAy8eORVNMiZ5-E9sIV0txIpeaN4,50
|
|
78
78
|
cognite/neat/graph/queries/_base.py,sha256=20A7GDBdmc35VmHVz5n0YCGPcnBAmUX-bM2ImHPManc,3844
|
|
79
79
|
cognite/neat/graph/queries/_construct.py,sha256=FxzSQqzCpo7lKVYerlLAY03oqCeFM5L6MozfBUblzr4,7341
|
|
80
80
|
cognite/neat/graph/queries/_shared.py,sha256=EwW2RbPttt7-z7QTgfKWlthA2Nq5d3bYyyewFkCA7R4,5043
|
|
81
81
|
cognite/neat/graph/stores/__init__.py,sha256=G-VG_YwfRt1kuPao07PDJyZ3w_0-eguzLUM13n-Z_RA,64
|
|
82
|
-
cognite/neat/graph/stores/_base.py,sha256=
|
|
82
|
+
cognite/neat/graph/stores/_base.py,sha256=z69uhzBhzl1JQJU9U-h9zAyySn25ZQTJRXam4BavnoY,10586
|
|
83
83
|
cognite/neat/graph/stores/_oxrdflib.py,sha256=A5zeRm5_e8ui_ihGpgstRDg_N7qcLZ3QZBRGrOXSGI0,9569
|
|
84
|
-
cognite/neat/graph/stores/_provenance.py,sha256=
|
|
84
|
+
cognite/neat/graph/stores/_provenance.py,sha256=HIXa-p7yc2l3HFkQWMnGPhn-t_FROEG21thADGkgy0c,3590
|
|
85
85
|
cognite/neat/graph/transformers/__init__.py,sha256=wXrNSyJNGnis3haaCKVPZ5y5kKSUsOUHnh-860ekatk,555
|
|
86
86
|
cognite/neat/graph/transformers/_base.py,sha256=b37Ek-9njuM5pTR_3XhnxCMrg_ip_2BMwM7ZhKpAAlw,328
|
|
87
87
|
cognite/neat/graph/transformers/_classic_cdf.py,sha256=ZHHJU-1-lXeufuZJSuDa2Zmu56PS9PcGeFYI91VZNI4,12214
|
|
@@ -188,28 +188,28 @@ cognite/neat/rules/analysis/_information_rules.py,sha256=fdSMyInsPJdgLHKwSkj2N9b
|
|
|
188
188
|
cognite/neat/rules/examples/__init__.py,sha256=nxIwueAcHgZhkYriGxnDLQmIyiT8PByPHbScjYKDKe0,374
|
|
189
189
|
cognite/neat/rules/examples/wind-energy.owl,sha256=NuomCA9FuuLF0JlSuG3OKqD4VBcHgSjDKFLV17G1zV8,65934
|
|
190
190
|
cognite/neat/rules/exceptions.py,sha256=YLnsbXXJdDSr_szQoioEtOdqDV8PR7RdQjpMP2SWeCs,123868
|
|
191
|
-
cognite/neat/rules/exporters/__init__.py,sha256=
|
|
192
|
-
cognite/neat/rules/exporters/_base.py,sha256=
|
|
193
|
-
cognite/neat/rules/exporters/_rules2dms.py,sha256=
|
|
191
|
+
cognite/neat/rules/exporters/__init__.py,sha256=nRMUBUf7yr1QPjyITeX2rTLtLLawHv24hhRE39d2-e0,1109
|
|
192
|
+
cognite/neat/rules/exporters/_base.py,sha256=qZt236sNKTbiM41sgVEYcEtuK5v8Pt14LMLBNiZrNWs,1936
|
|
193
|
+
cognite/neat/rules/exporters/_rules2dms.py,sha256=xK9xXJ7lLQnzrRlBUJQVLlY4SC-vnnjGUXOzaWvOKmY,14553
|
|
194
194
|
cognite/neat/rules/exporters/_rules2excel.py,sha256=HvUdXYHxfLMijYWdTnfqCsw3Izf8S-XDSve-2ZbqF8Y,14248
|
|
195
|
-
cognite/neat/rules/exporters/_rules2ontology.py,sha256=
|
|
195
|
+
cognite/neat/rules/exporters/_rules2ontology.py,sha256=bt8IuxaAYFRyZc1AlS-gYw9Jf6jBr5CYFOaJ3qPeoaA,20527
|
|
196
196
|
cognite/neat/rules/exporters/_rules2yaml.py,sha256=GA8eUYRxUfIU6IMvlyGO5JidkOD5eUKSbH3qAiFiaCg,3026
|
|
197
197
|
cognite/neat/rules/exporters/_validation.py,sha256=OlKIyf4nhSDehJwFHDQ8Zdf6HpNfW7dSe2s67eywHu4,4078
|
|
198
|
-
cognite/neat/rules/importers/__init__.py,sha256=
|
|
199
|
-
cognite/neat/rules/importers/_base.py,sha256=
|
|
200
|
-
cognite/neat/rules/importers/_dms2rules.py,sha256=
|
|
198
|
+
cognite/neat/rules/importers/__init__.py,sha256=Vxl2Iq1dMXUsI6Wb411xPI3rromdq50xZUci-S8faSw,1097
|
|
199
|
+
cognite/neat/rules/importers/_base.py,sha256=3LmDfR-f0nlLGcioWB8IbeZJ6uW5dvnzxJlqaMWc-u0,4516
|
|
200
|
+
cognite/neat/rules/importers/_dms2rules.py,sha256=Dqoh4qO5IVvjRpxLHZaqCgPC99_r4y7ncEo2WYMxwqU,19302
|
|
201
201
|
cognite/neat/rules/importers/_dtdl2rules/__init__.py,sha256=CNR-sUihs2mnR1bPMKs3j3L4ds3vFTsrl6YycExZTfU,68
|
|
202
202
|
cognite/neat/rules/importers/_dtdl2rules/_unit_lookup.py,sha256=wW4saKva61Q_i17guY0dc4OseJDQfqHy_QZBtm0OD6g,12134
|
|
203
203
|
cognite/neat/rules/importers/_dtdl2rules/dtdl_converter.py,sha256=ysmWUxZ0npwrTB0uiH5jA0v37sfCwowGaYk17IyxPUU,12663
|
|
204
|
-
cognite/neat/rules/importers/_dtdl2rules/dtdl_importer.py,sha256=
|
|
204
|
+
cognite/neat/rules/importers/_dtdl2rules/dtdl_importer.py,sha256=Psj3C2jembY_Wu7WWJIFIwrMawvjISjeqfBnoRy_csw,6740
|
|
205
205
|
cognite/neat/rules/importers/_dtdl2rules/spec.py,sha256=tim_MfN1J0F3Oeqk3BMgIA82d_MZvhRuRMsLK3B4PYc,11897
|
|
206
|
-
cognite/neat/rules/importers/_inference2rules.py,sha256=
|
|
206
|
+
cognite/neat/rules/importers/_inference2rules.py,sha256=OilV3aF3LTjFHK2Yzs8KktTGG41iPB4hh3u1aAwhNbI,11675
|
|
207
207
|
cognite/neat/rules/importers/_owl2rules/__init__.py,sha256=tdGcrgtozdQyST-pTlxIa4cLBNTLvtk1nNYR4vOdFSw,63
|
|
208
208
|
cognite/neat/rules/importers/_owl2rules/_owl2classes.py,sha256=QpTxvrTGczIa48X8lgXGnMN1AWPhHK0DR6uNq175xak,7357
|
|
209
209
|
cognite/neat/rules/importers/_owl2rules/_owl2metadata.py,sha256=nwnUaBNAAYMoBre2UmsnkJXUuaqGEpR3U3txDrH2w6g,7527
|
|
210
210
|
cognite/neat/rules/importers/_owl2rules/_owl2properties.py,sha256=eKr-e-ZTTV54PJ9UXNVPTT_c9XxszNPraS4Y43AF7qQ,7297
|
|
211
211
|
cognite/neat/rules/importers/_owl2rules/_owl2rules.py,sha256=41_wZFvt0A6TI55zlT04oQkvU7V73li4aGLgc4T4Lxo,6358
|
|
212
|
-
cognite/neat/rules/importers/_spreadsheet2rules.py,sha256=
|
|
212
|
+
cognite/neat/rules/importers/_spreadsheet2rules.py,sha256=vyYXNvP64dBGTWRWfrg7wtUcs0PdPiGLAHwE8itItAA,13072
|
|
213
213
|
cognite/neat/rules/importers/_yaml2rules.py,sha256=F0uksSz1A3po5OlRM2152_w5j8D9oYTLB9NFTkSMlWI,4275
|
|
214
214
|
cognite/neat/rules/issues/__init__.py,sha256=c12m0HAHHzF6oR8lKbULE3TxOPimTi9s1O9IIrtgh0g,549
|
|
215
215
|
cognite/neat/rules/issues/base.py,sha256=x2YLCfmqtPlFLoURq3qHaprXCpFaQdf0iWkql-EMyps,2446
|
|
@@ -251,7 +251,8 @@ cognite/neat/rules/models/information/_serializer.py,sha256=yti9I_xJruxrib66YIBI
|
|
|
251
251
|
cognite/neat/rules/models/information/_validation.py,sha256=Is2GzL2lZU3A5zPu3NjvlXfmIU2_Y10C5Nxi5Denz4g,7528
|
|
252
252
|
cognite/neat/rules/models/wrapped_entities.py,sha256=ThhjnNNrpgz0HeORIQ8Q894trxP73P7T_TuZj6qH2CU,7157
|
|
253
253
|
cognite/neat/utils/__init__.py,sha256=l5Nyqhqo25bcQXCOb_lk01cr-UXsG8cczz_y_I0u6bg,68
|
|
254
|
-
cognite/neat/utils/
|
|
254
|
+
cognite/neat/utils/auth.py,sha256=0UeZH4nx-0LizNsBrYJiquK6ZldNYk_2frLBZzcB5JM,11270
|
|
255
|
+
cognite/neat/utils/auxiliary.py,sha256=IOVbr6lPQulMJUyrrhfSsF6lIHch0Aw6KszMkBomprc,1248
|
|
255
256
|
cognite/neat/utils/cdf.py,sha256=piRx-6GRz4cCfBZD5rU0OM6ixQ3cj5TMzI0yCYUveR8,2422
|
|
256
257
|
cognite/neat/utils/cdf_classes.py,sha256=NEmz5UprBlqfqZnqJkRk5xjSpzazwHbhcWsMH_GNxP8,5831
|
|
257
258
|
cognite/neat/utils/cdf_loaders/__init__.py,sha256=s2aPR5XLo6WZ0ybstAJlcGFYkA7CyHW1XO-NYpL0V6o,483
|
|
@@ -262,9 +263,9 @@ cognite/neat/utils/cdf_loaders/data_classes.py,sha256=0apspfwVlFltYOZfmk_PNknS3Z
|
|
|
262
263
|
cognite/neat/utils/exceptions.py,sha256=-w4cAcvcoWLf-_ZwAl7QV_NysfqtQzIOd1Ti-mpxJgM,981
|
|
263
264
|
cognite/neat/utils/spreadsheet.py,sha256=LI0c7dlW0zXHkHw0NvB-gg6Df6cDcE3FbiaHBYLXdzQ,2714
|
|
264
265
|
cognite/neat/utils/text.py,sha256=4bg1_Q0lg7KsoxaDOvXrVyeY78BJN8i-27BlyDzUCls,3082
|
|
265
|
-
cognite/neat/utils/upload.py,sha256=
|
|
266
|
+
cognite/neat/utils/upload.py,sha256=nZEuDu22A1kTbl-ctzAJ2vx1cjiQtqdDdpC_mRRMvUI,3597
|
|
266
267
|
cognite/neat/utils/utils.py,sha256=1LEwR8gpHw_6pvEeLkW_cDU_lUun4qSsw_Rr3JsKwgA,14172
|
|
267
|
-
cognite/neat/utils/
|
|
268
|
+
cognite/neat/utils/xml_.py,sha256=ppLT3lQKVp8wOP-m8-tFY8uB2P4R76l7R_-kUtsABng,992
|
|
268
269
|
cognite/neat/workflows/__init__.py,sha256=oiKub_U9f5cA0I1nKl5dFkR4BD8_6Be9eMzQ_50PwP0,396
|
|
269
270
|
cognite/neat/workflows/_exceptions.py,sha256=ugI_X1XNpikAiL8zIggBjcx6q7WvOpRIgvxHrj2Rhr4,1348
|
|
270
271
|
cognite/neat/workflows/base.py,sha256=2cSnxfc9GSoTluneTWLJbE9rImp0wJt8--LHkQHQfi4,26800
|
|
@@ -309,8 +310,8 @@ cognite/neat/workflows/steps_registry.py,sha256=fkTX14ZA7_gkUYfWIlx7A1XbCidvqR23
|
|
|
309
310
|
cognite/neat/workflows/tasks.py,sha256=dqlJwKAb0jlkl7abbY8RRz3m7MT4SK8-7cntMWkOYjw,788
|
|
310
311
|
cognite/neat/workflows/triggers.py,sha256=_BLNplzoz0iic367u1mhHMHiUrCwP-SLK6_CZzfODX0,7071
|
|
311
312
|
cognite/neat/workflows/utils.py,sha256=gKdy3RLG7ctRhbCRwaDIWpL9Mi98zm56-d4jfHDqP1E,453
|
|
312
|
-
cognite_neat-0.
|
|
313
|
-
cognite_neat-0.
|
|
314
|
-
cognite_neat-0.
|
|
315
|
-
cognite_neat-0.
|
|
316
|
-
cognite_neat-0.
|
|
313
|
+
cognite_neat-0.85.0.dist-info/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
|
|
314
|
+
cognite_neat-0.85.0.dist-info/METADATA,sha256=v0E853i0iw38J4bJSXaqj-K7ZLL9aBaTO4roAkCu-VE,9493
|
|
315
|
+
cognite_neat-0.85.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
316
|
+
cognite_neat-0.85.0.dist-info/entry_points.txt,sha256=61FPqiWb25vbqB0KI7znG8nsg_ibLHBvTjYnkPvNFso,50
|
|
317
|
+
cognite_neat-0.85.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|