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,414 @@
1
+ import itertools
2
+ from collections.abc import Mapping, Set
3
+ from dataclasses import dataclass
4
+ from functools import lru_cache
5
+ from typing import Literal, cast
6
+
7
+ from openpyxl import Workbook
8
+ from openpyxl.cell import MergedCell
9
+ from openpyxl.styles import Border, Font, PatternFill, Side
10
+ from openpyxl.utils import get_column_letter
11
+ from openpyxl.worksheet.datavalidation import DataValidation
12
+ from openpyxl.worksheet.worksheet import Worksheet
13
+
14
+ from cognite.neat._data_model._constants import (
15
+ CDF_CDM_SPACE,
16
+ CDF_CDM_VERSION,
17
+ COGNITE_CONCEPTS_3D,
18
+ COGNITE_CONCEPTS_ANNOTATIONS,
19
+ COGNITE_CONCEPTS_CONFIGURATIONS,
20
+ COGNITE_CONCEPTS_INTERFACES,
21
+ COGNITE_CONCEPTS_MAIN,
22
+ )
23
+ from cognite.neat._data_model.importers._table_importer.data_classes import DMSContainer, DMSProperty, DMSView, TableDMS
24
+ from cognite.neat._data_model.models.dms import (
25
+ DMS_DATA_TYPES,
26
+ EnumProperty,
27
+ FileCDFExternalIdReference,
28
+ SequenceCDFExternalIdReference,
29
+ TimeseriesCDFExternalIdReference,
30
+ )
31
+ from cognite.neat._utils.useful_types import CellValueType, DataModelTableType
32
+
33
+ MAIN_HEADERS_BY_SHEET_NAME: Mapping[str, str] = {
34
+ "Properties": "Definition of Properties",
35
+ "Views": "Definition of Views",
36
+ "Containers": "Definition of Containers",
37
+ "Nodes": "Definition of Nodes",
38
+ "Enum": "Definition of Enum Collections",
39
+ }
40
+ MAX_COLUMN_WIDTH = 70.0
41
+ HEADER_ROWS = 2
42
+
43
+
44
+ @dataclass
45
+ class WorkbookOptions:
46
+ """Options for creating an Excel workbook from a data model.
47
+
48
+ Attributes:
49
+ adjust_column_width (bool): Whether to adjust the column widths to fit the content. Default
50
+ is True.
51
+ style_headers (bool): Whether to style the header rows. Default is True.
52
+ row_band_highlighting (bool): Whether to apply row band highlighting to the properties sheet.
53
+ Default is True.
54
+ separate_view_properties (bool): Whether to separate properties by view with an empty row.
55
+ Default is False.
56
+ add_dropdowns (bool): Whether to add drop-down menus for certain columns. Default is True.
57
+ dropdown_implements (Set[Literal["main", "interface", "configuration", "annotation", "3D"]]):
58
+ The types of Cognite concepts to include in the "implements" drop-down menu. Default is
59
+ {"main", "interface"}.
60
+ max_views (int): The maximum number of views to support in the drop-down menus. Default is 100.
61
+ max_containers (int): The maximum number of containers to support in the drop-down menus. Default is 100.
62
+ max_properties_per_view (int): The maximum number of properties per view to support in the
63
+ drop-down menus. Default is 100.
64
+ """
65
+
66
+ adjust_column_width: bool = True
67
+ style_headers: bool = True
68
+ row_band_highlighting: bool = True
69
+ separate_view_properties: bool = False
70
+ add_dropdowns: bool = True
71
+ dropdown_implements: Set[Literal["main", "interface", "configuration", "annotation", "3D"]] = frozenset(
72
+ {"main", "interface"}
73
+ )
74
+ max_views: int = 100
75
+ max_containers: int = 100
76
+ max_properties_per_view: int = 100
77
+
78
+
79
+ class WorkbookCreator:
80
+ # skip types which require special handling (enum) or are surpassed by CDM (CDF references)
81
+ DROPDOWN_DMS_TYPE_EXCLUDE = frozenset(
82
+ {
83
+ # MyPy does not understand that model_fields is in all pydantic classes.
84
+ prop.model_fields["type"].default # type: ignore[attr-defined]
85
+ for prop in [
86
+ EnumProperty,
87
+ TimeseriesCDFExternalIdReference,
88
+ SequenceCDFExternalIdReference,
89
+ FileCDFExternalIdReference,
90
+ ]
91
+ }
92
+ )
93
+
94
+ # These classer are used to refer to sheets that needs to be explicitly checked for in the
95
+ # workbook creation.
96
+ class Sheets:
97
+ metadata = cast(str, TableDMS.model_fields["metadata"].validation_alias)
98
+ properties = cast(str, TableDMS.model_fields["properties"].validation_alias)
99
+ views = cast(str, TableDMS.model_fields["views"].validation_alias)
100
+ containers = cast(str, TableDMS.model_fields["containers"].validation_alias)
101
+ dropdown_source = "_dropdown_source"
102
+
103
+ # The following classes are used to refer to sheets and columns that are used
104
+ # in dropdown creation.
105
+ class PropertyColumns:
106
+ view = cast(str, DMSProperty.model_fields["view"].validation_alias)
107
+ value_type = cast(str, DMSProperty.model_fields["value_type"].validation_alias)
108
+ immutable = cast(str, DMSProperty.model_fields["immutable"].validation_alias)
109
+ container = cast(str, DMSProperty.model_fields["container"].validation_alias)
110
+
111
+ class ContainerColumns:
112
+ container = cast(str, DMSContainer.model_fields["container"].validation_alias)
113
+ used_for = cast(str, DMSContainer.model_fields["used_for"].validation_alias)
114
+
115
+ class ViewColumns:
116
+ view = cast(str, DMSView.model_fields["view"].validation_alias)
117
+ implements = cast(str, DMSView.model_fields["implements"].validation_alias)
118
+ in_model = cast(str, DMSView.model_fields["in_model"].validation_alias)
119
+
120
+ class DropdownSourceColumns:
121
+ view = 1
122
+ implements = 2
123
+ value_type = 3
124
+ container = 4
125
+ in_model = 5
126
+ immutable = 5
127
+ used_for = 6
128
+
129
+ def __init__(self, options: WorkbookOptions | None = None) -> None:
130
+ options = options or WorkbookOptions()
131
+ self._adjust_column_width = options.adjust_column_width
132
+ self._style_headers = options.style_headers
133
+ self._row_band_highlighting = options.row_band_highlighting
134
+ self._separate_view_properties = options.separate_view_properties
135
+ self._add_dropdowns = options.add_dropdowns
136
+ self._dropdown_implements = options.dropdown_implements
137
+ self._max_views = options.max_views
138
+ self._max_containers = options.max_containers
139
+ self._max_properties_per_view = options.max_properties_per_view
140
+
141
+ def create_workbook(self, tables: DataModelTableType) -> Workbook:
142
+ """Creates an Excel workbook from the data model.
143
+
144
+ Args:
145
+ tables (DataModelTableType): The data model in table
146
+ """
147
+ workbook = Workbook()
148
+ # Remove default sheet named "Sheet"
149
+ workbook.remove(workbook["Sheet"])
150
+
151
+ index_by_sheet_name_column: dict[tuple[str, str], int] = {}
152
+ for sheet_name, table in tables.items():
153
+ if not table and sheet_name not in TableDMS.required_sheets():
154
+ continue
155
+ worksheet = workbook.create_sheet(title=sheet_name)
156
+ if sheet_name == self.Sheets.metadata:
157
+ self._write_metadata_to_worksheet(worksheet, table)
158
+ continue
159
+ if table:
160
+ column_headers = list(table[0].keys())
161
+ else:
162
+ column_headers = TableDMS.get_sheet_column_by_name(sheet_name, column_type="all")
163
+ self._write_table_to_worksheet(worksheet, table, MAIN_HEADERS_BY_SHEET_NAME[sheet_name], column_headers)
164
+ for i, column in enumerate(column_headers, 1):
165
+ index_by_sheet_name_column[(sheet_name, column)] = i
166
+
167
+ if self._adjust_column_width:
168
+ self._adjust_column_widths(worksheet)
169
+
170
+ if self._add_dropdowns:
171
+ self._add_drop_downs(workbook, index_by_sheet_name_column)
172
+ return workbook
173
+
174
+ @staticmethod
175
+ def _write_metadata_to_worksheet(worksheet: Worksheet, table: list[dict[str, CellValueType]]) -> None:
176
+ """Writes Metadata to the given worksheet.
177
+
178
+ Metadata is written as key-value pairs without headers.
179
+ """
180
+ for row in table:
181
+ worksheet.append(list(row.values()))
182
+
183
+ def _write_table_to_worksheet(
184
+ self, worksheet: Worksheet, table: list[dict[str, CellValueType]], main_header: str, column_headers: list[str]
185
+ ) -> None:
186
+ worksheet.append([main_header] + [""] * (len(column_headers) - 1))
187
+ if self._style_headers:
188
+ worksheet.merge_cells(start_row=1, start_column=1, end_row=1, end_column=max(3, len(column_headers)))
189
+ cell = worksheet.cell(row=1, column=1)
190
+ cell.font = Font(bold=True, size=20)
191
+ cell.fill = PatternFill(fgColor="FFC000", patternType="solid")
192
+
193
+ worksheet.append(column_headers)
194
+ header_row = 2 if main_header else 1
195
+ if self._style_headers:
196
+ for col_idx in range(1, len(column_headers) + 1):
197
+ cell = worksheet.cell(row=header_row, column=col_idx)
198
+ cell.font = Font(bold=True, size=14)
199
+ cell.fill = PatternFill(fgColor="FFD966", patternType="solid")
200
+
201
+ self._write_rows_to_worksheet(worksheet, table, column_headers)
202
+
203
+ if self._style_headers:
204
+ # openpyxl is not well typed
205
+ worksheet.freeze_panes = worksheet.cell(row=header_row + 1, column=1) # type: ignore[assignment]
206
+
207
+ def _write_rows_to_worksheet(
208
+ self, worksheet: Worksheet, table: list[dict[str, CellValueType]], headers: list[str]
209
+ ) -> None:
210
+ is_properties = worksheet.title == self.Sheets.properties
211
+ fill_colors = itertools.cycle(["CADCFC", "FFFFFF"])
212
+ fill_color = next(fill_colors)
213
+ is_new_view = False
214
+ last_view_value: CellValueType = None
215
+ side = Side(style="thin")
216
+ for row in table:
217
+ if is_properties:
218
+ is_new_view = row[self.PropertyColumns.view] != last_view_value and last_view_value is not None
219
+ if is_new_view and is_properties and self._separate_view_properties:
220
+ worksheet.append([None] * len(headers)) # Add an empty row between views
221
+ if self._row_band_highlighting:
222
+ for cell in worksheet[worksheet.max_row]:
223
+ cell.border = Border(left=side, right=side, top=side, bottom=side)
224
+
225
+ worksheet.append(list(row.values()))
226
+ if self._row_band_highlighting and is_new_view and is_properties:
227
+ fill_color = next(fill_colors)
228
+
229
+ if self._row_band_highlighting and is_properties:
230
+ for cell in worksheet[worksheet.max_row]:
231
+ cell.fill = PatternFill(fgColor=fill_color, fill_type="solid")
232
+ cell.border = Border(left=side, right=side, top=side, bottom=side)
233
+
234
+ if is_properties:
235
+ last_view_value = row[self.PropertyColumns.view]
236
+
237
+ @classmethod
238
+ def _adjust_column_widths(cls, worksheet: Worksheet) -> None:
239
+ for column_cells in worksheet.columns:
240
+ try:
241
+ max_length = max(len(str(cell.value)) for cell in column_cells if cell.value is not None)
242
+ except ValueError:
243
+ max_length = 0
244
+
245
+ selected_column = column_cells[0]
246
+ if isinstance(selected_column, MergedCell):
247
+ selected_column = column_cells[1]
248
+
249
+ current = worksheet.column_dimensions[selected_column.column_letter].width or (max_length + 0.5) # type: ignore[union-attr]
250
+ worksheet.column_dimensions[selected_column.column_letter].width = min( # type: ignore[union-attr]
251
+ max(current, max_length + 0.5), MAX_COLUMN_WIDTH
252
+ )
253
+ return None
254
+
255
+ def _add_drop_downs(self, workbook: Workbook, index_by_sheet_name_column: dict[tuple[str, str], int]) -> None:
256
+ """Adds drop down menus to specific columns for fast and accurate data entry
257
+
258
+ Args:
259
+ workbook: Workbook representation of the Excel file.
260
+ index_by_sheet_name_column: A mapping of (sheet name, column name) to column index.
261
+ """
262
+
263
+ self._create_dropdown_source_sheet(workbook)
264
+
265
+ property_sheet = workbook[self.Sheets.properties]
266
+ self._add_validation(
267
+ property_sheet,
268
+ self.DropdownSourceColumns.view,
269
+ self._max_views,
270
+ index_by_sheet_name_column[(self.Sheets.properties, self.PropertyColumns.view)],
271
+ self._max_views,
272
+ )
273
+ self._add_validation(
274
+ property_sheet,
275
+ self.DropdownSourceColumns.value_type,
276
+ len(DMS_DATA_TYPES) - len(self.DROPDOWN_DMS_TYPE_EXCLUDE) + self._max_views,
277
+ index_by_sheet_name_column[(self.Sheets.properties, self.PropertyColumns.value_type)],
278
+ self._max_views * self._max_properties_per_view,
279
+ )
280
+ self._add_validation(
281
+ property_sheet,
282
+ self.DropdownSourceColumns.immutable,
283
+ 2, # True, False
284
+ index_by_sheet_name_column[(self.Sheets.properties, self.PropertyColumns.immutable)],
285
+ self._max_views * self._max_properties_per_view,
286
+ )
287
+ self._add_validation(
288
+ property_sheet,
289
+ self.DropdownSourceColumns.container,
290
+ self._max_containers,
291
+ index_by_sheet_name_column[(self.Sheets.properties, self.PropertyColumns.container)],
292
+ self._max_views * self._max_properties_per_view,
293
+ )
294
+
295
+ view_sheet = workbook[self.Sheets.views]
296
+ self._add_validation(
297
+ view_sheet,
298
+ self.DropdownSourceColumns.implements,
299
+ self._max_views + len(self._get_cognite_concepts()),
300
+ index_by_sheet_name_column[(self.Sheets.views, self.ViewColumns.implements)],
301
+ self._max_views,
302
+ )
303
+ self._add_validation(
304
+ view_sheet,
305
+ self.DropdownSourceColumns.in_model,
306
+ 3, # True, False, None
307
+ index_by_sheet_name_column[(self.Sheets.views, self.ViewColumns.in_model)],
308
+ self._max_views,
309
+ )
310
+ container_sheet = workbook[self.Sheets.containers]
311
+ self._add_validation(
312
+ container_sheet,
313
+ self.DropdownSourceColumns.used_for,
314
+ 3, # node, edge, all
315
+ index_by_sheet_name_column[(self.Sheets.containers, self.ContainerColumns.used_for)],
316
+ self._max_containers,
317
+ )
318
+
319
+ def _add_validation(
320
+ self, sheet: Worksheet, column_index: int, row_range: int, sheet_column_index: int, sheet_row_range: int
321
+ ) -> None:
322
+ """Adds data validation to a specific column in a sheet.
323
+
324
+ Args:
325
+ sheet: The worksheet to add the data validation to.
326
+ column_index: The column index in the dropdown source sheet to use as the source for the drop-down.
327
+ row_range: The number of rows in the dropdown source sheet to use as the source for the drop-down.
328
+ sheet_column_index: The column index in the target sheet to add the data validation to.
329
+ sheet_row_range: The number of rows in the target sheet to add the data validation to.
330
+ """
331
+ letter = get_column_letter(column_index)
332
+ data_validation = DataValidation(
333
+ type="list", formula1=f"={self.Sheets.dropdown_source}!${letter}$1:${letter}${row_range}"
334
+ )
335
+ sheet.add_data_validation(data_validation)
336
+ target_letter = get_column_letter(sheet_column_index)
337
+ data_validation.add(f"{target_letter}{HEADER_ROWS + 1}:{target_letter}{HEADER_ROWS + sheet_row_range}")
338
+
339
+ def _create_dropdown_source_sheet(self, workbook: Workbook) -> None:
340
+ """This methods creates a hidden sheet in the workbook which contains
341
+ the source data for the drop-down menus.
342
+
343
+ Args:
344
+ workbook: Workbook representation of the Excel file.
345
+
346
+ """
347
+ dropdown_sheet = workbook.create_sheet(title=self.Sheets.dropdown_source)
348
+ exclude = self.DROPDOWN_DMS_TYPE_EXCLUDE
349
+ for no, dms_type in enumerate([type for type in DMS_DATA_TYPES.keys() if type not in exclude], 1):
350
+ dropdown_sheet.cell(row=no, column=self.DropdownSourceColumns.value_type, value=dms_type)
351
+
352
+ cognite_concepts = self._get_cognite_concepts()
353
+
354
+ for i, concept in enumerate(cognite_concepts, 1):
355
+ dropdown_sheet.cell(
356
+ row=i,
357
+ column=self.DropdownSourceColumns.implements,
358
+ value=f"{CDF_CDM_SPACE}:{concept}(version={CDF_CDM_VERSION})",
359
+ )
360
+
361
+ dms_type_count = len(DMS_DATA_TYPES) - len(exclude)
362
+ core_concept_count = len(cognite_concepts)
363
+ for i in range(1, self._max_views + 1):
364
+ source_row = i + HEADER_ROWS
365
+ view_reference = f'=IF(ISBLANK({self.Sheets.views}!A{source_row}), "", {self.Sheets.views}!A{source_row})'
366
+ dropdown_sheet.cell(row=i, column=self.DropdownSourceColumns.view, value=view_reference)
367
+ dropdown_sheet.cell(
368
+ row=i + core_concept_count, column=self.DropdownSourceColumns.implements, value=view_reference
369
+ )
370
+ dropdown_sheet.cell(
371
+ row=i + dms_type_count, column=self.DropdownSourceColumns.value_type, value=view_reference
372
+ )
373
+
374
+ for i in range(1, self._max_containers + 1):
375
+ source_row = i + HEADER_ROWS
376
+ container_reference = (
377
+ f'=IF(ISBLANK({self.Sheets.containers}!A{source_row}), "", {self.Sheets.containers}!A{source_row})'
378
+ )
379
+ dropdown_sheet.cell(row=i, column=self.DropdownSourceColumns.container, value=container_reference)
380
+
381
+ for i, value in enumerate([True, False, None], 1):
382
+ dropdown_sheet.cell(row=i, column=self.DropdownSourceColumns.in_model, value=value)
383
+
384
+ for i, value in enumerate(["node", "edge", "all"], 1):
385
+ dropdown_sheet.cell(row=i, column=self.DropdownSourceColumns.used_for, value=value)
386
+
387
+ dropdown_sheet.sheet_state = "hidden"
388
+
389
+ def _get_cognite_concepts(self) -> list[str]:
390
+ """Gets the cognite concepts based on the dropdown_implements setting."""
391
+ return _get_cognite_concepts(self._dropdown_implements)
392
+
393
+
394
+ @lru_cache(maxsize=1)
395
+ def _get_cognite_concepts(
396
+ dropdown_implements: Set[Literal["main", "interface", "configuration", "annotation", "3D"]],
397
+ ) -> list[str]:
398
+ """Gets the cognite concepts based on the dropdown_implements setting.
399
+
400
+ This is moved outside of the class to enable caching.
401
+ """
402
+ cognite_concepts: list[str] = []
403
+
404
+ if "main" in dropdown_implements:
405
+ cognite_concepts.extend(COGNITE_CONCEPTS_MAIN)
406
+ if "interface" in dropdown_implements:
407
+ cognite_concepts.extend(COGNITE_CONCEPTS_INTERFACES)
408
+ if "configuration" in dropdown_implements:
409
+ cognite_concepts.extend(COGNITE_CONCEPTS_CONFIGURATIONS)
410
+ if "annotation" in dropdown_implements:
411
+ cognite_concepts.extend(COGNITE_CONCEPTS_ANNOTATIONS)
412
+ if "3D" in dropdown_implements:
413
+ cognite_concepts.extend(COGNITE_CONCEPTS_3D)
414
+ return cognite_concepts