cognite-neat 0.87.0__py3-none-any.whl → 0.87.4__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 (87) hide show
  1. cognite/neat/_version.py +1 -1
  2. cognite/neat/app/api/configuration.py +1 -10
  3. cognite/neat/app/api/routers/data_exploration.py +1 -1
  4. cognite/neat/config.py +84 -17
  5. cognite/neat/graph/extractors/_classic_cdf/_assets.py +1 -1
  6. cognite/neat/graph/extractors/_classic_cdf/_events.py +1 -1
  7. cognite/neat/graph/extractors/_classic_cdf/_files.py +1 -1
  8. cognite/neat/graph/extractors/_classic_cdf/_labels.py +1 -1
  9. cognite/neat/graph/extractors/_classic_cdf/_relationships.py +1 -1
  10. cognite/neat/graph/extractors/_classic_cdf/_sequences.py +1 -1
  11. cognite/neat/graph/extractors/_classic_cdf/_timeseries.py +1 -1
  12. cognite/neat/graph/extractors/_dexpi.py +1 -1
  13. cognite/neat/graph/extractors/_mock_graph_generator.py +1 -1
  14. cognite/neat/graph/loaders/_rdf2asset.py +108 -52
  15. cognite/neat/graph/loaders/_rdf2dms.py +6 -6
  16. cognite/neat/graph/queries/_base.py +20 -11
  17. cognite/neat/graph/queries/_construct.py +3 -3
  18. cognite/neat/graph/queries/_shared.py +1 -1
  19. cognite/neat/graph/stores/_base.py +14 -3
  20. cognite/neat/graph/transformers/__init__.py +3 -0
  21. cognite/neat/graph/transformers/_rdfpath.py +42 -0
  22. cognite/neat/legacy/graph/extractors/_mock_graph_generator.py +1 -1
  23. cognite/neat/legacy/graph/loaders/_asset_loader.py +2 -2
  24. cognite/neat/legacy/graph/loaders/core/rdf_to_assets.py +5 -2
  25. cognite/neat/legacy/graph/loaders/core/rdf_to_relationships.py +4 -1
  26. cognite/neat/legacy/graph/loaders/rdf_to_dms.py +3 -1
  27. cognite/neat/legacy/graph/transformations/query_generator/sparql.py +1 -1
  28. cognite/neat/legacy/graph/transformations/transformer.py +1 -1
  29. cognite/neat/legacy/rules/exporters/_rules2dms.py +8 -3
  30. cognite/neat/legacy/rules/exporters/_rules2graphql.py +1 -1
  31. cognite/neat/legacy/rules/exporters/_rules2ontology.py +2 -1
  32. cognite/neat/legacy/rules/exporters/_rules2pydantic_models.py +3 -4
  33. cognite/neat/legacy/rules/importers/_dms2rules.py +4 -1
  34. cognite/neat/legacy/rules/importers/_graph2rules.py +5 -32
  35. cognite/neat/legacy/rules/importers/_owl2rules/_owl2classes.py +1 -1
  36. cognite/neat/legacy/rules/importers/_owl2rules/_owl2metadata.py +2 -1
  37. cognite/neat/legacy/rules/importers/_owl2rules/_owl2properties.py +1 -1
  38. cognite/neat/legacy/rules/models/raw_rules.py +1 -1
  39. cognite/neat/rules/analysis/_asset.py +15 -0
  40. cognite/neat/rules/analysis/_base.py +1 -1
  41. cognite/neat/rules/analysis/_information.py +40 -12
  42. cognite/neat/rules/exporters/_rules2dms.py +1 -1
  43. cognite/neat/rules/exporters/_rules2ontology.py +2 -1
  44. cognite/neat/rules/importers/_dms2rules.py +10 -1
  45. cognite/neat/rules/importers/_inference2rules.py +1 -5
  46. cognite/neat/rules/importers/_owl2rules/_owl2classes.py +1 -1
  47. cognite/neat/rules/importers/_owl2rules/_owl2metadata.py +2 -1
  48. cognite/neat/rules/importers/_owl2rules/_owl2properties.py +1 -1
  49. cognite/neat/rules/issues/spreadsheet.py +35 -0
  50. cognite/neat/rules/models/_rdfpath.py +17 -21
  51. cognite/neat/rules/models/asset/_validation.py +38 -1
  52. cognite/neat/rules/models/dms/_exporter.py +9 -3
  53. cognite/neat/rules/models/dms/_rules.py +1 -0
  54. cognite/neat/rules/models/dms/_rules_input.py +3 -0
  55. cognite/neat/rules/models/dms/_schema.py +5 -4
  56. cognite/neat/rules/models/entities.py +26 -8
  57. cognite/neat/rules/models/information/_validation.py +1 -1
  58. cognite/neat/utils/__init__.py +0 -3
  59. cognite/neat/utils/auth.py +47 -28
  60. cognite/neat/utils/auxiliary.py +141 -1
  61. cognite/neat/utils/cdf/__init__.py +0 -0
  62. cognite/neat/utils/{cdf_classes.py → cdf/data_classes.py} +122 -2
  63. cognite/neat/utils/{cdf_loaders → cdf/loaders}/_data_modeling.py +37 -0
  64. cognite/neat/utils/{cdf_loaders → cdf/loaders}/_ingestion.py +2 -1
  65. cognite/neat/utils/collection_.py +18 -0
  66. cognite/neat/utils/rdf_.py +165 -0
  67. cognite/neat/utils/text.py +4 -0
  68. cognite/neat/utils/time_.py +17 -0
  69. cognite/neat/utils/upload.py +13 -1
  70. cognite/neat/workflows/_exceptions.py +5 -5
  71. cognite/neat/workflows/base.py +1 -1
  72. cognite/neat/workflows/steps/lib/current/rules_validator.py +2 -2
  73. cognite/neat/workflows/steps/lib/legacy/graph_extractor.py +1 -1
  74. cognite/neat/workflows/steps/lib/legacy/graph_loader.py +1 -1
  75. cognite/neat/workflows/steps/lib/legacy/rules_exporter.py +1 -1
  76. cognite/neat/workflows/steps/lib/legacy/rules_importer.py +1 -1
  77. {cognite_neat-0.87.0.dist-info → cognite_neat-0.87.4.dist-info}/METADATA +2 -2
  78. {cognite_neat-0.87.0.dist-info → cognite_neat-0.87.4.dist-info}/RECORD +83 -83
  79. cognite/neat/utils/cdf.py +0 -59
  80. cognite/neat/utils/cdf_loaders/data_classes.py +0 -121
  81. cognite/neat/utils/exceptions.py +0 -41
  82. cognite/neat/utils/utils.py +0 -429
  83. /cognite/neat/utils/{cdf_loaders → cdf/loaders}/__init__.py +0 -0
  84. /cognite/neat/utils/{cdf_loaders → cdf/loaders}/_base.py +0 -0
  85. {cognite_neat-0.87.0.dist-info → cognite_neat-0.87.4.dist-info}/LICENSE +0 -0
  86. {cognite_neat-0.87.0.dist-info → cognite_neat-0.87.4.dist-info}/WHEEL +0 -0
  87. {cognite_neat-0.87.0.dist-info → cognite_neat-0.87.4.dist-info}/entry_points.txt +0 -0
@@ -179,9 +179,21 @@ class NeatGraphStore:
179
179
  warnings.warn("Desired type not found in graph!", stacklevel=2)
180
180
  return None
181
181
 
182
- if InformationAnalysis(self.rules).has_hop_transformations():
182
+ analysis = InformationAnalysis(self.rules)
183
+ has_hop_transformations = analysis.has_hop_transformations()
184
+ has_self_reference_transformations = analysis.has_self_reference_property_transformations()
185
+ if has_hop_transformations or has_self_reference_transformations:
186
+ msg = (
187
+ f"Rules contain [{'Hop' if has_hop_transformations else '' }"
188
+ f", {'SelfReferenceProperty' if has_self_reference_transformations else '' }]"
189
+ " rdfpath."
190
+ f" Run [{'ReduceHopTraversal' if has_hop_transformations else '' }"
191
+ f", {'AddSelfReferenceProperty' if has_self_reference_transformations else '' }]"
192
+ " transformer(s) first!"
193
+ )
194
+
183
195
  warnings.warn(
184
- "Rules contain Hop rdfpath, run ReduceHopTraversal transformer first!",
196
+ msg,
185
197
  stacklevel=2,
186
198
  )
187
199
  return None
@@ -189,7 +201,6 @@ class NeatGraphStore:
189
201
  instance_ids = self.queries.list_instances_ids_of_class(self.rules.metadata.namespace[class_])
190
202
 
191
203
  property_renaming_config = InformationAnalysis(self.rules).define_property_renaming_config(class_entity)
192
- print(property_renaming_config)
193
204
 
194
205
  for instance_id in instance_ids:
195
206
  yield self.queries.describe(instance_id, property_renaming_config)
@@ -6,6 +6,7 @@ from ._classic_cdf import (
6
6
  AssetSequenceConnector,
7
7
  AssetTimeSeriesConnector,
8
8
  )
9
+ from ._rdfpath import AddSelfReferenceProperty
9
10
 
10
11
  __all__ = [
11
12
  "AddAssetDepth",
@@ -14,6 +15,7 @@ __all__ = [
14
15
  "AssetFileConnector",
15
16
  "AssetEventConnector",
16
17
  "AssetRelationshipConnector",
18
+ "AddSelfReferenceProperty",
17
19
  ]
18
20
 
19
21
  Transformers = (
@@ -23,4 +25,5 @@ Transformers = (
23
25
  | AssetFileConnector
24
26
  | AssetEventConnector
25
27
  | AssetRelationshipConnector
28
+ | AddSelfReferenceProperty
26
29
  )
@@ -1,3 +1,9 @@
1
+ from rdflib import RDF, Graph
2
+
3
+ from cognite.neat.rules.analysis import InformationAnalysis
4
+ from cognite.neat.rules.models._rdfpath import RDFPath, SingleProperty
5
+ from cognite.neat.rules.models.information import InformationRules
6
+
1
7
  from ._base import BaseTransformer
2
8
 
3
9
 
@@ -5,3 +11,39 @@ class ReduceHopTraversal(BaseTransformer):
5
11
  """ReduceHopTraversal is a transformer that reduces the number of hops to direct connection."""
6
12
 
7
13
  ...
14
+
15
+
16
+ class AddSelfReferenceProperty(BaseTransformer):
17
+ description: str = "Adds property that contains id of reference to all references of given class in Rules"
18
+ _use_only_once: bool = True
19
+ _need_changes = frozenset({})
20
+
21
+ def __init__(
22
+ self,
23
+ rules: InformationRules,
24
+ ):
25
+ self.rules = rules
26
+ self.properties = InformationAnalysis(rules).all_reference_transformations()
27
+
28
+ def transform(self, graph: Graph) -> None:
29
+ for property_ in self.properties:
30
+ prefix = property_.transformation.traversal.class_.prefix
31
+ suffix = property_.transformation.traversal.class_.suffix
32
+
33
+ namespace = self.rules.prefixes[prefix] if prefix in self.rules.prefixes else self.rules.metadata.namespace
34
+
35
+ for reference in graph.subjects(RDF.type, namespace[suffix]):
36
+ graph.add(
37
+ (
38
+ reference,
39
+ self.rules.metadata.namespace[property_.property_],
40
+ reference,
41
+ )
42
+ )
43
+
44
+ traversal = SingleProperty.from_string(
45
+ class_=property_.class_.id,
46
+ property_=f"{self.rules.metadata.prefix}:{property_.property_}",
47
+ )
48
+
49
+ property_.transformation = RDFPath(traversal=traversal)
@@ -20,7 +20,7 @@ from cognite.neat.legacy.rules.analysis import (
20
20
  from cognite.neat.legacy.rules.exporters._rules2rules import subset_rules
21
21
  from cognite.neat.legacy.rules.models import Rules
22
22
  from cognite.neat.legacy.rules.models.value_types import XSD_VALUE_TYPE_MAPPINGS
23
- from cognite.neat.utils.utils import remove_namespace_from_uri
23
+ from cognite.neat.utils.rdf_ import remove_namespace_from_uri
24
24
 
25
25
  from ._base import BaseExtractor
26
26
 
@@ -15,8 +15,8 @@ from rdflib.query import ResultRow
15
15
  from cognite.neat.legacy.graph.stores import NeatGraphStoreBase
16
16
  from cognite.neat.legacy.rules.models import Rules
17
17
  from cognite.neat.legacy.rules.models.rules import Property
18
- from cognite.neat.utils import remove_namespace_from_uri
19
- from cognite.neat.utils.utils import epoch_now_ms
18
+ from cognite.neat.utils.rdf_ import remove_namespace_from_uri
19
+ from cognite.neat.utils.time_ import epoch_now_ms
20
20
 
21
21
  from ._base import CogniteLoader
22
22
 
@@ -18,7 +18,10 @@ from rdflib.term import URIRef
18
18
  from cognite.neat.legacy.graph.loaders.core.models import AssetTemplate
19
19
  from cognite.neat.legacy.graph.stores import NeatGraphStoreBase
20
20
  from cognite.neat.legacy.rules.models.rules import Property, Rules
21
- from cognite.neat.utils.utils import chunker, datetime_utc_now, remove_namespace_from_uri, retry_decorator
21
+ from cognite.neat.utils.auxiliary import retry_decorator
22
+ from cognite.neat.utils.collection_ import chunker
23
+ from cognite.neat.utils.rdf_ import remove_namespace_from_uri
24
+ from cognite.neat.utils.time_ import datetime_utc_now
22
25
 
23
26
  if sys.version_info >= (3, 11):
24
27
  from datetime import UTC
@@ -899,7 +902,7 @@ def _micro_batch_push(
899
902
  except CogniteDuplicatedError:
900
903
  # this is handling of very rare case when some assets might be lost . Normally this should not happen.
901
904
  # Last attempt to recover
902
- client.assets.create_hierarchy(batch, upsert=True)
905
+ client.assets.create_hierarchy(batch, upsert=True) # type: ignore[arg-type]
903
906
 
904
907
  delta_time = (datetime_utc_now() - start_time).seconds
905
908
 
@@ -14,7 +14,10 @@ from cognite.neat.legacy.graph.loaders.core.models import RelationshipDefinition
14
14
  from cognite.neat.legacy.graph.loaders.core.rdf_to_assets import _categorize_cdf_assets
15
15
  from cognite.neat.legacy.graph.stores import NeatGraphStoreBase
16
16
  from cognite.neat.legacy.rules.models.rules import Rules
17
- from cognite.neat.utils.utils import chunker, datetime_utc_now, epoch_now_ms, remove_namespace_from_uri, retry_decorator
17
+ from cognite.neat.utils.auxiliary import retry_decorator
18
+ from cognite.neat.utils.collection_ import chunker
19
+ from cognite.neat.utils.rdf_ import remove_namespace_from_uri
20
+ from cognite.neat.utils.time_ import datetime_utc_now, epoch_now_ms
18
21
 
19
22
 
20
23
  def define_relationships(rules: Rules, data_set_id: int, stop_on_exception: bool = False) -> RelationshipDefinitions:
@@ -13,7 +13,9 @@ from cognite.neat.legacy.graph.transformations.query_generator.sparql import tri
13
13
  from cognite.neat.legacy.rules.exporters._rules2dms import DMSSchemaComponents
14
14
  from cognite.neat.legacy.rules.exporters._rules2pydantic_models import add_class_prefix_to_xid, rules_to_pydantic_models
15
15
  from cognite.neat.legacy.rules.models.rules import Rules
16
- from cognite.neat.utils.utils import chunker, datetime_utc_now, retry_decorator
16
+ from cognite.neat.utils.auxiliary import retry_decorator
17
+ from cognite.neat.utils.collection_ import chunker
18
+ from cognite.neat.utils.time_ import datetime_utc_now
17
19
 
18
20
  from ._base import CogniteLoader
19
21
 
@@ -21,7 +21,7 @@ from cognite.neat.legacy.rules.models.rdfpath import (
21
21
  parse_traversal,
22
22
  )
23
23
  from cognite.neat.legacy.rules.models.rules import Rules
24
- from cognite.neat.utils.utils import remove_namespace_from_uri
24
+ from cognite.neat.utils.rdf_ import remove_namespace_from_uri
25
25
 
26
26
 
27
27
  def _generate_prefix_header(prefixes: dict[str, Namespace] | None = None) -> str:
@@ -24,7 +24,7 @@ from cognite.neat.legacy.rules.models.rdfpath import (
24
24
  parse_rule,
25
25
  )
26
26
  from cognite.neat.legacy.rules.models.rules import Rules
27
- from cognite.neat.utils.utils import remove_namespace_from_uri
27
+ from cognite.neat.utils.rdf_ import remove_namespace_from_uri
28
28
 
29
29
  prom_total_proc_rules_g = Gauge("neat_total_processed_rules", "Number of processed rules", ["state"])
30
30
  rules_processing_timing_metric = Gauge(
@@ -8,6 +8,7 @@ from pathlib import Path
8
8
  from typing import ClassVar, Literal, cast, no_type_check
9
9
 
10
10
  import yaml
11
+ from cognite.client.data_classes.data_modeling.data_types import ListablePropertyType
11
12
 
12
13
  from cognite.neat.legacy.rules.models.value_types import ValueTypeMapping
13
14
 
@@ -45,7 +46,7 @@ from cognite.neat.legacy.rules.exporters._base import BaseExporter
45
46
  from cognite.neat.legacy.rules.exporters._validation import are_entity_names_dms_compliant
46
47
  from cognite.neat.legacy.rules.models._base import ContainerEntity, EntityTypes, ParentClass
47
48
  from cognite.neat.legacy.rules.models.rules import Class, Property, Rules
48
- from cognite.neat.utils.utils import generate_exception_report
49
+ from cognite.neat.utils.auxiliary import generate_exception_report
49
50
 
50
51
  if sys.version_info < (3, 11):
51
52
  from exceptiongroup import ExceptionGroup
@@ -278,13 +279,17 @@ class DMSSchemaComponents(BaseModel):
278
279
  existing_property, default_value=None
279
280
  )
280
281
 
281
- # scenario: property hold multiple values -> set is_list to True
282
+ # scenario: property holds multiple values -> set is_list to True
282
283
  if (
283
284
  not isinstance(existing_property.type, DirectRelation)
284
285
  and not isinstance(api_container_property.type, DirectRelation)
286
+ and isinstance(existing_property.type, ListablePropertyType)
287
+ and isinstance(api_container_property.type, ListablePropertyType)
285
288
  and existing_property.type.is_list != api_container_property.type.is_list
286
289
  ):
287
- containers[container_id].properties[container_property_id].type.is_list = True
290
+ type_ = containers[container_id].properties[container_property_id].type
291
+ if isinstance(type_, ListablePropertyType):
292
+ type_.is_list = True
288
293
 
289
294
  if errors:
290
295
  raise ExceptionGroup("Properties value types have been redefined! This is prohibited! Aborting!", errors)
@@ -14,7 +14,7 @@ from cognite.neat.legacy.rules.analysis import to_class_property_pairs
14
14
  from cognite.neat.legacy.rules.exporters._validation import are_entity_names_dms_compliant, are_properties_redefined
15
15
  from cognite.neat.legacy.rules.models.rules import Rules
16
16
  from cognite.neat.legacy.rules.models.value_types import XSD_VALUE_TYPE_MAPPINGS
17
- from cognite.neat.utils.utils import generate_exception_report
17
+ from cognite.neat.utils.auxiliary import generate_exception_report
18
18
 
19
19
  from ._base import BaseExporter
20
20
 
@@ -14,7 +14,8 @@ from cognite.neat.legacy.rules.exporters._base import BaseExporter
14
14
  from cognite.neat.legacy.rules.exporters._validation import are_properties_redefined
15
15
  from cognite.neat.legacy.rules.models.rules import Class, Metadata, Property, Rules
16
16
  from cognite.neat.legacy.rules.models.value_types import XSD_VALUE_TYPE_MAPPINGS
17
- from cognite.neat.utils.utils import generate_exception_report, remove_namespace_from_uri
17
+ from cognite.neat.utils.auxiliary import generate_exception_report
18
+ from cognite.neat.utils.rdf_ import remove_namespace_from_uri
18
19
 
19
20
  if sys.version_info >= (3, 11):
20
21
  from typing import Self
@@ -11,7 +11,6 @@ from cognite.client.data_classes.data_modeling.views import SingleHopConnectionD
11
11
  from pydantic import BaseModel, ConfigDict, Field, create_model
12
12
  from pydantic._internal._model_construction import ModelMetaclass
13
13
  from rdflib import Graph, URIRef
14
- from typing_extensions import TypeAliasType
15
14
 
16
15
  from cognite.neat.legacy.graph.loaders.core.rdf_to_assets import NeatMetadataKeys
17
16
  from cognite.neat.legacy.graph.transformations.query_generator.sparql import build_construct_query, triples2dictionary
@@ -21,7 +20,7 @@ from cognite.neat.legacy.rules.exporters._rules2dms import DMSSchemaComponents
21
20
  from cognite.neat.legacy.rules.exporters._validation import are_entity_names_dms_compliant
22
21
  from cognite.neat.legacy.rules.models.rules import Property, Rules
23
22
  from cognite.neat.legacy.rules.models.value_types import ValueTypeMapping
24
- from cognite.neat.utils.utils import create_sha256_hash, generate_exception_report
23
+ from cognite.neat.utils.auxiliary import create_sha256_hash, generate_exception_report
25
24
 
26
25
  if sys.version_info >= (3, 11):
27
26
  from datetime import UTC
@@ -30,8 +29,8 @@ else:
30
29
 
31
30
  UTC = timezone.utc
32
31
 
33
- EdgeOneToOne: TypeAlias = TypeAliasType("EdgeOneToOne", str) # type: ignore[valid-type]
34
- EdgeOneToMany: TypeAlias = TypeAliasType("EdgeOneToMany", list[str]) # type: ignore[valid-type]
32
+ EdgeOneToOne: TypeAlias = str # type: ignore[valid-type]
33
+ EdgeOneToMany: TypeAlias = list[str] # type: ignore[valid-type]
35
34
 
36
35
 
37
36
  def default_model_configuration(
@@ -13,6 +13,7 @@ from cognite.client.data_classes.data_modeling import (
13
13
  SingleHopConnectionDefinition,
14
14
  View,
15
15
  )
16
+ from cognite.client.data_classes.data_modeling.data_types import ListablePropertyType
16
17
  from cognite.client.data_classes.data_modeling.ids import DataModelIdentifier, ViewId
17
18
 
18
19
  from cognite.neat.legacy.rules.models.tables import Tables
@@ -129,7 +130,9 @@ class DMSImporter(BaseImporter):
129
130
 
130
131
  max_count: str | float = "1"
131
132
  if isinstance(prop, SingleHopConnectionDefinition) or (
132
- isinstance(prop, MappedProperty) and prop.type.is_list
133
+ isinstance(prop, MappedProperty)
134
+ and isinstance(prop.type, ListablePropertyType)
135
+ and prop.type.is_list
133
136
  ):
134
137
  max_count = float("nan")
135
138
 
@@ -14,11 +14,7 @@ from cognite.neat.constants import get_default_prefixes
14
14
  from cognite.neat.legacy.rules import exceptions
15
15
  from cognite.neat.legacy.rules.exporters._rules2rules import to_dms_name
16
16
  from cognite.neat.legacy.rules.models.tables import Tables
17
- from cognite.neat.utils.utils import (
18
- get_namespace,
19
- remove_namespace_from_uri,
20
- uri_to_short_form,
21
- )
17
+ from cognite.neat.utils.rdf_ import get_namespace, remove_namespace_from_uri, uri_to_short_form
22
18
 
23
19
  from ._base import BaseImporter
24
20
 
@@ -78,26 +74,11 @@ def _create_default_properties_parsing_config() -> dict[str, tuple[str, ...]]:
78
74
 
79
75
  def _create_default_classes_parsing_config() -> dict[str, tuple[str, ...]]:
80
76
  # TODO: these are to be read from Class pydantic model
81
- return {
82
- "header": (
83
- "Class",
84
- "Description",
85
- "Parent Class",
86
- "Source",
87
- "Source Entity Name",
88
- "Match Type",
89
- "Comment",
90
- )
91
- }
77
+ return {"header": ("Class", "Description", "Parent Class", "Source", "Source Entity Name", "Match Type", "Comment")}
92
78
 
93
79
 
94
80
  def _parse_prefixes_df(prefixes: dict[str, Namespace]) -> pd.DataFrame:
95
- return pd.DataFrame.from_dict(
96
- {
97
- "Prefix": list(prefixes.keys()),
98
- "URI": [str(uri) for uri in prefixes.values()],
99
- }
100
- )
81
+ return pd.DataFrame.from_dict({"Prefix": list(prefixes.keys()), "URI": [str(uri) for uri in prefixes.values()]})
101
82
 
102
83
 
103
84
  def _parse_metadata_df() -> pd.DataFrame:
@@ -202,18 +183,10 @@ def _graph_to_data_model_dict(graph: Graph, max_number_of_instance: int = -1) ->
202
183
  )
203
184
  class_name = f"{class_name}_{len(data_model)+1}"
204
185
 
205
- data_model[class_name] = {
206
- "properties": {},
207
- "uri": uri_to_short_form(class_, prefixes),
208
- }
186
+ data_model[class_name] = {"properties": {}, "uri": uri_to_short_form(class_, prefixes)}
209
187
 
210
188
  for instance in _get_class_instance_ids(graph, class_, max_number_of_instance):
211
- for (
212
- property_,
213
- occurrence,
214
- data_type,
215
- object_type,
216
- ) in _define_instance_properties(graph, instance):
189
+ for property_, occurrence, data_type, object_type in _define_instance_properties(graph, instance):
217
190
  property_name = remove_namespace_from_uri(property_)
218
191
  _add_uri_namespace_to_prefixes(property_, prefixes)
219
192
 
@@ -4,7 +4,7 @@ import numpy as np
4
4
  import pandas as pd
5
5
  from rdflib import OWL, Graph
6
6
 
7
- from cognite.neat.utils.utils import remove_namespace_from_uri
7
+ from cognite.neat.utils.rdf_ import remove_namespace_from_uri
8
8
 
9
9
 
10
10
  def parse_owl_classes(graph: Graph, make_compliant: bool = False, language: str = "en") -> pd.DataFrame:
@@ -10,7 +10,8 @@ from cognite.neat.legacy.rules.models.rules import (
10
10
  prefix_compliance_regex,
11
11
  version_compliance_regex,
12
12
  )
13
- from cognite.neat.utils.utils import convert_rdflib_content, remove_none_elements_from_set
13
+ from cognite.neat.utils.collection_ import remove_none_elements_from_set
14
+ from cognite.neat.utils.rdf_ import convert_rdflib_content
14
15
 
15
16
 
16
17
  def parse_owl_metadata(graph: Graph, make_compliant: bool = False) -> pd.DataFrame:
@@ -4,7 +4,7 @@ import numpy as np
4
4
  import pandas as pd
5
5
  from rdflib import Graph
6
6
 
7
- from cognite.neat.utils.utils import remove_namespace_from_uri
7
+ from cognite.neat.utils.rdf_ import remove_namespace_from_uri
8
8
 
9
9
  from ._owl2classes import _data_type_property_class, _object_property_class, _thing_class
10
10
 
@@ -24,7 +24,7 @@ from cognite.neat.legacy.rules.models.tables import Tables
24
24
 
25
25
  # importers:
26
26
  from cognite.neat.rules import exceptions
27
- from cognite.neat.utils.utils import generate_exception_report
27
+ from cognite.neat.utils.auxiliary import generate_exception_report
28
28
 
29
29
  __all__ = ["RawRules"]
30
30
 
@@ -1,4 +1,5 @@
1
1
  import warnings
2
+ from graphlib import TopologicalSorter
2
3
  from typing import cast
3
4
 
4
5
  from cognite.neat.rules.models import AssetRules
@@ -6,6 +7,7 @@ from cognite.neat.rules.models._rdfpath import RDFPath
6
7
  from cognite.neat.rules.models.asset import AssetClass, AssetProperty
7
8
  from cognite.neat.rules.models.entities import (
8
9
  AssetEntity,
10
+ AssetFields,
9
11
  ClassEntity,
10
12
  EntityTypes,
11
13
  ReferenceEntity,
@@ -95,6 +97,19 @@ class AssetAnalysis(BaseAnalysis[AssetRules, AssetClass, AssetProperty, ClassEnt
95
97
 
96
98
  return class_property_pairs
97
99
 
100
+ def class_topological_sort(self) -> list[ClassEntity]:
101
+ child_parent_asset: dict[ClassEntity, set[ClassEntity]] = {}
102
+ for class_, properties in self.asset_definition().items():
103
+ child_parent_asset[class_] = set()
104
+ for property_ in properties.values():
105
+ if any(
106
+ cast(AssetEntity, implementation).property_ == AssetFields.parentExternalId
107
+ for implementation in property_.implementation
108
+ ):
109
+ child_parent_asset[property_.class_].add(cast(ClassEntity, property_.value_type))
110
+
111
+ return list(TopologicalSorter(child_parent_asset).static_order())
112
+
98
113
  def asset_definition(
99
114
  self, only_rdfpath: bool = False, consider_inheritance: bool = False
100
115
  ) -> dict[ClassEntity, dict[str, AssetProperty]]:
@@ -17,7 +17,7 @@ from cognite.neat.rules.models.entities import (
17
17
  ReferenceEntity,
18
18
  )
19
19
  from cognite.neat.rules.models.information import InformationProperty
20
- from cognite.neat.utils.utils import get_inheritance_path
20
+ from cognite.neat.utils.rdf_ import get_inheritance_path
21
21
 
22
22
  T_Rules = TypeVar("T_Rules", bound=BaseRules)
23
23
  T_Property = TypeVar("T_Property", bound=BaseModel)
@@ -3,16 +3,22 @@ import warnings
3
3
  from typing import Any, cast
4
4
 
5
5
  from pydantic import ValidationError
6
+ from rdflib import URIRef
6
7
 
7
8
  from cognite.neat.rules.models import SchemaCompleteness
8
- from cognite.neat.rules.models._rdfpath import Hop, RDFPath, SingleProperty
9
+ from cognite.neat.rules.models._rdfpath import (
10
+ Hop,
11
+ RDFPath,
12
+ SelfReferenceProperty,
13
+ SingleProperty,
14
+ )
9
15
  from cognite.neat.rules.models.entities import ClassEntity, ReferenceEntity
10
16
  from cognite.neat.rules.models.information import (
11
17
  InformationClass,
12
18
  InformationProperty,
13
19
  InformationRules,
14
20
  )
15
- from cognite.neat.utils.utils import get_inheritance_path
21
+ from cognite.neat.utils.rdf_ import get_inheritance_path
16
22
 
17
23
  from ._base import BaseAnalysis
18
24
 
@@ -56,24 +62,46 @@ class InformationAnalysis(BaseAnalysis[InformationRules, InformationClass, Infor
56
62
  prop_.transformation and isinstance(prop_.transformation.traversal, Hop) for prop_ in self.rules.properties
57
63
  )
58
64
 
59
- def define_property_renaming_config(self, class_: ClassEntity) -> dict[str, str]:
60
- property_renaming_configuration = {}
65
+ def has_self_reference_property_transformations(self):
66
+ return any(
67
+ prop_.transformation and isinstance(prop_.transformation.traversal, SelfReferenceProperty)
68
+ for prop_ in self.rules.properties
69
+ )
70
+
71
+ def all_reference_transformations(self):
72
+ return [
73
+ prop_
74
+ for prop_ in self.rules.properties
75
+ if prop_.transformation and isinstance(prop_.transformation.traversal, SelfReferenceProperty)
76
+ ]
77
+
78
+ def define_property_renaming_config(self, class_: ClassEntity) -> dict[str | URIRef, str]:
79
+ property_renaming_configuration: dict[str | URIRef, str] = {}
61
80
 
62
81
  if definitions := self.class_property_pairs(only_rdfpath=True, consider_inheritance=True).get(class_, None):
63
82
  for property_id, definition in definitions.items():
83
+ transformation = cast(RDFPath, definition.transformation)
84
+
85
+ # use case we have a single property rdf path, and defined prefix
86
+ # in either metadata or prefixes of rules
64
87
  if isinstance(
65
- cast(RDFPath, definition.transformation).traversal,
88
+ transformation.traversal,
66
89
  SingleProperty,
90
+ ) and (
91
+ transformation.traversal.property.prefix in self.rules.prefixes
92
+ or transformation.traversal.property.prefix == self.rules.metadata.prefix
67
93
  ):
68
- graph_property = cast(
69
- SingleProperty,
70
- cast(RDFPath, definition.transformation).traversal,
71
- ).property.suffix
94
+ namespace = (
95
+ self.rules.metadata.namespace
96
+ if transformation.traversal.property.prefix == self.rules.metadata.prefix
97
+ else self.rules.prefixes[transformation.traversal.property.prefix]
98
+ )
72
99
 
73
- else:
74
- graph_property = property_id
100
+ property_renaming_configuration[namespace[transformation.traversal.property.suffix]] = property_id
75
101
 
76
- property_renaming_configuration[graph_property] = property_id
102
+ # otherwise we default to the property id
103
+ else:
104
+ property_renaming_configuration[property_id] = property_id
77
105
 
78
106
  return property_renaming_configuration
79
107
 
@@ -20,7 +20,7 @@ from cognite.neat.rules._shared import Rules
20
20
  from cognite.neat.rules.issues import IssueList
21
21
  from cognite.neat.rules.models import InformationRules
22
22
  from cognite.neat.rules.models.dms import DMSRules, DMSSchema, PipelineSchema
23
- from cognite.neat.utils.cdf_loaders import (
23
+ from cognite.neat.utils.cdf.loaders import (
24
24
  ContainerLoader,
25
25
  DataModelingLoader,
26
26
  DataModelLoader,
@@ -20,7 +20,8 @@ from cognite.neat.rules.models.information import (
20
20
  InformationProperty,
21
21
  InformationRules,
22
22
  )
23
- from cognite.neat.utils.utils import generate_exception_report, remove_namespace_from_uri
23
+ from cognite.neat.utils.auxiliary import generate_exception_report
24
+ from cognite.neat.utils.rdf_ import remove_namespace_from_uri
24
25
 
25
26
  from ._base import BaseExporter
26
27
  from ._validation import are_properties_redefined
@@ -8,6 +8,7 @@ from cognite.client import CogniteClient
8
8
  from cognite.client import data_modeling as dm
9
9
  from cognite.client.data_classes.data_modeling import DataModelId, DataModelIdentifier
10
10
  from cognite.client.data_classes.data_modeling.containers import BTreeIndex, InvertedIndex
11
+ from cognite.client.data_classes.data_modeling.data_types import ListablePropertyType
11
12
  from cognite.client.data_classes.data_modeling.views import (
12
13
  MultiEdgeConnectionApply,
13
14
  MultiReverseDirectRelationApply,
@@ -345,6 +346,7 @@ class DMSImporter(BaseImporter):
345
346
  value_type=value_type,
346
347
  is_list=self._get_is_list(prop),
347
348
  nullable=self._get_nullable(prop),
349
+ immutable=self._get_immutable(prop),
348
350
  default=self._get_default(prop),
349
351
  container=ContainerEntity.from_id(prop.container) if isinstance(prop, dm.MappedPropertyApply) else None,
350
352
  container_property=prop.container_property_identifier if isinstance(prop, dm.MappedPropertyApply) else None,
@@ -401,9 +403,16 @@ class DMSImporter(BaseImporter):
401
403
  else:
402
404
  return None
403
405
 
406
+ def _get_immutable(self, prop: ViewPropertyApply) -> bool | None:
407
+ if isinstance(prop, dm.MappedPropertyApply):
408
+ return self._container_prop_unsafe(prop).immutable
409
+ else:
410
+ return None
411
+
404
412
  def _get_is_list(self, prop: ViewPropertyApply) -> bool | None:
405
413
  if isinstance(prop, dm.MappedPropertyApply):
406
- return self._container_prop_unsafe(prop).type.is_list
414
+ prop_type = self._container_prop_unsafe(prop).type
415
+ return isinstance(prop_type, ListablePropertyType) and prop_type.is_list
407
416
  elif isinstance(prop, MultiEdgeConnectionApply | MultiReverseDirectRelationApply):
408
417
  return True
409
418
  elif isinstance(prop, SingleEdgeConnectionApply | SingleReverseDirectRelationApply):
@@ -17,11 +17,7 @@ from cognite.neat.rules.models.information import (
17
17
  InformationMetadata,
18
18
  InformationRulesInput,
19
19
  )
20
- from cognite.neat.utils.utils import (
21
- get_namespace,
22
- remove_namespace_from_uri,
23
- uri_to_short_form,
24
- )
20
+ from cognite.neat.utils.rdf_ import get_namespace, remove_namespace_from_uri, uri_to_short_form
25
21
 
26
22
  ORDERED_CLASSES_QUERY = """SELECT ?class (count(?s) as ?instances )
27
23
  WHERE { ?s a ?class . }
@@ -5,7 +5,7 @@ import pandas as pd
5
5
  from rdflib import OWL, Graph
6
6
 
7
7
  from cognite.neat.rules.models._base import MatchType
8
- from cognite.neat.utils.utils import remove_namespace_from_uri
8
+ from cognite.neat.utils.rdf_ import remove_namespace_from_uri
9
9
 
10
10
 
11
11
  def parse_owl_classes(graph: Graph, language: str = "en") -> list[dict]:
@@ -9,7 +9,8 @@ from cognite.neat.rules.models._types._base import (
9
9
  PREFIX_COMPLIANCE_REGEX,
10
10
  VERSION_COMPLIANCE_REGEX,
11
11
  )
12
- from cognite.neat.utils.utils import convert_rdflib_content, remove_none_elements_from_set
12
+ from cognite.neat.utils.collection_ import remove_none_elements_from_set
13
+ from cognite.neat.utils.rdf_ import convert_rdflib_content
13
14
 
14
15
 
15
16
  def parse_owl_metadata(graph: Graph) -> dict:
@@ -5,7 +5,7 @@ import pandas as pd
5
5
  from rdflib import Graph
6
6
 
7
7
  from cognite.neat.rules.models._base import MatchType
8
- from cognite.neat.utils.utils import remove_namespace_from_uri
8
+ from cognite.neat.utils.rdf_ import remove_namespace_from_uri
9
9
 
10
10
  from ._owl2classes import _data_type_property_class, _object_property_class, _thing_class
11
11