cognite-neat 0.85.11__py3-none-any.whl → 0.86.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.

Files changed (30) hide show
  1. cognite/neat/_version.py +1 -1
  2. cognite/neat/app/api/routers/core.py +4 -4
  3. cognite/neat/graph/extractors/_mock_graph_generator.py +1 -1
  4. cognite/neat/graph/loaders/_rdf2dms.py +33 -18
  5. cognite/neat/graph/queries/_base.py +58 -5
  6. cognite/neat/graph/queries/_construct.py +15 -13
  7. cognite/neat/graph/stores/_base.py +18 -10
  8. cognite/neat/graph/transformers/_rdfpath.py +7 -0
  9. cognite/neat/rules/analysis/_information_rules.py +9 -2
  10. cognite/neat/rules/exporters/_base.py +4 -4
  11. cognite/neat/rules/exporters/_rules2dms.py +1 -1
  12. cognite/neat/rules/exporters/_rules2ontology.py +1 -1
  13. cognite/neat/rules/importers/_base.py +4 -4
  14. cognite/neat/rules/importers/_inference2rules.py +4 -1
  15. cognite/neat/rules/importers/_owl2rules/_owl2metadata.py +1 -1
  16. cognite/neat/rules/importers/_spreadsheet2rules.py +5 -5
  17. cognite/neat/rules/models/__init__.py +3 -3
  18. cognite/neat/rules/models/_base.py +3 -3
  19. cognite/neat/rules/models/asset/_rules.py +5 -5
  20. cognite/neat/rules/models/data_types.py +4 -4
  21. cognite/neat/rules/models/dms/_converter.py +3 -3
  22. cognite/neat/rules/models/dms/_rules.py +3 -3
  23. cognite/neat/rules/models/information/_converter.py +3 -3
  24. cognite/neat/rules/models/information/_rules.py +3 -3
  25. cognite/neat/utils/utils.py +54 -18
  26. {cognite_neat-0.85.11.dist-info → cognite_neat-0.86.0.dist-info}/METADATA +1 -1
  27. {cognite_neat-0.85.11.dist-info → cognite_neat-0.86.0.dist-info}/RECORD +30 -29
  28. {cognite_neat-0.85.11.dist-info → cognite_neat-0.86.0.dist-info}/LICENSE +0 -0
  29. {cognite_neat-0.85.11.dist-info → cognite_neat-0.86.0.dist-info}/WHEEL +0 -0
  30. {cognite_neat-0.85.11.dist-info → cognite_neat-0.86.0.dist-info}/entry_points.txt +0 -0
cognite/neat/_version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.85.11"
1
+ __version__ = "0.86.0"
@@ -31,21 +31,21 @@ async def convert_data_model_to_rules(file: UploadFile):
31
31
 
32
32
  # read as Excel rules
33
33
  if suffix == ".xlsx":
34
- rules, issues = importers.ExcelImporter(filepath=temp_filepath).to_rules(role=RoleTypes.dms_architect)
34
+ rules, issues = importers.ExcelImporter(filepath=temp_filepath).to_rules(role=RoleTypes.dms)
35
35
 
36
36
  # load as OWL
37
37
  elif suffix in [".ttl", ".owl"]:
38
- rules, issues = importers.OWLImporter(filepath=temp_filepath).to_rules(role=RoleTypes.dms_architect)
38
+ rules, issues = importers.OWLImporter(filepath=temp_filepath).to_rules(role=RoleTypes.dms)
39
39
 
40
40
  # load as YAML
41
41
  elif suffix in [".yml", ".yaml"]:
42
- rules, issues = importers.YAMLImporter.from_file(temp_filepath).to_rules(role=RoleTypes.dms_architect)
42
+ rules, issues = importers.YAMLImporter.from_file(temp_filepath).to_rules(role=RoleTypes.dms)
43
43
 
44
44
  # load as JSON
45
45
  elif suffix == ".json":
46
46
  with temp_filepath.open() as temp:
47
47
  json_data = json.load(temp)
48
- rules, issues = importers.YAMLImporter(raw_data=json.loads(json_data)).to_rules(role=RoleTypes.dms_architect)
48
+ rules, issues = importers.YAMLImporter(raw_data=json.loads(json_data)).to_rules(role=RoleTypes.dms)
49
49
 
50
50
  # Remove the temporary file
51
51
  temp_filepath.unlink()
@@ -42,7 +42,7 @@ class MockGraphGenerator(BaseExtractor):
42
42
  allow_isolated_classes: bool = True,
43
43
  ):
44
44
  if isinstance(rules, DMSRules):
45
- self.rules = rules.as_information_architect_rules()
45
+ self.rules = rules.as_information_rules()
46
46
  elif isinstance(rules, InformationRules):
47
47
  self.rules = rules
48
48
  else:
@@ -1,8 +1,7 @@
1
1
  import json
2
- from collections import defaultdict
3
2
  from collections.abc import Iterable, Sequence
4
3
  from pathlib import Path
5
- from typing import Any
4
+ from typing import Any, get_args
6
5
 
7
6
  import yaml
8
7
  from cognite.client import CogniteClient
@@ -20,7 +19,7 @@ from cognite.neat.graph.issues import loader as loader_issues
20
19
  from cognite.neat.graph.stores import NeatGraphStore
21
20
  from cognite.neat.issues import NeatIssue, NeatIssueList
22
21
  from cognite.neat.rules.models import DMSRules
23
- from cognite.neat.rules.models.data_types import _DATA_TYPE_BY_DMS_TYPE
22
+ from cognite.neat.rules.models.data_types import _DATA_TYPE_BY_DMS_TYPE, Json
24
23
  from cognite.neat.utils.upload import UploadResult
25
24
  from cognite.neat.utils.utils import create_sha256_hash
26
25
 
@@ -106,8 +105,8 @@ class DMSLoader(CDFLoader[dm.InstanceApply]):
106
105
  yield from issues
107
106
  tracker.issue(issues)
108
107
  class_name = self.class_by_view_id.get(view.as_id(), view.external_id)
109
- triples = self.graph_store.read(class_name)
110
- for identifier, properties in _triples2dictionary(triples).items():
108
+
109
+ for identifier, properties in self.graph_store.read(class_name):
111
110
  try:
112
111
  yield self._create_node(identifier, properties, pydantic_cls, view_id)
113
112
  except ValueError as e:
@@ -145,7 +144,9 @@ class DMSLoader(CDFLoader[dm.InstanceApply]):
145
144
  issues = NeatIssueList[NeatIssue]()
146
145
  field_definitions: dict[str, tuple[type, Any]] = {}
147
146
  edge_by_property: dict[str, dm.EdgeConnection] = {}
147
+ validators: dict[str, classmethod] = {}
148
148
  direct_relation_by_property: dict[str, dm.DirectRelation] = {}
149
+ json_fields: list[str] = []
149
150
  for prop_name, prop in view.properties.items():
150
151
  if isinstance(prop, dm.EdgeConnection):
151
152
  edge_by_property[prop_name] = prop
@@ -163,6 +164,9 @@ class DMSLoader(CDFLoader[dm.InstanceApply]):
163
164
  )
164
165
  )
165
166
  continue
167
+
168
+ if data_type == Json:
169
+ json_fields.append(prop_name)
166
170
  python_type = data_type.python
167
171
  if prop.type.is_list:
168
172
  python_type = list[python_type]
@@ -175,13 +179,29 @@ class DMSLoader(CDFLoader[dm.InstanceApply]):
175
179
  field_definitions[prop_name] = (python_type, default_value)
176
180
 
177
181
  def parse_list(cls, value: Any, info: ValidationInfo) -> list[str]:
178
- if isinstance(value, list) and cls.model_fields[info.field_name].annotation is not list:
182
+ if isinstance(value, list) and list.__name__ not in _get_field_value_types(cls, info):
179
183
  if len(value) == 1:
180
184
  return value[0]
181
185
  raise ValueError(f"Got multiple values for {info.field_name}: {value}")
186
+
182
187
  return value
183
188
 
184
- validators: dict[str, classmethod] = {"parse_list": field_validator("*", mode="before")(parse_list)} # type: ignore[dict-item,arg-type]
189
+ def parse_json_string(cls, value: Any, info: ValidationInfo) -> dict:
190
+ if isinstance(value, dict):
191
+ return value
192
+ elif isinstance(value, str):
193
+ try:
194
+ return json.loads(value)
195
+ except json.JSONDecodeError as error:
196
+ raise ValueError(f"Not valid JSON string for {info.field_name}: {value}, error {error}") from error
197
+ else:
198
+ raise ValueError(f"Expect valid JSON string or dict for {info.field_name}: {value}")
199
+
200
+ if json_fields:
201
+ validators["parse_json_string"] = field_validator(*json_fields, mode="before")(parse_json_string) # type: ignore[assignment, arg-type]
202
+
203
+ validators["parse_list"] = field_validator("*", mode="before")(parse_list) # type: ignore[assignment, arg-type]
204
+
185
205
  if direct_relation_by_property:
186
206
 
187
207
  def parse_direct_relation(cls, value: list, info: ValidationInfo) -> dict | list[dict]:
@@ -280,7 +300,10 @@ class DMSLoader(CDFLoader[dm.InstanceApply]):
280
300
  result.created.update(item.as_id() for item in e.successful)
281
301
  yield result
282
302
  else:
283
- for instance_type, instances in {"Nodes": upserted.nodes, "Edges": upserted.edges}.items():
303
+ for instance_type, instances in {
304
+ "Nodes": upserted.nodes,
305
+ "Edges": upserted.edges,
306
+ }.items():
284
307
  result = UploadResult[InstanceId](name=instance_type, issues=read_issues)
285
308
  for instance in instances: # type: ignore[attr-defined]
286
309
  if instance.was_modified and instance.created_time == instance.last_updated_time:
@@ -292,13 +315,5 @@ class DMSLoader(CDFLoader[dm.InstanceApply]):
292
315
  yield result
293
316
 
294
317
 
295
- def _triples2dictionary(
296
- triples: Iterable[tuple[str, str, str]],
297
- ) -> dict[str, dict[str, list[str]]]:
298
- """Converts list of triples to dictionary"""
299
- values_by_property_by_identifier: dict[str, dict[str, list[str]]] = defaultdict(lambda: defaultdict(list))
300
- for id_, property_, value in triples:
301
- # avoid issue with strings "None", "nan", "null" being treated as values
302
- if value.lower() not in ["", "None", "nan", "null"]:
303
- values_by_property_by_identifier[id_][property_].append(value)
304
- return values_by_property_by_identifier
318
+ def _get_field_value_types(cls, info):
319
+ return [type_.__name__ for type_ in get_args(cls.model_fields[info.field_name].annotation)]
@@ -1,4 +1,5 @@
1
1
  import warnings
2
+ from collections import defaultdict
2
3
  from typing import Literal, cast, overload
3
4
 
4
5
  from rdflib import RDF, Graph, URIRef
@@ -93,12 +94,63 @@ class Queries:
93
94
  )
94
95
  return []
95
96
 
96
- def construct_instances_of_class(self, class_: str, properties_optional: bool = True) -> list[tuple[str, str, str]]:
97
+ def describe(
98
+ self,
99
+ instance_id: URIRef,
100
+ property_renaming_config: dict | None = None,
101
+ ) -> tuple[str, dict[str, list[str]]]:
102
+ """DESCRIBE instance for a given class from the graph store
103
+
104
+ Args:
105
+ instance_id: Instance id for which we want to generate query
106
+ property_rename_config: Dictionary to rename properties, default None
107
+
108
+ Returns:
109
+ Dictionary of instance properties
110
+ """
111
+
112
+ property_values: dict[str, list[str]] = defaultdict(list)
113
+
114
+ for subject, predicate, object_ in cast(list[ResultRow], self.graph.query(f"DESCRIBE <{instance_id}>")):
115
+ # We cannot include the RDF.type in case there is a neat:type property
116
+ # or if the object is empty
117
+ if predicate != RDF.type and object_.lower() not in [
118
+ "",
119
+ "none",
120
+ "nan",
121
+ "null",
122
+ ]:
123
+ # we are skipping deep validation with Pydantic to remove namespace here
124
+ # as it reduce time to process triples by 10-15x
125
+ identifier, property_, value = cast( # type: ignore[misc]
126
+ (str, str, str),
127
+ remove_namespace_from_uri(*(subject, predicate, object_), validation="prefix"),
128
+ ) # type: ignore[misc, index]
129
+
130
+ if property_renaming_config:
131
+ predicate = property_renaming_config.get(property_, property_)
132
+
133
+ property_values[property_].append(value)
134
+ if property_values:
135
+ return (
136
+ identifier,
137
+ property_values,
138
+ )
139
+ else:
140
+ return () # type: ignore [return-value]
141
+
142
+ def construct_instances_of_class(
143
+ self,
144
+ class_: str,
145
+ properties_optional: bool = True,
146
+ instance_id: URIRef | None = None,
147
+ ) -> list[tuple[str, str, str]]:
97
148
  """CONSTRUCT instances for a given class from the graph store
98
149
 
99
150
  Args:
100
151
  class_: Class entity for which we want to generate query
101
152
  properties_optional: Whether to make all properties optional, default True
153
+ instance_ids: List of instance ids to filter on, default None (all)
102
154
 
103
155
  Returns:
104
156
  List of triples for instances of the given class
@@ -106,10 +158,11 @@ class Queries:
106
158
 
107
159
  if self.rules and (
108
160
  query := build_construct_query(
109
- ClassEntity(prefix=self.rules.metadata.prefix, suffix=class_),
110
- self.graph,
111
- self.rules,
112
- properties_optional,
161
+ class_=ClassEntity(prefix=self.rules.metadata.prefix, suffix=class_),
162
+ graph=self.graph,
163
+ rules=self.rules,
164
+ properties_optional=properties_optional,
165
+ instance_id=instance_id,
113
166
  )
114
167
  ):
115
168
  result = self.graph.query(query)
@@ -18,8 +18,8 @@ from cognite.neat.utils.utils import most_occurring_element
18
18
  from ._shared import Triple, hop2property_path
19
19
 
20
20
  _QUERY_TEMPLATE = """CONSTRUCT {{ {graph_template} }}
21
- WHERE {{ {graph_pattern}
22
- {filter}
21
+ WHERE {{ {bind_instance_id}
22
+ {graph_pattern}
23
23
  }}"""
24
24
 
25
25
 
@@ -28,7 +28,7 @@ def build_construct_query(
28
28
  graph: Graph,
29
29
  rules: InformationRules,
30
30
  properties_optional: bool = True,
31
- class_instances: list[URIRef] | None = None,
31
+ instance_id: URIRef | None = None,
32
32
  ) -> str | None:
33
33
  """Builds a CONSTRUCT query for a given class and rules and optionally filters by class instances.
34
34
 
@@ -53,6 +53,7 @@ def build_construct_query(
53
53
  This is the reason why there is an option to make all properties optional, so that
54
54
  the query will return all instances that have at least one property defined.
55
55
  """
56
+
56
57
  if (
57
58
  transformations := InformationArchitectRulesAnalysis(rules)
58
59
  .class_property_pairs(only_rdfpath=True, consider_inheritance=True)
@@ -63,22 +64,20 @@ def build_construct_query(
63
64
  )
64
65
 
65
66
  return _QUERY_TEMPLATE.format(
67
+ bind_instance_id=(f"BIND(<{instance_id}> AS ?instance)" if instance_id else ""),
66
68
  graph_template="\n".join(triples2sparql_statement(templates)),
67
69
  graph_pattern="\n".join(triples2sparql_statement(patterns)),
68
- filter="" if not class_instances else add_filter(class_instances),
69
70
  )
70
71
 
71
72
  else:
72
73
  return None
73
74
 
74
75
 
75
- def add_filter(class_instances: list[URIRef]):
76
- class_instances_formatted = [f"<{instance}>" for instance in class_instances]
77
- return f"FILTER (?instance IN ({', '.join(class_instances_formatted)}))"
78
-
79
-
80
76
  def to_construct_triples(
81
- graph: Graph, transformations: list[InformationProperty], prefixes: dict, properties_optional: bool = True
77
+ graph: Graph,
78
+ transformations: list[InformationProperty],
79
+ prefixes: dict,
80
+ properties_optional: bool = True,
82
81
  ) -> tuple[list[Triple], list[Triple]]:
83
82
  """Converts transformations of a class to CONSTRUCT triples which are used to generate CONSTRUCT query
84
83
 
@@ -124,7 +123,10 @@ def to_construct_triples(
124
123
  # use case AllReferences: binding instance to certain rdf property
125
124
  if isinstance(traversal, AllReferences):
126
125
  graph_pattern_triple = Triple(
127
- subject="BIND(?instance", predicate="AS", object=f"{graph_template_triple.object})", optional=False
126
+ subject="BIND(?instance",
127
+ predicate="AS",
128
+ object=f"{graph_template_triple.object})",
129
+ optional=False,
128
130
  )
129
131
 
130
132
  # use case SingleProperty: simple property traversal
@@ -133,7 +135,7 @@ def to_construct_triples(
133
135
  subject=graph_template_triple.subject,
134
136
  predicate=traversal.property.id,
135
137
  object=graph_template_triple.object,
136
- optional=True if properties_optional else not transformation.is_mandatory,
138
+ optional=(True if properties_optional else not transformation.is_mandatory),
137
139
  )
138
140
 
139
141
  # use case Hop: property traversal with multiple hops turned into property path
@@ -143,7 +145,7 @@ def to_construct_triples(
143
145
  subject="?instance",
144
146
  predicate=hop2property_path(graph, traversal, prefixes),
145
147
  object=graph_template_triple.object,
146
- optional=True if properties_optional else not transformation.is_mandatory,
148
+ optional=(True if properties_optional else not transformation.is_mandatory),
147
149
  )
148
150
 
149
151
  # other type of rdfpaths are skipped
@@ -15,6 +15,7 @@ from cognite.neat.graph.extractors import RdfFileExtractor, TripleExtractors
15
15
  from cognite.neat.graph.models import Triple
16
16
  from cognite.neat.graph.queries import Queries
17
17
  from cognite.neat.graph.transformers import Transformers
18
+ from cognite.neat.rules.analysis import InformationArchitectRulesAnalysis
18
19
  from cognite.neat.rules.models import InformationRules
19
20
  from cognite.neat.rules.models.entities import ClassEntity
20
21
  from cognite.neat.utils.auxiliary import local_import
@@ -165,25 +166,32 @@ class NeatGraphStore:
165
166
  )
166
167
  )
167
168
 
168
- def read(self, class_: str) -> list[tuple[str, str, str]]:
169
+ def read(self, class_: str) -> Iterable[tuple[str, dict[str, list[str]]]]:
169
170
  """Read instances for given view from the graph store."""
170
- # PLACEHOLDER: Implement reading instances for a given view
171
- # not yet developed
172
171
 
173
172
  if not self.rules:
174
- warnings.warn(
175
- "No rules found for the graph store, returning empty list.",
176
- stacklevel=2,
177
- )
178
- return []
173
+ warnings.warn("Rules not found in graph store!", stacklevel=2)
174
+ return None
179
175
 
180
176
  class_entity = ClassEntity(prefix=self.rules.metadata.prefix, suffix=class_)
181
177
 
182
178
  if class_entity not in [definition.class_ for definition in self.rules.classes.data]:
183
179
  warnings.warn("Desired type not found in graph!", stacklevel=2)
184
- return []
180
+ return None
181
+
182
+ if InformationArchitectRulesAnalysis(self.rules).has_hop_transformations():
183
+ warnings.warn(
184
+ "Rules contain Hop rdfpath, run ReduceHopTraversal transformer first!",
185
+ stacklevel=2,
186
+ )
187
+ return None
188
+
189
+ instance_ids = self.queries.list_instances_ids_of_class(self.rules.metadata.namespace[class_])
190
+
191
+ property_renaming_config = InformationArchitectRulesAnalysis(self.rules).define_property_renaming_config()
185
192
 
186
- return self.queries.construct_instances_of_class(class_)
193
+ for instance_id in instance_ids:
194
+ yield self.queries.describe(instance_id, property_renaming_config)
187
195
 
188
196
  def _parse_file(
189
197
  self,
@@ -0,0 +1,7 @@
1
+ from ._base import BaseTransformer
2
+
3
+
4
+ class ReduceHopTraversal(BaseTransformer):
5
+ """ReduceHopTraversal is a transformer that reduces the number of hops to direct connection."""
6
+
7
+ ...
@@ -8,7 +8,7 @@ import pandas as pd
8
8
  from pydantic import ValidationError
9
9
 
10
10
  from cognite.neat.rules.models import SchemaCompleteness
11
- from cognite.neat.rules.models._rdfpath import RDFPath
11
+ from cognite.neat.rules.models._rdfpath import Hop, RDFPath
12
12
  from cognite.neat.rules.models.asset import AssetClass, AssetProperty, AssetRules
13
13
  from cognite.neat.rules.models.entities import (
14
14
  AssetEntity,
@@ -401,7 +401,14 @@ class _SharedAnalysis(Generic[T_Rules, T_Property, T_Class]):
401
401
  class InformationArchitectRulesAnalysis(_SharedAnalysis[InformationRules, InformationProperty, InformationClass]):
402
402
  """Assumes analysis over only the complete schema"""
403
403
 
404
- ...
404
+ def has_hop_transformations(self):
405
+ return any(
406
+ prop_.transformation and isinstance(prop_.transformation.traversal, Hop) for prop_ in self.rules.properties
407
+ )
408
+
409
+ def define_property_renaming_config(self) -> dict[str, str]:
410
+ # placeholder comes in new PR
411
+ return {}
405
412
 
406
413
 
407
414
  class AssetArchitectRulesAnalysis(_SharedAnalysis[AssetRules, AssetProperty, AssetClass]):
@@ -28,10 +28,10 @@ class BaseExporter(ABC, Generic[T_Export]):
28
28
  def _convert_to_output_role(self, rules: Rules, output_role: RoleTypes | None = None) -> Rules:
29
29
  if rules.metadata.role is output_role or output_role is None:
30
30
  return rules
31
- elif output_role is RoleTypes.dms_architect and isinstance(rules, InformationRules):
32
- return rules.as_dms_architect_rules()
33
- elif output_role is RoleTypes.information_architect and isinstance(rules, DMSRules):
34
- return rules.as_information_architect_rules()
31
+ elif output_role is RoleTypes.dms and isinstance(rules, InformationRules):
32
+ return rules.as_dms_rules()
33
+ elif output_role is RoleTypes.information and isinstance(rules, DMSRules):
34
+ return rules.as_information_rules()
35
35
  else:
36
36
  raise NotImplementedError(f"Role {output_role} is not supported for {type(rules).__name__} rules")
37
37
 
@@ -118,7 +118,7 @@ class DMSExporter(CDFExporter[DMSSchema]):
118
118
  if isinstance(rules, DMSRules):
119
119
  dms_rules = rules
120
120
  elif isinstance(rules, InformationRules):
121
- dms_rules = rules.as_dms_architect_rules()
121
+ dms_rules = rules.as_dms_rules()
122
122
  else:
123
123
  raise ValueError(f"{type(rules).__name__} cannot be exported to DMS")
124
124
  return dms_rules.as_schema(include_pipeline=self.export_pipeline, instance_space=self.instance_space)
@@ -95,7 +95,7 @@ class Ontology(OntologyModel):
95
95
  if isinstance(input_rules, InformationRules):
96
96
  rules = input_rules
97
97
  elif isinstance(input_rules, DMSRules):
98
- rules = input_rules.as_information_architect_rules()
98
+ rules = input_rules.as_information_rules()
99
99
  else:
100
100
  raise ValueError(f"{type(input_rules).__name__} cannot be exported to Ontology")
101
101
 
@@ -55,10 +55,10 @@ class BaseImporter(ABC):
55
55
 
56
56
  if rules.metadata.role is role or role is None:
57
57
  output = rules
58
- elif isinstance(rules, DMSRules) or isinstance(rules, AssetRules) and role is RoleTypes.information_architect:
59
- output = rules.as_information_architect_rules()
60
- elif isinstance(rules, InformationRules) or isinstance(rules, AssetRules) and role is RoleTypes.dms_architect:
61
- output = rules.as_dms_architect_rules()
58
+ elif isinstance(rules, DMSRules) or isinstance(rules, AssetRules) and role is RoleTypes.information:
59
+ output = rules.as_information_rules()
60
+ elif isinstance(rules, InformationRules) or isinstance(rules, AssetRules) and role is RoleTypes.dms:
61
+ output = rules.as_dms_rules()
62
62
  else:
63
63
  raise NotImplementedError(f"Role {role} is not supported for {type(rules).__name__} rules")
64
64
 
@@ -75,7 +75,9 @@ class InferenceImporter(BaseImporter):
75
75
  self.graph = graph
76
76
  self.max_number_of_instance = max_number_of_instance
77
77
  self.prefix = prefix
78
- self.check_for_json_string = check_for_json_string
78
+ self.check_for_json_string = (
79
+ check_for_json_string if graph.store.__class__.__name__ != "OxigraphStore" else False
80
+ )
79
81
 
80
82
  @classmethod
81
83
  def from_graph_store(
@@ -235,6 +237,7 @@ class InferenceImporter(BaseImporter):
235
237
  query.replace("instance_id", instance)
236
238
  ): # type: ignore[misc]
237
239
  property_id = remove_namespace_from_uri(property_uri)
240
+
238
241
  self._add_uri_namespace_to_prefixes(cast(URIRef, property_uri), prefixes)
239
242
  value_type_uri = data_type_uri if data_type_uri else object_type_uri
240
243
 
@@ -51,7 +51,7 @@ def parse_owl_metadata(graph: Graph) -> dict:
51
51
 
52
52
  raw_metadata = convert_rdflib_content(
53
53
  {
54
- "role": RoleTypes.information_architect,
54
+ "role": RoleTypes.information,
55
55
  "schema": SchemaCompleteness.partial,
56
56
  "prefix": results[1].pop(),
57
57
  "namespace": Namespace(results[0].pop()),
@@ -36,9 +36,9 @@ SOURCE_SHEET__TARGET_FIELD__HEADERS = [
36
36
  "Properties",
37
37
  {
38
38
  RoleTypes.domain_expert: "Property",
39
- RoleTypes.information_architect: "Property",
40
- RoleTypes.asset_architect: "Property",
41
- RoleTypes.dms_architect: "View Property",
39
+ RoleTypes.information: "Property",
40
+ RoleTypes.asset: "Property",
41
+ RoleTypes.dms: "View Property",
42
42
  },
43
43
  ),
44
44
  ("Classes", "Classes", "Class"),
@@ -334,9 +334,9 @@ class GoogleSheetImporter(BaseImporter):
334
334
 
335
335
  if role == RoleTypes.domain_expert:
336
336
  output = rules_model.model_validate(sheets)
337
- elif role == RoleTypes.information_architect:
337
+ elif role == RoleTypes.information:
338
338
  output = rules_model.model_validate(sheets)
339
- elif role == RoleTypes.dms_architect:
339
+ elif role == RoleTypes.dms:
340
340
  output = rules_model.model_validate(sheets)
341
341
  else:
342
342
  raise ValueError(f"Role {role} is not valid.")
@@ -8,9 +8,9 @@ from .dms._schema import DMSSchema
8
8
 
9
9
  RULES_PER_ROLE: dict[RoleTypes, type[DomainRules] | type[InformationRules] | type[AssetRules] | type[DMSRules]] = {
10
10
  RoleTypes.domain_expert: DomainRules,
11
- RoleTypes.information_architect: InformationRules,
12
- RoleTypes.asset_architect: AssetRules,
13
- RoleTypes.dms_architect: DMSRules,
11
+ RoleTypes.information: InformationRules,
12
+ RoleTypes.asset: AssetRules,
13
+ RoleTypes.dms: DMSRules,
14
14
  }
15
15
 
16
16
 
@@ -150,9 +150,9 @@ class DataModelType(StrEnum):
150
150
 
151
151
  class RoleTypes(StrEnum):
152
152
  domain_expert = "domain expert"
153
- information_architect = "information architect"
154
- asset_architect = "asset architect"
155
- dms_architect = "DMS Architect"
153
+ information = "information architect"
154
+ asset = "asset architect"
155
+ dms = "DMS Architect"
156
156
 
157
157
 
158
158
  class MatchType(StrEnum):
@@ -35,7 +35,7 @@ else:
35
35
 
36
36
 
37
37
  class AssetMetadata(InformationMetadata):
38
- role: ClassVar[RoleTypes] = RoleTypes.asset_architect
38
+ role: ClassVar[RoleTypes] = RoleTypes.asset
39
39
 
40
40
 
41
41
  class AssetClass(InformationClass): ...
@@ -148,12 +148,12 @@ class AssetRules(BaseRules):
148
148
  def as_domain_rules(self) -> DomainRules:
149
149
  from ._converter import _AssetRulesConverter
150
150
 
151
- return _AssetRulesConverter(self.as_information_architect_rules()).as_domain_rules()
151
+ return _AssetRulesConverter(self.as_information_rules()).as_domain_rules()
152
152
 
153
- def as_dms_architect_rules(self) -> "DMSRules":
153
+ def as_dms_rules(self) -> "DMSRules":
154
154
  from ._converter import _AssetRulesConverter
155
155
 
156
- return _AssetRulesConverter(self.as_information_architect_rules()).as_dms_architect_rules()
156
+ return _AssetRulesConverter(self.as_information_rules()).as_dms_rules()
157
157
 
158
- def as_information_architect_rules(self) -> InformationRules:
158
+ def as_information_rules(self) -> InformationRules:
159
159
  return InformationRules.model_validate(self.model_dump())
@@ -237,7 +237,7 @@ class Literal(DataType):
237
237
 
238
238
  class Timeseries(DataType):
239
239
  name = "timeseries"
240
- python = dms.TimeSeriesReference
240
+ python = str
241
241
  dms = dms.TimeSeriesReference
242
242
  graphql = "TimeSeries"
243
243
  xsd = "string"
@@ -246,7 +246,7 @@ class Timeseries(DataType):
246
246
 
247
247
  class File(DataType):
248
248
  name = "file"
249
- python = dms.FileReference
249
+ python = str
250
250
  dms = dms.FileReference
251
251
  graphql = "File"
252
252
  xsd = "string"
@@ -255,7 +255,7 @@ class File(DataType):
255
255
 
256
256
  class Sequence(DataType):
257
257
  name = "sequence"
258
- python = dms.SequenceReference
258
+ python = str
259
259
  dms = dms.SequenceReference
260
260
  graphql = "Sequence"
261
261
  xsd = "string"
@@ -264,7 +264,7 @@ class Sequence(DataType):
264
264
 
265
265
  class Json(DataType):
266
266
  name = "json"
267
- python = dms.Json
267
+ python = dict
268
268
  dms = dms.Json
269
269
  graphql = "Json"
270
270
  xsd = "json"
@@ -32,7 +32,7 @@ class _DMSRulesConverter:
32
32
  def as_domain_rules(self) -> "DomainRules":
33
33
  raise NotImplementedError("DomainRules not implemented yet")
34
34
 
35
- def as_information_architect_rules(
35
+ def as_information_rules(
36
36
  self,
37
37
  ) -> "InformationRules":
38
38
  from cognite.neat.rules.models.information._rules import (
@@ -94,8 +94,8 @@ class _DMSRulesConverter:
94
94
  metadata=metadata,
95
95
  properties=SheetList[InformationProperty](data=properties),
96
96
  classes=SheetList[InformationClass](data=classes),
97
- last=self.dms.last.as_information_architect_rules() if self.dms.last else None,
98
- reference=self.dms.reference.as_information_architect_rules() if self.dms.reference else None,
97
+ last=self.dms.last.as_information_rules() if self.dms.last else None,
98
+ reference=self.dms.reference.as_information_rules() if self.dms.reference else None,
99
99
  )
100
100
 
101
101
  @classmethod
@@ -58,7 +58,7 @@ _DEFAULT_VERSION = "1"
58
58
 
59
59
 
60
60
  class DMSMetadata(BaseMetadata):
61
- role: ClassVar[RoleTypes] = RoleTypes.dms_architect
61
+ role: ClassVar[RoleTypes] = RoleTypes.dms
62
62
  data_model_type: DataModelType = Field(DataModelType.enterprise, alias="dataModelType")
63
63
  schema_: SchemaCompleteness = Field(alias="schema")
64
64
  extension: ExtensionCategory = ExtensionCategory.addition
@@ -382,10 +382,10 @@ class DMSRules(BaseRules):
382
382
 
383
383
  return _DMSExporter(self, include_pipeline, instance_space).to_schema()
384
384
 
385
- def as_information_architect_rules(self) -> "InformationRules":
385
+ def as_information_rules(self) -> "InformationRules":
386
386
  from ._converter import _DMSRulesConverter
387
387
 
388
- return _DMSRulesConverter(self).as_information_architect_rules()
388
+ return _DMSRulesConverter(self).as_information_rules()
389
389
 
390
390
  def as_domain_expert_rules(self) -> DomainRules:
391
391
  from ._converter import _DMSRulesConverter
@@ -79,7 +79,7 @@ class _InformationRulesConverter:
79
79
  prefixes=self.rules.prefixes,
80
80
  )
81
81
 
82
- def as_dms_architect_rules(self) -> "DMSRules":
82
+ def as_dms_rules(self) -> "DMSRules":
83
83
  from cognite.neat.rules.models.dms._rules import (
84
84
  DMSContainer,
85
85
  DMSProperty,
@@ -112,8 +112,8 @@ class _InformationRulesConverter:
112
112
  for cls_ in self.rules.classes
113
113
  ]
114
114
 
115
- last_dms_rules = self.rules.last.as_dms_architect_rules() if self.rules.last else None
116
- ref_dms_rules = self.rules.reference.as_dms_architect_rules() if self.rules.reference else None
115
+ last_dms_rules = self.rules.last.as_dms_rules() if self.rules.last else None
116
+ ref_dms_rules = self.rules.reference.as_dms_rules() if self.rules.reference else None
117
117
 
118
118
  class_by_entity = {cls_.class_: cls_ for cls_ in self.rules.classes}
119
119
  if self.rules.last:
@@ -59,7 +59,7 @@ else:
59
59
 
60
60
 
61
61
  class InformationMetadata(BaseMetadata):
62
- role: ClassVar[RoleTypes] = RoleTypes.information_architect
62
+ role: ClassVar[RoleTypes] = RoleTypes.information
63
63
  data_model_type: DataModelType = Field(DataModelType.enterprise, alias="dataModelType")
64
64
  schema_: SchemaCompleteness = Field(SchemaCompleteness.partial, alias="schema")
65
65
  extension: ExtensionCategoryType | None = ExtensionCategory.addition
@@ -348,7 +348,7 @@ class InformationRules(BaseRules):
348
348
 
349
349
  return _InformationRulesConverter(self).as_asset_architect_rules()
350
350
 
351
- def as_dms_architect_rules(self) -> "DMSRules":
351
+ def as_dms_rules(self) -> "DMSRules":
352
352
  from ._converter import _InformationRulesConverter
353
353
 
354
- return _InformationRulesConverter(self).as_dms_architect_rules()
354
+ return _InformationRulesConverter(self).as_dms_rules()
@@ -7,20 +7,30 @@ from collections import Counter, OrderedDict
7
7
  from collections.abc import Iterable
8
8
  from datetime import datetime
9
9
  from functools import wraps
10
- from typing import TypeAlias, cast, overload
10
+ from typing import Literal, TypeAlias, cast, overload
11
11
 
12
12
  import pandas as pd
13
13
  from cognite.client import ClientConfig, CogniteClient
14
- from cognite.client.credentials import CredentialProvider, OAuthClientCredentials, OAuthInteractive, Token
14
+ from cognite.client.credentials import (
15
+ CredentialProvider,
16
+ OAuthClientCredentials,
17
+ OAuthInteractive,
18
+ Token,
19
+ )
15
20
  from cognite.client.exceptions import CogniteDuplicatedError, CogniteReadTimeout
16
21
  from pydantic import HttpUrl, TypeAdapter, ValidationError
17
22
  from pydantic_core import ErrorDetails
18
23
  from pyparsing import Any
19
- from rdflib import Literal, Namespace
24
+ from rdflib import Literal as RdfLiteral
25
+ from rdflib import Namespace
20
26
  from rdflib.term import URIRef
21
27
 
22
28
  from cognite.neat import _version
23
- from cognite.neat.utils.cdf import CogniteClientConfig, InteractiveCogniteClient, ServiceCogniteClient
29
+ from cognite.neat.utils.cdf import (
30
+ CogniteClientConfig,
31
+ InteractiveCogniteClient,
32
+ ServiceCogniteClient,
33
+ )
24
34
 
25
35
  if sys.version_info >= (3, 11):
26
36
  from datetime import UTC
@@ -30,12 +40,15 @@ else:
30
40
  UTC = timezone.utc
31
41
 
32
42
 
33
- Triple: TypeAlias = tuple[URIRef, URIRef, Literal | URIRef]
43
+ Triple: TypeAlias = tuple[URIRef, URIRef, RdfLiteral | URIRef]
34
44
 
35
45
 
36
46
  def get_cognite_client_from_config(config: ServiceCogniteClient) -> CogniteClient:
37
47
  credentials = OAuthClientCredentials(
38
- token_url=config.token_url, client_id=config.client_id, client_secret=config.client_secret, scopes=config.scopes
48
+ token_url=config.token_url,
49
+ client_id=config.client_id,
50
+ client_secret=config.client_secret,
51
+ scopes=config.scopes,
39
52
  )
40
53
 
41
54
  return _get_cognite_client(config, credentials)
@@ -75,15 +88,25 @@ def _get_cognite_client(config: CogniteClientConfig, credentials: CredentialProv
75
88
 
76
89
 
77
90
  @overload
78
- def remove_namespace_from_uri(*URI: URIRef | str, special_separator: str = "#_") -> str: ...
91
+ def remove_namespace_from_uri(
92
+ *URI: URIRef | str,
93
+ special_separator: str = "#_",
94
+ validation: Literal["full", "prefix"] = "prefix",
95
+ ) -> str: ...
79
96
 
80
97
 
81
98
  @overload
82
- def remove_namespace_from_uri(*URI: tuple[URIRef | str, ...], special_separator: str = "#_") -> tuple[str, ...]: ...
99
+ def remove_namespace_from_uri(
100
+ *URI: tuple[URIRef | str, ...],
101
+ special_separator: str = "#_",
102
+ validation: Literal["full", "prefix"] = "prefix",
103
+ ) -> tuple[str, ...]: ...
83
104
 
84
105
 
85
106
  def remove_namespace_from_uri(
86
- *URI: URIRef | str | tuple[URIRef | str, ...], special_separator: str = "#_"
107
+ *URI: URIRef | str | tuple[URIRef | str, ...],
108
+ special_separator: str = "#_",
109
+ validation: Literal["full", "prefix"] = "prefix",
87
110
  ) -> tuple[str, ...] | str:
88
111
  """Removes namespace from URI
89
112
 
@@ -93,6 +116,9 @@ def remove_namespace_from_uri(
93
116
  special_separator : str
94
117
  Special separator to use instead of # or / if present in URI
95
118
  Set by default to "#_" which covers special client use case
119
+ validation: str
120
+ Validation type to use for URI. If set to "full", URI will be validated using pydantic
121
+ If set to "prefix", only check if URI starts with http or https will be made
96
122
 
97
123
  Returns
98
124
  Entities id without namespace
@@ -114,11 +140,17 @@ def remove_namespace_from_uri(
114
140
 
115
141
  output = []
116
142
  for u in uris:
117
- try:
118
- _ = TypeAdapter(HttpUrl).validate_python(u)
119
- output.append(u.split(special_separator if special_separator in u else "#" if "#" in u else "/")[-1])
120
- except ValidationError:
121
- output.append(str(u))
143
+ if validation == "full":
144
+ try:
145
+ _ = TypeAdapter(HttpUrl).validate_python(u)
146
+ output.append(u.split(special_separator if special_separator in u else "#" if "#" in u else "/")[-1])
147
+ except ValidationError:
148
+ output.append(str(u))
149
+ else:
150
+ if u.lower().startswith("http"):
151
+ output.append(u.split(special_separator if special_separator in u else "#" if "#" in u else "/")[-1])
152
+ else:
153
+ output.append(str(u))
122
154
 
123
155
  return tuple(output) if len(output) > 1 else output[0]
124
156
 
@@ -154,8 +186,8 @@ def as_neat_compliant_uri(uri: URIRef) -> URIRef:
154
186
  return URIRef(f"{namespace}{compliant_uri}")
155
187
 
156
188
 
157
- def convert_rdflib_content(content: Literal | URIRef | dict | list) -> Any:
158
- if isinstance(content, Literal) or isinstance(content, URIRef):
189
+ def convert_rdflib_content(content: RdfLiteral | URIRef | dict | list) -> Any:
190
+ if isinstance(content, RdfLiteral) or isinstance(content, URIRef):
159
191
  return content.toPython()
160
192
  elif isinstance(content, dict):
161
193
  return {key: convert_rdflib_content(value) for key, value in content.items()}
@@ -192,7 +224,9 @@ def _traverse(hierarchy: dict, graph: dict, names: list[str]) -> dict:
192
224
 
193
225
 
194
226
  def get_generation_order(
195
- class_linkage: pd.DataFrame, parent_col: str = "source_class", child_col: str = "target_class"
227
+ class_linkage: pd.DataFrame,
228
+ parent_col: str = "source_class",
229
+ child_col: str = "target_class",
196
230
  ) -> dict:
197
231
  parent_child_list = class_linkage[[parent_col, child_col]].values.tolist()
198
232
  # Build a directed graph and a list of all names that have no parent
@@ -318,7 +352,9 @@ def generate_exception_report(exceptions: list[dict] | list[ErrorDetails] | None
318
352
  return report
319
353
 
320
354
 
321
- def _order_expectations_by_type(exceptions: list[dict] | list[ErrorDetails]) -> dict[str, list[str]]:
355
+ def _order_expectations_by_type(
356
+ exceptions: list[dict] | list[ErrorDetails],
357
+ ) -> dict[str, list[str]]:
322
358
  exception_dict: dict[str, list[str]] = {}
323
359
  for exception in exceptions:
324
360
  if not isinstance(exception["loc"], str) and isinstance(exception["loc"], Iterable):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cognite-neat
3
- Version: 0.85.11
3
+ Version: 0.86.0
4
4
  Summary: Knowledge graph transformation
5
5
  Home-page: https://cognite-neat.readthedocs-hosted.com/
6
6
  License: Apache-2.0
@@ -1,6 +1,6 @@
1
1
  cognite/neat/__init__.py,sha256=AiexNcHdAHFbrrbo9c65gtil1dqx_SGraDH1PSsXjKE,126
2
2
  cognite/neat/_shared.py,sha256=RSaHm2eJceTlvb-hMMe4nHgoHdPYDfN3XcxDXo24k3A,1530
3
- cognite/neat/_version.py,sha256=bVP2BELxIGHP-amVHOwETotJ5zyQqFcbe7c26GvSm-c,24
3
+ cognite/neat/_version.py,sha256=mYct1UR8Rb7usms6EgqHp-uduOQsYVzy_Xhv8wi369Y,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
@@ -10,7 +10,7 @@ cognite/neat/app/api/data_classes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeR
10
10
  cognite/neat/app/api/data_classes/rest.py,sha256=yVWqFkBCDCGooOWaE5nun4No8B-PBa6svdenIjBINdo,1675
11
11
  cognite/neat/app/api/explorer.py,sha256=OlLI-RbQGjXEuDgtmFfBuTXfnRVemTJDKbL9VvXLr6Y,1891
12
12
  cognite/neat/app/api/routers/configuration.py,sha256=rg9GihPPYjgNj1n_wWqfASO4iMXWh_US5sgNJCwejCE,585
13
- cognite/neat/app/api/routers/core.py,sha256=cHMX0JoxFHQB65VkFCvOprSkO8tFydECYtVFfRq9yfE,3523
13
+ cognite/neat/app/api/routers/core.py,sha256=WznuQHzGkhBzf_GrHFiaSCXewBiQcrT4O6kYaJtaBYA,3483
14
14
  cognite/neat/app/api/routers/crud.py,sha256=VCQMjvcLosELkmMZRiunyd-RK5sltQFjcCSrGk5kwXc,4597
15
15
  cognite/neat/app/api/routers/data_exploration.py,sha256=243dZcMJU-ZE-pSu2oIJMbQQmpyo-74i4Vtd7d1mgbg,13704
16
16
  cognite/neat/app/api/routers/metrics.py,sha256=S_bUQk_GjfQq7WbEhSVdow4MUYBZ_bZNafzgcKogXK8,210
@@ -65,26 +65,27 @@ cognite/neat/graph/extractors/_classic_cdf/_relationships.py,sha256=GzxnvIflmHVn
65
65
  cognite/neat/graph/extractors/_classic_cdf/_sequences.py,sha256=rhMEPY5PCxLnErwPPzdHH02c9o7rn0whLtnvcrLDjr8,4677
66
66
  cognite/neat/graph/extractors/_classic_cdf/_timeseries.py,sha256=rxhAe7BcJFg2-eFgBSTb6Trkw53XgZfU5-wLrjqZHEQ,6122
67
67
  cognite/neat/graph/extractors/_dexpi.py,sha256=xIw3kSaQ17k_bAuecvrVRic70PUhFHtcyy-ReLt36Q4,9385
68
- cognite/neat/graph/extractors/_mock_graph_generator.py,sha256=w6lIgwvVwkvK725S9MLFZU8lLxjxXt_621_nChupAkQ,14791
68
+ cognite/neat/graph/extractors/_mock_graph_generator.py,sha256=AgP_1cY4msKB65vJlvVualGLnmB7tuVCDBOQxcBHpIo,14781
69
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
72
  cognite/neat/graph/loaders/__init__.py,sha256=BteVkTklPVUB2W-bbzZug-cEUrx8ZFA-YcQPSxWVpTI,678
73
73
  cognite/neat/graph/loaders/_base.py,sha256=yIXJ7H5VeVb_mqMCM36BYyEOQMbIZcV60RxqD-Xrj-Y,3032
74
74
  cognite/neat/graph/loaders/_rdf2asset.py,sha256=aFby7BwIrW253LEJ4XqGeUuf4jG9VUe8Lg7OlUnXMlM,4493
75
- cognite/neat/graph/loaders/_rdf2dms.py,sha256=2PCL8De02xlEkTmgG299k5tiZcKPnoNzCQfI1AgS2Gg,14060
75
+ cognite/neat/graph/loaders/_rdf2dms.py,sha256=gZVtwFCnhHZeXIks_Drke6PqSICEpwX-_i1g9Dg5AiQ,14471
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
- cognite/neat/graph/queries/_base.py,sha256=yO1i2HPA2RiXMehANImDPxSkL6QB6LwvD22HvfdFt70,6023
79
- cognite/neat/graph/queries/_construct.py,sha256=FxzSQqzCpo7lKVYerlLAY03oqCeFM5L6MozfBUblzr4,7341
78
+ cognite/neat/graph/queries/_base.py,sha256=YtYZesgiPgFP2CnvhsZyOA2LxsjyEVh7-w9T1MjLHgw,8033
79
+ cognite/neat/graph/queries/_construct.py,sha256=glzZETFjcmtPdS0KUzWvq9bPoCcDBz1bPnD0u_Fk_F4,7214
80
80
  cognite/neat/graph/queries/_shared.py,sha256=1-cBnoqyHQazOdNc7J5kk-_GrlHSSnYsBdNJcRD5QyI,5061
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=r6NShdYp7KZBQ9WBY1BUFZa5X0SPm509vZjnllmiSIo,11085
82
+ cognite/neat/graph/stores/_base.py,sha256=JNXII_UG9adCl94-OhM5IMr-9Y8I4w7z2qc2d3QOxMA,11553
83
83
  cognite/neat/graph/stores/_oxrdflib.py,sha256=A5zeRm5_e8ui_ihGpgstRDg_N7qcLZ3QZBRGrOXSGI0,9569
84
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=6xX-OBSJT5DAQrTJ-nuhCfGNaSk5Iktxn-WIMfzEIqo,13189
88
+ cognite/neat/graph/transformers/_rdfpath.py,sha256=TAkYdT1HSyrW_ZDLv-wjaiKiyUBrl0Zjz73UVTRmMtw,189
88
89
  cognite/neat/issues.py,sha256=pxQfqfBseMDE8JM0iqZnkLXngeyeFfT0TFtu1UuAd4c,4629
89
90
  cognite/neat/legacy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
90
91
  cognite/neat/legacy/graph/__init__.py,sha256=31uTeejWOSd-I8iUG8GOZFhHZcQCsBitJ6X8vu2r1nU,73
@@ -184,32 +185,32 @@ cognite/neat/rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
184
185
  cognite/neat/rules/_shared.py,sha256=Ak2K9YnLhvmp8womNI3bmjaooQZkY9E33-DJ97P9wZg,195
185
186
  cognite/neat/rules/analysis/__init__.py,sha256=ne6VlpFloufvxddDMbm7pLugnRpDv6ymaxB6_1XBxXw,188
186
187
  cognite/neat/rules/analysis/_base.py,sha256=JLYWYM6ZOviH_Lfu-kMX8UYmGHKt2LHq2BMITL-Plrw,395
187
- cognite/neat/rules/analysis/_information_rules.py,sha256=EW0hDTsYSaWgfdndLg299q4jlq1r0dZkP2Gmnj8R2Ew,20846
188
+ cognite/neat/rules/analysis/_information_rules.py,sha256=8MLOtE91_EkSwn6CZv6GJokrs1_2yDBwrvpySOZemJI,21154
188
189
  cognite/neat/rules/examples/__init__.py,sha256=nxIwueAcHgZhkYriGxnDLQmIyiT8PByPHbScjYKDKe0,374
189
190
  cognite/neat/rules/examples/wind-energy.owl,sha256=NuomCA9FuuLF0JlSuG3OKqD4VBcHgSjDKFLV17G1zV8,65934
190
191
  cognite/neat/rules/exceptions.py,sha256=YLnsbXXJdDSr_szQoioEtOdqDV8PR7RdQjpMP2SWeCs,123868
191
192
  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
193
+ cognite/neat/rules/exporters/_base.py,sha256=vJXY7qdo4blDZemfDXuuYCkUt1cTa5PsOLMdll7OcGw,1896
194
+ cognite/neat/rules/exporters/_rules2dms.py,sha256=_2QkQhfx4c92RDaXsuX_k_Q2LkdOJ627eYgQNvCYj8s,14543
194
195
  cognite/neat/rules/exporters/_rules2excel.py,sha256=bVYq0zmMLDEzSDD39_DQOL6rFGBgRMq5lE7xVMAg8i8,14328
195
- cognite/neat/rules/exporters/_rules2ontology.py,sha256=h5akLKnhVxRfIiOredA3ILqD4qr-qizyP0gd6oNmswo,20608
196
+ cognite/neat/rules/exporters/_rules2ontology.py,sha256=dMbnKni69HG5KgjTYLf7Cn_2Q3dzr9QQjII8r43y4Qk,20598
196
197
  cognite/neat/rules/exporters/_rules2yaml.py,sha256=GA8eUYRxUfIU6IMvlyGO5JidkOD5eUKSbH3qAiFiaCg,3026
197
198
  cognite/neat/rules/exporters/_validation.py,sha256=OlKIyf4nhSDehJwFHDQ8Zdf6HpNfW7dSe2s67eywHu4,4078
198
199
  cognite/neat/rules/importers/__init__.py,sha256=Vxl2Iq1dMXUsI6Wb411xPI3rromdq50xZUci-S8faSw,1097
199
- cognite/neat/rules/importers/_base.py,sha256=C8_Q99H3Sxds7HO_5aLkw8PItk3Zojxbz4uwx1xgxQM,4550
200
+ cognite/neat/rules/importers/_base.py,sha256=EgXF2pmJ90LbmFs5rAMwh151wGX3PGkhTTF6rC-DzOg,4510
200
201
  cognite/neat/rules/importers/_dms2rules.py,sha256=Dqoh4qO5IVvjRpxLHZaqCgPC99_r4y7ncEo2WYMxwqU,19302
201
202
  cognite/neat/rules/importers/_dtdl2rules/__init__.py,sha256=CNR-sUihs2mnR1bPMKs3j3L4ds3vFTsrl6YycExZTfU,68
202
203
  cognite/neat/rules/importers/_dtdl2rules/_unit_lookup.py,sha256=wW4saKva61Q_i17guY0dc4OseJDQfqHy_QZBtm0OD6g,12134
203
204
  cognite/neat/rules/importers/_dtdl2rules/dtdl_converter.py,sha256=ysmWUxZ0npwrTB0uiH5jA0v37sfCwowGaYk17IyxPUU,12663
204
205
  cognite/neat/rules/importers/_dtdl2rules/dtdl_importer.py,sha256=Psj3C2jembY_Wu7WWJIFIwrMawvjISjeqfBnoRy_csw,6740
205
206
  cognite/neat/rules/importers/_dtdl2rules/spec.py,sha256=tim_MfN1J0F3Oeqk3BMgIA82d_MZvhRuRMsLK3B4PYc,11897
206
- cognite/neat/rules/importers/_inference2rules.py,sha256=U2fNqBtN_NMtFAm7uSiejfxNFWIvUjHv5JriOEI5Z3I,13704
207
+ cognite/neat/rules/importers/_inference2rules.py,sha256=9ndiy36aJSR-I5wTUcC9vb08zWUZshrSTiunplXtt40,13793
207
208
  cognite/neat/rules/importers/_owl2rules/__init__.py,sha256=tdGcrgtozdQyST-pTlxIa4cLBNTLvtk1nNYR4vOdFSw,63
208
209
  cognite/neat/rules/importers/_owl2rules/_owl2classes.py,sha256=dACjYeCa_OhpQgqccI4w478dEINbISUMzpVkCOoRRL8,7384
209
- cognite/neat/rules/importers/_owl2rules/_owl2metadata.py,sha256=nwnUaBNAAYMoBre2UmsnkJXUuaqGEpR3U3txDrH2w6g,7527
210
+ cognite/neat/rules/importers/_owl2rules/_owl2metadata.py,sha256=dojTk6NKK2STzVSuh0ithFHHAbttIY09rHGnioEY3eA,7517
210
211
  cognite/neat/rules/importers/_owl2rules/_owl2properties.py,sha256=3-yiCyh5In7jLhIytEK7ktG9suuv6QMa5xCs2TQvHZM,7342
211
212
  cognite/neat/rules/importers/_owl2rules/_owl2rules.py,sha256=41_wZFvt0A6TI55zlT04oQkvU7V73li4aGLgc4T4Lxo,6358
212
- cognite/neat/rules/importers/_spreadsheet2rules.py,sha256=vyYXNvP64dBGTWRWfrg7wtUcs0PdPiGLAHwE8itItAA,13072
213
+ cognite/neat/rules/importers/_spreadsheet2rules.py,sha256=ZJJiO15Br9f8HS5D0A5PgtA726XkMNzfd15PWu1tMHA,13022
213
214
  cognite/neat/rules/importers/_yaml2rules.py,sha256=F0uksSz1A3po5OlRM2152_w5j8D9oYTLB9NFTkSMlWI,4275
214
215
  cognite/neat/rules/issues/__init__.py,sha256=c12m0HAHHzF6oR8lKbULE3TxOPimTi9s1O9IIrtgh0g,549
215
216
  cognite/neat/rules/issues/base.py,sha256=x2YLCfmqtPlFLoURq3qHaprXCpFaQdf0iWkql-EMyps,2446
@@ -219,8 +220,8 @@ cognite/neat/rules/issues/formatters.py,sha256=_ag2bJ9hncOj8pAGJvTTEPs9kTtxbD7vk
219
220
  cognite/neat/rules/issues/importing.py,sha256=uSk4TXo_CO3bglBZkaiWekXLXXd31UWIZE95clVSLz4,13417
220
221
  cognite/neat/rules/issues/spreadsheet.py,sha256=Nu4yThMhQcYD1bbcTsnaz5ij8XahqzrxnWyoyw1MN58,16805
221
222
  cognite/neat/rules/issues/spreadsheet_file.py,sha256=YCp0Pk_TsiqYuOPdWpjUpre-zvi2c5_MvrC_dxw10YY,4964
222
- cognite/neat/rules/models/__init__.py,sha256=IqAg-h8PlcXcR_l-MECNMcVxMecF57vdg-Y488mBgWM,917
223
- cognite/neat/rules/models/_base.py,sha256=uZrP_TRu3aljL3XZGMyNtlQDsMPwUEsfSNjGhRdMg88,11234
223
+ cognite/neat/rules/models/__init__.py,sha256=DHitrcmu9in2F8NqBE1O2J4UU_-MAlY6sB1MfigY4IU,887
224
+ cognite/neat/rules/models/_base.py,sha256=KhfF5lh8xy19N0Vp5lrO9auXV7luUTO1gmCW_-dOswY,11204
224
225
  cognite/neat/rules/models/_constants.py,sha256=zPREgHT79_4FMg58QlaXc7A8XKRJrjP5SUgh63jDnTk,31
225
226
  cognite/neat/rules/models/_rdfpath.py,sha256=t7h_9LMQrcj9JaYV2AXN_sYymbAvy-iyuAOjlhaTmog,12174
226
227
  cognite/neat/rules/models/_types/__init__.py,sha256=l1tGxzE7ezNHIL72AoEvNHN2IFuitxOLxiHJG__s6t4,305
@@ -228,15 +229,15 @@ cognite/neat/rules/models/_types/_base.py,sha256=2GhLUE1ukV8X8SGL_JDxpbWGZyAvOnS
228
229
  cognite/neat/rules/models/_types/_field.py,sha256=h2RrhjxdaRbzHG5EyduyHLkCJJmQoyZb9pYCkgMcnVk,3203
229
230
  cognite/neat/rules/models/asset/__init__.py,sha256=qNon0kHleCPo2eT82TmeBAfiDDdwdKNU-Xdewuz8JRA,231
230
231
  cognite/neat/rules/models/asset/_converter.py,sha256=PrTh9ZZkqSJBviiJE4xc3pClCsaWu2tTYOdgwg6_VOk,150
231
- cognite/neat/rules/models/asset/_rules.py,sha256=fYp1pMJtioUtT747fo5NX69lgvPiPtHwXf_YuX--SEc,6195
232
+ cognite/neat/rules/models/asset/_rules.py,sha256=8-_93xKjopX4iABe0k9ryn4kPYJZpzjD1IgAbwpSwk8,6135
232
233
  cognite/neat/rules/models/asset/_rules_input.py,sha256=LiT-85CVgDz2ng65CtrRa77r4rnmg3E4Q6DC7-gv0dE,6257
233
234
  cognite/neat/rules/models/asset/_serializer.py,sha256=ixqRf9qEzvChgysRaDX4g_vHVDtRBCsPYC9sOn0-ShE,3365
234
235
  cognite/neat/rules/models/asset/_validation.py,sha256=86ymEgMZpG1eWu53PviUyUFnQBUJmYDZggUDXufBYLI,148
235
- cognite/neat/rules/models/data_types.py,sha256=xAjm8UVEQlSylfkUJWiWP2NaK6dLYRDABF9g8CNWLTc,6076
236
+ cognite/neat/rules/models/data_types.py,sha256=mHTjWh47VzLwrr0w6dRf59LW7pTTGRTgsxvtW9p0JWw,6020
236
237
  cognite/neat/rules/models/dms/__init__.py,sha256=Wzyqzz2ZIjpUbDg04CMuuIAw-f2A02DayNeqO9R-2Hw,491
237
- cognite/neat/rules/models/dms/_converter.py,sha256=QaJT0z0Yo4gkG9tHPZkU8idF8PK7c-tDahbyIT-WJQU,5959
238
+ cognite/neat/rules/models/dms/_converter.py,sha256=7_R5F3nbknCRxLrOg02tRU4FLYM6nn46bewLl4YSr98,5929
238
239
  cognite/neat/rules/models/dms/_exporter.py,sha256=DRL5ahcBEdBltHLA2rzLyUfqG5SZkqINkqmYGDkQVg0,24785
239
- cognite/neat/rules/models/dms/_rules.py,sha256=M7qv4uTZ-qpnIFQtoExEDppz0m0beNPm01djZxaj0yo,20118
240
+ cognite/neat/rules/models/dms/_rules.py,sha256=RD6951cP16PEZWeA23k46cAZ9DHkWGZwR3vMIN3oX9k,20088
240
241
  cognite/neat/rules/models/dms/_rules_input.py,sha256=M5AqwW-p6z_qAum-1HE_lmONSmg-vF1ak7Y_AiM8vnU,13525
241
242
  cognite/neat/rules/models/dms/_schema.py,sha256=balykJXJy93HJzBZN-KBYrRJJvGsaEtQeX7-z0tbX7w,49566
242
243
  cognite/neat/rules/models/dms/_serializer.py,sha256=iqp2zyyf8jEcU-R3PERuN8nu248xIqyxiWj4owAn92g,6406
@@ -244,8 +245,8 @@ cognite/neat/rules/models/dms/_validation.py,sha256=5mk9L99FSwC8Ok7weEjnFJ_OZnmq
244
245
  cognite/neat/rules/models/domain.py,sha256=wZ-DeIPFnacbNlxSrRuLzUpnhHdTpzNc22z0sDfisi4,2880
245
246
  cognite/neat/rules/models/entities.py,sha256=u8jbE7n99FKKND6U9ogoUfhjtataDtATprAyRgBNwrw,20823
246
247
  cognite/neat/rules/models/information/__init__.py,sha256=HR6g8xgyU53U7Ck8pPdbT70817Q4NC1r1pCRq5SA8iw,291
247
- cognite/neat/rules/models/information/_converter.py,sha256=nsfOCe13c3gqbbF1mrQHofemzYKpvg_NKjJZDwSXo5E,13960
248
- cognite/neat/rules/models/information/_rules.py,sha256=v8ptTif8X55wYaNHvsx65jK7PP2ClSYWyFWUyI2rbyY,13487
248
+ cognite/neat/rules/models/information/_converter.py,sha256=J3mY5clqMY1PR_EmIT-GsTBJ16XCpHQG8EkQWvpqdnI,13930
249
+ cognite/neat/rules/models/information/_rules.py,sha256=08iDnKI5l_kcIjtRjSANr79oMHAtHXjnX7dYN_tUo4U,13457
249
250
  cognite/neat/rules/models/information/_rules_input.py,sha256=1aVaF7VrqaLR-NOq4RR0lnzMp0USCvAPfMA9PjS_mgo,10609
250
251
  cognite/neat/rules/models/information/_serializer.py,sha256=yti9I_xJruxrib66YIBInhze___Io-oPTQH6uWDumPE,3503
251
252
  cognite/neat/rules/models/information/_validation.py,sha256=K4RTd1I8jrqTHUaPFtAQ8bvS8a4ES9efqXRqQX9wQ8I,8258
@@ -264,7 +265,7 @@ cognite/neat/utils/exceptions.py,sha256=-w4cAcvcoWLf-_ZwAl7QV_NysfqtQzIOd1Ti-mpx
264
265
  cognite/neat/utils/spreadsheet.py,sha256=LI0c7dlW0zXHkHw0NvB-gg6Df6cDcE3FbiaHBYLXdzQ,2714
265
266
  cognite/neat/utils/text.py,sha256=4bg1_Q0lg7KsoxaDOvXrVyeY78BJN8i-27BlyDzUCls,3082
266
267
  cognite/neat/utils/upload.py,sha256=nZEuDu22A1kTbl-ctzAJ2vx1cjiQtqdDdpC_mRRMvUI,3597
267
- cognite/neat/utils/utils.py,sha256=vtrBrjMqLIdPuIPEY9MwEEvzeu7vm-regFcU8y4pzeI,14226
268
+ cognite/neat/utils/utils.py,sha256=1EReJhllbJ-7rluI8N_0lldVx5xzpEso-cVVR01F6RI,15042
268
269
  cognite/neat/utils/xml_.py,sha256=ppLT3lQKVp8wOP-m8-tFY8uB2P4R76l7R_-kUtsABng,992
269
270
  cognite/neat/workflows/__init__.py,sha256=oiKub_U9f5cA0I1nKl5dFkR4BD8_6Be9eMzQ_50PwP0,396
270
271
  cognite/neat/workflows/_exceptions.py,sha256=ugI_X1XNpikAiL8zIggBjcx6q7WvOpRIgvxHrj2Rhr4,1348
@@ -310,8 +311,8 @@ cognite/neat/workflows/steps_registry.py,sha256=fkTX14ZA7_gkUYfWIlx7A1XbCidvqR23
310
311
  cognite/neat/workflows/tasks.py,sha256=dqlJwKAb0jlkl7abbY8RRz3m7MT4SK8-7cntMWkOYjw,788
311
312
  cognite/neat/workflows/triggers.py,sha256=_BLNplzoz0iic367u1mhHMHiUrCwP-SLK6_CZzfODX0,7071
312
313
  cognite/neat/workflows/utils.py,sha256=gKdy3RLG7ctRhbCRwaDIWpL9Mi98zm56-d4jfHDqP1E,453
313
- cognite_neat-0.85.11.dist-info/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
314
- cognite_neat-0.85.11.dist-info/METADATA,sha256=dofrglhVYBscSaExRgcBzxsXGN7a1cNkk1srGCk692w,9494
315
- cognite_neat-0.85.11.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
316
- cognite_neat-0.85.11.dist-info/entry_points.txt,sha256=61FPqiWb25vbqB0KI7znG8nsg_ibLHBvTjYnkPvNFso,50
317
- cognite_neat-0.85.11.dist-info/RECORD,,
314
+ cognite_neat-0.86.0.dist-info/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
315
+ cognite_neat-0.86.0.dist-info/METADATA,sha256=Ass8LW31jCG7Te930YQQNxUK8Ocl3hDmi8KacuraxLA,9493
316
+ cognite_neat-0.86.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
317
+ cognite_neat-0.86.0.dist-info/entry_points.txt,sha256=61FPqiWb25vbqB0KI7znG8nsg_ibLHBvTjYnkPvNFso,50
318
+ cognite_neat-0.86.0.dist-info/RECORD,,