cognite-neat 0.126.0__py3-none-any.whl → 0.126.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 (75) hide show
  1. cognite/neat/_client/__init__.py +4 -0
  2. cognite/neat/_client/api.py +8 -0
  3. cognite/neat/_client/client.py +19 -0
  4. cognite/neat/_client/config.py +40 -0
  5. cognite/neat/_client/containers_api.py +73 -0
  6. cognite/neat/_client/data_classes.py +10 -0
  7. cognite/neat/_client/data_model_api.py +63 -0
  8. cognite/neat/_client/spaces_api.py +67 -0
  9. cognite/neat/_client/views_api.py +82 -0
  10. cognite/neat/_data_model/_analysis.py +127 -0
  11. cognite/neat/_data_model/_constants.py +59 -0
  12. cognite/neat/_data_model/_shared.py +46 -0
  13. cognite/neat/_data_model/deployer/__init__.py +0 -0
  14. cognite/neat/_data_model/deployer/_differ.py +113 -0
  15. cognite/neat/_data_model/deployer/_differ_container.py +354 -0
  16. cognite/neat/_data_model/deployer/_differ_data_model.py +29 -0
  17. cognite/neat/_data_model/deployer/_differ_space.py +9 -0
  18. cognite/neat/_data_model/deployer/_differ_view.py +194 -0
  19. cognite/neat/_data_model/deployer/data_classes.py +176 -0
  20. cognite/neat/_data_model/exporters/__init__.py +4 -0
  21. cognite/neat/_data_model/exporters/_base.py +6 -1
  22. cognite/neat/_data_model/exporters/_table_exporter/__init__.py +0 -0
  23. cognite/neat/_data_model/exporters/_table_exporter/exporter.py +106 -0
  24. cognite/neat/_data_model/exporters/_table_exporter/workbook.py +414 -0
  25. cognite/neat/_data_model/exporters/_table_exporter/writer.py +391 -0
  26. cognite/neat/_data_model/importers/__init__.py +2 -1
  27. cognite/neat/_data_model/importers/_api_importer.py +88 -0
  28. cognite/neat/_data_model/importers/_table_importer/data_classes.py +48 -8
  29. cognite/neat/_data_model/importers/_table_importer/importer.py +74 -5
  30. cognite/neat/_data_model/importers/_table_importer/reader.py +63 -7
  31. cognite/neat/_data_model/models/dms/__init__.py +17 -1
  32. cognite/neat/_data_model/models/dms/_base.py +12 -8
  33. cognite/neat/_data_model/models/dms/_constants.py +1 -1
  34. cognite/neat/_data_model/models/dms/_constraints.py +2 -1
  35. cognite/neat/_data_model/models/dms/_container.py +5 -5
  36. cognite/neat/_data_model/models/dms/_data_model.py +3 -3
  37. cognite/neat/_data_model/models/dms/_data_types.py +8 -1
  38. cognite/neat/_data_model/models/dms/_http.py +18 -0
  39. cognite/neat/_data_model/models/dms/_indexes.py +2 -1
  40. cognite/neat/_data_model/models/dms/_references.py +17 -4
  41. cognite/neat/_data_model/models/dms/_space.py +11 -7
  42. cognite/neat/_data_model/models/dms/_view_property.py +7 -4
  43. cognite/neat/_data_model/models/dms/_views.py +16 -6
  44. cognite/neat/_data_model/validation/__init__.py +0 -0
  45. cognite/neat/_data_model/validation/_base.py +16 -0
  46. cognite/neat/_data_model/validation/dms/__init__.py +9 -0
  47. cognite/neat/_data_model/validation/dms/_orchestrator.py +68 -0
  48. cognite/neat/_data_model/validation/dms/_validators.py +139 -0
  49. cognite/neat/_exceptions.py +15 -3
  50. cognite/neat/_issues.py +39 -6
  51. cognite/neat/_session/__init__.py +3 -0
  52. cognite/neat/_session/_physical.py +88 -0
  53. cognite/neat/_session/_session.py +34 -25
  54. cognite/neat/_session/_wrappers.py +61 -0
  55. cognite/neat/_state_machine/__init__.py +10 -0
  56. cognite/neat/{_session/_state_machine → _state_machine}/_base.py +11 -1
  57. cognite/neat/_state_machine/_states.py +53 -0
  58. cognite/neat/_store/__init__.py +3 -0
  59. cognite/neat/_store/_provenance.py +55 -0
  60. cognite/neat/_store/_store.py +124 -0
  61. cognite/neat/_utils/_reader.py +194 -0
  62. cognite/neat/_utils/http_client/__init__.py +14 -20
  63. cognite/neat/_utils/http_client/_client.py +22 -61
  64. cognite/neat/_utils/http_client/_data_classes.py +167 -268
  65. cognite/neat/_utils/text.py +6 -0
  66. cognite/neat/_utils/useful_types.py +23 -2
  67. cognite/neat/_version.py +1 -1
  68. cognite/neat/v0/core/_data_model/importers/_rdf/_shared.py +2 -2
  69. {cognite_neat-0.126.0.dist-info → cognite_neat-0.126.1.dist-info}/METADATA +1 -1
  70. {cognite_neat-0.126.0.dist-info → cognite_neat-0.126.1.dist-info}/RECORD +72 -38
  71. cognite/neat/_data_model/exporters/_table_exporter.py +0 -35
  72. cognite/neat/_session/_state_machine/__init__.py +0 -23
  73. cognite/neat/_session/_state_machine/_states.py +0 -150
  74. {cognite_neat-0.126.0.dist-info → cognite_neat-0.126.1.dist-info}/WHEEL +0 -0
  75. {cognite_neat-0.126.0.dist-info → cognite_neat-0.126.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,4 @@
1
+ from .client import NeatClient
2
+ from .config import NeatClientConfig
3
+
4
+ __all__ = ["NeatClient", "NeatClientConfig"]
@@ -0,0 +1,8 @@
1
+ from cognite.neat._client.config import NeatClientConfig
2
+ from cognite.neat._utils.http_client import HTTPClient
3
+
4
+
5
+ class NeatAPI:
6
+ def __init__(self, neat_config: NeatClientConfig, http_client: HTTPClient) -> None:
7
+ self._config = neat_config
8
+ self._http_client = http_client
@@ -0,0 +1,19 @@
1
+ from cognite.client import ClientConfig, CogniteClient
2
+
3
+ from cognite.neat._utils.http_client import HTTPClient
4
+
5
+ from .config import NeatClientConfig
6
+ from .containers_api import ContainersAPI
7
+ from .data_model_api import DataModelsAPI
8
+ from .spaces_api import SpacesAPI
9
+ from .views_api import ViewsAPI
10
+
11
+
12
+ class NeatClient:
13
+ def __init__(self, cognite_client_or_config: CogniteClient | ClientConfig) -> None:
14
+ self.config = NeatClientConfig(cognite_client_or_config)
15
+ http_client = HTTPClient(self.config)
16
+ self.data_models = DataModelsAPI(self.config, http_client)
17
+ self.views = ViewsAPI(self.config, http_client)
18
+ self.containers = ContainersAPI(self.config, http_client)
19
+ self.spaces = SpacesAPI(self.config, http_client)
@@ -0,0 +1,40 @@
1
+ from cognite.client import ClientConfig, CogniteClient
2
+
3
+
4
+ class NeatClientConfig(ClientConfig):
5
+ def __init__(self, cognite_client_or_config: CogniteClient | ClientConfig):
6
+ config = (
7
+ cognite_client_or_config.config
8
+ if isinstance(cognite_client_or_config, CogniteClient)
9
+ else cognite_client_or_config
10
+ )
11
+ super().__init__(
12
+ client_name=config.client_name,
13
+ project=config.project,
14
+ credentials=config.credentials,
15
+ api_subversion=config.api_subversion,
16
+ base_url=config.base_url,
17
+ max_workers=config.max_workers,
18
+ headers=config.headers,
19
+ timeout=config.timeout,
20
+ file_transfer_timeout=config.file_transfer_timeout,
21
+ debug=config.debug,
22
+ )
23
+
24
+ def create_api_url(self, endpoint: str) -> str:
25
+ """Create a full API URL for the given endpoint.
26
+
27
+ Args:
28
+ endpoint (str): The API endpoint to append to the base URL.
29
+
30
+ Returns:
31
+ str: The full API URL.
32
+
33
+ Examples:
34
+ >>> config = NeatClientConfig(cluster="bluefield", project="my_project", ...)
35
+ >>> config.create_api_url("/models/instances")
36
+ "https://bluefield.cognitedata.com/api/v1/my_project/models/instances"
37
+ """
38
+ if not endpoint.startswith("/"):
39
+ endpoint = f"/{endpoint}"
40
+ return f"{self.base_url}/api/v1/projects/{self.project}{endpoint}"
@@ -0,0 +1,73 @@
1
+ from __future__ import annotations
2
+
3
+ from cognite.neat._data_model.models.dms import ContainerReference, ContainerResponse
4
+ from cognite.neat._utils.http_client import ItemIDBody, ItemsRequest, ParametersRequest
5
+ from cognite.neat._utils.useful_types import PrimitiveType
6
+
7
+ from .api import NeatAPI
8
+ from .data_classes import PagedResponse
9
+
10
+
11
+ class ContainersAPI(NeatAPI):
12
+ def retrieve(
13
+ self,
14
+ items: list[ContainerReference],
15
+ ) -> list[ContainerResponse]:
16
+ """Retrieve containers by their identifiers.
17
+
18
+ Args:
19
+ items: List of (space, external_id) tuples identifying the containers to retrieve.
20
+
21
+ Returns:
22
+ List of ContainerResponse objects.
23
+ """
24
+ if not items:
25
+ return []
26
+ if len(items) > 1000:
27
+ raise ValueError("Cannot retrieve more than 1000 containers at once.")
28
+
29
+ result = self._http_client.request_with_retries(
30
+ ItemsRequest(
31
+ endpoint_url=self._config.create_api_url("/models/containers/byids"),
32
+ method="POST",
33
+ body=ItemIDBody(items=items),
34
+ )
35
+ )
36
+ result.raise_for_status()
37
+ result = PagedResponse[ContainerResponse].model_validate_json(result.success_response.body)
38
+ return result.items
39
+
40
+ def list(
41
+ self,
42
+ space: str | None = None,
43
+ include_global: bool = False,
44
+ limit: int = 10,
45
+ ) -> list[ContainerResponse]:
46
+ """List containers in CDF Project.
47
+
48
+ Args:
49
+ space: If specified, only containers in this space are returned.
50
+ include_global: If True, include global containers.
51
+ limit: Maximum number of containers to return. Max is 1000.
52
+
53
+ Returns:
54
+ List of ContainerResponse objects.
55
+ """
56
+ if limit > 1000:
57
+ raise ValueError("Pagination is not (yet) supported for listing containers. The maximum limit is 1000.")
58
+ parameters: dict[str, PrimitiveType] = {
59
+ "includeGlobal": include_global,
60
+ "limit": limit,
61
+ }
62
+ if space is not None:
63
+ parameters["space"] = space
64
+ result = self._http_client.request_with_retries(
65
+ ParametersRequest(
66
+ endpoint_url=self._config.create_api_url("/models/containers"),
67
+ method="GET",
68
+ parameters=parameters,
69
+ )
70
+ )
71
+ result.raise_for_status()
72
+ result = PagedResponse[ContainerResponse].model_validate_json(result.success_response.body)
73
+ return result.items
@@ -0,0 +1,10 @@
1
+ from typing import Generic, TypeVar
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+ T = TypeVar("T", bound=BaseModel)
6
+
7
+
8
+ class PagedResponse(BaseModel, Generic[T]):
9
+ items: list[T]
10
+ next_cursor: str | None = Field(None, alias="nextCursor")
@@ -0,0 +1,63 @@
1
+ from cognite.neat._data_model.models.dms import DataModelReference, DataModelResponse
2
+ from cognite.neat._utils.http_client import ItemIDBody, ItemsRequest, ParametersRequest
3
+ from cognite.neat._utils.useful_types import PrimitiveType
4
+
5
+ from .api import NeatAPI
6
+ from .data_classes import PagedResponse
7
+
8
+
9
+ class DataModelsAPI(NeatAPI):
10
+ def retrieve(
11
+ self,
12
+ items: list[DataModelReference],
13
+ ) -> list[DataModelResponse]:
14
+ """Retrieve data models by their identifiers.
15
+
16
+ Args:
17
+ items: List of data models references identifying the data models to retrieve.
18
+ Returns:
19
+ List of DataModelResponse objects.
20
+ """
21
+ if not items:
22
+ return []
23
+ if len(items) > 1000:
24
+ raise ValueError("Cannot retrieve more than 1000 containers at once.")
25
+
26
+ result = self._http_client.request_with_retries(
27
+ ItemsRequest(
28
+ endpoint_url=self._config.create_api_url("/models/datamodels/byids"),
29
+ method="POST",
30
+ body=ItemIDBody(items=items),
31
+ )
32
+ )
33
+ result.raise_for_status()
34
+ result = PagedResponse[DataModelResponse].model_validate_json(result.success_response.body)
35
+ return result.items
36
+
37
+ def list(
38
+ self,
39
+ space: str | None = None,
40
+ all_versions: bool = False,
41
+ include_global: bool = False,
42
+ limit: int = 10,
43
+ ) -> list[DataModelResponse]:
44
+ """List data models in CDF Project."""
45
+ if limit > 1000:
46
+ raise ValueError("Pagination is not (yet) supported for listing data models. The maximum limit is 1000.")
47
+ parameters: dict[str, PrimitiveType] = {
48
+ "allVersions": all_versions,
49
+ "includeGlobal": include_global,
50
+ "limit": limit,
51
+ }
52
+ if space is not None:
53
+ parameters["space"] = space
54
+ result = self._http_client.request_with_retries(
55
+ ParametersRequest(
56
+ endpoint_url=self._config.create_api_url("/models/datamodels"),
57
+ method="GET",
58
+ parameters=parameters,
59
+ )
60
+ )
61
+ result.raise_for_status()
62
+ result = PagedResponse[DataModelResponse].model_validate_json(result.success_response.body)
63
+ return result.items
@@ -0,0 +1,67 @@
1
+ from __future__ import annotations
2
+
3
+ from cognite.neat._data_model.models.dms import SpaceResponse
4
+ from cognite.neat._data_model.models.dms._references import SpaceReference
5
+ from cognite.neat._utils.http_client import ItemIDBody, ItemsRequest, ParametersRequest
6
+ from cognite.neat._utils.useful_types import PrimitiveType
7
+
8
+ from .api import NeatAPI
9
+ from .data_classes import PagedResponse
10
+
11
+
12
+ class SpacesAPI(NeatAPI):
13
+ def retrieve(self, spaces: list[SpaceReference]) -> list[SpaceResponse]:
14
+ """Retrieve spaces by their identifiers.
15
+
16
+ Args:
17
+ spaces: List of space identifiers to retrieve.
18
+
19
+ Returns:
20
+ List of SpaceResponse objects.
21
+ """
22
+ if not spaces:
23
+ return []
24
+ if len(spaces) > 1000:
25
+ raise ValueError("Cannot retrieve more than 1000 spaces at once.")
26
+
27
+ result = self._http_client.request_with_retries(
28
+ ItemsRequest(
29
+ endpoint_url=self._config.create_api_url("/models/spaces/byids"),
30
+ method="POST",
31
+ body=ItemIDBody(items=spaces),
32
+ )
33
+ )
34
+ result.raise_for_status()
35
+ result = PagedResponse[SpaceResponse].model_validate_json(result.success_response.body)
36
+ return result.items
37
+
38
+ def list(
39
+ self,
40
+ include_global: bool = False,
41
+ limit: int = 10,
42
+ ) -> list[SpaceResponse]:
43
+ """List spaces in CDF Project.
44
+
45
+ Args:
46
+ include_global: If True, include global spaces.
47
+ limit: Maximum number of spaces to return. Max is 1000.
48
+
49
+ Returns:
50
+ List of SpaceResponse objects.
51
+ """
52
+ if limit > 1000:
53
+ raise ValueError("Pagination is not (yet) supported for listing spaces. The maximum limit is 1000.")
54
+ parameters: dict[str, PrimitiveType] = {
55
+ "includeGlobal": include_global,
56
+ "limit": limit,
57
+ }
58
+ result = self._http_client.request_with_retries(
59
+ ParametersRequest(
60
+ endpoint_url=self._config.create_api_url("/models/spaces"),
61
+ method="GET",
62
+ parameters=parameters,
63
+ )
64
+ )
65
+ result.raise_for_status()
66
+ result = PagedResponse[SpaceResponse].model_validate_json(result.success_response.body)
67
+ return result.items
@@ -0,0 +1,82 @@
1
+ from __future__ import annotations
2
+
3
+ from cognite.neat._data_model.models.dms import ViewReference, ViewResponse
4
+ from cognite.neat._utils.http_client import ItemIDBody, ItemsRequest, ParametersRequest
5
+ from cognite.neat._utils.useful_types import PrimitiveType
6
+
7
+ from .api import NeatAPI
8
+ from .data_classes import PagedResponse
9
+
10
+
11
+ class ViewsAPI(NeatAPI):
12
+ def retrieve(
13
+ self,
14
+ items: list[ViewReference],
15
+ include_inherited_properties: bool = True,
16
+ ) -> list[ViewResponse]:
17
+ """Retrieve views by their identifiers.
18
+
19
+ Args:
20
+ items: List of (space, external_id, version) tuples identifying the views to retrieve.
21
+ include_inherited_properties: If True, include properties inherited from parent views.
22
+
23
+ Returns:
24
+ List of ViewResponse objects.
25
+ """
26
+ if not items:
27
+ return []
28
+ if len(items) > 1000:
29
+ raise ValueError("Cannot retrieve more than 1000 views at once.")
30
+
31
+ result = self._http_client.request_with_retries(
32
+ ItemsRequest(
33
+ endpoint_url=self._config.create_api_url("/models/views/byids"),
34
+ method="POST",
35
+ body=ItemIDBody(items=items),
36
+ parameters={"includeInheritedProperties": include_inherited_properties},
37
+ )
38
+ )
39
+ result.raise_for_status()
40
+ result = PagedResponse[ViewResponse].model_validate_json(result.success_response.body)
41
+ return result.items
42
+
43
+ def list(
44
+ self,
45
+ space: str | None = None,
46
+ all_versions: bool = False,
47
+ include_inherited_properties: bool = True,
48
+ include_global: bool = False,
49
+ limit: int = 10,
50
+ ) -> list[ViewResponse]:
51
+ """List views in CDF Project.
52
+
53
+ Args:
54
+ space: If specified, only views in this space are returned.
55
+ all_versions: If True, return all versions. If False, only return the latest version.
56
+ include_inherited_properties: If True, include properties inherited from parent views.
57
+ include_global: If True, include global views.
58
+ limit: Maximum number of views to return. Max is 1000.
59
+
60
+ Returns:
61
+ List of ViewResponse objects.
62
+ """
63
+ if limit > 1000:
64
+ raise ValueError("Pagination is not (yet) supported for listing views. The maximum limit is 1000.")
65
+ parameters: dict[str, PrimitiveType] = {
66
+ "allVersions": all_versions,
67
+ "includeInheritedProperties": include_inherited_properties,
68
+ "includeGlobal": include_global,
69
+ "limit": limit,
70
+ }
71
+ if space is not None:
72
+ parameters["space"] = space
73
+ result = self._http_client.request_with_retries(
74
+ ParametersRequest(
75
+ endpoint_url=self._config.create_api_url("/models/views"),
76
+ method="GET",
77
+ parameters=parameters,
78
+ )
79
+ )
80
+ result.raise_for_status()
81
+ result = PagedResponse[ViewResponse].model_validate_json(result.success_response.body)
82
+ return result.items
@@ -0,0 +1,127 @@
1
+ from graphlib import TopologicalSorter
2
+
3
+ from cognite.neat._data_model.models.dms._references import ContainerReference, ViewReference
4
+ from cognite.neat._data_model.models.dms._schema import RequestSchema
5
+ from cognite.neat._data_model.models.dms._view_property import (
6
+ EdgeProperty,
7
+ ReverseDirectRelationProperty,
8
+ ViewCorePropertyRequest,
9
+ )
10
+ from cognite.neat._data_model.models.dms._views import ViewRequest
11
+
12
+
13
+ class DataModelAnalysis:
14
+ def __init__(
15
+ self,
16
+ physical: RequestSchema | None = None,
17
+ ) -> None:
18
+ self._physical = physical
19
+
20
+ @property
21
+ def physical(self) -> RequestSchema:
22
+ if self._physical is None:
23
+ raise ValueError("Physical Data Model is required for this analysis")
24
+ return self._physical
25
+
26
+ def referenced_views(self, include_connection_end_node_types: bool = False) -> set[ViewReference]:
27
+ """Get all referenced views in the physical data model."""
28
+ referenced_views = set()
29
+
30
+ for view in self.physical.views:
31
+ referenced_views.add(view.as_reference())
32
+ if view.implements:
33
+ for implement in view.implements:
34
+ referenced_views.add(implement)
35
+
36
+ if include_connection_end_node_types:
37
+ referenced_views |= set(self.connection_end_node_types.values())
38
+
39
+ return referenced_views
40
+
41
+ @property
42
+ def referenced_containers(self) -> set[ContainerReference]:
43
+ """Get all referenced containers in the physical data model."""
44
+ referenced_containers = set()
45
+
46
+ for view in self.physical.views:
47
+ for property_ in view.properties.values():
48
+ if isinstance(property_, ViewCorePropertyRequest):
49
+ referenced_containers.add(property_.container)
50
+
51
+ for container in self.physical.containers:
52
+ referenced_containers.add(container.as_reference())
53
+
54
+ return referenced_containers
55
+
56
+ @property
57
+ def view_ancestors(self) -> dict[ViewReference, set[ViewReference]]:
58
+ """Get a mapping of each view to its ancestors in the physical data model."""
59
+ implements_by_view = self.implements_by_view
60
+
61
+ # Topological sort to ensure that concepts include all ancestors
62
+ for view in list(TopologicalSorter(implements_by_view).static_order()):
63
+ if view not in implements_by_view:
64
+ continue
65
+ implements_by_view[view] |= {
66
+ grand_parent
67
+ for parent in implements_by_view[view]
68
+ for grand_parent in implements_by_view.get(parent, set())
69
+ }
70
+
71
+ return implements_by_view
72
+
73
+ @property
74
+ def implements_by_view(self) -> dict[ViewReference, set[ViewReference]]:
75
+ """Get a mapping of each view to the views it implements."""
76
+ implements_mapping: dict[ViewReference, set[ViewReference]] = {}
77
+
78
+ for view in self.physical.views:
79
+ view_ref = view.as_reference()
80
+ if view_ref not in implements_mapping:
81
+ implements_mapping[view_ref] = set()
82
+ if view.implements:
83
+ for implement in view.implements:
84
+ implements_mapping[view_ref].add(implement)
85
+
86
+ return implements_mapping
87
+
88
+ def view_by_reference(self, include_inherited_properties: bool = True) -> dict[ViewReference, ViewRequest]:
89
+ """Get a mapping of view references to their corresponding ViewRequest objects."""
90
+ view_ancestors = self.view_ancestors
91
+
92
+ view_by_reference: dict[ViewReference, ViewRequest] = {
93
+ view.as_reference(): view.model_copy(deep=True) for view in self.physical.views
94
+ }
95
+
96
+ if include_inherited_properties:
97
+ for ref, view in view_by_reference.items():
98
+ for ancestor in view_ancestors.get(ref, set()):
99
+ if ancestor_view := view_by_reference.get(ancestor):
100
+ if ancestor_view.properties:
101
+ view.properties.update(ancestor_view.properties)
102
+
103
+ return view_by_reference
104
+
105
+ @property
106
+ def connection_end_node_types(self) -> dict[tuple[ViewReference, str], ViewReference]:
107
+ """Get a mapping of view references to their corresponding ViewRequest objects."""
108
+ view_by_reference = self.view_by_reference(include_inherited_properties=False)
109
+ connection_end_node_types: dict[tuple[ViewReference, str], ViewReference] = {}
110
+
111
+ for view_ref, view in view_by_reference.items():
112
+ if not view.properties:
113
+ continue
114
+ for prop_ref, property_ in view.properties.items():
115
+ # direct relation
116
+ if isinstance(property_, ViewCorePropertyRequest) and property_.source:
117
+ connection_end_node_types[(view_ref, prop_ref)] = property_.source
118
+
119
+ # reverse direct relation
120
+ if isinstance(property_, ReverseDirectRelationProperty) and property_.source:
121
+ connection_end_node_types[(view_ref, prop_ref)] = property_.source
122
+
123
+ # edge property
124
+ if isinstance(property_, EdgeProperty) and property_.source:
125
+ connection_end_node_types[(view_ref, prop_ref)] = property_.source
126
+
127
+ return connection_end_node_types
@@ -1,3 +1,62 @@
1
1
  from ._identifiers import NameSpace
2
2
 
3
3
  XML_SCHEMA_NAMESPACE = NameSpace("http://www.w3.org/2001/XMLSchema#")
4
+
5
+ CDF_CDM_SPACE = "cdf_cdm"
6
+ CDF_CDM_VERSION = "v1"
7
+
8
+ COGNITE_CONCEPTS_MAIN = (
9
+ "CogniteAsset",
10
+ "CogniteEquipment",
11
+ "CogniteActivity",
12
+ "CogniteTimeSeries",
13
+ "CogniteFile",
14
+ )
15
+
16
+ COGNITE_CONCEPTS_INTERFACES = (
17
+ "CogniteDescribable",
18
+ "CogniteSourceable",
19
+ "CogniteSchedulable",
20
+ "CogniteVisualizable",
21
+ )
22
+
23
+ COGNITE_CONCEPTS_CONFIGURATIONS = (
24
+ "CogniteSourceSystem",
25
+ "CogniteUnit",
26
+ "CogniteAssetClass",
27
+ "CogniteAssetType",
28
+ "CogniteEquipmentType",
29
+ "CogniteFileCategory",
30
+ )
31
+ COGNITE_CONCEPTS_ANNOTATIONS = (
32
+ "CogniteAnnotation",
33
+ "CogniteDiagramAnnotation",
34
+ )
35
+ COGNITE_CONCEPTS_3D = (
36
+ "CogniteCubeMap",
37
+ "CogniteCADRevision",
38
+ "CognitePointCloudVolume",
39
+ "Cognite360ImageAnnotation",
40
+ "Cognite3DObject",
41
+ "Cognite3DRevision",
42
+ "Cognite360Image",
43
+ "Cognite360ImageCollection",
44
+ "Cognite360ImageStation",
45
+ "CognitePointCloudModel",
46
+ "Cognite3DTransformation",
47
+ "Cognite360ImageModel",
48
+ "Cognite3DModel",
49
+ "CogniteCADModel",
50
+ "CognitePointCloudRevision",
51
+ "CogniteCADNode",
52
+ )
53
+
54
+ COGNITE_CONCEPTS: tuple[str, ...] = (
55
+ *COGNITE_CONCEPTS_MAIN,
56
+ *COGNITE_CONCEPTS_INTERFACES,
57
+ *COGNITE_CONCEPTS_CONFIGURATIONS,
58
+ *COGNITE_CONCEPTS_ANNOTATIONS,
59
+ *COGNITE_CONCEPTS_3D,
60
+ )
61
+
62
+ COGNITE_SPACES = (CDF_CDM_SPACE,)
@@ -0,0 +1,46 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Any
3
+
4
+ from cognite.neat._client.client import NeatClient
5
+ from cognite.neat._issues import IssueList
6
+
7
+
8
+ class OnSuccess(ABC):
9
+ """Abstract base class for post-activity success handlers."""
10
+
11
+ def __init__(self, client: NeatClient | None = None) -> None:
12
+ self._client = client
13
+ self._issues: IssueList = IssueList()
14
+ self._results: list = []
15
+ self._has_run = False
16
+
17
+ @property
18
+ def issues(self) -> IssueList:
19
+ """List of issues found during the success handler execution."""
20
+ if not self._has_run:
21
+ raise RuntimeError("OnSuccess handler has not been run yet.")
22
+ return self._issues
23
+
24
+ @property
25
+ def results(self) -> list:
26
+ """List of results produced during the success handler execution."""
27
+ if not self._has_run:
28
+ raise RuntimeError("OnSuccess handler has not been run yet.")
29
+ return self._results
30
+
31
+ @abstractmethod
32
+ def run(self, data_model: Any) -> None:
33
+ """Execute the success handler on the data model."""
34
+ pass
35
+
36
+
37
+ class OnSuccessIssuesChecker(OnSuccess):
38
+ """Abstract base class for post-activity success handlers that check for issues of the data model."""
39
+
40
+ ...
41
+
42
+
43
+ class OnSuccessResultProducer(OnSuccess):
44
+ """Abstract base class for post-activity success handlers that produce desired outcomes using the data model."""
45
+
46
+ ...
File without changes