cognite-neat 0.92.2__py3-none-any.whl → 0.92.3__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 +1 @@
1
- __version__ = "0.92.2"
1
+ __version__ = "0.92.3"
@@ -11,6 +11,7 @@ from openpyxl import Workbook
11
11
  from openpyxl.cell import MergedCell
12
12
  from openpyxl.styles import Alignment, Border, Font, PatternFill, Side
13
13
  from openpyxl.worksheet.worksheet import Worksheet
14
+ from rdflib import Namespace
14
15
 
15
16
  from cognite.neat.rules._shared import VerifiedRules
16
17
  from cognite.neat.rules.models import (
@@ -22,6 +23,7 @@ from cognite.neat.rules.models import (
22
23
  from cognite.neat.rules.models.dms import DMSMetadata
23
24
  from cognite.neat.rules.models.domain import DomainMetadata
24
25
  from cognite.neat.rules.models.information import InformationMetadata
26
+ from cognite.neat.rules.models.information._rules import InformationRules
25
27
 
26
28
  from ._base import BaseExporter
27
29
 
@@ -133,6 +135,9 @@ class ExcelExporter(BaseExporter[VerifiedRules, Workbook]):
133
135
  self._write_sheets(workbook, dumped_reference_rules, rules, sheet_prefix="Ref")
134
136
  self._write_metadata_sheet(workbook, dumped_reference_rules["Metadata"], sheet_prefix="Ref")
135
137
 
138
+ if isinstance(rules, InformationRules) and rules.prefixes:
139
+ self._write_prefixes_sheet(workbook, rules.prefixes)
140
+
136
141
  if self._styling_level > 0:
137
142
  self._adjust_column_widths(workbook)
138
143
 
@@ -209,6 +214,16 @@ class ExcelExporter(BaseExporter[VerifiedRules, Workbook]):
209
214
  for cell in metadata_sheet["A"]:
210
215
  cell.font = Font(bold=True, size=12)
211
216
 
217
+ def _write_prefixes_sheet(self, workbook: Workbook, prefixes: dict[str, Namespace]) -> None:
218
+ metadata_sheet = workbook.create_sheet("Prefixes")
219
+ metadata_sheet.append(["Prefix", "Namespace"])
220
+ for key, value in prefixes.items():
221
+ metadata_sheet.append([key, value])
222
+
223
+ if self._styling_level > 1:
224
+ for cell in metadata_sheet["A"]:
225
+ cell.font = Font(bold=True, size=12)
226
+
212
227
  @classmethod
213
228
  def _get_item_class(cls, annotation: GenericAlias) -> type[SheetRow]:
214
229
  if not isinstance(annotation, GenericAlias):
@@ -11,6 +11,7 @@ from typing import Literal, cast
11
11
  import pandas as pd
12
12
  from cognite.client.utils._importing import local_import
13
13
  from pandas import ExcelFile
14
+ from rdflib import Namespace
14
15
 
15
16
  from cognite.neat.issues import IssueList
16
17
  from cognite.neat.issues.errors import (
@@ -19,6 +20,7 @@ from cognite.neat.issues.errors import (
19
20
  FileReadError,
20
21
  PropertyDefinitionDuplicatedError,
21
22
  )
23
+ from cognite.neat.issues.warnings import FileMissingRequiredFieldWarning
22
24
  from cognite.neat.rules._shared import ReadRules, T_InputRules
23
25
  from cognite.neat.rules.models import (
24
26
  INPUT_RULES_BY_ROLE,
@@ -93,6 +95,7 @@ class ReadResult:
93
95
  sheets: dict[str, dict | list]
94
96
  read_info_by_sheet: dict[str, SpreadsheetRead]
95
97
  metadata: MetadataRaw
98
+ prefixes: dict[str, Namespace] | None = None
96
99
 
97
100
  @property
98
101
  def role(self) -> RoleTypes:
@@ -122,6 +125,10 @@ class SpreadsheetReader:
122
125
  def metadata_sheet_name(self) -> str:
123
126
  return f"{self._sheet_prefix}Metadata"
124
127
 
128
+ @property
129
+ def prefixes_sheet_name(self) -> str:
130
+ return "Prefixes"
131
+
125
132
  @property
126
133
  def seen_sheets(self) -> set[str]:
127
134
  if not self._seen_files:
@@ -149,6 +156,14 @@ class SpreadsheetReader:
149
156
  return None
150
157
  sheets["Metadata"] = dict(metadata)
151
158
 
159
+ # Special case for reading prefixes as they are suppose to be read only once
160
+ if (
161
+ self.prefixes_sheet_name in excel_file.sheet_names
162
+ and not self._sheet_prefix
163
+ and (prefixes := self._read_prefixes(excel_file, filepath))
164
+ ):
165
+ sheets["Prefixes"] = prefixes
166
+
152
167
  return ReadResult(sheets, read_info_by_sheet, metadata)
153
168
 
154
169
  def _read_metadata(self, excel_file: ExcelFile, filepath: Path) -> MetadataRaw | None:
@@ -163,6 +178,25 @@ class SpreadsheetReader:
163
178
  return None
164
179
  return metadata
165
180
 
181
+ def _read_prefixes(self, excel_file: ExcelFile, filepath: Path) -> dict[str, Namespace] | None:
182
+ if self.prefixes_sheet_name not in excel_file.sheet_names:
183
+ return None
184
+
185
+ else:
186
+ prefixes = {}
187
+
188
+ for row in read_individual_sheet(excel_file, "Prefixes", expected_headers=["Prefix", "Namespace"]):
189
+ if "Prefix" in row and "Namespace" in row:
190
+ prefixes[row["Prefix"]] = row["Namespace"]
191
+ else:
192
+ if "Prefix" not in row:
193
+ self.issue_list.append(FileMissingRequiredFieldWarning(filepath, "prefixes", "prefix"))
194
+ if "Namespace" not in row:
195
+ self.issue_list.append(FileMissingRequiredFieldWarning(filepath, "prefixes", "namespace"))
196
+ return None
197
+
198
+ return prefixes
199
+
166
200
  def _read_sheets(
167
201
  self, excel_file: ExcelFile, read_role: RoleTypes
168
202
  ) -> tuple[dict[str, dict | list] | None, dict[str, SpreadsheetRead]]:
@@ -66,11 +66,15 @@ class InputRules(Generic[T_BaseRules], ABC):
66
66
  candidate = type_
67
67
  elif isinstance(type_, GenericAlias) and type_.__origin__ is list and is_dataclass(type_.__args__[0]):
68
68
  candidate = type_.__args__[0]
69
+
70
+ # this handles prefixes
71
+ elif isinstance(type_, GenericAlias) and type_.__origin__ is dict:
72
+ candidate = type_
69
73
  else:
70
74
  continue
71
75
 
72
- if hasattr(candidate, "_load"):
73
- output[field_.name] = candidate
76
+ output[field_.name] = candidate
77
+
74
78
  return output
75
79
 
76
80
  @classmethod
@@ -88,10 +92,16 @@ class InputRules(Generic[T_BaseRules], ABC):
88
92
  else:
89
93
  continue
90
94
 
91
- if isinstance(value, dict):
92
- args[field_name] = field_type._load(value) # type: ignore[attr-defined]
93
- elif isinstance(value, list) and value and isinstance(value[0], dict):
94
- args[field_name] = [field_type._load(item) for item in value] # type: ignore[attr-defined]
95
+ # Handles the case where the field is a dataclass
96
+ if hasattr(field_type, "_load"):
97
+ if isinstance(value, dict):
98
+ args[field_name] = field_type._load(value) # type: ignore[attr-defined]
99
+ elif isinstance(value, list) and value and isinstance(value[0], dict):
100
+ args[field_name] = [field_type._load(item) for item in value] # type: ignore[attr-defined]
101
+ # Handles the case where the field holds non-dataclass values, e.g. a prefixes dict
102
+ else:
103
+ args[field_name] = value
104
+
95
105
  return cls(**args)
96
106
 
97
107
  def _dataclass_fields(self) -> list[Field]:
@@ -108,6 +108,14 @@ class SchemaModel(BaseModel):
108
108
  """Returns a set of mandatory fields for the model."""
109
109
  return _get_required_fields(cls, use_alias)
110
110
 
111
+ @field_validator("*", mode="before")
112
+ def strip_string(cls, value: Any) -> Any:
113
+ if isinstance(value, str):
114
+ return value.strip()
115
+ elif isinstance(value, list):
116
+ return [entry.strip() if isinstance(entry, str) else entry for entry in value]
117
+ return value
118
+
111
119
 
112
120
  class BaseMetadata(SchemaModel):
113
121
  """
@@ -279,12 +287,6 @@ class BaseRules(SchemaModel, ABC):
279
287
 
280
288
 
281
289
  class SheetRow(SchemaModel):
282
- @field_validator("*", mode="before")
283
- def strip_string(cls, value: Any) -> Any:
284
- if isinstance(value, str):
285
- return value.strip()
286
- return value
287
-
288
290
  @abstractmethod
289
291
  def _identifier(self) -> tuple[Hashable, ...]:
290
292
  raise NotImplementedError()
@@ -98,15 +98,15 @@ class DMSMetadata(BaseMetadata):
98
98
 
99
99
  @field_validator("schema_", mode="plain")
100
100
  def as_enum_schema(cls, value: str) -> SchemaCompleteness:
101
- return SchemaCompleteness(value)
101
+ return SchemaCompleteness(value.strip())
102
102
 
103
103
  @field_validator("extension", mode="plain")
104
104
  def as_enum_extension(cls, value: str) -> ExtensionCategory:
105
- return ExtensionCategory(value)
105
+ return ExtensionCategory(value.strip())
106
106
 
107
107
  @field_validator("data_model_type", mode="plain")
108
108
  def as_enum_model_type(cls, value: str) -> DataModelType:
109
- return DataModelType(value)
109
+ return DataModelType(value.strip())
110
110
 
111
111
  @field_validator("description", mode="before")
112
112
  def nan_as_none(cls, value):
@@ -17,6 +17,7 @@ from cognite.client.data_classes.data_modeling.ids import (
17
17
  from pydantic import (
18
18
  BaseModel,
19
19
  Field,
20
+ field_validator,
20
21
  model_serializer,
21
22
  model_validator,
22
23
  )
@@ -97,6 +98,14 @@ class Entity(BaseModel, extra="ignore"):
97
98
  def as_str(self) -> str:
98
99
  return str(self)
99
100
 
101
+ @field_validator("*", mode="before")
102
+ def strip_string(cls, value: Any) -> Any:
103
+ if isinstance(value, str):
104
+ return value.strip()
105
+ elif isinstance(value, list):
106
+ return [entry.strip() if isinstance(entry, str) else entry for entry in value]
107
+ return value
108
+
100
109
  @classmethod
101
110
  def _parse(cls, raw: str, defaults: dict) -> dict:
102
111
  if not (result := ENTITY_PATTERN.match(raw)):
@@ -100,15 +100,15 @@ class InformationMetadata(BaseMetadata):
100
100
 
101
101
  @field_validator("schema_", mode="plain")
102
102
  def as_enum_schema(cls, value: str) -> SchemaCompleteness:
103
- return SchemaCompleteness(value)
103
+ return SchemaCompleteness(value.strip())
104
104
 
105
105
  @field_validator("extension", mode="plain")
106
106
  def as_enum_extension(cls, value: str) -> ExtensionCategory:
107
- return ExtensionCategory(value)
107
+ return ExtensionCategory(value.strip())
108
108
 
109
109
  @field_validator("data_model_type", mode="plain")
110
110
  def as_enum_model_type(cls, value: str) -> DataModelType:
111
- return DataModelType(value)
111
+ return DataModelType(value.strip())
112
112
 
113
113
  def as_identifier(self) -> str:
114
114
  return f"{self.prefix}:{self.name}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cognite-neat
3
- Version: 0.92.2
3
+ Version: 0.92.3
4
4
  Summary: Knowledge graph transformation
5
5
  Home-page: https://cognite-neat.readthedocs-hosted.com/
6
6
  License: Apache-2.0
@@ -1,6 +1,6 @@
1
1
  cognite/neat/__init__.py,sha256=AiexNcHdAHFbrrbo9c65gtil1dqx_SGraDH1PSsXjKE,126
2
2
  cognite/neat/_shared.py,sha256=RSaHm2eJceTlvb-hMMe4nHgoHdPYDfN3XcxDXo24k3A,1530
3
- cognite/neat/_version.py,sha256=ncCF0g_Polw_j6zF_9uC4cFeVf2A3yKhEjvukXrW1bU,23
3
+ cognite/neat/_version.py,sha256=lVR6wo2EG_y7_rGumaLFRR6XKSf-pN9UmvqzXkNi7II,23
4
4
  cognite/neat/app/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  cognite/neat/app/api/asgi/metrics.py,sha256=nxFy7L5cChTI0a-zkCiJ59Aq8yLuIJp5c9Dg0wRXtV0,152
6
6
  cognite/neat/app/api/configuration.py,sha256=L1DCtLZ1HZku8I2z-JWd5RDsXhIsboFsKwAMhkrm-bY,3600
@@ -109,7 +109,7 @@ cognite/neat/rules/examples/wind-energy.owl,sha256=NuomCA9FuuLF0JlSuG3OKqD4VBcHg
109
109
  cognite/neat/rules/exporters/__init__.py,sha256=nRMUBUf7yr1QPjyITeX2rTLtLLawHv24hhRE39d2-e0,1109
110
110
  cognite/neat/rules/exporters/_base.py,sha256=Er8G2DRNUtD1RbDOe9_c6H8cVwXbkTQzGfqof7J9OhA,1329
111
111
  cognite/neat/rules/exporters/_rules2dms.py,sha256=UekIEl9m-ZHu7AjPr0yaDrAkE3AMJaTcL2dkYdE17Ko,14448
112
- cognite/neat/rules/exporters/_rules2excel.py,sha256=BqXEDORmshvBZMMsDs8LXOPILl2gf5I0kyVmTodtanY,14223
112
+ cognite/neat/rules/exporters/_rules2excel.py,sha256=x_BqsgqgHzPguZZ52-jFjXu3hFxuPSx3FZ8bO798IZo,14898
113
113
  cognite/neat/rules/exporters/_rules2ontology.py,sha256=qrSY8se-AUABaJt_7NOH46Htoq6mXAEMO4eN3dCzvG8,21705
114
114
  cognite/neat/rules/exporters/_rules2yaml.py,sha256=7N8Y5jXnt8I8TVGBP9pDtw838VCxWFeA3B-JZZou5GE,3195
115
115
  cognite/neat/rules/exporters/_validation.py,sha256=A0kyrIEu51ZXl47CXmO4ZOT0whO5iKNwMY-BwMc2scA,680
@@ -134,11 +134,11 @@ cognite/neat/rules/importers/_rdf/_owl2rules/_owl2metadata.py,sha256=3eTXm0irYJc
134
134
  cognite/neat/rules/importers/_rdf/_owl2rules/_owl2properties.py,sha256=2nuhRr7ZEEAEN94IFRYwrt_T4WqmQUzOpqrNuji_Vi4,2145
135
135
  cognite/neat/rules/importers/_rdf/_owl2rules/_owl2rules.py,sha256=nH_hJGIEG9LKAjC7q5owggwGT40XLNiMctyxqN8u-dY,2510
136
136
  cognite/neat/rules/importers/_rdf/_shared.py,sha256=qZuJm2LiB_eScbRkoTOL7Qf6CJQ124Dv2Kxylo-Rzts,19771
137
- cognite/neat/rules/importers/_spreadsheet2rules.py,sha256=2GhBLEq6jyu2TbnX6MTlSx4LaWOdSfz213Lo45nTaM4,11036
137
+ cognite/neat/rules/importers/_spreadsheet2rules.py,sha256=3VnvgdLcUcwxSf0SH_OS0ywmjyyQZuQhX_Qd-z0qaoQ,12465
138
138
  cognite/neat/rules/importers/_yaml2rules.py,sha256=aap5Nso_7EBNrHtG4pt8tT4jNzCYUQz4twHdmqrGya8,3139
139
139
  cognite/neat/rules/models/__init__.py,sha256=ZqbSC2UhPtq31P1RUHoiXGO2q6FoPwqUvrTorpgLZTU,1524
140
- cognite/neat/rules/models/_base_input.py,sha256=fw8v9PSZO6wgVwDHvfW9m39ipX4hXvxoSmpK51kbaMU,5869
141
- cognite/neat/rules/models/_base_rules.py,sha256=QbcAg1cmsWzQtADyhqVEiX1PT_XsW-37YXVR1NIBtSw,12940
140
+ cognite/neat/rules/models/_base_input.py,sha256=EQTYAPpvR4mFHPXalERPjiRgKobc0D_YB2yGkbzj8i0,6251
141
+ cognite/neat/rules/models/_base_rules.py,sha256=7pdSAaWfXMcEiOE2Dg-hmCg_NZZ2qtKJBXDlRpXAmeQ,13069
142
142
  cognite/neat/rules/models/_rdfpath.py,sha256=oyMpmL_t0R5Uocdm3CA9iDLT2ZJVr2BIuz4cxaUlabM,11881
143
143
  cognite/neat/rules/models/_types.py,sha256=VM40gfADOzw5UFy-olCBotComra0MsAafjyUlaIgFV8,2875
144
144
  cognite/neat/rules/models/asset/__init__.py,sha256=Z2tQEABW-q66bmHNcxMuIxPmYQBcGdiSZt7fHGe01dQ,363
@@ -148,7 +148,7 @@ cognite/neat/rules/models/asset/_validation.py,sha256=3goorodISq_mlyXroaivcMOZ-Q
148
148
  cognite/neat/rules/models/data_types.py,sha256=jTYsWqQPuvwHytInRU0Y2TGF4aVBF83v0vp_SH9KgLA,9722
149
149
  cognite/neat/rules/models/dms/__init__.py,sha256=CUqUlVjz4yZX_-61F-2ofSoV7N9MlSYx2N7vM-omp7E,640
150
150
  cognite/neat/rules/models/dms/_exporter.py,sha256=4XiFCeXZOZuj5Ke1E-_rQJvPIcyRl7lIb2dHCfkYS4M,28126
151
- cognite/neat/rules/models/dms/_rules.py,sha256=Tx36M7nc0ryLMYlwBMdrKpgdGSIBTLuKjE0vbuoApVQ,19184
151
+ cognite/neat/rules/models/dms/_rules.py,sha256=VanBtkUKltUXPucQ5qVxvmK-apR7SyCZX-kkGFZ5D6k,19208
152
152
  cognite/neat/rules/models/dms/_rules_input.py,sha256=v5-zlb4VJi5Q610rnPLU1aHKzXmGwoUTrDzAkJFfEQY,10911
153
153
  cognite/neat/rules/models/dms/_schema.py,sha256=lc6Q0EUchOAUSTRiJnWc6UPBz7LjCW5NEvIGwNakcSI,50724
154
154
  cognite/neat/rules/models/dms/_validation.py,sha256=EnupSDjeCi-Sqs6ube1wQ2FxL3DP5O8vUaSojWqT-I0,15790
@@ -157,11 +157,11 @@ cognite/neat/rules/models/entities/__init__.py,sha256=ORRN2bkgbotGKAzxU66ff5JrbW
157
157
  cognite/neat/rules/models/entities/_constants.py,sha256=r_Knlqmmb6QFgiSS0Yb_9UrhwYnaSBCYy2Wt9gODLhw,2316
158
158
  cognite/neat/rules/models/entities/_loaders.py,sha256=uzMRAULggTxrP3B27_78i6anui3br4Ck6o9vmctqxkk,2691
159
159
  cognite/neat/rules/models/entities/_multi_value.py,sha256=3DejtsIWJOA96y9wZMhjDBP5lOxJH9l27YZUxr9JIEY,2060
160
- cognite/neat/rules/models/entities/_single_value.py,sha256=lqz-3LY5qB6Q4nVIZQxpKHzppq7ZJC6FRKZMcBKDqVs,17078
160
+ cognite/neat/rules/models/entities/_single_value.py,sha256=GDfB1zmpdfsScUjRtfy1U6VSogeGya9UVjkMWxAsunw,17405
161
161
  cognite/neat/rules/models/entities/_types.py,sha256=df9rnXJJKciv2Bp-Ve2q4xdEJt6WWniq12Z0hW2d6sk,1917
162
162
  cognite/neat/rules/models/entities/_wrapped.py,sha256=FxC8HztW_tUUtuArAOwxyFfkdJnSEB4bgZoNmmmfiPk,7137
163
163
  cognite/neat/rules/models/information/__init__.py,sha256=fVvgXt-JuyZCP_mLgIVaeKD9pdAXe2BWUxU_BZs8e5g,480
164
- cognite/neat/rules/models/information/_rules.py,sha256=sPZdZ2ed7Wk0OEgi90niUXNii-tw3mf8yAw8-fRGnD4,14361
164
+ cognite/neat/rules/models/information/_rules.py,sha256=8AXNJBnw91Fs_Da71CIG5rxerOLsh_tI_CEc64pm7PQ,14385
165
165
  cognite/neat/rules/models/information/_rules_input.py,sha256=wKBISvbJ5IsPhl72hsF4hmOiza8nqN-4tTczl-Mif-w,5274
166
166
  cognite/neat/rules/models/information/_validation.py,sha256=mOgtIUwkXn9VZIKkdbPidWn8uepPfh9pUfkldQCWB0c,9205
167
167
  cognite/neat/rules/transformers/__init__.py,sha256=Iun5-3uDmzUzcO4IFneJ453PWAx6F_c-5LhkvrIrSc0,666
@@ -217,8 +217,8 @@ cognite/neat/workflows/steps_registry.py,sha256=FjMsFBlFFy82ABUzDnWoFidYODV3pp3c
217
217
  cognite/neat/workflows/tasks.py,sha256=dqlJwKAb0jlkl7abbY8RRz3m7MT4SK8-7cntMWkOYjw,788
218
218
  cognite/neat/workflows/triggers.py,sha256=_BLNplzoz0iic367u1mhHMHiUrCwP-SLK6_CZzfODX0,7071
219
219
  cognite/neat/workflows/utils.py,sha256=gKdy3RLG7ctRhbCRwaDIWpL9Mi98zm56-d4jfHDqP1E,453
220
- cognite_neat-0.92.2.dist-info/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
221
- cognite_neat-0.92.2.dist-info/METADATA,sha256=YLOUEbDeru-k2r75u3nM70vEsrO79oAl2bmmuu-tyas,9431
222
- cognite_neat-0.92.2.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
223
- cognite_neat-0.92.2.dist-info/entry_points.txt,sha256=61FPqiWb25vbqB0KI7znG8nsg_ibLHBvTjYnkPvNFso,50
224
- cognite_neat-0.92.2.dist-info/RECORD,,
220
+ cognite_neat-0.92.3.dist-info/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
221
+ cognite_neat-0.92.3.dist-info/METADATA,sha256=BQD0C1oIYoUSbH1p9TKbBNISOPE_GUqnHDY4uos9lU0,9431
222
+ cognite_neat-0.92.3.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
223
+ cognite_neat-0.92.3.dist-info/entry_points.txt,sha256=61FPqiWb25vbqB0KI7znG8nsg_ibLHBvTjYnkPvNFso,50
224
+ cognite_neat-0.92.3.dist-info/RECORD,,