cognite-neat 1.0.30__py3-none-any.whl → 1.0.32__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cognite/neat/_client/data_classes.py +32 -0
- cognite/neat/_client/statistics_api.py +28 -1
- cognite/neat/_data_model/_analysis.py +8 -3
- cognite/neat/_data_model/_constants.py +4 -0
- cognite/neat/_data_model/{validation/dms → rules}/_base.py +11 -5
- cognite/neat/_data_model/rules/cdf/__init__.py +3 -0
- cognite/neat/_data_model/rules/cdf/_base.py +5 -0
- cognite/neat/_data_model/rules/cdf/_orchestrator.py +56 -0
- cognite/neat/_data_model/rules/cdf/_spaces.py +47 -0
- cognite/neat/_data_model/{validation → rules}/dms/__init__.py +2 -2
- cognite/neat/_data_model/{validation → rules}/dms/_ai_readiness.py +17 -17
- cognite/neat/_data_model/rules/dms/_base.py +5 -0
- cognite/neat/_data_model/{validation → rules}/dms/_connections.py +23 -23
- cognite/neat/_data_model/{validation → rules}/dms/_consistency.py +3 -3
- cognite/neat/_data_model/{validation → rules}/dms/_containers.py +9 -9
- cognite/neat/_data_model/{validation → rules}/dms/_limits.py +14 -14
- cognite/neat/_data_model/{validation → rules}/dms/_orchestrator.py +7 -7
- cognite/neat/_data_model/{validation → rules}/dms/_performance.py +14 -13
- cognite/neat/_data_model/{validation → rules}/dms/_views.py +7 -7
- cognite/neat/_session/_cdf.py +15 -1
- cognite/neat/_session/_physical.py +6 -6
- cognite/neat/_session/_wrappers.py +1 -1
- cognite/neat/_state_machine/_states.py +1 -1
- cognite/neat/_store/_store.py +19 -1
- cognite/neat/_version.py +1 -1
- {cognite_neat-1.0.30.dist-info → cognite_neat-1.0.32.dist-info}/METADATA +1 -1
- {cognite_neat-1.0.30.dist-info → cognite_neat-1.0.32.dist-info}/RECORD +29 -24
- {cognite_neat-1.0.30.dist-info → cognite_neat-1.0.32.dist-info}/WHEEL +1 -1
- /cognite/neat/_data_model/{validation → rules}/__init__.py +0 -0
|
@@ -4,13 +4,13 @@ from pyparsing import cast
|
|
|
4
4
|
|
|
5
5
|
from cognite.neat._data_model.models.dms._constraints import Constraint, RequiresConstraintDefinition
|
|
6
6
|
from cognite.neat._data_model.models.dms._view_property import ViewCorePropertyRequest
|
|
7
|
-
from cognite.neat._data_model.
|
|
7
|
+
from cognite.neat._data_model.rules.dms._base import DataModelRule
|
|
8
8
|
from cognite.neat._issues import ConsistencyError
|
|
9
9
|
|
|
10
10
|
BASE_CODE = "NEAT-DMS-CONTAINER"
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
class ExternalContainerDoesNotExist(
|
|
13
|
+
class ExternalContainerDoesNotExist(DataModelRule):
|
|
14
14
|
"""
|
|
15
15
|
Validates that any container referenced by a view property, when the
|
|
16
16
|
referenced container does not belong to the data model's space, exists in CDF.
|
|
@@ -33,7 +33,7 @@ class ExternalContainerDoesNotExist(DataModelValidator):
|
|
|
33
33
|
code = f"{BASE_CODE}-001"
|
|
34
34
|
issue_type = ConsistencyError
|
|
35
35
|
|
|
36
|
-
def
|
|
36
|
+
def validate(self) -> list[ConsistencyError]:
|
|
37
37
|
errors: list[ConsistencyError] = []
|
|
38
38
|
|
|
39
39
|
if not self.validation_resources.merged_data_model.views:
|
|
@@ -73,7 +73,7 @@ class ExternalContainerDoesNotExist(DataModelValidator):
|
|
|
73
73
|
return errors
|
|
74
74
|
|
|
75
75
|
|
|
76
|
-
class ExternalContainerPropertyDoesNotExist(
|
|
76
|
+
class ExternalContainerPropertyDoesNotExist(DataModelRule):
|
|
77
77
|
"""
|
|
78
78
|
Validates that any container property referenced by a view property, when the
|
|
79
79
|
referenced container does not belong to the data model's space, exists in CDF.
|
|
@@ -97,7 +97,7 @@ class ExternalContainerPropertyDoesNotExist(DataModelValidator):
|
|
|
97
97
|
code = f"{BASE_CODE}-002"
|
|
98
98
|
issue_type = ConsistencyError
|
|
99
99
|
|
|
100
|
-
def
|
|
100
|
+
def validate(self) -> list[ConsistencyError]:
|
|
101
101
|
errors: list[ConsistencyError] = []
|
|
102
102
|
|
|
103
103
|
if self.validation_resources.merged_data_model.views:
|
|
@@ -144,7 +144,7 @@ class ExternalContainerPropertyDoesNotExist(DataModelValidator):
|
|
|
144
144
|
return errors
|
|
145
145
|
|
|
146
146
|
|
|
147
|
-
class RequiredContainerDoesNotExist(
|
|
147
|
+
class RequiredContainerDoesNotExist(DataModelRule):
|
|
148
148
|
"""
|
|
149
149
|
Validates that any container required by another container exists in the data model.
|
|
150
150
|
|
|
@@ -165,7 +165,7 @@ class RequiredContainerDoesNotExist(DataModelValidator):
|
|
|
165
165
|
code = f"{BASE_CODE}-003"
|
|
166
166
|
issue_type = ConsistencyError
|
|
167
167
|
|
|
168
|
-
def
|
|
168
|
+
def validate(self) -> list[ConsistencyError]:
|
|
169
169
|
errors: list[ConsistencyError] = []
|
|
170
170
|
|
|
171
171
|
for container_ref in self.validation_resources.merged.containers:
|
|
@@ -199,7 +199,7 @@ class RequiredContainerDoesNotExist(DataModelValidator):
|
|
|
199
199
|
return errors
|
|
200
200
|
|
|
201
201
|
|
|
202
|
-
class RequiresConstraintCycle(
|
|
202
|
+
class RequiresConstraintCycle(DataModelRule):
|
|
203
203
|
"""
|
|
204
204
|
Validates that requires constraints between containers do not form cycles.
|
|
205
205
|
|
|
@@ -221,7 +221,7 @@ class RequiresConstraintCycle(DataModelValidator):
|
|
|
221
221
|
issue_type = ConsistencyError
|
|
222
222
|
alpha = True # Still in development
|
|
223
223
|
|
|
224
|
-
def
|
|
224
|
+
def validate(self) -> list[ConsistencyError]:
|
|
225
225
|
errors: list[ConsistencyError] = []
|
|
226
226
|
optimal_edges = self.validation_resources.oriented_mst_edges
|
|
227
227
|
|
|
@@ -8,15 +8,15 @@ from cognite.neat._data_model.models.dms._indexes import BtreeIndex, InvertedInd
|
|
|
8
8
|
from cognite.neat._data_model.models.dms._view_property import (
|
|
9
9
|
ViewCorePropertyRequest,
|
|
10
10
|
)
|
|
11
|
-
from cognite.neat._data_model.
|
|
12
|
-
|
|
11
|
+
from cognite.neat._data_model.rules.dms._base import (
|
|
12
|
+
DataModelRule,
|
|
13
13
|
)
|
|
14
14
|
from cognite.neat._issues import ConsistencyError, Recommendation
|
|
15
15
|
|
|
16
16
|
BASE_CODE = "NEAT-DMS-LIMITS"
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
class DataModelViewCountIsOutOfLimits(
|
|
19
|
+
class DataModelViewCountIsOutOfLimits(DataModelRule):
|
|
20
20
|
"""Validates that the data model does not exceed the maximum number of views.
|
|
21
21
|
|
|
22
22
|
## What it does
|
|
@@ -36,7 +36,7 @@ class DataModelViewCountIsOutOfLimits(DataModelValidator):
|
|
|
36
36
|
code = f"{BASE_CODE}-DATA-MODEL-001"
|
|
37
37
|
issue_type = ConsistencyError
|
|
38
38
|
|
|
39
|
-
def
|
|
39
|
+
def validate(self) -> list[ConsistencyError]:
|
|
40
40
|
errors: list[ConsistencyError] = []
|
|
41
41
|
|
|
42
42
|
if self.validation_resources.merged_data_model.views is None:
|
|
@@ -66,7 +66,7 @@ class DataModelViewCountIsOutOfLimits(DataModelValidator):
|
|
|
66
66
|
### View level limits
|
|
67
67
|
|
|
68
68
|
|
|
69
|
-
class ViewPropertyCountIsOutOfLimits(
|
|
69
|
+
class ViewPropertyCountIsOutOfLimits(DataModelRule):
|
|
70
70
|
"""Validates that a view does not exceed the maximum number of properties.
|
|
71
71
|
|
|
72
72
|
## What it does
|
|
@@ -83,7 +83,7 @@ class ViewPropertyCountIsOutOfLimits(DataModelValidator):
|
|
|
83
83
|
code = f"{BASE_CODE}-VIEW-001"
|
|
84
84
|
issue_type = ConsistencyError
|
|
85
85
|
|
|
86
|
-
def
|
|
86
|
+
def validate(self) -> list[ConsistencyError]:
|
|
87
87
|
errors: list[ConsistencyError] = []
|
|
88
88
|
|
|
89
89
|
for view_ref in self.validation_resources.merged_data_model.views or []:
|
|
@@ -117,7 +117,7 @@ class ViewPropertyCountIsOutOfLimits(DataModelValidator):
|
|
|
117
117
|
return errors
|
|
118
118
|
|
|
119
119
|
|
|
120
|
-
class ViewContainerCountIsOutOfLimits(
|
|
120
|
+
class ViewContainerCountIsOutOfLimits(DataModelRule):
|
|
121
121
|
"""Validates that a view does not reference too many containers.
|
|
122
122
|
|
|
123
123
|
## What it does
|
|
@@ -135,7 +135,7 @@ class ViewContainerCountIsOutOfLimits(DataModelValidator):
|
|
|
135
135
|
code = f"{BASE_CODE}-VIEW-002"
|
|
136
136
|
issue_type = Recommendation
|
|
137
137
|
|
|
138
|
-
def
|
|
138
|
+
def validate(self) -> list[Recommendation]:
|
|
139
139
|
recommendations: list[Recommendation] = []
|
|
140
140
|
|
|
141
141
|
# Single loop over all views
|
|
@@ -166,7 +166,7 @@ class ViewContainerCountIsOutOfLimits(DataModelValidator):
|
|
|
166
166
|
return recommendations
|
|
167
167
|
|
|
168
168
|
|
|
169
|
-
class ViewImplementsCountIsOutOfLimits(
|
|
169
|
+
class ViewImplementsCountIsOutOfLimits(DataModelRule):
|
|
170
170
|
"""Validates that a view does not implement too many other views.
|
|
171
171
|
|
|
172
172
|
## What it does
|
|
@@ -183,7 +183,7 @@ class ViewImplementsCountIsOutOfLimits(DataModelValidator):
|
|
|
183
183
|
code = f"{BASE_CODE}-VIEW-003"
|
|
184
184
|
issue_type = ConsistencyError
|
|
185
185
|
|
|
186
|
-
def
|
|
186
|
+
def validate(self) -> list[ConsistencyError]:
|
|
187
187
|
errors: list[ConsistencyError] = []
|
|
188
188
|
|
|
189
189
|
# Single loop over all views
|
|
@@ -206,7 +206,7 @@ class ViewImplementsCountIsOutOfLimits(DataModelValidator):
|
|
|
206
206
|
### Container level limits
|
|
207
207
|
|
|
208
208
|
|
|
209
|
-
class ContainerPropertyCountIsOutOfLimits(
|
|
209
|
+
class ContainerPropertyCountIsOutOfLimits(DataModelRule):
|
|
210
210
|
"""Validates that a container does not exceed the maximum number of properties.
|
|
211
211
|
|
|
212
212
|
## What it does
|
|
@@ -224,7 +224,7 @@ class ContainerPropertyCountIsOutOfLimits(DataModelValidator):
|
|
|
224
224
|
code = f"{BASE_CODE}-CONTAINER-001"
|
|
225
225
|
issue_type = ConsistencyError
|
|
226
226
|
|
|
227
|
-
def
|
|
227
|
+
def validate(self) -> list[ConsistencyError]:
|
|
228
228
|
errors: list[ConsistencyError] = []
|
|
229
229
|
# Single loop over all containers
|
|
230
230
|
for container_ref in self.validation_resources.merged.containers:
|
|
@@ -263,7 +263,7 @@ class ContainerPropertyCountIsOutOfLimits(DataModelValidator):
|
|
|
263
263
|
return errors
|
|
264
264
|
|
|
265
265
|
|
|
266
|
-
class ContainerPropertyListSizeIsOutOfLimits(
|
|
266
|
+
class ContainerPropertyListSizeIsOutOfLimits(DataModelRule):
|
|
267
267
|
"""Validates that container property list sizes do not exceed CDF limits.
|
|
268
268
|
|
|
269
269
|
## What it does
|
|
@@ -288,7 +288,7 @@ class ContainerPropertyListSizeIsOutOfLimits(DataModelValidator):
|
|
|
288
288
|
code = f"{BASE_CODE}-CONTAINER-002"
|
|
289
289
|
issue_type = ConsistencyError
|
|
290
290
|
|
|
291
|
-
def
|
|
291
|
+
def validate(self) -> list[ConsistencyError]:
|
|
292
292
|
errors: list[ConsistencyError] = []
|
|
293
293
|
|
|
294
294
|
# Single loop over all containers
|
|
@@ -6,14 +6,14 @@ from cognite.neat._data_model._shared import OnSuccessIssuesChecker
|
|
|
6
6
|
from cognite.neat._data_model._snapshot import SchemaSnapshot
|
|
7
7
|
from cognite.neat._data_model.models.dms._limits import SchemaLimits
|
|
8
8
|
from cognite.neat._data_model.models.dms._schema import RequestSchema
|
|
9
|
+
from cognite.neat._data_model.rules.dms._base import DataModelRule
|
|
9
10
|
from cognite.neat._utils.auxiliary import get_concrete_subclasses
|
|
10
11
|
from cognite.neat._utils.useful_types import ModusOperandi
|
|
11
12
|
|
|
12
|
-
from ._base import DataModelValidator
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
class DmsDataModelRulesOrchestrator(OnSuccessIssuesChecker):
|
|
15
|
+
"""DMS Data Model rules orchestrator, used to execute DMS data model rules on a single data model represented
|
|
16
|
+
as RequestSchema."""
|
|
17
17
|
|
|
18
18
|
def __init__(
|
|
19
19
|
self,
|
|
@@ -37,8 +37,8 @@ class DmsDataModelValidation(OnSuccessIssuesChecker):
|
|
|
37
37
|
validation_resources = self._gather_validation_resources(request_schema)
|
|
38
38
|
|
|
39
39
|
# Initialize all validators
|
|
40
|
-
validators: list[
|
|
41
|
-
validator(validation_resources) for validator in get_concrete_subclasses(
|
|
40
|
+
validators: list[DataModelRule] = [
|
|
41
|
+
validator(validation_resources) for validator in get_concrete_subclasses(DataModelRule)
|
|
42
42
|
]
|
|
43
43
|
|
|
44
44
|
# Run validators
|
|
@@ -46,7 +46,7 @@ class DmsDataModelValidation(OnSuccessIssuesChecker):
|
|
|
46
46
|
if validator.alpha and not self._enable_alpha_validators:
|
|
47
47
|
continue
|
|
48
48
|
if self._can_run_validator(validator.code, validator.issue_type):
|
|
49
|
-
self._issues.extend(validator.
|
|
49
|
+
self._issues.extend(validator.validate())
|
|
50
50
|
|
|
51
51
|
self._has_run = True
|
|
52
52
|
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
from cognite.neat._data_model._analysis import RequiresChangeStatus
|
|
4
4
|
from cognite.neat._data_model._constants import COGNITE_SPACES
|
|
5
|
-
from cognite.neat._data_model.
|
|
5
|
+
from cognite.neat._data_model.rules.dms._base import DataModelRule
|
|
6
6
|
from cognite.neat._issues import Recommendation
|
|
7
7
|
|
|
8
8
|
BASE_CODE = "NEAT-DMS-PERFORMANCE"
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
class MissingRequiresConstraint(
|
|
11
|
+
class MissingRequiresConstraint(DataModelRule):
|
|
12
12
|
"""
|
|
13
13
|
Recommends adding requires constraints to optimize query performance.
|
|
14
14
|
|
|
@@ -31,7 +31,7 @@ class MissingRequiresConstraint(DataModelValidator):
|
|
|
31
31
|
issue_type = Recommendation
|
|
32
32
|
alpha = True
|
|
33
33
|
|
|
34
|
-
def
|
|
34
|
+
def validate(self) -> list[Recommendation]:
|
|
35
35
|
recommendations: list[Recommendation] = []
|
|
36
36
|
|
|
37
37
|
for view_ref in self.validation_resources.merged.views:
|
|
@@ -50,7 +50,7 @@ class MissingRequiresConstraint(DataModelValidator):
|
|
|
50
50
|
|
|
51
51
|
message = (
|
|
52
52
|
f"View '{view_ref!s}' is not optimized for querying. "
|
|
53
|
-
f"Add a 'requires' constraint from '{src!s}' to '{dst!s}'."
|
|
53
|
+
f"Add a 'requires' constraint from the container '{src!s}' to '{dst!s}'."
|
|
54
54
|
)
|
|
55
55
|
if not is_safe:
|
|
56
56
|
# Find a superset view to suggest for ingestion
|
|
@@ -75,7 +75,7 @@ class MissingRequiresConstraint(DataModelValidator):
|
|
|
75
75
|
return recommendations
|
|
76
76
|
|
|
77
77
|
|
|
78
|
-
class SuboptimalRequiresConstraint(
|
|
78
|
+
class SuboptimalRequiresConstraint(DataModelRule):
|
|
79
79
|
"""
|
|
80
80
|
Recommends removing requires constraints that are not optimal.
|
|
81
81
|
|
|
@@ -100,7 +100,7 @@ class SuboptimalRequiresConstraint(DataModelValidator):
|
|
|
100
100
|
issue_type = Recommendation
|
|
101
101
|
alpha = True
|
|
102
102
|
|
|
103
|
-
def
|
|
103
|
+
def validate(self) -> list[Recommendation]:
|
|
104
104
|
recommendations: list[Recommendation] = []
|
|
105
105
|
|
|
106
106
|
for view_ref in self.validation_resources.merged.views:
|
|
@@ -113,8 +113,9 @@ class SuboptimalRequiresConstraint(DataModelValidator):
|
|
|
113
113
|
recommendations.append(
|
|
114
114
|
Recommendation(
|
|
115
115
|
message=(
|
|
116
|
-
f"View '{view_ref!s}'
|
|
117
|
-
"that
|
|
116
|
+
f"View '{view_ref!s}' is mapping to container '{src!s}' "
|
|
117
|
+
f"that has a requires constraint to '{dst!s}'. This constraint is "
|
|
118
|
+
"not part of the optimal structure. Consider removing it."
|
|
118
119
|
),
|
|
119
120
|
fix="Remove the unnecessary requires constraint",
|
|
120
121
|
code=self.code,
|
|
@@ -124,7 +125,7 @@ class SuboptimalRequiresConstraint(DataModelValidator):
|
|
|
124
125
|
return recommendations
|
|
125
126
|
|
|
126
127
|
|
|
127
|
-
class UnresolvableQueryPerformance(
|
|
128
|
+
class UnresolvableQueryPerformance(DataModelRule):
|
|
128
129
|
"""
|
|
129
130
|
Identifies views with query performance issues that cannot be resolved.
|
|
130
131
|
This is likely to be caused by unintended modeling choices.
|
|
@@ -157,7 +158,7 @@ class UnresolvableQueryPerformance(DataModelValidator):
|
|
|
157
158
|
issue_type = Recommendation
|
|
158
159
|
alpha = True
|
|
159
160
|
|
|
160
|
-
def
|
|
161
|
+
def validate(self) -> list[Recommendation]:
|
|
161
162
|
recommendations: list[Recommendation] = []
|
|
162
163
|
|
|
163
164
|
for view_ref in self.validation_resources.merged.views:
|
|
@@ -170,8 +171,8 @@ class UnresolvableQueryPerformance(DataModelValidator):
|
|
|
170
171
|
recommendations.append(
|
|
171
172
|
Recommendation(
|
|
172
173
|
message=(
|
|
173
|
-
f"View '{view_ref!s}'
|
|
174
|
-
"
|
|
174
|
+
f"View '{view_ref!s}' is not optimized for querying. It maps only to CDF "
|
|
175
|
+
"built-in containers and some of these lack requires constraints between them. "
|
|
175
176
|
"Consider adding a view-specific container that requires the others."
|
|
176
177
|
),
|
|
177
178
|
fix="Add a container that requires the others, or restructure the view",
|
|
@@ -182,7 +183,7 @@ class UnresolvableQueryPerformance(DataModelValidator):
|
|
|
182
183
|
recommendations.append(
|
|
183
184
|
Recommendation(
|
|
184
185
|
message=(
|
|
185
|
-
f"View '{view_ref!s}'
|
|
186
|
+
f"View '{view_ref!s}' is not optimized for querying. "
|
|
186
187
|
"No valid requires constraint solution was found. "
|
|
187
188
|
"Consider adding a view-specific container that requires the others."
|
|
188
189
|
),
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"""Validators for checking containers in the data model."""
|
|
2
2
|
|
|
3
3
|
from cognite.neat._data_model.models.dms._view_property import ViewCorePropertyRequest
|
|
4
|
-
from cognite.neat._data_model.
|
|
4
|
+
from cognite.neat._data_model.rules.dms._base import DataModelRule
|
|
5
5
|
from cognite.neat._issues import ConsistencyError
|
|
6
6
|
|
|
7
7
|
BASE_CODE = "NEAT-DMS-VIEW"
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
class ViewToContainerMappingNotPossible(
|
|
10
|
+
class ViewToContainerMappingNotPossible(DataModelRule):
|
|
11
11
|
"""Validates that container and container property referenced by view property exist.
|
|
12
12
|
|
|
13
13
|
## What it does
|
|
@@ -26,7 +26,7 @@ class ViewToContainerMappingNotPossible(DataModelValidator):
|
|
|
26
26
|
code = f"{BASE_CODE}-001"
|
|
27
27
|
issue_type = ConsistencyError
|
|
28
28
|
|
|
29
|
-
def
|
|
29
|
+
def validate(self) -> list[ConsistencyError]:
|
|
30
30
|
errors: list[ConsistencyError] = []
|
|
31
31
|
|
|
32
32
|
if not self.validation_resources.merged_data_model.views:
|
|
@@ -79,7 +79,7 @@ class ViewToContainerMappingNotPossible(DataModelValidator):
|
|
|
79
79
|
return errors
|
|
80
80
|
|
|
81
81
|
|
|
82
|
-
class ImplementedViewNotExisting(
|
|
82
|
+
class ImplementedViewNotExisting(DataModelRule):
|
|
83
83
|
"""Validates that implemented (inherited) view exists.
|
|
84
84
|
|
|
85
85
|
## What it does
|
|
@@ -97,7 +97,7 @@ class ImplementedViewNotExisting(DataModelValidator):
|
|
|
97
97
|
code = f"{BASE_CODE}-002"
|
|
98
98
|
issue_type = ConsistencyError
|
|
99
99
|
|
|
100
|
-
def
|
|
100
|
+
def validate(self) -> list[ConsistencyError]:
|
|
101
101
|
errors: list[ConsistencyError] = []
|
|
102
102
|
|
|
103
103
|
if not self.validation_resources.merged_data_model.views:
|
|
@@ -126,7 +126,7 @@ class ImplementedViewNotExisting(DataModelValidator):
|
|
|
126
126
|
return errors
|
|
127
127
|
|
|
128
128
|
|
|
129
|
-
class CyclicImplements(
|
|
129
|
+
class CyclicImplements(DataModelRule):
|
|
130
130
|
"""Validates that view implements are not forming a cycle (i.e. cyclic graph of implements)
|
|
131
131
|
|
|
132
132
|
## What it does
|
|
@@ -146,7 +146,7 @@ class CyclicImplements(DataModelValidator):
|
|
|
146
146
|
issue_type = ConsistencyError
|
|
147
147
|
alpha = True
|
|
148
148
|
|
|
149
|
-
def
|
|
149
|
+
def validate(self) -> list[ConsistencyError]:
|
|
150
150
|
errors: list[ConsistencyError] = []
|
|
151
151
|
|
|
152
152
|
for cycle in self.validation_resources.implements_cycles:
|
cognite/neat/_session/_cdf.py
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
# /Users/nikola/repos/neat/cognite/neat/_session/_cdf.py
|
|
2
1
|
import uuid
|
|
3
2
|
|
|
4
3
|
from cognite.neat._client import NeatClient
|
|
5
4
|
from cognite.neat._config import NeatConfig
|
|
5
|
+
from cognite.neat._data_model.rules.cdf._orchestrator import CDFRulesOrchestrator
|
|
6
|
+
from cognite.neat._session._wrappers import session_wrapper
|
|
6
7
|
from cognite.neat._store._store import NeatStore
|
|
7
8
|
|
|
8
9
|
from ._html._render import render
|
|
9
10
|
|
|
10
11
|
|
|
12
|
+
@session_wrapper
|
|
11
13
|
class CDF:
|
|
12
14
|
"""Read from a data source into NeatSession graph store."""
|
|
13
15
|
|
|
@@ -34,3 +36,15 @@ class CDF:
|
|
|
34
36
|
"data_models_limit": self._store.cdf_limits.data_models.limit,
|
|
35
37
|
},
|
|
36
38
|
)
|
|
39
|
+
|
|
40
|
+
def analyze(self) -> None:
|
|
41
|
+
"""Analyze the entity of CDF data models."""
|
|
42
|
+
|
|
43
|
+
on_success = CDFRulesOrchestrator(
|
|
44
|
+
limits=self._store.cdf_limits,
|
|
45
|
+
space_statistics=self._store.cdf_space_statistics,
|
|
46
|
+
can_run_validator=self._config.validation.can_run_validator,
|
|
47
|
+
enable_alpha_validators=self._config.alpha.enable_experimental_validators,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
return self._store.cdf_analyze(on_success)
|
|
@@ -16,7 +16,7 @@ from cognite.neat._data_model.exporters import (
|
|
|
16
16
|
from cognite.neat._data_model.exporters._table_exporter.workbook import WorkbookOptions
|
|
17
17
|
from cognite.neat._data_model.importers import DMSAPICreator, DMSAPIImporter, DMSImporter, DMSTableImporter
|
|
18
18
|
from cognite.neat._data_model.models.dms import DataModelReference
|
|
19
|
-
from cognite.neat._data_model.
|
|
19
|
+
from cognite.neat._data_model.rules.dms import DmsDataModelRulesOrchestrator
|
|
20
20
|
from cognite.neat._exceptions import UserInputError
|
|
21
21
|
from cognite.neat._state_machine import PhysicalState
|
|
22
22
|
from cognite.neat._store._store import NeatStore
|
|
@@ -109,7 +109,7 @@ class ReadPhysicalDataModel:
|
|
|
109
109
|
else:
|
|
110
110
|
raise UserInputError(f"Unsupported format: {format}. Supported formats are 'neat' and 'toolkit'.")
|
|
111
111
|
|
|
112
|
-
on_success =
|
|
112
|
+
on_success = DmsDataModelRulesOrchestrator(
|
|
113
113
|
modus_operandi=self._config.modeling.mode,
|
|
114
114
|
cdf_snapshot=self._store.cdf_snapshot,
|
|
115
115
|
limits=self._store.cdf_limits,
|
|
@@ -138,7 +138,7 @@ class ReadPhysicalDataModel:
|
|
|
138
138
|
else:
|
|
139
139
|
raise UserInputError(f"Unsupported format: {format}. Supported formats are 'neat' and 'toolkit'.")
|
|
140
140
|
|
|
141
|
-
on_success =
|
|
141
|
+
on_success = DmsDataModelRulesOrchestrator(
|
|
142
142
|
modus_operandi=self._config.modeling.mode,
|
|
143
143
|
cdf_snapshot=self._store.cdf_snapshot,
|
|
144
144
|
limits=self._store.cdf_limits,
|
|
@@ -158,7 +158,7 @@ class ReadPhysicalDataModel:
|
|
|
158
158
|
path = NeatReader.create(io).materialize_path()
|
|
159
159
|
reader = DMSTableImporter.from_excel(path)
|
|
160
160
|
|
|
161
|
-
on_success =
|
|
161
|
+
on_success = DmsDataModelRulesOrchestrator(
|
|
162
162
|
modus_operandi=self._config.modeling.mode,
|
|
163
163
|
cdf_snapshot=self._store.cdf_snapshot,
|
|
164
164
|
limits=self._store.cdf_limits,
|
|
@@ -181,7 +181,7 @@ class ReadPhysicalDataModel:
|
|
|
181
181
|
DataModelReference(space=space, external_id=external_id, version=version), self._client
|
|
182
182
|
)
|
|
183
183
|
|
|
184
|
-
on_success =
|
|
184
|
+
on_success = DmsDataModelRulesOrchestrator(
|
|
185
185
|
modus_operandi=self._config.modeling.mode,
|
|
186
186
|
cdf_snapshot=self._store.cdf_snapshot,
|
|
187
187
|
limits=self._store.cdf_limits,
|
|
@@ -337,7 +337,7 @@ def create(
|
|
|
337
337
|
cdf_snapshot=self._store.cdf_snapshot,
|
|
338
338
|
)
|
|
339
339
|
|
|
340
|
-
on_success =
|
|
340
|
+
on_success = DmsDataModelRulesOrchestrator(
|
|
341
341
|
modus_operandi=self._config.modeling.mode,
|
|
342
342
|
cdf_snapshot=self._store.cdf_snapshot,
|
|
343
343
|
limits=self._store.cdf_limits,
|
|
@@ -28,7 +28,7 @@ def session_wrapper(cls: type[T_Class]) -> type[T_Class]:
|
|
|
28
28
|
identifier = f"{cls.__name__}.{func.__name__}"
|
|
29
29
|
try:
|
|
30
30
|
res = func(self, *args, **kwargs)
|
|
31
|
-
if not self._store.provenance or "DataModel" not in identifier:
|
|
31
|
+
if not self._store.provenance or ("DataModel" not in identifier and "CDF" not in identifier):
|
|
32
32
|
print(f"{display_name} ✅")
|
|
33
33
|
if _COLLECTOR.can_collect:
|
|
34
34
|
_COLLECTOR.collect("action", {"action": identifier, "success": True})
|
|
@@ -34,7 +34,7 @@ class EmptyState(State):
|
|
|
34
34
|
The initial state with empty NEAT store.
|
|
35
35
|
"""
|
|
36
36
|
|
|
37
|
-
def transition(self, event: Any) -> State:
|
|
37
|
+
def transition(self, event: Any | None) -> State:
|
|
38
38
|
if isinstance(event, DMSImporter):
|
|
39
39
|
return PhysicalState()
|
|
40
40
|
return ForbiddenState(self)
|
cognite/neat/_store/_store.py
CHANGED
|
@@ -4,6 +4,7 @@ from datetime import datetime, timezone
|
|
|
4
4
|
from typing import Any, cast
|
|
5
5
|
|
|
6
6
|
from cognite.neat._client.client import NeatClient
|
|
7
|
+
from cognite.neat._client.data_classes import SpaceStatisticsResponse
|
|
7
8
|
from cognite.neat._config import NeatConfig
|
|
8
9
|
from cognite.neat._data_model._shared import OnSuccess, OnSuccessIssuesChecker, OnSuccessResultProducer
|
|
9
10
|
from cognite.neat._data_model._snapshot import SchemaSnapshot
|
|
@@ -36,6 +37,15 @@ class NeatStore:
|
|
|
36
37
|
# Placeholder for CDF schema and limit snapshot
|
|
37
38
|
self._cdf_snapshot: SchemaSnapshot | None = None
|
|
38
39
|
self._cdf_limits: SchemaLimits | None = None
|
|
40
|
+
self._cdf_space_statistics: SpaceStatisticsResponse | None = None
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def cdf_space_statistics(self) -> SpaceStatisticsResponse:
|
|
44
|
+
if self._cdf_space_statistics is None:
|
|
45
|
+
self._cdf_space_statistics = self._client.statistics.space_statistics(
|
|
46
|
+
[space.space for space in self.cdf_snapshot.spaces.keys()]
|
|
47
|
+
)
|
|
48
|
+
return self._cdf_space_statistics
|
|
39
49
|
|
|
40
50
|
@property
|
|
41
51
|
def cdf_limits(self) -> SchemaLimits:
|
|
@@ -91,8 +101,16 @@ class NeatStore:
|
|
|
91
101
|
and isinstance(on_success, SchemaDeployer)
|
|
92
102
|
and not on_success.options.dry_run
|
|
93
103
|
):
|
|
94
|
-
# Update CDF snapshot after
|
|
104
|
+
# Update CDF snapshot and space statistics after deployment
|
|
95
105
|
self._cdf_snapshot = SchemaSnapshot.fetch_entire_cdf(self._client)
|
|
106
|
+
self._cdf_space_statistics = self._client.statistics.space_statistics(
|
|
107
|
+
[space.space for space in self.cdf_snapshot.spaces.keys()]
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
def cdf_analyze(self, on_success: OnSuccess) -> None:
|
|
111
|
+
"""Analyze the entity of CDF data models"""
|
|
112
|
+
change, _ = self._do_activity(lambda: self.cdf_snapshot, on_success)
|
|
113
|
+
self.provenance.append(change)
|
|
96
114
|
|
|
97
115
|
def _gather_data_model(self, writer: DMSExporter) -> PhysicalDataModel:
|
|
98
116
|
"""Gather the current physical data model from the store
|
cognite/neat/_version.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
__version__ = "1.0.
|
|
1
|
+
__version__ = "1.0.32"
|
|
2
2
|
__engine__ = "^2.0.4"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cognite-neat
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.32
|
|
4
4
|
Summary: Knowledge graph transformation
|
|
5
5
|
Author: Nikola Vasiljevic, Anders Albert
|
|
6
6
|
Author-email: Nikola Vasiljevic <nikola.vasiljevic@cognite.com>, Anders Albert <anders.albert@cognite.com>
|