cognite-neat 0.123.22__py3-none-any.whl → 0.123.23__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.

cognite/neat/_version.py CHANGED
@@ -1,2 +1,2 @@
1
- __version__ = "0.123.22"
1
+ __version__ = "0.123.23"
2
2
  __engine__ = "^2.0.4"
@@ -161,3 +161,9 @@ def get_parameters_by_method(obj: object, prefix: str = "") -> dict[str, dict[st
161
161
  def get_parameters(obj: Callable) -> dict[str, type]:
162
162
  annotations = inspect.get_annotations(obj)
163
163
  return {name: annotations[name] for name in annotations if name != "return"}
164
+
165
+
166
+ def filter_kwargs_by_method(kwargs: dict[str, Any], method: Callable) -> dict[str, Any]:
167
+ """Filter kwargs by method parameters."""
168
+ signature = inspect.signature(method)
169
+ return {k: v for k, v in kwargs.items() if k in signature.parameters}
@@ -2,6 +2,7 @@ from cognite.neat.core._data_model.models.conceptual._verified import Conceptual
2
2
  from cognite.neat.core._data_model.models.physical._verified import PhysicalDataModel
3
3
  from cognite.neat.session._session._data_model._read import ReadAPI
4
4
  from cognite.neat.session._session._data_model._show import ShowAPI
5
+ from cognite.neat.session._session._data_model._write import WriteAPI
5
6
  from cognite.neat.session._state import SessionState
6
7
  from cognite.neat.session.exceptions import session_class_wrapper
7
8
 
@@ -13,6 +14,7 @@ class DataModelAPI:
13
14
  def __init__(self, state: SessionState) -> None:
14
15
  self._state = state
15
16
  self.read = ReadAPI(state)
17
+ self.write = WriteAPI(state)
16
18
  self.show = ShowAPI(state)
17
19
 
18
20
  @property
@@ -0,0 +1,335 @@
1
+ import warnings
2
+ from pathlib import Path
3
+ from typing import Any, Literal, cast, overload
4
+
5
+ from cognite.client.data_classes.data_modeling import DataModelIdentifier
6
+
7
+ from cognite.neat.core._client._api_client import NeatClient
8
+ from cognite.neat.core._constants import COGNITE_MODELS
9
+ from cognite.neat.core._data_model import exporters
10
+ from cognite.neat.core._data_model._shared import VerifiedDataModel
11
+ from cognite.neat.core._data_model.importers._dms2data_model import DMSImporter
12
+ from cognite.neat.core._data_model.models.conceptual._verified import ConceptualDataModel
13
+ from cognite.neat.core._data_model.models.physical._verified import PhysicalDataModel, PhysicalMetadata
14
+ from cognite.neat.core._issues._base import IssueList
15
+ from cognite.neat.core._issues._contextmanagers import catch_issues
16
+ from cognite.neat.core._utils.auxiliary import filter_kwargs_by_method
17
+ from cognite.neat.core._utils.reader._base import NeatReader
18
+ from cognite.neat.core._utils.upload import UploadResultList
19
+ from cognite.neat.session._state import SessionState
20
+ from cognite.neat.session.exceptions import NeatSessionError, session_class_wrapper
21
+
22
+ InternalWriterName = Literal["excel", "ontology", "shacl", "cdf", "yaml"]
23
+
24
+
25
+ @session_class_wrapper
26
+ class WriteAPI:
27
+ def __init__(self, state: SessionState) -> None:
28
+ self._state = state
29
+
30
+ def __call__(
31
+ self, name: str, io: str | Path | None = None, **kwargs: Any
32
+ ) -> str | UploadResultList | IssueList | None:
33
+ """Provides access to the writers for exporting data models to different formats.
34
+
35
+ Args:
36
+ name (str): The name of format (e.g. Excel) writer is handling.
37
+ io (str | Path | None): The input/output interface for the writer.
38
+ **kwargs (Any): Additional keyword arguments for the writer.
39
+
40
+ !!! note "kwargs"
41
+ Users must consult the documentation of the writer
42
+ to understand what keyword arguments are supported.
43
+ """
44
+
45
+ # Clean the input name once before matching.
46
+ clean_name: InternalWriterName | str = name.strip().lower()
47
+
48
+ match clean_name:
49
+ case "excel":
50
+ if io is None:
51
+ raise NeatSessionError("'io' parameter is required for Excel format.")
52
+ return self.excel(cast(str | Path, io), **filter_kwargs_by_method(kwargs, self.excel))
53
+ case "cdf":
54
+ return self.cdf(**filter_kwargs_by_method(kwargs, self.cdf))
55
+ case "yaml":
56
+ return self.yaml(io, **filter_kwargs_by_method(kwargs, self.yaml))
57
+ case "ontology":
58
+ if io is None:
59
+ raise NeatSessionError("'io' parameter is required for ontology format.")
60
+ self.ontology(cast(str | Path, io))
61
+ return None
62
+ case "shacl":
63
+ if io is None:
64
+ raise NeatSessionError("'io' parameter is required for SHACL format.")
65
+ self.shacl(cast(str | Path, io))
66
+ return None
67
+ case _:
68
+ raise NeatSessionError(
69
+ f"Unsupported data model writer: {name}. "
70
+ "Please use one of the following: 'excel', 'cdf', 'yaml', 'ontology', 'shacl'."
71
+ )
72
+
73
+ def excel(
74
+ self,
75
+ io: str | Path,
76
+ *,
77
+ include_reference: bool | DataModelIdentifier = True,
78
+ include_properties: Literal["same-space", "all"] = "all",
79
+ add_empty_rows: bool = False,
80
+ ) -> IssueList | None:
81
+ """Export the verified data model to Excel.
82
+
83
+ Args:
84
+ io: The file path or file-like object to write the Excel file to.
85
+ include_reference: If True, the reference data model will be included. Defaults to True.
86
+ Note that this only applies if you have created the data model using the
87
+ create.enterprise_model(...), create.solution_model(), or create.data_product_model() methods.
88
+ You can also provide a DataModelIdentifier directly, which will be read from CDF
89
+ include_properties: The properties to include in the Excel file. Defaults to "all".
90
+ - "same-space": Only properties that are in the same space as the data model will be included.
91
+ add_empty_rows: If True, empty rows will be added between each component. Defaults to False.
92
+
93
+ Example:
94
+ Export conceptual data model to an Excel file
95
+ ```python
96
+ conceptual_dm_file_name = "conceptual_data_model.xlsx"
97
+ neat.data_model.write.excel(conceptual_dm_file_name)
98
+ ```
99
+
100
+ Example:
101
+ Read CogniteCore model, convert it to an enterprise model, and export it to an excel file
102
+ ```python
103
+ client = CogniteClient()
104
+ neat = NeatSession(client)
105
+
106
+ neat.data_model.read.cdf(("cdf_cdm", "CogniteCore", "v1"))
107
+ neat.data_model.create.enterprise_model(
108
+ data_model_id=("sp_doctrino_space", "ExtensionCore", "v1"),
109
+ org_name="MyOrg",
110
+ )
111
+ physical_dm_file_name = "physical_dm.xlsx"
112
+ neat.data_model.write.excel(physical_dm_file_name, include_reference=True)
113
+ ```
114
+
115
+ Example:
116
+ Read the data model ("my_space", "ISA95Model", "v5") and export it to an excel file with the
117
+ CogniteCore model in the reference sheets.
118
+ ```python
119
+ client = CogniteClient()
120
+ neat = NeatSession(client)
121
+
122
+ neat.data_model.read.cdf(("my_space", "ISA95Model", "v5"))
123
+ physical_dm_file_name = "physical_dm.xlsx"
124
+ neat.data_model.write.excel(physical_dm_file_name, include_reference=("cdf_cdm", "CogniteCore", "v1"))
125
+ """
126
+ reference_data_model_with_prefix: tuple[VerifiedDataModel, str] | None = None
127
+ include_properties = include_properties.strip().lower()
128
+ if include_properties not in ["same-space", "all"]:
129
+ raise NeatSessionError(
130
+ f"Invalid include_properties value: '{include_properties}'. Must be 'same-space' or 'all'."
131
+ )
132
+
133
+ if include_reference is not False:
134
+ if include_reference is True and self._state.last_reference is not None:
135
+ ref_data_model: ConceptualDataModel | PhysicalDataModel | None = self._state.last_reference
136
+ elif include_reference is True:
137
+ ref_data_model = None
138
+ else:
139
+ if not self._state.client:
140
+ raise NeatSessionError("No client provided!")
141
+ ref_data_model = None
142
+ with catch_issues() as issues:
143
+ ref_read = DMSImporter.from_data_model_id(self._state.client, include_reference).to_data_model()
144
+ if ref_read.unverified_data_model is not None:
145
+ ref_data_model = ref_read.unverified_data_model.as_verified_data_model()
146
+ if ref_data_model is None or issues.has_errors:
147
+ issues.action = f"Read {include_reference}"
148
+ return issues
149
+ if ref_data_model is not None:
150
+ prefix = "Ref"
151
+ if (
152
+ isinstance(ref_data_model.metadata, PhysicalMetadata)
153
+ and ref_data_model.metadata.as_data_model_id() in COGNITE_MODELS
154
+ ):
155
+ prefix = "CDM"
156
+ reference_data_model_with_prefix = ref_data_model, prefix
157
+
158
+ exporter = exporters.ExcelExporter(
159
+ styling="maximal",
160
+ reference_data_model_with_prefix=reference_data_model_with_prefix,
161
+ add_empty_rows=add_empty_rows,
162
+ include_properties=cast(Literal["same-space", "all"], include_properties),
163
+ )
164
+ self._state.data_model_store.export_to_file(exporter, NeatReader.create(io).materialize_path())
165
+ return None
166
+
167
+ def cdf(
168
+ self,
169
+ *,
170
+ existing: Literal["fail", "skip", "update", "force", "recreate"] = "update",
171
+ dry_run: bool = False,
172
+ drop_data: bool = False,
173
+ ) -> UploadResultList:
174
+ """Export the verified DMS data model to CDF.
175
+
176
+ Args:
177
+ existing: What to do if the component already exists. Defaults to "update".
178
+ See the note below for more information about the options.
179
+ dry_run: If True, no changes will be made to CDF. Defaults to False.
180
+ drop_data: If existing is 'force' or 'recreate' and the operation will lead to data loss,
181
+ the component will be skipped unless drop_data is True. Defaults to False.
182
+ Note this only applies to spaces and containers if they contain data.
183
+
184
+ !!! note "Data Model creation modes"
185
+ - "fail": If any component already exists, the export will fail.
186
+ - "skip": If any component already exists, it will be skipped.
187
+ - "update": If any component already exists, it will be updated. For data models, views, and containers
188
+ this means combining the existing and new component. Fo example, for data models the new
189
+ views will be added to the existing views.
190
+ - "force": If any component already exists, and the update fails, it will be deleted and recreated.
191
+ - "recreate": All components will be deleted and recreated. The exception is spaces, which will be updated.
192
+
193
+ """
194
+
195
+ self._state._raise_exception_if_condition_not_met(
196
+ "Export DMS data model to CDF",
197
+ client_required=True,
198
+ )
199
+
200
+ exporter = exporters.DMSExporter(existing=existing, drop_data=drop_data)
201
+
202
+ result = self._state.data_model_store.export_to_cdf(exporter, cast(NeatClient, self._state.client), dry_run)
203
+ print("You can inspect the details with the .inspect.outcome.data_model(...) method.")
204
+ return result
205
+
206
+ @overload
207
+ def yaml(
208
+ self,
209
+ io: None,
210
+ *,
211
+ format: Literal["neat", "toolkit"] = "neat",
212
+ skip_system_spaces: bool = True,
213
+ ) -> str: ...
214
+
215
+ @overload
216
+ def yaml(
217
+ self,
218
+ io: str | Path,
219
+ *,
220
+ format: Literal["neat", "toolkit"] = "neat",
221
+ skip_system_spaces: bool = True,
222
+ ) -> None: ...
223
+
224
+ def yaml(
225
+ self,
226
+ io: str | Path | None = None,
227
+ *,
228
+ format: Literal["neat", "toolkit"] = "neat",
229
+ skip_system_spaces: bool = True,
230
+ ) -> str | None:
231
+ """Export the verified data model to YAML.
232
+
233
+ Args:
234
+ io: The file path or file-like object to write the YAML file to. Defaults to None.
235
+ format: The format of the YAML file. Defaults to "neat".
236
+ skip_system_spaces: If True, system spaces will be skipped. Defaults to True.
237
+
238
+ !!! note "YAML formats"
239
+ - "neat": This is the format Neat uses to store the data model.
240
+ - "toolkit": This is the format used by Cognite Toolkit, that matches the CDF API.
241
+
242
+ Returns:
243
+ str | None: If io is None, the YAML string will be returned. Otherwise, None will be returned.
244
+
245
+ Example:
246
+ Export to yaml file in the case of "neat" format
247
+ ```python
248
+ your_yaml_file_name = "neat_dm.yaml"
249
+ neat.data_model.write.yaml(your_yaml_file_name, format="neat")
250
+ ```
251
+
252
+ Example:
253
+ Export yaml files as a zip folder in the case of "toolkit" format
254
+ ```python
255
+ your_zip_folder_name = "toolkit_data_model_files.zip"
256
+ neat.data_model.write.yaml(your_zip_folder_name, format="toolkit")
257
+ ```
258
+
259
+ Example:
260
+ Export yaml files to a folder in the case of "toolkit" format
261
+ ```python
262
+ your_folder_name = "my_project/data_model_files"
263
+ neat.data_model.write.yaml(your_folder_name, format="toolkit")
264
+ ```
265
+ """
266
+
267
+ if format == "neat":
268
+ exporter = exporters.YAMLExporter()
269
+ if io is None:
270
+ return self._state.data_model_store.export(exporter)
271
+
272
+ self._state.data_model_store.export_to_file(exporter, NeatReader.create(io).materialize_path())
273
+ elif format == "toolkit":
274
+ if io is None:
275
+ raise NeatSessionError(
276
+ "Please provide a zip file or directory path to write the YAML files to."
277
+ "This is required for the 'toolkit' format."
278
+ )
279
+ user_path = NeatReader.create(io).materialize_path()
280
+ if user_path.suffix == "" and not user_path.exists():
281
+ user_path.mkdir(parents=True)
282
+ self._state.data_model_store.export_to_file(
283
+ exporters.DMSExporter(remove_cdf_spaces=skip_system_spaces), user_path
284
+ )
285
+ else:
286
+ raise NeatSessionError("Please provide a valid format. 'neat' or 'toolkit'")
287
+
288
+ return None
289
+
290
+ def ontology(self, io: str | Path) -> None:
291
+ """Write out data model as OWL ontology.
292
+
293
+ Args:
294
+ io: The file path to file-like object to write the session to.
295
+
296
+ Example:
297
+ Export the session to a file
298
+ ```python
299
+ ontology_file_name = "neat_session.ttl"
300
+ neat.data_model.write.ontology(ontology_file_name)
301
+ ```
302
+ """
303
+
304
+ filepath = self._prepare_ttl_filepath(io)
305
+ exporter = exporters.OWLExporter()
306
+ self._state.data_model_store.export_to_file(exporter, filepath)
307
+ return None
308
+
309
+ def shacl(self, io: str | Path) -> None:
310
+ """Write out data model as SHACL shapes.
311
+
312
+ Args:
313
+ io: The file path to file-like object to write the session to.
314
+
315
+ Example:
316
+ Export the session to a file
317
+ ```python
318
+ shacl_file_name = "neat_session.shacl.ttl"
319
+ neat.data_model.write.shacl(shacl_file_name)
320
+ ```
321
+ """
322
+
323
+ filepath = self._prepare_ttl_filepath(io)
324
+ exporter = exporters.SHACLExporter()
325
+ self._state.data_model_store.export_to_file(exporter, filepath)
326
+ return None
327
+
328
+ def _prepare_ttl_filepath(self, io: str | Path) -> Path:
329
+ """Ensures the filepath has a .ttl extension, adding it if missing."""
330
+ filepath = NeatReader.create(io).materialize_path()
331
+ if filepath.suffix != ".ttl":
332
+ warnings.filterwarnings("default")
333
+ warnings.warn("File extension is not .ttl, adding it to the file name", stacklevel=2)
334
+ filepath = filepath.with_suffix(".ttl")
335
+ return filepath
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cognite-neat
3
- Version: 0.123.22
3
+ Version: 0.123.23
4
4
  Summary: Knowledge graph transformation
5
5
  Project-URL: Documentation, https://cognite-neat.readthedocs-hosted.com/
6
6
  Project-URL: Homepage, https://cognite-neat.readthedocs-hosted.com/
@@ -1,5 +1,5 @@
1
1
  cognite/neat/__init__.py,sha256=12StS1dzH9_MElqxGvLWrNsxCJl9Hv8A2a9D0E5OD_U,193
2
- cognite/neat/_version.py,sha256=F_PTAPIzLmGDm4RPxIsNpijbHtxGJrALannZQ5hHcUY,47
2
+ cognite/neat/_version.py,sha256=0ecHvh-Qq-gIDd9cT8TLmFo99So1sxYnycVfCgckPL8,47
3
3
  cognite/neat/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  cognite/neat/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  cognite/neat/core/_config.py,sha256=WT1BS8uADcFvGoUYOOfwFOVq_VBl472TisdoA3wLick,280
@@ -145,7 +145,7 @@ cognite/neat/core/_store/_provenance.py,sha256=aMEsq27dZ4NZ6XEC8hA0fIDF13i1ZP3Qw
145
145
  cognite/neat/core/_store/exceptions.py,sha256=jcd1Gv65mfTdC4cipFAMWUNghEmdLS_lwPH1FB_ebxI,1656
146
146
  cognite/neat/core/_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
147
147
  cognite/neat/core/_utils/auth.py,sha256=tP_diUZdtacUkM8TLlbSOyHlNcq9VGh-4o_7myWRU_o,14763
148
- cognite/neat/core/_utils/auxiliary.py,sha256=nQAvIysrtigDTefuxTRGFiNUUBYy-iSDJPhvw-6RB50,6859
148
+ cognite/neat/core/_utils/auxiliary.py,sha256=FpeVlscVue4QFaUM3jt7LLiAMkiec6IvpYrPlDUzKM8,7112
149
149
  cognite/neat/core/_utils/collection_.py,sha256=zVrSmm4045pjw6Pt6y4VPTIJ4dXdMJPyOV70LdFyDBM,2376
150
150
  cognite/neat/core/_utils/graph_transformations_report.py,sha256=ORVH7lw357TPOq4elU5lH46Qx6GCLVrSj-1nX6Ggk1U,1235
151
151
  cognite/neat/core/_utils/io_.py,sha256=D2Mg8sOxfBoDg3fC0jBzaxO3vkXmr0QvZSgYIv6xRkM,386
@@ -187,14 +187,15 @@ cognite/neat/session/exceptions.py,sha256=z5jxwfVTXDCCFZKTTYVIaksNKqb9CMa2tyIZgy
187
187
  cognite/neat/session/_session/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
188
188
  cognite/neat/session/_session/_data_model/__init__.py,sha256=417QF6wm3r-bLTmhYGXL_5XnEFShCklLCoGg3YBOIqY,62
189
189
  cognite/neat/session/_session/_data_model/_read.py,sha256=B_mVOt_9uKzG5vbrZG2Uf5D0FQGjcCDEdfAhIp2veUI,7902
190
- cognite/neat/session/_session/_data_model/_routes.py,sha256=wF83vLtmgyGCM2zxnHq0m3-sPQXQamObc58u2kSN7nQ,1666
190
+ cognite/neat/session/_session/_data_model/_routes.py,sha256=FtCMbqvji2KqAPDkZ4yXXp_Fuf6mSFTpNRyVfWOMzFE,1773
191
191
  cognite/neat/session/_session/_data_model/_show.py,sha256=yX4BTIeBzcCcllfJvGm8g4qy13heFmcJtpXPixI8T2o,5835
192
+ cognite/neat/session/_session/_data_model/_write.py,sha256=qpb15cnGLknkDkxKndpdvLxhsmJ4XkXfuFD4-CDw0qE,14612
192
193
  cognite/neat/session/_state/README.md,sha256=o6N7EL98lgyWffw8IoEUf2KG5uSKveD5__TW45YzVjA,902
193
194
  cognite/neat/session/engine/__init__.py,sha256=D3MxUorEs6-NtgoICqtZ8PISQrjrr4dvca6n48bu_bI,120
194
195
  cognite/neat/session/engine/_import.py,sha256=1QxA2_EK613lXYAHKQbZyw2yjo5P9XuiX4Z6_6-WMNQ,169
195
196
  cognite/neat/session/engine/_interface.py,sha256=3W-cYr493c_mW3P5O6MKN1xEQg3cA7NHR_ev3zdF9Vk,533
196
197
  cognite/neat/session/engine/_load.py,sha256=g52uYakQM03VqHt_RDHtpHso1-mFFifH5M4T2ScuH8A,5198
197
- cognite_neat-0.123.22.dist-info/METADATA,sha256=cIvYIW2976HqHJSdiseJuSEG3om5ldv2Z-csEbZQt6Y,9172
198
- cognite_neat-0.123.22.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
199
- cognite_neat-0.123.22.dist-info/licenses/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
200
- cognite_neat-0.123.22.dist-info/RECORD,,
198
+ cognite_neat-0.123.23.dist-info/METADATA,sha256=f78SKr8-LucvAchjKK1niKDLVAWwdadAm5x4dOdl_5s,9172
199
+ cognite_neat-0.123.23.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
200
+ cognite_neat-0.123.23.dist-info/licenses/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
201
+ cognite_neat-0.123.23.dist-info/RECORD,,