cognite-neat 0.72.1__py3-none-any.whl → 0.72.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.
cognite/neat/_version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.72.1"
1
+ __version__ = "0.72.3"
@@ -1,11 +1,13 @@
1
1
  import json
2
2
  import shutil
3
3
  import tempfile
4
+ from copy import deepcopy
4
5
  from pathlib import Path
5
6
  from typing import cast
6
7
 
7
8
  from fastapi import APIRouter, UploadFile
8
9
 
10
+ from cognite.neat.app.api.configuration import NEAT_APP
9
11
  from cognite.neat.rules import exporters, importers
10
12
  from cognite.neat.rules.models._rules import DMSRules
11
13
  from cognite.neat.rules.models._rules.base import RoleTypes
@@ -55,8 +57,36 @@ async def convert_data_model_to_rules(file: UploadFile):
55
57
  @router.post("/api/core/rules2dms")
56
58
  async def convert_rules_to_dms(rules: DMSRules):
57
59
  dms_schema = exporters.DMSExporter().export(rules)
60
+ containers = {f"{container.space}:{container.external_id}": container.dump() for container in dms_schema.containers}
61
+ views = {f"{view.space}:{view.external_id}": view.dump() for view in dms_schema.views}
62
+
63
+ if views and containers:
64
+ _to_visualization_compliant_views(views, containers)
58
65
 
59
66
  return {
60
- "views": dms_schema.views.dump() if dms_schema.views else None,
61
- "containers": dms_schema.containers.dump() if dms_schema.containers else None,
67
+ "views": list(views.values()) if views else None,
68
+ "containers": list(containers.values()) if containers else None,
62
69
  }
70
+
71
+
72
+ def _to_visualization_compliant_views(views, containers):
73
+ for view in views.values():
74
+ for property in view["properties"].values():
75
+ # needs coping information from container:
76
+ if property.get("container", None) and property["container"]["type"] == "container":
77
+ container_id = f"{property['container']['space']}:{property['container']['externalId']}"
78
+ container_property_def = deepcopy(
79
+ containers[container_id]["properties"][property["containerPropertyIdentifier"]]
80
+ )
81
+ property["type"] = container_property_def["type"]
82
+ container_property_def.pop("type")
83
+ property.update(container_property_def)
84
+
85
+
86
+ @router.post("/api/core/publish-rules")
87
+ async def publish_rules_as_data_model(rules: DMSRules):
88
+ if NEAT_APP.cdf_client:
89
+ uploaded = exporters.DMSExporter().export_to_cdf(rules, NEAT_APP.cdf_client)
90
+ return {"uploaded": uploaded}
91
+ else:
92
+ return {"uploaded": []}
cognite/neat/constants.py CHANGED
@@ -11,6 +11,7 @@ EXAMPLE_RULES = PACKAGE_DIRECTORY / "rules" / "examples"
11
11
  EXAMPLE_GRAPHS = PACKAGE_DIRECTORY / "graph" / "examples"
12
12
  EXAMPLE_WORKFLOWS = PACKAGE_DIRECTORY / "workflows" / "examples"
13
13
 
14
+ DEFAULT_NAMESPACE = Namespace("http://purl.org/cognite/neat#")
14
15
 
15
16
  PREFIXES = {
16
17
  "rdf": RDF._NS,
@@ -27,10 +28,10 @@ PREFIXES = {
27
28
  "md": Namespace("http://iec.ch/TC57/61970-552/ModelDescription/1#"),
28
29
  "pti": Namespace("http://www.pti-us.com/PTI_CIM-schema-cim16#"),
29
30
  "tnt": Namespace("http://purl.org/cognite/tnt#"),
30
- "neat": Namespace("http://purl.org/cognite/neat#"),
31
+ "neat": DEFAULT_NAMESPACE,
31
32
  }
32
33
 
33
- DEFAULT_NAMESPACE = Namespace("http://purl.org/cognite/app#")
34
+
34
35
  DEFAULT_URI = ""
35
36
 
36
37
  DEFAULT_DOCS_URL = "https://cognite-neat.readthedocs-hosted.com/en/latest/"
@@ -40,8 +40,6 @@ class DMSExporter(CDFExporter[DMSSchema]):
40
40
  If set, only export components in the given spaces. Defaults to None which means all spaces.
41
41
  existing_handling (Literal["fail", "skip", "update", "force"], optional): How to handle existing components.
42
42
  Defaults to "update". See below for details.
43
- standardize_casing(bool, optional): Whether to standardize the casing. This means PascalCase for external ID
44
- of views, containers, and data models, and camelCase for properties.
45
43
  export_pipeline (bool, optional): Whether to export the pipeline. Defaults to False. This means setting
46
44
  up transformations, RAW databases and tables to populate the data model.
47
45
  instance_space (str, optional): The space to use for the instance. Defaults to None.
@@ -59,14 +57,12 @@ class DMSExporter(CDFExporter[DMSSchema]):
59
57
  export_components: Component | Collection[Component] = "all",
60
58
  include_space: set[str] | None = None,
61
59
  existing_handling: Literal["fail", "skip", "update", "force"] = "update",
62
- standardize_casing: bool = True,
63
60
  export_pipeline: bool = False,
64
61
  instance_space: str | None = None,
65
62
  ):
66
63
  self.export_components = {export_components} if isinstance(export_components, str) else set(export_components)
67
64
  self.include_space = include_space
68
65
  self.existing_handling = existing_handling
69
- self.standardize_casing = standardize_casing
70
66
  self.export_pipeline = export_pipeline
71
67
  self.instance_space = instance_space
72
68
  self._schema: DMSSchema | None = None
@@ -119,11 +115,11 @@ class DMSExporter(CDFExporter[DMSSchema]):
119
115
  )
120
116
  is_new_model = dms_rules.reference is None
121
117
  if is_new_model or is_solution_model:
122
- return dms_rules.as_schema(self.standardize_casing, self.export_pipeline, self.instance_space)
118
+ return dms_rules.as_schema(self.export_pipeline, self.instance_space)
123
119
 
124
120
  # This is an extension of an existing model.
125
121
  reference_rules = cast(DMSRules, dms_rules.reference).copy(deep=True)
126
- reference_schema = reference_rules.as_schema(self.standardize_casing, self.export_pipeline)
122
+ reference_schema = reference_rules.as_schema(self.export_pipeline)
127
123
 
128
124
  # Todo Move this to an appropriate location
129
125
  # Merging Reference with User Rules
@@ -146,7 +142,7 @@ class DMSExporter(CDFExporter[DMSSchema]):
146
142
  property_.reference = None
147
143
  combined_rules.properties.append(property_)
148
144
 
149
- schema = combined_rules.as_schema(self.standardize_casing, self.export_pipeline, self.instance_space)
145
+ schema = combined_rules.as_schema(self.export_pipeline, self.instance_space)
150
146
 
151
147
  if dms_rules.metadata.extension in (ExtensionCategory.addition, ExtensionCategory.reshape):
152
148
  # We do not freeze views as they might be changed, even for addition,
@@ -8,6 +8,7 @@ from pydantic import BaseModel, ConfigDict, ValidationInfo, field_validator
8
8
  from rdflib import DCTERMS, OWL, RDF, RDFS, XSD, BNode, Graph, Literal, Namespace, URIRef
9
9
  from rdflib.collection import Collection as GraphCollection
10
10
 
11
+ from cognite.neat.constants import DEFAULT_NAMESPACE as NEAT_NAMESPACE
11
12
  from cognite.neat.rules import exceptions
12
13
  from cognite.neat.rules._analysis._information_rules import InformationArchitectRulesAnalysis
13
14
  from cognite.neat.rules.models._rules import DMSRules
@@ -217,6 +218,7 @@ class OWLMetadata(InformationMetadata):
217
218
  (URIRef(self.namespace), DCTERMS.hasVersion, Literal(self.version)),
218
219
  (URIRef(self.namespace), OWL.versionInfo, Literal(self.version)),
219
220
  (URIRef(self.namespace), RDFS.label, Literal(self.name)),
221
+ (URIRef(self.namespace), NEAT_NAMESPACE.prefix, Literal(self.prefix)),
220
222
  (URIRef(self.namespace), DCTERMS.title, Literal(self.name)),
221
223
  (URIRef(self.namespace), DCTERMS.created, Literal(self.created, datatype=XSD.dateTime)),
222
224
  (URIRef(self.namespace), DCTERMS.description, Literal(self.description)),
@@ -3,6 +3,7 @@ import re
3
3
 
4
4
  from rdflib import Graph, Namespace
5
5
 
6
+ from cognite.neat.constants import DEFAULT_NAMESPACE
6
7
  from cognite.neat.rules.models._rules.base import RoleTypes, SchemaCompleteness
7
8
  from cognite.neat.rules.models.rules import (
8
9
  prefix_compliance_regex,
@@ -29,23 +30,23 @@ def parse_owl_metadata(graph: Graph, make_compliant: bool = False) -> dict:
29
30
  """
30
31
  # TODO: Move dataframe to dict representation
31
32
 
32
- query = """SELECT ?namespace ?prefix ?version ?created ?updated ?title ?description ?creator ?rights ?license
33
- WHERE {
33
+ query = f"""SELECT ?namespace ?prefix ?version ?created ?updated ?title ?description ?creator ?rights ?license
34
+ WHERE {{
34
35
  ?namespace a owl:Ontology .
35
- OPTIONAL {?namespace owl:versionInfo ?version }.
36
- OPTIONAL {?namespace dcterms:creator ?creator }.
37
- OPTIONAL {?namespace dcterms:title|rdfs:label|skos:prefLabel ?title }.
38
- OPTIONAL {?namespace dcterms:modified ?updated }.
39
- OPTIONAL {?namespace dcterms:created ?created }.
40
- OPTIONAL {?namespace dcterms:description ?description }.
41
-
42
- OPTIONAL {?namespace dcterms:rights|dc:rights ?rights }.
43
-
44
- OPTIONAL {?namespace dcterms:license|dc:license ?license }.
36
+ OPTIONAL {{?namespace owl:versionInfo ?version }}.
37
+ OPTIONAL {{?namespace dcterms:creator ?creator }}.
38
+ OPTIONAL {{?namespace <{DEFAULT_NAMESPACE.prefix}> ?prefix }}.
39
+ OPTIONAL {{?namespace dcterms:title|rdfs:label|skos:prefLabel ?title }}.
40
+ OPTIONAL {{?namespace dcterms:modified ?updated }}.
41
+ OPTIONAL {{?namespace dcterms:created ?created }}.
42
+ OPTIONAL {{?namespace dcterms:description ?description }}.
43
+ OPTIONAL {{?namespace dcterms:rights|dc:rights ?rights }}.
44
+
45
+ OPTIONAL {{?namespace dcterms:license|dc:license ?license }}.
45
46
  FILTER (!isBlank(?namespace))
46
47
  FILTER (!bound(?description) || LANG(?description) = "" || LANGMATCHES(LANG(?description), "en"))
47
48
  FILTER (!bound(?title) || LANG(?title) = "" || LANGMATCHES(LANG(?title), "en"))
48
- }
49
+ }}
49
50
  """
50
51
 
51
52
  results = [{item for item in sublist} for sublist in list(zip(*graph.query(query), strict=True))]
@@ -72,7 +73,6 @@ def parse_owl_metadata(graph: Graph, make_compliant: bool = False) -> dict:
72
73
  )
73
74
 
74
75
  if make_compliant:
75
- raw_metadata.pop("created")
76
76
  return make_metadata_compliant(raw_metadata)
77
77
 
78
78
  return raw_metadata
@@ -176,7 +176,7 @@ def fix_date(
176
176
  if date := metadata.get(date_type, None):
177
177
  try:
178
178
  if isinstance(date, datetime.datetime):
179
- pass
179
+ return metadata
180
180
  elif isinstance(date, datetime.date):
181
181
  metadata[date_type] = datetime.datetime.combine(metadata[date_type], datetime.datetime.min.time())
182
182
  elif isinstance(date, str):
@@ -40,6 +40,8 @@ def parse_owl_properties(graph: Graph, make_compliant: bool = False, language: s
40
40
  FILTER (!bound(?class) || !isBlank(?class))
41
41
  FILTER (!bound(?name) || LANG(?name) = "" || LANGMATCHES(LANG(?name), "en"))
42
42
  FILTER (!bound(?description) || LANG(?description) = "" || LANGMATCHES(LANG(?description), "en"))
43
+ BIND(IF(bound(?minCount), ?minCount, 0) AS ?minCount)
44
+ BIND(IF(bound(?maxCount), ?maxCount, 1) AS ?maxCount)
43
45
  }
44
46
  """
45
47
 
@@ -38,7 +38,7 @@ class OWLImporter(BaseImporter):
38
38
 
39
39
  """
40
40
 
41
- def __init__(self, owl_filepath: Path, make_compliant: bool = True):
41
+ def __init__(self, owl_filepath: Path, make_compliant: bool = False):
42
42
  self.owl_filepath = owl_filepath
43
43
  self.make_compliant = make_compliant
44
44
 
@@ -4,6 +4,7 @@ generating a list of rules based on which nodes that form the graph are made.
4
4
  """
5
5
 
6
6
  from collections import UserDict, defaultdict
7
+ from dataclasses import dataclass
7
8
  from pathlib import Path
8
9
  from typing import Literal, cast, overload
9
10
 
@@ -49,6 +50,12 @@ class MetadataRaw(UserDict):
49
50
  def has_schema_field(self) -> bool:
50
51
  return self.get("schema") in [schema.value for schema in SchemaCompleteness.__members__.values()]
51
52
 
53
+ @property
54
+ def schema(self) -> SchemaCompleteness | None:
55
+ if not self.has_schema_field:
56
+ return None
57
+ return SchemaCompleteness(self["schema"])
58
+
52
59
  def is_valid(self, issue_list: IssueList, filepath: Path) -> bool:
53
60
  if not self.has_role_field:
54
61
  issue_list.append(issues.spreadsheet_file.RoleMissingOrUnsupportedError(filepath))
@@ -61,6 +68,14 @@ class MetadataRaw(UserDict):
61
68
  return True
62
69
 
63
70
 
71
+ @dataclass
72
+ class ReadResult:
73
+ sheets: dict[str, dict | list]
74
+ read_info_by_sheet: dict[str, SpreadsheetRead]
75
+ role: RoleTypes
76
+ schema: SchemaCompleteness | None
77
+
78
+
64
79
  class SpreadsheetReader:
65
80
  def __init__(self, issue_list: IssueList, is_reference: bool = False):
66
81
  self.issue_list = issue_list
@@ -79,7 +94,7 @@ class SpreadsheetReader:
79
94
  def to_reference_sheet(cls, sheet_name: str) -> str:
80
95
  return f"Ref{sheet_name}"
81
96
 
82
- def read(self, filepath: Path) -> Rules | None:
97
+ def read(self, filepath: Path) -> None | ReadResult:
83
98
  with pd.ExcelFile(filepath) as excel_file:
84
99
  if self.metadata_sheet_name not in excel_file.sheet_names:
85
100
  self.issue_list.append(
@@ -95,21 +110,10 @@ class SpreadsheetReader:
95
110
  return None
96
111
 
97
112
  sheets, read_info_by_sheet = self._read_sheets(metadata, excel_file)
98
- if self.issue_list.has_errors:
99
- return None
100
-
101
- rules_cls = RULES_PER_ROLE[metadata.role]
102
- with _handle_issues(
103
- self.issue_list,
104
- error_cls=issues.spreadsheet.InvalidSheetError,
105
- error_args={"read_info_by_sheet": read_info_by_sheet},
106
- ) as future:
107
- rules = rules_cls.model_validate(sheets) # type: ignore[attr-defined]
108
-
109
- if future.result == "failure" or self.issue_list.has_errors:
113
+ if sheets is None or self.issue_list.has_errors:
110
114
  return None
111
115
 
112
- return rules
116
+ return ReadResult(sheets, read_info_by_sheet, metadata.role, metadata.schema)
113
117
 
114
118
  def _read_sheets(
115
119
  self, metadata: MetadataRaw, excel_file: ExcelFile
@@ -167,43 +171,60 @@ class ExcelImporter(BaseImporter):
167
171
  is_reference: bool = False,
168
172
  ) -> tuple[Rules | None, IssueList] | Rules:
169
173
  issue_list = IssueList(title=f"'{self.filepath.name}'")
170
-
171
174
  if not self.filepath.exists():
172
175
  issue_list.append(issues.spreadsheet_file.SpreadsheetNotFoundError(self.filepath))
173
176
  return self._return_or_raise(issue_list, errors)
174
177
 
175
- user_rules: Rules | None = None
178
+ user_result: ReadResult | None = None
176
179
  if not is_reference:
177
- user_rules = SpreadsheetReader(issue_list, is_reference=False).read(self.filepath)
178
- if issue_list.has_errors:
180
+ user_result = SpreadsheetReader(issue_list, is_reference=False).read(self.filepath)
181
+ if user_result is None or issue_list.has_errors:
179
182
  return self._return_or_raise(issue_list, errors)
180
183
 
181
- reference_rules: Rules | None = None
184
+ reference_result: ReadResult | None = None
182
185
  if is_reference or (
183
- user_rules
184
- and user_rules.metadata.role != RoleTypes.domain_expert
185
- and cast(DMSRules | InformationRules, user_rules).metadata.schema_ == SchemaCompleteness.extended
186
+ user_result
187
+ and user_result.role != RoleTypes.domain_expert
188
+ and user_result.schema == SchemaCompleteness.extended
186
189
  ):
187
- reference_rules = SpreadsheetReader(issue_list, is_reference=True).read(self.filepath)
190
+ reference_result = SpreadsheetReader(issue_list, is_reference=True).read(self.filepath)
188
191
  if issue_list.has_errors:
189
192
  return self._return_or_raise(issue_list, errors)
190
193
 
191
- if user_rules and reference_rules and user_rules.metadata.role != reference_rules.metadata.role:
194
+ if user_result and reference_result and user_result.role != reference_result.role:
192
195
  issue_list.append(issues.spreadsheet_file.RoleMismatchError(self.filepath))
193
196
  return self._return_or_raise(issue_list, errors)
194
197
 
195
- if user_rules and reference_rules:
196
- rules = user_rules
197
- rules.reference = reference_rules
198
- elif user_rules:
199
- rules = user_rules
200
- elif reference_rules:
201
- rules = reference_rules
198
+ if user_result and reference_result:
199
+ user_result.sheets["reference"] = reference_result.sheets
200
+ sheets = user_result.sheets
201
+ original_role = user_result.role
202
+ read_info_by_sheet = user_result.read_info_by_sheet
203
+ read_info_by_sheet.update(reference_result.read_info_by_sheet)
204
+ elif user_result:
205
+ sheets = user_result.sheets
206
+ original_role = user_result.role
207
+ read_info_by_sheet = user_result.read_info_by_sheet
208
+ elif reference_result:
209
+ sheets = reference_result.sheets
210
+ original_role = reference_result.role
211
+ read_info_by_sheet = reference_result.read_info_by_sheet
202
212
  else:
203
213
  raise ValueError(
204
214
  "No rules were generated. This should have been caught earlier. " f"Bug in {type(self).__name__}."
205
215
  )
206
216
 
217
+ rules_cls = RULES_PER_ROLE[original_role]
218
+ with _handle_issues(
219
+ issue_list,
220
+ error_cls=issues.spreadsheet.InvalidSheetError,
221
+ error_args={"read_info_by_sheet": read_info_by_sheet},
222
+ ) as future:
223
+ rules = rules_cls.model_validate(sheets) # type: ignore[attr-defined]
224
+
225
+ if future.result == "failure" or issue_list.has_errors:
226
+ return self._return_or_raise(issue_list, errors)
227
+
207
228
  return self._to_output(
208
229
  rules,
209
230
  issue_list,
@@ -24,6 +24,8 @@ __all__ = [
24
24
  "EmptyContainerWarning",
25
25
  "UnsupportedRelationWarning",
26
26
  "MultipleReferenceWarning",
27
+ "HasDataFilterOnNoPropertiesViewWarning",
28
+ "NodeTypeFilterOnParentViewWarning",
27
29
  ]
28
30
 
29
31
 
@@ -329,3 +331,44 @@ class MultipleReferenceWarning(DMSSchemaWarning):
329
331
  output["view_id"] = self.view_id.dump()
330
332
  output["implements"] = [view.dump() for view in self.implements]
331
333
  return output
334
+
335
+
336
+ @dataclass(frozen=True)
337
+ class HasDataFilterOnNoPropertiesViewWarning(DMSSchemaWarning):
338
+ description = "Attempting to set a HasData filter on a view without properties."
339
+ fix = "Add properties to the view or use a node type filter"
340
+ error_name: ClassVar[str] = "HasDataFilterOnNoPropertiesViewWarning"
341
+ view_id: dm.ViewId
342
+
343
+ def message(self) -> str:
344
+ return (
345
+ f"Cannot set hasData filter on view {self.view_id} as it does not have properties in any containers. "
346
+ "Using a node type filter instead."
347
+ )
348
+
349
+ def dump(self) -> dict[str, Any]:
350
+ output = super().dump()
351
+ output["view_id"] = self.view_id.dump()
352
+ return output
353
+
354
+
355
+ @dataclass(frozen=True)
356
+ class NodeTypeFilterOnParentViewWarning(DMSSchemaWarning):
357
+ description = (
358
+ "Setting a node type filter on a parent view. This is no "
359
+ "recommended as parent views are typically used for multiple type of nodes."
360
+ )
361
+ fix = "Use a HasData filter instead"
362
+ error_name: ClassVar[str] = "NodeTypeFilterOnParentViewWarning"
363
+ view_id: dm.ViewId
364
+
365
+ def message(self) -> str:
366
+ return (
367
+ f"Setting a node type filter on parent view {self.view_id}. This is not recommended as "
368
+ "parent views are typically used for multiple types of nodes."
369
+ )
370
+
371
+ def dump(self) -> dict[str, Any]:
372
+ output = super().dump()
373
+ output["view_id"] = self.view_id.dump()
374
+ return output
@@ -14,7 +14,6 @@ from cognite.neat.rules.models.rdfpath import (
14
14
  TransformationRuleType,
15
15
  parse_rule,
16
16
  )
17
- from cognite.neat.utils.text import to_pascal
18
17
 
19
18
  if sys.version_info >= (3, 11):
20
19
  from enum import StrEnum
@@ -197,15 +196,14 @@ class ContainerEntity(Entity):
197
196
  def from_id(cls, container_id: ContainerId) -> "ContainerEntity":
198
197
  return ContainerEntity(prefix=container_id.space, suffix=container_id.external_id)
199
198
 
200
- def as_id(self, default_space: str | None, standardize_casing: bool = True) -> ContainerId:
199
+ def as_id(self, default_space: str | None) -> ContainerId:
201
200
  if self.space is Undefined and default_space is None:
202
201
  raise ValueError("Space is Undefined! Set default_space!")
203
202
 
204
- external_id = to_pascal(self.external_id) if standardize_casing else self.external_id
205
203
  if self.space is Undefined:
206
- return ContainerId(space=cast(str, default_space), external_id=external_id)
204
+ return ContainerId(space=cast(str, default_space), external_id=self.external_id)
207
205
  else:
208
- return ContainerId(space=self.space, external_id=external_id)
206
+ return ContainerId(space=self.space, external_id=self.external_id)
209
207
 
210
208
 
211
209
  class ViewEntity(Entity):
@@ -233,7 +231,6 @@ class ViewEntity(Entity):
233
231
  allow_none: Literal[False] = False,
234
232
  default_space: str | None = None,
235
233
  default_version: str | None = None,
236
- standardize_casing: bool = True,
237
234
  ) -> ViewId:
238
235
  ...
239
236
 
@@ -243,7 +240,6 @@ class ViewEntity(Entity):
243
240
  allow_none: Literal[True],
244
241
  default_space: str | None = None,
245
242
  default_version: str | None = None,
246
- standardize_casing: bool = True,
247
243
  ) -> ViewId | None:
248
244
  ...
249
245
 
@@ -252,7 +248,6 @@ class ViewEntity(Entity):
252
248
  allow_none: bool = False,
253
249
  default_space: str | None = None,
254
250
  default_version: str | None = None,
255
- standardize_casing: bool = True,
256
251
  ) -> ViewId | None:
257
252
  if self.suffix is Unknown and allow_none:
258
253
  return None
@@ -265,8 +260,7 @@ class ViewEntity(Entity):
265
260
  raise ValueError("space is required")
266
261
  if version is None:
267
262
  raise ValueError("version is required")
268
- external_id = to_pascal(self.external_id) if standardize_casing else self.external_id
269
- return ViewId(space=space, external_id=external_id, version=version)
263
+ return ViewId(space=space, external_id=self.external_id, version=version)
270
264
 
271
265
 
272
266
  class ViewPropEntity(ViewEntity):
@@ -303,14 +297,10 @@ class ViewPropEntity(ViewEntity):
303
297
  property_=prop_id.property,
304
298
  )
305
299
 
306
- def as_prop_id(
307
- self, default_space: str | None = None, default_version: str | None = None, standardize_casing: bool = True
308
- ) -> PropertyId:
300
+ def as_prop_id(self, default_space: str | None = None, default_version: str | None = None) -> PropertyId:
309
301
  if self.property_ is None:
310
302
  raise ValueError("property is required to create PropertyId")
311
- return PropertyId(
312
- source=self.as_id(False, default_space, default_version, standardize_casing), property=self.property_
313
- )
303
+ return PropertyId(source=self.as_id(False, default_space, default_version), property=self.property_)
314
304
 
315
305
  @property
316
306
  def versioned_id(self) -> str:
@@ -19,7 +19,6 @@ from rdflib import Namespace
19
19
  import cognite.neat.rules.issues.spreadsheet
20
20
  from cognite.neat.rules import issues
21
21
  from cognite.neat.rules.models._rules.domain_rules import DomainRules
22
- from cognite.neat.utils.text import to_camel
23
22
 
24
23
  from ._types import (
25
24
  CdfValueType,
@@ -207,11 +206,11 @@ class DMSContainer(SheetEntity):
207
206
  reference: ReferenceType = Field(alias="Reference", default=None)
208
207
  constraint: ContainerListType | None = Field(None, alias="Constraint")
209
208
 
210
- def as_container(self, default_space: str, standardize_casing: bool = True) -> dm.ContainerApply:
211
- container_id = self.container.as_id(default_space, standardize_casing)
209
+ def as_container(self, default_space: str) -> dm.ContainerApply:
210
+ container_id = self.container.as_id(default_space)
212
211
  constraints: dict[str, dm.Constraint] = {}
213
212
  for constraint in self.constraint or []:
214
- requires = dm.RequiresConstraint(constraint.as_id(default_space, standardize_casing))
213
+ requires = dm.RequiresConstraint(constraint.as_id(default_space))
215
214
  constraints[f"{constraint.space}_{constraint.external_id}"] = requires
216
215
 
217
216
  return dm.ContainerApply(
@@ -243,20 +242,18 @@ class DMSView(SheetEntity):
243
242
  view: ViewType = Field(alias="View")
244
243
  implements: ViewListType | None = Field(None, alias="Implements")
245
244
  reference: ReferenceType = Field(alias="Reference", default=None)
245
+ filter_: Literal["hasData", "nodeType"] | None = Field(None, alias="Filter")
246
246
  in_model: bool = Field(True, alias="InModel")
247
247
 
248
- def as_view(self, default_space: str, default_version: str, standardize_casing: bool = True) -> dm.ViewApply:
249
- view_id = self.view.as_id(False, default_space, default_version, standardize_casing)
248
+ def as_view(self, default_space: str, default_version: str) -> dm.ViewApply:
249
+ view_id = self.view.as_id(False, default_space, default_version)
250
250
  return dm.ViewApply(
251
251
  space=view_id.space,
252
252
  external_id=view_id.external_id,
253
253
  version=view_id.version or default_version,
254
254
  name=self.name or None,
255
255
  description=self.description,
256
- implements=[
257
- parent.as_id(False, default_space, default_version, standardize_casing)
258
- for parent in self.implements or []
259
- ]
256
+ implements=[parent.as_id(False, default_space, default_version) for parent in self.implements or []]
260
257
  or None,
261
258
  properties={},
262
259
  )
@@ -563,10 +560,8 @@ class DMSRules(BaseRules):
563
560
  "Containers" if info.by_alias else "containers": containers,
564
561
  }
565
562
 
566
- def as_schema(
567
- self, standardize_casing: bool = True, include_pipeline: bool = False, instance_space: str | None = None
568
- ) -> DMSSchema:
569
- return _DMSExporter(standardize_casing, include_pipeline, instance_space).to_schema(self)
563
+ def as_schema(self, include_pipeline: bool = False, instance_space: str | None = None) -> DMSSchema:
564
+ return _DMSExporter(include_pipeline, instance_space).to_schema(self)
570
565
 
571
566
  def as_information_architect_rules(self) -> "InformationRules":
572
567
  return _DMSRulesConverter(self).as_information_architect_rules()
@@ -598,17 +593,12 @@ class _DMSExporter:
598
593
  (This module cannot have a dependency on the exporter module, as it would create a circular dependency.)
599
594
 
600
595
  Args
601
- standardize_casing (bool): If True, the casing of the identifiers will be standardized. This means external IDs
602
- are PascalCase and property names are camelCase.
603
596
  include_pipeline (bool): If True, the pipeline will be included with the schema. Pipeline means the
604
597
  raw tables and transformations necessary to populate the data model.
605
598
  instance_space (str): The space to use for the instance. Defaults to None,`Rules.metadata.space` will be used
606
599
  """
607
600
 
608
- def __init__(
609
- self, standardize_casing: bool = True, include_pipeline: bool = False, instance_space: str | None = None
610
- ):
611
- self.standardize_casing = standardize_casing
601
+ def __init__(self, include_pipeline: bool = False, instance_space: str | None = None):
612
602
  self.include_pipeline = include_pipeline
613
603
  self.instance_space = instance_space
614
604
 
@@ -627,9 +617,7 @@ class _DMSExporter:
627
617
  )
628
618
 
629
619
  views_not_in_model = {
630
- view.view.as_id(False, default_space, default_version, self.standardize_casing)
631
- for view in rules.views
632
- if not view.in_model
620
+ view.view.as_id(False, default_space, default_version) for view in rules.views if not view.in_model
633
621
  }
634
622
  data_model = rules.metadata.as_data_model()
635
623
  data_model.views = sorted(
@@ -674,9 +662,11 @@ class _DMSExporter:
674
662
  default_space: str,
675
663
  default_version: str,
676
664
  ) -> tuple[dm.ViewApplyList, dm.NodeApplyList]:
677
- views = dm.ViewApplyList(
678
- [dms_view.as_view(default_space, default_version, self.standardize_casing) for dms_view in dms_views]
679
- )
665
+ views = dm.ViewApplyList([dms_view.as_view(default_space, default_version) for dms_view in dms_views])
666
+ dms_view_by_id = {
667
+ dms_view.view.as_id(False, default_space, default_version): dms_view for dms_view in dms_views
668
+ }
669
+
680
670
  for view in views:
681
671
  view_id = view.as_id()
682
672
  view.properties = {}
@@ -688,7 +678,7 @@ class _DMSExporter:
688
678
  # This is not yet supported in the CDF API, a warning has already been issued, here we convert it to
689
679
  # a multi-edge connection.
690
680
  if isinstance(prop.value_type, ViewEntity):
691
- source = prop.value_type.as_id(False, default_space, default_version, self.standardize_casing)
681
+ source = prop.value_type.as_id(False, default_space, default_version)
692
682
  else:
693
683
  raise ValueError(
694
684
  "Direct relation must have a view as value type. "
@@ -703,43 +693,48 @@ class _DMSExporter:
703
693
  direction="outwards",
704
694
  )
705
695
  elif prop.container and prop.container_property and prop.view_property:
706
- container_prop_identifier = (
707
- to_camel(prop.container_property) if self.standardize_casing else prop.container_property
708
- )
696
+ container_prop_identifier = prop.container_property
709
697
  extra_args: dict[str, Any] = {}
710
698
  if prop.relation == "direct" and isinstance(prop.value_type, ViewEntity):
711
- extra_args["source"] = prop.value_type.as_id(
712
- True, default_space, default_version, self.standardize_casing
713
- )
699
+ extra_args["source"] = prop.value_type.as_id(True, default_space, default_version)
714
700
  elif prop.relation == "direct" and not isinstance(prop.value_type, ViewEntity):
715
701
  raise ValueError(
716
702
  "Direct relation must have a view as value type. "
717
703
  "This should have been validated in the rules"
718
704
  )
719
705
  view_property = dm.MappedPropertyApply(
720
- container=prop.container.as_id(default_space, self.standardize_casing),
706
+ container=prop.container.as_id(default_space),
721
707
  container_property_identifier=container_prop_identifier,
722
708
  **extra_args,
723
709
  )
724
710
  elif prop.view and prop.view_property and prop.relation == "multiedge":
725
711
  if isinstance(prop.value_type, ViewEntity):
726
- source = prop.value_type.as_id(False, default_space, default_version, self.standardize_casing)
712
+ source = prop.value_type.as_id(False, default_space, default_version)
727
713
  else:
728
714
  raise ValueError(
729
715
  "Multiedge relation must have a view as value type. "
730
716
  "This should have been validated in the rules"
731
717
  )
732
- view_property = dm.MultiEdgeConnectionApply(
733
- type=dm.DirectRelationReference(
718
+ if isinstance(prop.reference, ReferenceEntity):
719
+ ref_view_prop = prop.reference.as_prop_id(default_space, default_version)
720
+ edge_type = dm.DirectRelationReference(
721
+ space=ref_view_prop.source.space,
722
+ external_id=f"{ref_view_prop.source.external_id}.{ref_view_prop.property}",
723
+ )
724
+ else:
725
+ edge_type = dm.DirectRelationReference(
734
726
  space=source.space,
735
727
  external_id=f"{prop.view.external_id}.{prop.view_property}",
736
- ),
728
+ )
729
+
730
+ view_property = dm.MultiEdgeConnectionApply(
731
+ type=edge_type,
737
732
  source=source,
738
733
  direction="outwards",
739
734
  )
740
735
  elif prop.view and prop.view_property and prop.relation == "reversedirect":
741
736
  if isinstance(prop.value_type, ViewPropEntity):
742
- source = prop.value_type.as_id(False, default_space, default_version, self.standardize_casing)
737
+ source = prop.value_type.as_id(False, default_space, default_version)
743
738
  else:
744
739
  raise ValueError(
745
740
  "Reverse direct relation must have a view as value type. "
@@ -759,11 +754,19 @@ class _DMSExporter:
759
754
  warnings.warn(
760
755
  issues.dms.ReverseOfDirectRelationListWarning(view_id, prop.property_), stacklevel=2
761
756
  )
762
- view_property = dm.MultiEdgeConnectionApply(
763
- type=dm.DirectRelationReference(
757
+ if isinstance(reverse_prop.reference, ReferenceEntity):
758
+ ref_view_prop = reverse_prop.reference.as_prop_id(default_space, default_version)
759
+ edge_type = dm.DirectRelationReference(
760
+ space=ref_view_prop.source.space,
761
+ external_id=f"{ref_view_prop.source.external_id}.{ref_view_prop.property}",
762
+ )
763
+ else:
764
+ edge_type = dm.DirectRelationReference(
764
765
  space=source.space,
765
766
  external_id=f"{reverse_prop.view.external_id}.{reverse_prop.view_property}",
766
- ),
767
+ )
768
+ view_property = dm.MultiEdgeConnectionApply(
769
+ type=edge_type,
767
770
  source=source,
768
771
  direction="inwards",
769
772
  )
@@ -791,29 +794,43 @@ class _DMSExporter:
791
794
  continue
792
795
  else:
793
796
  continue
794
- prop_name = to_camel(prop.view_property) if self.standardize_casing else prop.view_property
797
+ prop_name = prop.view_property
795
798
  view.properties[prop_name] = view_property
796
799
 
797
800
  node_types = dm.NodeApplyList([])
798
801
  parent_views = {parent for view in views for parent in view.implements or []}
799
- node_type_flag = False
800
802
  for view in views:
801
803
  ref_containers = sorted(view.referenced_containers(), key=lambda c: c.as_tuple())
804
+ dms_view = dms_view_by_id.get(view.as_id())
802
805
  has_data = dm.filters.HasData(containers=list(ref_containers)) if ref_containers else None
803
- node_type = dm.filters.Equals(["node", "type"], {"space": view.space, "externalId": view.external_id})
806
+ if dms_view and isinstance(dms_view.reference, ReferenceEntity):
807
+ # If the view is a reference, we implement the reference view,
808
+ # and need the filter to match the reference
809
+ ref_view = dms_view.reference.as_id(False, default_space, default_version)
810
+ node_type = dm.filters.Equals(
811
+ ["node", "type"], {"space": ref_view.space, "externalId": ref_view.external_id}
812
+ )
813
+ else:
814
+ node_type = dm.filters.Equals(["node", "type"], {"space": view.space, "externalId": view.external_id})
804
815
  if view.as_id() in parent_views:
805
- view.filter = has_data
806
- elif has_data is None:
807
- # Child filter without container properties
808
- if node_type_flag:
809
- # Transformations do not yet support setting node type.
816
+ if dms_view and dms_view.filter_ == "nodeType":
817
+ warnings.warn(issues.dms.NodeTypeFilterOnParentViewWarning(view.as_id()), stacklevel=2)
810
818
  view.filter = node_type
811
819
  node_types.append(dm.NodeApply(space=view.space, external_id=view.external_id, sources=[]))
820
+ else:
821
+ view.filter = has_data
822
+ elif has_data is None:
823
+ # Child filter without container properties
824
+ if dms_view and dms_view.filter_ == "hasData":
825
+ warnings.warn(issues.dms.HasDataFilterOnNoPropertiesViewWarning(view.as_id()), stacklevel=2)
826
+ view.filter = node_type
827
+ node_types.append(dm.NodeApply(space=view.space, external_id=view.external_id, sources=[]))
812
828
  else:
813
- # Child filter with its own container properties
814
- if node_type_flag:
815
- # Transformations do not yet support setting node type.
816
- view.filter = dm.filters.And(has_data, node_type)
829
+ if dms_view and (dms_view.filter_ == "hasData" or dms_view.filter_ is None):
830
+ # Default option
831
+ view.filter = has_data
832
+ elif dms_view and dms_view.filter_ == "nodeType":
833
+ view.filter = node_type
817
834
  node_types.append(dm.NodeApply(space=view.space, external_id=view.external_id, sources=[]))
818
835
  else:
819
836
  view.filter = has_data
@@ -826,10 +843,7 @@ class _DMSExporter:
826
843
  default_space: str,
827
844
  ) -> dm.ContainerApplyList:
828
845
  containers = dm.ContainerApplyList(
829
- [
830
- dms_container.as_container(default_space, self.standardize_casing)
831
- for dms_container in dms_container or []
832
- ]
846
+ [dms_container.as_container(default_space) for dms_container in dms_container or []]
833
847
  )
834
848
  container_to_drop = set()
835
849
  for container in containers:
@@ -846,7 +860,7 @@ class _DMSExporter:
846
860
  else:
847
861
  type_cls = dm.DirectRelation
848
862
 
849
- prop_name = to_camel(prop.container_property) if self.standardize_casing else prop.container_property
863
+ prop_name = prop.container_property
850
864
 
851
865
  if type_cls is dm.DirectRelation:
852
866
  container.properties[prop_name] = dm.ContainerProperty(
@@ -907,21 +921,21 @@ class _DMSExporter:
907
921
  container_properties_by_id: dict[dm.ContainerId, list[DMSProperty]] = defaultdict(list)
908
922
  view_properties_by_id: dict[dm.ViewId, list[DMSProperty]] = defaultdict(list)
909
923
  for prop in rules.properties:
910
- view_id = prop.view.as_id(False, default_space, default_version, self.standardize_casing)
924
+ view_id = prop.view.as_id(False, default_space, default_version)
911
925
  view_properties_by_id[view_id].append(prop)
912
926
 
913
927
  if prop.container and prop.container_property:
914
928
  if prop.relation == "direct" and prop.is_list:
915
929
  warnings.warn(
916
930
  issues.dms.DirectRelationListWarning(
917
- container_id=prop.container.as_id(default_space, self.standardize_casing),
918
- view_id=prop.view.as_id(False, default_space, default_version, self.standardize_casing),
931
+ container_id=prop.container.as_id(default_space),
932
+ view_id=prop.view.as_id(False, default_space, default_version),
919
933
  property=prop.container_property,
920
934
  ),
921
935
  stacklevel=2,
922
936
  )
923
937
  continue
924
- container_id = prop.container.as_id(default_space, self.standardize_casing)
938
+ container_id = prop.container.as_id(default_space)
925
939
  container_properties_by_id[container_id].append(prop)
926
940
 
927
941
  return container_properties_by_id, view_properties_by_id
@@ -102,7 +102,6 @@ class RulesToDMS(Step):
102
102
  if multi_space_components_create
103
103
  else {input_rules.metadata.space if isinstance(input_rules, DMSRules) else input_rules.metadata.prefix},
104
104
  existing_handling=existing_components_handling,
105
- standardize_casing=False,
106
105
  )
107
106
 
108
107
  output_dir = self.data_store_path / Path("staging")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cognite-neat
3
- Version: 0.72.1
3
+ Version: 0.72.3
4
4
  Summary: Knowledge graph transformation
5
5
  Home-page: https://cognite-neat.readthedocs-hosted.com/
6
6
  License: Apache-2.0
@@ -1,5 +1,5 @@
1
1
  cognite/neat/__init__.py,sha256=v-rRiDOgZ3sQSMQKq0vgUQZvpeOkoHFXissAx6Ktg84,61
2
- cognite/neat/_version.py,sha256=-bsES2AHa1TNyPmsDMRScqqA4ezbJdvAUS3UylEI4rQ,23
2
+ cognite/neat/_version.py,sha256=AZKRaRERnGxRM4Vpp2s8T1LNhTACd4GALrf4Zjj-jCM,23
3
3
  cognite/neat/app/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  cognite/neat/app/api/asgi/metrics.py,sha256=nxFy7L5cChTI0a-zkCiJ59Aq8yLuIJp5c9Dg0wRXtV0,152
5
5
  cognite/neat/app/api/configuration.py,sha256=xnKdBE_dtq1nRvKa79YGA_wimI5UhoSRuBQz4LkLzQw,4606
@@ -10,7 +10,7 @@ cognite/neat/app/api/data_classes/configuration.py,sha256=oBnnX6Zam7TOstiLpQbi3G
10
10
  cognite/neat/app/api/data_classes/rest.py,sha256=yVWqFkBCDCGooOWaE5nun4No8B-PBa6svdenIjBINdo,1675
11
11
  cognite/neat/app/api/explorer.py,sha256=OlLI-RbQGjXEuDgtmFfBuTXfnRVemTJDKbL9VvXLr6Y,1891
12
12
  cognite/neat/app/api/routers/configuration.py,sha256=tFiEbtFHNVehMwM8T-IvnWpDOL_y-wCt-wd5w-Z4PQk,554
13
- cognite/neat/app/api/routers/core.py,sha256=OO9M611KG9QAdCVurWQPiU6wj6GVsTzs5DdXlCFA-wI,2191
13
+ cognite/neat/app/api/routers/core.py,sha256=ZU7sZ1QgFtrNHR-Y6DVzxLZSIJoZZeCvlXLgp2oO46U,3583
14
14
  cognite/neat/app/api/routers/crud.py,sha256=Cnvw77JWCs_wzeoQYdWwGfFns8LgtYmsYWgKPtud3BA,4646
15
15
  cognite/neat/app/api/routers/data_exploration.py,sha256=XlpEbggy1mK1XmwVtLZmrXWulTzdaGQaKAyHs3H04qU,13653
16
16
  cognite/neat/app/api/routers/metrics.py,sha256=S_bUQk_GjfQq7WbEhSVdow4MUYBZ_bZNafzgcKogXK8,210
@@ -39,7 +39,7 @@ cognite/neat/app/ui/neat-app/build/static/js/main.2efd96b2.js.LICENSE.txt,sha256
39
39
  cognite/neat/app/ui/neat-app/build/static/js/main.2efd96b2.js.map,sha256=zUzgUBAKbtIFkXu3E6wz1hL7IKv8Xi86iym_P5OPATU,6234629
40
40
  cognite/neat/app/ui/neat-app/build/static/media/logo.8093b84df9ed36a174c629d6fe0b730d.svg,sha256=EYf9q9JoVJ1L1np-XloeEZXCmaibzKmmpXCKn_44xzA,240334
41
41
  cognite/neat/config.py,sha256=5_dTuoL5crCmbSdKNuNOMQJVPNGiPy7ib2MlMkgPlOM,1503
42
- cognite/neat/constants.py,sha256=O3BpKbqfre0jQF6h72Yr-mY0jIByqI_dkbI3rnHdwqM,1228
42
+ cognite/neat/constants.py,sha256=5ujOhkmobXBleswTahlLltQwDu9bl7w00nwrVyr5_0k,1205
43
43
  cognite/neat/exceptions.py,sha256=CM7aCvbek9klOgjTsJ9bfEA8t7KTAL6dc7Mviu4NvSI,4268
44
44
  cognite/neat/graph/__init__.py,sha256=31uTeejWOSd-I8iUG8GOZFhHZcQCsBitJ6X8vu2r1nU,73
45
45
  cognite/neat/graph/examples/Knowledge-Graph-Nordic44-dirty.xml,sha256=ujJip6XBs5n8enVDPzNnuGkMBwv8g21tIr1sEVJpK5M,1439359
@@ -113,9 +113,9 @@ cognite/neat/rules/exporter/_validation.py,sha256=CnEer181-EdnWl3yOuZJKOJ80W7H7q
113
113
  cognite/neat/rules/exporters/__init__.py,sha256=Gn3CjkVKHJF9Po1ZPH4wAJ-sRW9up7b2CpXm-eReV3Q,413
114
114
  cognite/neat/rules/exporters/_base.py,sha256=aRCzRjGDoXILkGvASev2UjVvLXrVCRTFiKgYwzJZqAo,1518
115
115
  cognite/neat/rules/exporters/_models.py,sha256=f_RbFhoyD27z6Dsk4upYMHp7JHZRCfIvZsEzH5JSvtc,1645
116
- cognite/neat/rules/exporters/_rules2dms.py,sha256=hvmMxwL9RCAA1b2i5RndjgWnKJv3TKkxdWFovLpJacA,12221
116
+ cognite/neat/rules/exporters/_rules2dms.py,sha256=JPwaD42STCLi3N2zH8fKeKhWTNUsT-KsM3t56Pzap3A,11854
117
117
  cognite/neat/rules/exporters/_rules2excel.py,sha256=uK-aS9sBwXUCFQLIO1jciBQrB4w7ySF6MafDqG23hrQ,9080
118
- cognite/neat/rules/exporters/_rules2ontology.py,sha256=70T28d1tcT179kt5yOZQlLgAQ67uydz3XbhbA10IRuI,19768
118
+ cognite/neat/rules/exporters/_rules2ontology.py,sha256=PqE62FIPWFWUkivyxzOUVFf9Nx8yVJghZBB9A_7us4Q,19922
119
119
  cognite/neat/rules/exporters/_rules2yaml.py,sha256=HKgFlpgD7U2vWLQC_VdSvkDk19QgeVAd_J8wQ9ZgrN8,3038
120
120
  cognite/neat/rules/exporters/_validation.py,sha256=E6nn1QicaJpDFiXrYRzwTqsJ5VULVzzeqhCBVlRxH4M,4092
121
121
  cognite/neat/rules/importer/__init__.py,sha256=h1owL8pBPEtOmlIFAdkqAABH1A_Op5plh8C53og0uag,636
@@ -142,14 +142,14 @@ cognite/neat/rules/importers/_dtdl2rules/dtdl_importer.py,sha256=QThkjUuEVWI19yn
142
142
  cognite/neat/rules/importers/_dtdl2rules/spec.py,sha256=7Kd4WJEVoRoM8ssvl5zv2ALHDh3Mc0EUJ7v_6i8xJOk,11926
143
143
  cognite/neat/rules/importers/_owl2rules/__init__.py,sha256=tdGcrgtozdQyST-pTlxIa4cLBNTLvtk1nNYR4vOdFSw,63
144
144
  cognite/neat/rules/importers/_owl2rules/_owl2classes.py,sha256=tCEwwJPCdFLodM0q0gXfbyEe0rZvIG4emDTcUzDYRWI,7597
145
- cognite/neat/rules/importers/_owl2rules/_owl2metadata.py,sha256=kCTCAbUaUGgSwnH-jgFg01SfxD2VikyPy5L-vgxUjHA,7674
146
- cognite/neat/rules/importers/_owl2rules/_owl2properties.py,sha256=KNOrOySUXM9Krg6HEPNtiThlHfSEhd0EoQBtu_lczu8,7319
147
- cognite/neat/rules/importers/_owl2rules/_owl2rules.py,sha256=R8Z6f7f-MbKyr9fgKW5sStKlXxvUeOiS4lotjavIx2E,7119
148
- cognite/neat/rules/importers/_spreadsheet2rules.py,sha256=GVkTtWnQkM8nXkPAOs2UpxKnsPHA6898Tb7aTgcDDPM,10573
145
+ cognite/neat/rules/importers/_owl2rules/_owl2metadata.py,sha256=UPOPBYpOjpOdV8Bcbx31O62Tkjzg-nGjx8uE4JD-HoQ,7791
146
+ cognite/neat/rules/importers/_owl2rules/_owl2properties.py,sha256=VW0pC09Hm_EC0O89HX8RrGCpcemaWshIW7hKHWWZ63I,7443
147
+ cognite/neat/rules/importers/_owl2rules/_owl2rules.py,sha256=xVGOo5wnoXLI3E9OUIDfvpNLOIAhkbcC6--PVkUhgk4,7120
148
+ cognite/neat/rules/importers/_spreadsheet2rules.py,sha256=QIYTW-3Uc5ffFp3rJNyiqigWvc6x2eZTvhxqrXlGGSs,11481
149
149
  cognite/neat/rules/importers/_yaml2rules.py,sha256=sIaYY3Zo--v1cXSu65n4ZPv47cS-5InvSbpkw3Ahov4,4198
150
150
  cognite/neat/rules/issues/__init__.py,sha256=Ms6jgCxCezc5IgTOwCFtXQPtoVFfOvdcXj84_rs917I,563
151
151
  cognite/neat/rules/issues/base.py,sha256=dS4lmbW9VQ8awgOIB-Ah9z9LdNbCa-fPd8tbyPb8sM4,5856
152
- cognite/neat/rules/issues/dms.py,sha256=q5Sv81HiRpX4e7B3wzG3kILpbdGNrbYSyTlT3yw1d2A,11167
152
+ cognite/neat/rules/issues/dms.py,sha256=WB8N6MPbLFxdScJLGGY_zdErcrEXJnAsMladMB5aKa4,12722
153
153
  cognite/neat/rules/issues/fileread.py,sha256=n-GZaULOJF_MKkBIh1maaOuGZXOvZYw7Y6fDAS0jrBI,4492
154
154
  cognite/neat/rules/issues/formatters.py,sha256=_pSogWtfkt2JK0PZgWQffbj2On8vumFNshxOKAi5fYw,3346
155
155
  cognite/neat/rules/issues/importing.py,sha256=GqUywhBD840Fbc4DD5L2I0oEllJ78MTjpmXogVEjihA,7493
@@ -159,11 +159,11 @@ cognite/neat/rules/models/__init__.py,sha256=23T73EaHuS0dsYTh6tww6gXAc7S4rdx8e5n
159
159
  cognite/neat/rules/models/_base.py,sha256=1WNXBJHJ3nwnVoeNhpm9B6TBuqWYYgChkrdK4FJIpQM,4989
160
160
  cognite/neat/rules/models/_rules/__init__.py,sha256=jA4kMOAg4GJZjhCW1ovSjUCv-Top7O2HocZV0zJ78o4,517
161
161
  cognite/neat/rules/models/_rules/_types/__init__.py,sha256=Px0uB5fqk-8qH-HRi0ZvgGkLhYcS5A8EJ9QDB2TFwNQ,1299
162
- cognite/neat/rules/models/_rules/_types/_base.py,sha256=EsTqjXUP0zpuQ-Z_BMP-00rJBy2A2s-lJHzudIDAfqw,17145
162
+ cognite/neat/rules/models/_rules/_types/_base.py,sha256=okf8ebEcKrXf1rZQNp_cMsTS4pNKdJk2QMz_8-wi_so,16681
163
163
  cognite/neat/rules/models/_rules/_types/_field.py,sha256=dOVAU1jWCupFVnrYYwLfI-nNUC4rv4vXHMzpiObtWiw,10295
164
164
  cognite/neat/rules/models/_rules/_types/_value.py,sha256=ubyWmU6neyNxx17fqcciIjyB-CIpYNUuM97Xh2sVrYo,6308
165
165
  cognite/neat/rules/models/_rules/base.py,sha256=9DgtdCmpz84sMFxZB_stWkalVbjA4HQKsTMpSjjOVLU,10635
166
- cognite/neat/rules/models/_rules/dms_architect_rules.py,sha256=d4WKTyuSWWw6ioOYCnayTQcTWNGv-dys2LU3PBI8Fuc,49465
166
+ cognite/neat/rules/models/_rules/dms_architect_rules.py,sha256=bsuwCFiVFnDQuoAdwTu_-kp5oJGepuD24kLO9B_5YYc,50424
167
167
  cognite/neat/rules/models/_rules/dms_schema.py,sha256=-ru40beGY2WJvf9_sd5eO2Wh8x2qLQ2UmgzExloBWac,30229
168
168
  cognite/neat/rules/models/_rules/domain_rules.py,sha256=mOE4M6wOurmnAehxbnxvP9vIVXsFuKSiyMmD1shXKpA,2051
169
169
  cognite/neat/rules/models/_rules/information_rules.py,sha256=kETaZ3HsPw0EFXIeU-YhfEZeK4FhAh5RvNQAWbrcE-E,21026
@@ -211,7 +211,7 @@ cognite/neat/workflows/steps/lib/graph_extractor.py,sha256=vW9UpJScx5dFVCSairpOd
211
211
  cognite/neat/workflows/steps/lib/graph_loader.py,sha256=HfGg1HRZhbV58TFu89FTjKeUxGsbCYLeFJIQFDN_pQM,2341
212
212
  cognite/neat/workflows/steps/lib/graph_store.py,sha256=NV5SZFTrbq_gtZZZdoEL8tIohdbsieKmpwrdWAHis-E,6288
213
213
  cognite/neat/workflows/steps/lib/io_steps.py,sha256=QAGypoi1vP32BRiIgBZ0B4qsbFMcwhzpRiVUUnWysLA,16874
214
- cognite/neat/workflows/steps/lib/rules_exporter.py,sha256=qRIdsNvj-gWdGF6ilTfSXBwBeEEwwxVHH9g-gDPKNzY,18272
214
+ cognite/neat/workflows/steps/lib/rules_exporter.py,sha256=RDsRaRb9xRgFLO-x5qodDfyfDzQqXT0A-i2Se-FcFfI,18234
215
215
  cognite/neat/workflows/steps/lib/rules_importer.py,sha256=tckiHIS9Vnqx3df62jdtNwSm-Nk_XQwgo1sM0zKOw_s,7327
216
216
  cognite/neat/workflows/steps/lib/rules_validator.py,sha256=uGXcMncrtAu3IAMY3dqDNLfoL7sKSLzU1jz85xNrtO4,4785
217
217
  cognite/neat/workflows/steps/lib/v1/__init__.py,sha256=725aFzVqhE0tbVOAW70zWXTGKFiYImVupRZ4C5_IkUo,274
@@ -227,8 +227,8 @@ cognite/neat/workflows/steps_registry.py,sha256=PZVoHX4d6Vmjz6XzUFnFFWMCnrVnqkUC
227
227
  cognite/neat/workflows/tasks.py,sha256=dqlJwKAb0jlkl7abbY8RRz3m7MT4SK8-7cntMWkOYjw,788
228
228
  cognite/neat/workflows/triggers.py,sha256=_BLNplzoz0iic367u1mhHMHiUrCwP-SLK6_CZzfODX0,7071
229
229
  cognite/neat/workflows/utils.py,sha256=gKdy3RLG7ctRhbCRwaDIWpL9Mi98zm56-d4jfHDqP1E,453
230
- cognite_neat-0.72.1.dist-info/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
231
- cognite_neat-0.72.1.dist-info/METADATA,sha256=Ow2IjY4oEmsDS2NTfizqbgKBUapUvhV7WDWxBwIA5Ak,9321
232
- cognite_neat-0.72.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
233
- cognite_neat-0.72.1.dist-info/entry_points.txt,sha256=61FPqiWb25vbqB0KI7znG8nsg_ibLHBvTjYnkPvNFso,50
234
- cognite_neat-0.72.1.dist-info/RECORD,,
230
+ cognite_neat-0.72.3.dist-info/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
231
+ cognite_neat-0.72.3.dist-info/METADATA,sha256=4KC49y0DSL83A7qqb5OkxQv78ryoxQR22uLNhJs24Js,9321
232
+ cognite_neat-0.72.3.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
233
+ cognite_neat-0.72.3.dist-info/entry_points.txt,sha256=61FPqiWb25vbqB0KI7znG8nsg_ibLHBvTjYnkPvNFso,50
234
+ cognite_neat-0.72.3.dist-info/RECORD,,