cognite-neat 0.87.6__py3-none-any.whl → 0.88.1__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 (171) hide show
  1. cognite/neat/_version.py +1 -1
  2. cognite/neat/app/api/data_classes/rest.py +0 -19
  3. cognite/neat/app/api/explorer.py +6 -4
  4. cognite/neat/app/api/routers/configuration.py +1 -1
  5. cognite/neat/app/api/routers/crud.py +11 -21
  6. cognite/neat/app/api/routers/workflows.py +24 -94
  7. cognite/neat/app/ui/neat-app/build/asset-manifest.json +7 -7
  8. cognite/neat/app/ui/neat-app/build/index.html +1 -1
  9. cognite/neat/app/ui/neat-app/build/static/css/{main.38a62222.css → main.72e3d92e.css} +2 -2
  10. cognite/neat/app/ui/neat-app/build/static/css/main.72e3d92e.css.map +1 -0
  11. cognite/neat/app/ui/neat-app/build/static/js/main.5a52cf09.js +3 -0
  12. cognite/neat/app/ui/neat-app/build/static/js/{main.ec7f72e2.js.LICENSE.txt → main.5a52cf09.js.LICENSE.txt} +0 -9
  13. cognite/neat/app/ui/neat-app/build/static/js/main.5a52cf09.js.map +1 -0
  14. cognite/neat/config.py +44 -27
  15. cognite/neat/exceptions.py +6 -0
  16. cognite/neat/graph/extractors/_classic_cdf/_assets.py +21 -73
  17. cognite/neat/graph/extractors/_classic_cdf/_base.py +102 -0
  18. cognite/neat/graph/extractors/_classic_cdf/_events.py +46 -42
  19. cognite/neat/graph/extractors/_classic_cdf/_files.py +41 -45
  20. cognite/neat/graph/extractors/_classic_cdf/_labels.py +75 -52
  21. cognite/neat/graph/extractors/_classic_cdf/_relationships.py +49 -27
  22. cognite/neat/graph/extractors/_classic_cdf/_sequences.py +47 -50
  23. cognite/neat/graph/extractors/_classic_cdf/_timeseries.py +47 -49
  24. cognite/neat/graph/queries/_base.py +22 -29
  25. cognite/neat/graph/queries/_shared.py +1 -1
  26. cognite/neat/graph/stores/_base.py +24 -11
  27. cognite/neat/graph/transformers/_rdfpath.py +3 -2
  28. cognite/neat/issues.py +8 -0
  29. cognite/neat/rules/exporters/_rules2ontology.py +28 -20
  30. cognite/neat/rules/exporters/_validation.py +15 -21
  31. cognite/neat/rules/importers/_inference2rules.py +31 -35
  32. cognite/neat/rules/importers/_owl2rules/_owl2metadata.py +3 -7
  33. cognite/neat/rules/importers/_spreadsheet2rules.py +30 -27
  34. cognite/neat/rules/issues/dms.py +20 -0
  35. cognite/neat/rules/issues/importing.py +15 -0
  36. cognite/neat/rules/issues/ontology.py +298 -0
  37. cognite/neat/rules/issues/spreadsheet.py +48 -0
  38. cognite/neat/rules/issues/tables.py +72 -0
  39. cognite/neat/rules/models/_rdfpath.py +4 -4
  40. cognite/neat/rules/models/_types/_field.py +9 -19
  41. cognite/neat/rules/models/information/_rules.py +5 -4
  42. cognite/neat/utils/rdf_.py +17 -9
  43. cognite/neat/utils/regex_patterns.py +52 -0
  44. cognite/neat/workflows/steps/data_contracts.py +17 -43
  45. cognite/neat/workflows/steps/lib/current/graph_extractor.py +28 -24
  46. cognite/neat/workflows/steps/lib/current/graph_loader.py +4 -21
  47. cognite/neat/workflows/steps/lib/current/graph_store.py +18 -134
  48. cognite/neat/workflows/steps_registry.py +5 -7
  49. {cognite_neat-0.87.6.dist-info → cognite_neat-0.88.1.dist-info}/METADATA +2 -6
  50. cognite_neat-0.88.1.dist-info/RECORD +209 -0
  51. cognite/neat/app/api/routers/core.py +0 -91
  52. cognite/neat/app/api/routers/data_exploration.py +0 -336
  53. cognite/neat/app/api/routers/rules.py +0 -203
  54. cognite/neat/app/ui/neat-app/build/static/css/main.38a62222.css.map +0 -1
  55. cognite/neat/app/ui/neat-app/build/static/js/main.ec7f72e2.js +0 -3
  56. cognite/neat/app/ui/neat-app/build/static/js/main.ec7f72e2.js.map +0 -1
  57. cognite/neat/graph/stores/_oxrdflib.py +0 -247
  58. cognite/neat/legacy/__init__.py +0 -0
  59. cognite/neat/legacy/graph/__init__.py +0 -3
  60. cognite/neat/legacy/graph/examples/Knowledge-Graph-Nordic44-dirty.xml +0 -20182
  61. cognite/neat/legacy/graph/examples/Knowledge-Graph-Nordic44.xml +0 -20163
  62. cognite/neat/legacy/graph/examples/__init__.py +0 -10
  63. cognite/neat/legacy/graph/examples/skos-capturing-sheet-wind-topics.xlsx +0 -0
  64. cognite/neat/legacy/graph/exceptions.py +0 -90
  65. cognite/neat/legacy/graph/extractors/__init__.py +0 -6
  66. cognite/neat/legacy/graph/extractors/_base.py +0 -14
  67. cognite/neat/legacy/graph/extractors/_dexpi.py +0 -44
  68. cognite/neat/legacy/graph/extractors/_graph_capturing_sheet.py +0 -403
  69. cognite/neat/legacy/graph/extractors/_mock_graph_generator.py +0 -361
  70. cognite/neat/legacy/graph/loaders/__init__.py +0 -23
  71. cognite/neat/legacy/graph/loaders/_asset_loader.py +0 -511
  72. cognite/neat/legacy/graph/loaders/_base.py +0 -67
  73. cognite/neat/legacy/graph/loaders/_exceptions.py +0 -85
  74. cognite/neat/legacy/graph/loaders/core/__init__.py +0 -0
  75. cognite/neat/legacy/graph/loaders/core/labels.py +0 -58
  76. cognite/neat/legacy/graph/loaders/core/models.py +0 -136
  77. cognite/neat/legacy/graph/loaders/core/rdf_to_assets.py +0 -1046
  78. cognite/neat/legacy/graph/loaders/core/rdf_to_relationships.py +0 -559
  79. cognite/neat/legacy/graph/loaders/rdf_to_dms.py +0 -309
  80. cognite/neat/legacy/graph/loaders/validator.py +0 -87
  81. cognite/neat/legacy/graph/models.py +0 -6
  82. cognite/neat/legacy/graph/stores/__init__.py +0 -13
  83. cognite/neat/legacy/graph/stores/_base.py +0 -400
  84. cognite/neat/legacy/graph/stores/_graphdb_store.py +0 -52
  85. cognite/neat/legacy/graph/stores/_memory_store.py +0 -43
  86. cognite/neat/legacy/graph/stores/_oxigraph_store.py +0 -151
  87. cognite/neat/legacy/graph/stores/_oxrdflib.py +0 -247
  88. cognite/neat/legacy/graph/stores/_rdf_to_graph.py +0 -42
  89. cognite/neat/legacy/graph/transformations/__init__.py +0 -0
  90. cognite/neat/legacy/graph/transformations/entity_matcher.py +0 -101
  91. cognite/neat/legacy/graph/transformations/query_generator/__init__.py +0 -3
  92. cognite/neat/legacy/graph/transformations/query_generator/sparql.py +0 -575
  93. cognite/neat/legacy/graph/transformations/transformer.py +0 -322
  94. cognite/neat/legacy/rules/__init__.py +0 -0
  95. cognite/neat/legacy/rules/analysis.py +0 -231
  96. cognite/neat/legacy/rules/examples/Rules-Nordic44-to-graphql.xlsx +0 -0
  97. cognite/neat/legacy/rules/examples/Rules-Nordic44.xlsx +0 -0
  98. cognite/neat/legacy/rules/examples/__init__.py +0 -18
  99. cognite/neat/legacy/rules/examples/power-grid-containers.yaml +0 -124
  100. cognite/neat/legacy/rules/examples/power-grid-example.xlsx +0 -0
  101. cognite/neat/legacy/rules/examples/power-grid-model.yaml +0 -224
  102. cognite/neat/legacy/rules/examples/rules-template.xlsx +0 -0
  103. cognite/neat/legacy/rules/examples/sheet2cdf-transformation-rules.xlsx +0 -0
  104. cognite/neat/legacy/rules/examples/skos-rules.xlsx +0 -0
  105. cognite/neat/legacy/rules/examples/source-to-solution-mapping-rules.xlsx +0 -0
  106. cognite/neat/legacy/rules/examples/wind-energy.owl +0 -1511
  107. cognite/neat/legacy/rules/exceptions.py +0 -2972
  108. cognite/neat/legacy/rules/exporters/__init__.py +0 -20
  109. cognite/neat/legacy/rules/exporters/_base.py +0 -45
  110. cognite/neat/legacy/rules/exporters/_core/__init__.py +0 -5
  111. cognite/neat/legacy/rules/exporters/_core/rules2labels.py +0 -24
  112. cognite/neat/legacy/rules/exporters/_rules2dms.py +0 -885
  113. cognite/neat/legacy/rules/exporters/_rules2excel.py +0 -213
  114. cognite/neat/legacy/rules/exporters/_rules2graphql.py +0 -183
  115. cognite/neat/legacy/rules/exporters/_rules2ontology.py +0 -524
  116. cognite/neat/legacy/rules/exporters/_rules2pydantic_models.py +0 -748
  117. cognite/neat/legacy/rules/exporters/_rules2rules.py +0 -105
  118. cognite/neat/legacy/rules/exporters/_rules2triples.py +0 -38
  119. cognite/neat/legacy/rules/exporters/_validation.py +0 -146
  120. cognite/neat/legacy/rules/importers/__init__.py +0 -22
  121. cognite/neat/legacy/rules/importers/_base.py +0 -66
  122. cognite/neat/legacy/rules/importers/_dict2rules.py +0 -158
  123. cognite/neat/legacy/rules/importers/_dms2rules.py +0 -194
  124. cognite/neat/legacy/rules/importers/_graph2rules.py +0 -308
  125. cognite/neat/legacy/rules/importers/_json2rules.py +0 -39
  126. cognite/neat/legacy/rules/importers/_owl2rules/__init__.py +0 -3
  127. cognite/neat/legacy/rules/importers/_owl2rules/_owl2classes.py +0 -239
  128. cognite/neat/legacy/rules/importers/_owl2rules/_owl2metadata.py +0 -260
  129. cognite/neat/legacy/rules/importers/_owl2rules/_owl2properties.py +0 -217
  130. cognite/neat/legacy/rules/importers/_owl2rules/_owl2rules.py +0 -290
  131. cognite/neat/legacy/rules/importers/_spreadsheet2rules.py +0 -45
  132. cognite/neat/legacy/rules/importers/_xsd2rules.py +0 -20
  133. cognite/neat/legacy/rules/importers/_yaml2rules.py +0 -39
  134. cognite/neat/legacy/rules/models/__init__.py +0 -5
  135. cognite/neat/legacy/rules/models/_base.py +0 -151
  136. cognite/neat/legacy/rules/models/raw_rules.py +0 -316
  137. cognite/neat/legacy/rules/models/rdfpath.py +0 -237
  138. cognite/neat/legacy/rules/models/rules.py +0 -1289
  139. cognite/neat/legacy/rules/models/tables.py +0 -9
  140. cognite/neat/legacy/rules/models/value_types.py +0 -118
  141. cognite/neat/legacy/workflows/examples/Export_DMS/workflow.yaml +0 -89
  142. cognite/neat/legacy/workflows/examples/Export_Rules_to_Ontology/workflow.yaml +0 -152
  143. cognite/neat/legacy/workflows/examples/Extract_DEXPI_Graph_and_Export_Rules/workflow.yaml +0 -139
  144. cognite/neat/legacy/workflows/examples/Extract_RDF_Graph_and_Generate_Assets/workflow.yaml +0 -270
  145. cognite/neat/legacy/workflows/examples/Import_DMS/workflow.yaml +0 -65
  146. cognite/neat/legacy/workflows/examples/Ontology_to_Data_Model/workflow.yaml +0 -116
  147. cognite/neat/legacy/workflows/examples/Validate_Rules/workflow.yaml +0 -67
  148. cognite/neat/legacy/workflows/examples/Validate_Solution_Model/workflow.yaml +0 -64
  149. cognite/neat/legacy/workflows/examples/Visualize_Data_Model_Using_Mock_Graph/workflow.yaml +0 -95
  150. cognite/neat/legacy/workflows/examples/Visualize_Semantic_Data_Model/workflow.yaml +0 -111
  151. cognite/neat/rules/exceptions.py +0 -2972
  152. cognite/neat/rules/models/_types/_base.py +0 -16
  153. cognite/neat/workflows/examples/Export_Rules_to_Ontology/workflow.yaml +0 -152
  154. cognite/neat/workflows/examples/Extract_DEXPI_Graph_and_Export_Rules/workflow.yaml +0 -139
  155. cognite/neat/workflows/examples/Extract_RDF_Graph_and_Generate_Assets/workflow.yaml +0 -270
  156. cognite/neat/workflows/examples/Ontology_to_Data_Model/workflow.yaml +0 -116
  157. cognite/neat/workflows/migration/__init__.py +0 -0
  158. cognite/neat/workflows/migration/steps.py +0 -91
  159. cognite/neat/workflows/migration/wf_manifests.py +0 -33
  160. cognite/neat/workflows/steps/lib/legacy/__init__.py +0 -7
  161. cognite/neat/workflows/steps/lib/legacy/graph_contextualization.py +0 -82
  162. cognite/neat/workflows/steps/lib/legacy/graph_extractor.py +0 -746
  163. cognite/neat/workflows/steps/lib/legacy/graph_loader.py +0 -606
  164. cognite/neat/workflows/steps/lib/legacy/graph_store.py +0 -307
  165. cognite/neat/workflows/steps/lib/legacy/graph_transformer.py +0 -58
  166. cognite/neat/workflows/steps/lib/legacy/rules_exporter.py +0 -511
  167. cognite/neat/workflows/steps/lib/legacy/rules_importer.py +0 -612
  168. cognite_neat-0.87.6.dist-info/RECORD +0 -319
  169. {cognite_neat-0.87.6.dist-info → cognite_neat-0.88.1.dist-info}/LICENSE +0 -0
  170. {cognite_neat-0.87.6.dist-info → cognite_neat-0.88.1.dist-info}/WHEEL +0 -0
  171. {cognite_neat-0.87.6.dist-info → cognite_neat-0.88.1.dist-info}/entry_points.txt +0 -0
@@ -1,105 +0,0 @@
1
- """This module provides set of methods that perform conversion of TransformationRules
2
- to TransformationRules for purpose of for example:
3
-
4
- - subsetting the data model to only include desired classes and their properties
5
- - converting classes/properties ids/names to DMS compliant format
6
- """
7
-
8
- import logging
9
- import re
10
- import warnings
11
- from typing import Any
12
-
13
- from cognite.neat.legacy.rules.analysis import get_defined_classes
14
- from cognite.neat.legacy.rules.models.rules import Rules
15
-
16
-
17
- def subset_rules(rules: Rules, desired_classes: set, skip_validation: bool = False) -> Rules:
18
- """
19
- Subset transformation rules to only include desired classes and their properties.
20
-
21
- Args:
22
- transformation_rules: Instance of TransformationRules to subset
23
- desired_classes: Desired classes to include in the reduced data model
24
- skip_validation: Whether to skip underlying pydantic validation, by default False
25
-
26
- Returns:
27
- Instance of TransformationRules
28
-
29
- !!! note "Skipping Validation"
30
- It is fine to skip validation since we are deriving the reduced data model from data
31
- model (i.e. TransformationRules) which has already been validated.
32
-
33
- """
34
-
35
- defined_classes = get_defined_classes(rules)
36
- possible_classes = defined_classes.intersection(desired_classes)
37
- impossible_classes = desired_classes - possible_classes
38
-
39
- if not possible_classes:
40
- logging.error("None of the desired classes are defined in the data model!")
41
- raise ValueError("None of the desired classes are defined in the data model!")
42
-
43
- if impossible_classes:
44
- logging.warning(f"Could not find the following classes defined in the data model: {impossible_classes}")
45
- warnings.warn(
46
- f"Could not find the following classes defined in the data model: {impossible_classes}", stacklevel=2
47
- )
48
-
49
- reduced_data_model: dict[str, Any] = {
50
- "metadata": rules.metadata.model_copy(),
51
- "prefixes": (rules.prefixes or {}).copy(),
52
- "classes": {},
53
- "properties": {},
54
- "instances": (rules.instances or []).copy(),
55
- }
56
-
57
- logging.info(f"Reducing data model to only include the following classes: {possible_classes}")
58
- for class_ in possible_classes:
59
- reduced_data_model["classes"][class_] = rules.classes[class_]
60
-
61
- for id_, property_definition in rules.properties.items():
62
- if property_definition.class_id in possible_classes:
63
- reduced_data_model["properties"][id_] = property_definition
64
-
65
- if skip_validation:
66
- return Rules.model_construct(**reduced_data_model)
67
- else:
68
- return Rules(**reduced_data_model)
69
-
70
-
71
- def to_dms_compliant_rules(rules: Rules) -> Rules:
72
- raise NotImplementedError()
73
-
74
-
75
- # to be used for conversion to DMS compliant format
76
- def to_dms_name(name: str, entity_type: str, fix_casing: bool = False) -> str:
77
- """
78
- Repairs an entity name to conform to GraphQL naming convention
79
- >>> repair_name("wind-speed", "property")
80
- 'windspeed'
81
- >>> repair_name("Wind.Speed", "property", True)
82
- 'windSpeed'
83
- >>> repair_name("windSpeed", "class", True)
84
- 'WindSpeed'
85
- >>> repair_name("22windSpeed", "class")
86
- '_22windSpeed'
87
- """
88
-
89
- # Remove any non GraphQL compliant characters
90
- repaired_string = re.sub(r"[^_a-zA-Z0-9]", "", name)
91
-
92
- # Name must start with a letter or underscore
93
- if repaired_string[0].isdigit():
94
- repaired_string = f"_{repaired_string}"
95
-
96
- if not fix_casing:
97
- return repaired_string
98
- # Property names must be camelCase
99
- if entity_type == "property" and repaired_string[0].isupper():
100
- return repaired_string[0].lower() + repaired_string[1:]
101
- # Class names must be PascalCase
102
- elif entity_type == "class" and repaired_string[0].islower():
103
- return repaired_string[0].upper() + repaired_string[1:]
104
- else:
105
- return repaired_string
@@ -1,38 +0,0 @@
1
- from pathlib import Path
2
-
3
- from rdflib.term import Node
4
-
5
- from cognite.neat.legacy.rules.models.rules import Rules
6
-
7
- from ._base import BaseExporter
8
-
9
-
10
- class TripleExporter(BaseExporter[list[tuple[Node, Node, Node]]]):
11
- """
12
- Exporter for transformation rules instances sheet to RDF triples
13
- """
14
-
15
- def _export_to_file(self, filepath: Path) -> None:
16
- raise NotImplementedError("Export to file not implemented")
17
-
18
- def export(self) -> list[tuple[Node, Node, Node]]:
19
- return get_instances_as_triples(self.rules)
20
-
21
-
22
- def get_instances_as_triples(transformation_rules: Rules) -> list[tuple[Node, Node, Node]]:
23
- """
24
- Converts transformation rules instances sheet to RDF triples
25
-
26
- Args:
27
- transformation_rules: An instance of TransformationRules pydantic class
28
-
29
- Returns:
30
- List of triples provided as tuples
31
-
32
- """
33
- if transformation_rules.instances:
34
- return [
35
- (instance.instance, instance.property_, instance.value) # type: ignore[misc]
36
- for instance in transformation_rules.instances
37
- ]
38
- return []
@@ -1,146 +0,0 @@
1
- import re
2
- import warnings
3
- from typing import Literal, overload
4
-
5
- from cognite.neat.exceptions import wrangle_warnings
6
- from cognite.neat.legacy.rules import exceptions
7
- from cognite.neat.legacy.rules.models.rules import (
8
- Rules,
9
- dms_property_id_compliance_regex,
10
- value_id_compliance_regex,
11
- view_id_compliance_regex,
12
- )
13
-
14
-
15
- @overload
16
- def are_entity_names_dms_compliant(
17
- transformation_rules: Rules, return_report: Literal[True]
18
- ) -> tuple[bool, list[dict]]: ...
19
-
20
-
21
- @overload
22
- def are_entity_names_dms_compliant(transformation_rules: Rules, return_report: Literal[False] = False) -> bool: ...
23
-
24
-
25
- def are_entity_names_dms_compliant(
26
- transformation_rules: Rules, return_report: bool = False
27
- ) -> bool | tuple[bool, list[dict]]:
28
- """Check if data model definitions are valid."""
29
-
30
- flag: bool = True
31
- with warnings.catch_warnings(record=True) as validation_warnings:
32
- for class_ in transformation_rules.classes.values():
33
- if not re.match(view_id_compliance_regex, class_.class_id):
34
- warnings.warn(
35
- exceptions.EntityIDNotDMSCompliant(
36
- "Class", class_.class_id, f"[Classes/Class/{class_.class_id}]"
37
- ).message,
38
- category=exceptions.EntityIDNotDMSCompliant,
39
- stacklevel=2,
40
- )
41
- flag = False
42
-
43
- for row, property_ in transformation_rules.properties.items():
44
- # check class id which would resolve as view/container id
45
- if not re.match(view_id_compliance_regex, property_.class_id):
46
- warnings.warn(
47
- exceptions.EntityIDNotDMSCompliant(
48
- "Class", property_.class_id, f"[Properties/Class/{row}]"
49
- ).message,
50
- category=exceptions.EntityIDNotDMSCompliant,
51
- stacklevel=2,
52
- )
53
- flag = False
54
-
55
- # check property id which would resolve as view/container id
56
- if not re.match(dms_property_id_compliance_regex, property_.property_id):
57
- warnings.warn(
58
- exceptions.EntityIDNotDMSCompliant(
59
- "Property", property_.property_id, f"[Properties/Property/{row}]"
60
- ).message,
61
- category=exceptions.EntityIDNotDMSCompliant,
62
- stacklevel=2,
63
- )
64
- flag = False
65
-
66
- # check container external id
67
- if property_.container and not re.match(view_id_compliance_regex, property_.container.external_id):
68
- warnings.warn(
69
- exceptions.EntityIDNotDMSCompliant(
70
- "Container", property_.container.external_id, f"[Properties/Container/{row}]"
71
- ).message,
72
- category=exceptions.EntityIDNotDMSCompliant,
73
- stacklevel=2,
74
- )
75
- flag = False
76
-
77
- # check container property external id
78
- if property_.container_property and not re.match(
79
- dms_property_id_compliance_regex, property_.container_property
80
- ):
81
- warnings.warn(
82
- exceptions.EntityIDNotDMSCompliant(
83
- "Container Property", property_.container_property, f"[Properties/Container Property/{row}]"
84
- ).message,
85
- category=exceptions.EntityIDNotDMSCompliant,
86
- stacklevel=2,
87
- )
88
- flag = False
89
-
90
- # expected value type, as it is case sensitive should be ok
91
- if not re.match(value_id_compliance_regex, property_.expected_value_type.external_id):
92
- warnings.warn(
93
- exceptions.EntityIDNotDMSCompliant(
94
- "Value type", property_.expected_value_type.external_id, f"[Properties/Type/{row}]"
95
- ).message,
96
- category=exceptions.EntityIDNotDMSCompliant,
97
- stacklevel=2,
98
- )
99
- flag = False
100
-
101
- if return_report:
102
- return flag, wrangle_warnings(validation_warnings)
103
- else:
104
- return flag
105
-
106
-
107
- @overload
108
- def are_properties_redefined(transformation_rules: Rules, return_report: Literal[True]) -> tuple[bool, list[dict]]: ...
109
-
110
-
111
- @overload
112
- def are_properties_redefined(transformation_rules: Rules, return_report: Literal[False] = False) -> bool: ...
113
-
114
-
115
- def are_properties_redefined(
116
- transformation_rules: Rules, return_report: bool = False
117
- ) -> bool | tuple[bool, list[dict]]:
118
- flag: bool = False
119
- with warnings.catch_warnings(record=True) as validation_warnings:
120
- analyzed_properties = {}
121
- for property_ in transformation_rules.properties.values():
122
- if property_.property_id not in analyzed_properties:
123
- analyzed_properties[property_.property_id] = [property_.class_id]
124
- elif property_.class_id in analyzed_properties[property_.property_id]:
125
- flag = True
126
- warnings.warn(
127
- exceptions.PropertyRedefined(property_.property_id, property_.class_id).message,
128
- category=exceptions.EntityIDNotDMSCompliant,
129
- stacklevel=2,
130
- )
131
-
132
- else:
133
- analyzed_properties[property_.property_id].append(property_.class_id)
134
-
135
- if return_report:
136
- return flag, wrangle_warnings(validation_warnings)
137
- else:
138
- return flag
139
-
140
-
141
- def property_ids_camel_case_compliant(transformation_rules) -> bool | tuple[bool, list[dict]]:
142
- raise NotImplementedError()
143
-
144
-
145
- def class_id_pascal_case_compliant(transformation_rules) -> bool | tuple[bool, list[dict]]:
146
- raise NotImplementedError()
@@ -1,22 +0,0 @@
1
- from ._base import BaseImporter
2
- from ._dict2rules import ArbitraryDictImporter
3
- from ._dms2rules import DMSImporter
4
- from ._graph2rules import GraphImporter
5
- from ._json2rules import ArbitraryJSONImporter
6
- from ._owl2rules import OWLImporter
7
- from ._spreadsheet2rules import ExcelImporter, GoogleSheetImporter
8
- from ._xsd2rules import XSDImporter
9
- from ._yaml2rules import ArbitraryYAMLImporter
10
-
11
- __all__ = [
12
- "BaseImporter",
13
- "ArbitraryDictImporter",
14
- "ArbitraryJSONImporter",
15
- "ArbitraryYAMLImporter",
16
- "DMSImporter",
17
- "OWLImporter",
18
- "XSDImporter",
19
- "GraphImporter",
20
- "ExcelImporter",
21
- "GoogleSheetImporter",
22
- ]
@@ -1,66 +0,0 @@
1
- import getpass
2
- from abc import ABC, abstractmethod
3
- from datetime import datetime
4
-
5
- import pandas as pd
6
- from pydantic_core import ErrorDetails
7
-
8
- from cognite.neat.legacy.rules.models.raw_rules import RawRules
9
- from cognite.neat.legacy.rules.models.rules import Rules
10
-
11
-
12
- class BaseImporter(ABC):
13
- """
14
- BaseImporter class which all importers inherit from.
15
- """
16
-
17
- @abstractmethod
18
- def to_tables(self) -> dict[str, pd.DataFrame]:
19
- """Creates raw tables from the data."""
20
- raise NotImplementedError
21
-
22
- def to_raw_rules(self) -> RawRules:
23
- """Creates `RawRules` object from the data."""
24
-
25
- tables = self.to_tables()
26
-
27
- return RawRules.from_tables(tables=tables, importer_type=self.__class__.__name__)
28
-
29
- def to_rules(
30
- self,
31
- return_report: bool = False,
32
- skip_validation: bool = False,
33
- validators_to_skip: set[str] | None = None,
34
- ) -> tuple[Rules | None, list[ErrorDetails] | None, list | None] | Rules:
35
- """
36
- Creates `Rules` object from the data.
37
-
38
- Args:
39
- return_report: To return validation report. Defaults to False.
40
- skip_validation: Bypasses Rules validation. Defaults to False.
41
- validators_to_skip: List of validators to skip. Defaults to None.
42
-
43
- Returns:
44
- Instance of `Rules`, which can be validated, not validated based on
45
- `skip_validation` flag, or partially validated if `validators_to_skip` is set,
46
- and optional list of errors and warnings if
47
- `return_report` is set to True.
48
-
49
- !!! Note "Skip Validation
50
- `skip_validation` flag should be only used for purpose when `Rules` object
51
- is exported to an Excel file. Do not use this flag for any other purpose!
52
- """
53
-
54
- raw_rules = self.to_raw_rules()
55
-
56
- return raw_rules.to_rules(return_report, skip_validation, validators_to_skip)
57
-
58
- def _default_metadata(self):
59
- return {
60
- "prefix": "neat",
61
- "version": "0.1.0",
62
- "title": "Neat Imported Data Model",
63
- "created": datetime.now().replace(microsecond=0).isoformat(),
64
- "creator": getpass.getuser(),
65
- "description": f"Imported using {type(self).__name__}",
66
- }
@@ -1,158 +0,0 @@
1
- from datetime import datetime, timezone
2
- from typing import Any, Literal
3
-
4
- import pandas as pd
5
-
6
- from cognite.neat.legacy.rules.models.tables import Tables
7
-
8
- from ._base import BaseImporter
9
-
10
-
11
- class ArbitraryDictImporter(BaseImporter):
12
- """
13
- Importer for an arbitrary dictionary.
14
-
15
- This importer infers the data model from the dictionary based on the shape of the data.
16
-
17
- Args:
18
- data: dictionary containing Rules definitions.
19
- relationship_direction: Direction of relationships, either "parent-to-child" or "child-to-parent". Dictionaries
20
- are nested with children nested inside parents. This option determines whether the resulting rules
21
- will have an edge from parents to children or from children to parents.
22
- """
23
-
24
- def __init__(
25
- self,
26
- data: dict[str, Any],
27
- relationship_direction: Literal["parent-to-child", "child-to-parent"] = "parent-to-child",
28
- ):
29
- self.data = data
30
- self.relationship_direction = relationship_direction
31
-
32
- def to_tables(self) -> dict[str, pd.DataFrame]:
33
- metadata = pd.Series(
34
- dict(
35
- title="OpenAPI to DM transformation rules",
36
- description="OpenAPI to DM transformation rules",
37
- version="0.1",
38
- creator="Cognite",
39
- created=datetime.now(timezone.utc).replace(microsecond=0).isoformat(),
40
- namespace="http://purl.org/cognite/neat#",
41
- prefix="neat",
42
- data_model_name="OpenAPI",
43
- cdf_space_name="OpenAPI",
44
- )
45
- ).reset_index()
46
- finder = _TripleFinder(self.relationship_direction)
47
- finder.find_triples(self.data)
48
-
49
- return {
50
- Tables.metadata: metadata,
51
- Tables.classes: pd.DataFrame(finder.classes).T,
52
- Tables.properties: pd.DataFrame(finder.properties).T,
53
- }
54
-
55
-
56
- class _TripleFinder:
57
- def __init__(self, relationship_direction: Literal["parent-to-child", "child-to-parent"]) -> None:
58
- self.classes: dict[str, dict[str, Any]] = {}
59
- self.properties: dict[str, dict[str, Any]] = {}
60
- self.relationship_direction = relationship_direction
61
-
62
- def find_triples(self, data: dict[str, Any]) -> None:
63
- self._convert_dict_to_classes_and_props(data)
64
-
65
- def _convert_dict_to_classes_and_props(
66
- self, data: dict, parent_property_name: str | None = None, grand_parent_property_name: str | None = None
67
- ) -> None:
68
- if isinstance(data, dict) and len(data) == 0:
69
- return
70
- elif isinstance(data, dict) and parent_property_name is None:
71
- for key, value in data.items():
72
- self._convert_dict_to_classes_and_props(value, key)
73
- elif isinstance(data, dict):
74
- self.add_class(parent_property_name, "missing", grand_parent_property_name, is_list=False)
75
- for key, value in data.items():
76
- self._convert_dict_to_classes_and_props(value, key, parent_property_name)
77
- elif isinstance(data, list):
78
- if parent_property_name is not None and grand_parent_property_name is not None:
79
- data_type = self._get_list_type(data, parent_property_name)
80
- self.add_property(grand_parent_property_name, parent_property_name, data_type, "missing", is_list=True)
81
- for item in data:
82
- self._convert_dict_to_classes_and_props(item, parent_property_name, grand_parent_property_name)
83
- elif isinstance(data, bool | int | float | str) and parent_property_name is not None:
84
- data_type = self._get_primitive_data_type(data)
85
- self.add_property(grand_parent_property_name, parent_property_name, data_type, "missing")
86
- else:
87
- raise ValueError(f"Unknown type {type(data)}")
88
-
89
- def add_class(
90
- self, class_name: str, description: str = "", parent_class_name: str | None = None, is_list: bool = False
91
- ):
92
- if class_name in self.classes:
93
- return
94
- class_ = {"Class": class_name, "description": description}
95
- if parent_class_name:
96
- if self.relationship_direction == "child-to-parent":
97
- self.add_property(class_name, "parent", parent_class_name, "missing", is_list=False)
98
- elif self.relationship_direction == "parent-to-child":
99
- self.add_property(parent_class_name, class_name, class_name, "missing", is_list)
100
- else:
101
- raise ValueError(f"Unknown relationship direction {self.relationship_direction}")
102
- self.classes[class_name] = class_
103
-
104
- def add_property(
105
- self,
106
- class_name: str,
107
- property_name: str,
108
- property_type: str,
109
- description: str = "missing",
110
- is_list: bool = False,
111
- ):
112
- if class_name + property_name in self.properties:
113
- return
114
- prop = dict(
115
- class_id=class_name,
116
- property_id=property_name,
117
- property_name=property_name,
118
- property_type="ObjectProperty",
119
- description=description,
120
- expected_value_type=property_type,
121
- max_count=1 if not is_list else None,
122
- cdf_resource_type="Asset",
123
- resource_type_property="Asset",
124
- rule_type="rdfpath",
125
- rule=f"neat:{class_name}(neat:{property_name})",
126
- label="linked to",
127
- )
128
- self.properties[class_name + property_name] = prop
129
-
130
- @staticmethod
131
- def _get_primitive_data_type(data: Any, errors: Literal["raise", "empty"] = "raise") -> str:
132
- data_type = type(data)
133
- if data_type is bool:
134
- return "boolean"
135
- elif data_type is int:
136
- return "integer"
137
- elif data_type is float:
138
- return "float"
139
- elif data_type is str and not pd.isna(pd.to_datetime(data, errors="coerce")):
140
- return "dateTime"
141
- elif data_type is str:
142
- return "string"
143
-
144
- if errors == "empty":
145
- return ""
146
- else:
147
- raise ValueError(f"Unknown primitive type {data_type}")
148
-
149
- @classmethod
150
- def _get_list_type(cls, data: list[Any], class_name: str) -> str:
151
- if isinstance(data[0], dict):
152
- return class_name
153
-
154
- data_types = {cls._get_primitive_data_type(item, "empty") for item in data}
155
- if "" in data_types or len(data_types) > 1:
156
- # Fallback to string
157
- return "string"
158
- return data_types.pop()