cognite-neat 0.87.6__py3-none-any.whl → 0.88.0__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 (125) hide show
  1. cognite/neat/_version.py +1 -1
  2. cognite/neat/app/api/data_classes/rest.py +0 -19
  3. cognite/neat/app/api/explorer.py +6 -4
  4. cognite/neat/app/api/routers/crud.py +11 -21
  5. cognite/neat/app/api/routers/workflows.py +24 -94
  6. cognite/neat/graph/stores/_base.py +5 -0
  7. cognite/neat/rules/importers/_inference2rules.py +31 -35
  8. cognite/neat/workflows/steps/data_contracts.py +17 -43
  9. cognite/neat/workflows/steps/lib/current/graph_extractor.py +28 -24
  10. cognite/neat/workflows/steps/lib/current/graph_loader.py +4 -21
  11. cognite/neat/workflows/steps/lib/current/graph_store.py +18 -134
  12. cognite/neat/workflows/steps_registry.py +5 -7
  13. {cognite_neat-0.87.6.dist-info → cognite_neat-0.88.0.dist-info}/METADATA +1 -1
  14. {cognite_neat-0.87.6.dist-info → cognite_neat-0.88.0.dist-info}/RECORD +17 -125
  15. cognite/neat/app/api/routers/core.py +0 -91
  16. cognite/neat/app/api/routers/data_exploration.py +0 -336
  17. cognite/neat/app/api/routers/rules.py +0 -203
  18. cognite/neat/legacy/__init__.py +0 -0
  19. cognite/neat/legacy/graph/__init__.py +0 -3
  20. cognite/neat/legacy/graph/examples/Knowledge-Graph-Nordic44-dirty.xml +0 -20182
  21. cognite/neat/legacy/graph/examples/Knowledge-Graph-Nordic44.xml +0 -20163
  22. cognite/neat/legacy/graph/examples/__init__.py +0 -10
  23. cognite/neat/legacy/graph/examples/skos-capturing-sheet-wind-topics.xlsx +0 -0
  24. cognite/neat/legacy/graph/exceptions.py +0 -90
  25. cognite/neat/legacy/graph/extractors/__init__.py +0 -6
  26. cognite/neat/legacy/graph/extractors/_base.py +0 -14
  27. cognite/neat/legacy/graph/extractors/_dexpi.py +0 -44
  28. cognite/neat/legacy/graph/extractors/_graph_capturing_sheet.py +0 -403
  29. cognite/neat/legacy/graph/extractors/_mock_graph_generator.py +0 -361
  30. cognite/neat/legacy/graph/loaders/__init__.py +0 -23
  31. cognite/neat/legacy/graph/loaders/_asset_loader.py +0 -511
  32. cognite/neat/legacy/graph/loaders/_base.py +0 -67
  33. cognite/neat/legacy/graph/loaders/_exceptions.py +0 -85
  34. cognite/neat/legacy/graph/loaders/core/__init__.py +0 -0
  35. cognite/neat/legacy/graph/loaders/core/labels.py +0 -58
  36. cognite/neat/legacy/graph/loaders/core/models.py +0 -136
  37. cognite/neat/legacy/graph/loaders/core/rdf_to_assets.py +0 -1046
  38. cognite/neat/legacy/graph/loaders/core/rdf_to_relationships.py +0 -559
  39. cognite/neat/legacy/graph/loaders/rdf_to_dms.py +0 -309
  40. cognite/neat/legacy/graph/loaders/validator.py +0 -87
  41. cognite/neat/legacy/graph/models.py +0 -6
  42. cognite/neat/legacy/graph/stores/__init__.py +0 -13
  43. cognite/neat/legacy/graph/stores/_base.py +0 -400
  44. cognite/neat/legacy/graph/stores/_graphdb_store.py +0 -52
  45. cognite/neat/legacy/graph/stores/_memory_store.py +0 -43
  46. cognite/neat/legacy/graph/stores/_oxigraph_store.py +0 -151
  47. cognite/neat/legacy/graph/stores/_oxrdflib.py +0 -247
  48. cognite/neat/legacy/graph/stores/_rdf_to_graph.py +0 -42
  49. cognite/neat/legacy/graph/transformations/__init__.py +0 -0
  50. cognite/neat/legacy/graph/transformations/entity_matcher.py +0 -101
  51. cognite/neat/legacy/graph/transformations/query_generator/__init__.py +0 -3
  52. cognite/neat/legacy/graph/transformations/query_generator/sparql.py +0 -575
  53. cognite/neat/legacy/graph/transformations/transformer.py +0 -322
  54. cognite/neat/legacy/rules/__init__.py +0 -0
  55. cognite/neat/legacy/rules/analysis.py +0 -231
  56. cognite/neat/legacy/rules/examples/Rules-Nordic44-to-graphql.xlsx +0 -0
  57. cognite/neat/legacy/rules/examples/Rules-Nordic44.xlsx +0 -0
  58. cognite/neat/legacy/rules/examples/__init__.py +0 -18
  59. cognite/neat/legacy/rules/examples/power-grid-containers.yaml +0 -124
  60. cognite/neat/legacy/rules/examples/power-grid-example.xlsx +0 -0
  61. cognite/neat/legacy/rules/examples/power-grid-model.yaml +0 -224
  62. cognite/neat/legacy/rules/examples/rules-template.xlsx +0 -0
  63. cognite/neat/legacy/rules/examples/sheet2cdf-transformation-rules.xlsx +0 -0
  64. cognite/neat/legacy/rules/examples/skos-rules.xlsx +0 -0
  65. cognite/neat/legacy/rules/examples/source-to-solution-mapping-rules.xlsx +0 -0
  66. cognite/neat/legacy/rules/examples/wind-energy.owl +0 -1511
  67. cognite/neat/legacy/rules/exceptions.py +0 -2972
  68. cognite/neat/legacy/rules/exporters/__init__.py +0 -20
  69. cognite/neat/legacy/rules/exporters/_base.py +0 -45
  70. cognite/neat/legacy/rules/exporters/_core/__init__.py +0 -5
  71. cognite/neat/legacy/rules/exporters/_core/rules2labels.py +0 -24
  72. cognite/neat/legacy/rules/exporters/_rules2dms.py +0 -885
  73. cognite/neat/legacy/rules/exporters/_rules2excel.py +0 -213
  74. cognite/neat/legacy/rules/exporters/_rules2graphql.py +0 -183
  75. cognite/neat/legacy/rules/exporters/_rules2ontology.py +0 -524
  76. cognite/neat/legacy/rules/exporters/_rules2pydantic_models.py +0 -748
  77. cognite/neat/legacy/rules/exporters/_rules2rules.py +0 -105
  78. cognite/neat/legacy/rules/exporters/_rules2triples.py +0 -38
  79. cognite/neat/legacy/rules/exporters/_validation.py +0 -146
  80. cognite/neat/legacy/rules/importers/__init__.py +0 -22
  81. cognite/neat/legacy/rules/importers/_base.py +0 -66
  82. cognite/neat/legacy/rules/importers/_dict2rules.py +0 -158
  83. cognite/neat/legacy/rules/importers/_dms2rules.py +0 -194
  84. cognite/neat/legacy/rules/importers/_graph2rules.py +0 -308
  85. cognite/neat/legacy/rules/importers/_json2rules.py +0 -39
  86. cognite/neat/legacy/rules/importers/_owl2rules/__init__.py +0 -3
  87. cognite/neat/legacy/rules/importers/_owl2rules/_owl2classes.py +0 -239
  88. cognite/neat/legacy/rules/importers/_owl2rules/_owl2metadata.py +0 -260
  89. cognite/neat/legacy/rules/importers/_owl2rules/_owl2properties.py +0 -217
  90. cognite/neat/legacy/rules/importers/_owl2rules/_owl2rules.py +0 -290
  91. cognite/neat/legacy/rules/importers/_spreadsheet2rules.py +0 -45
  92. cognite/neat/legacy/rules/importers/_xsd2rules.py +0 -20
  93. cognite/neat/legacy/rules/importers/_yaml2rules.py +0 -39
  94. cognite/neat/legacy/rules/models/__init__.py +0 -5
  95. cognite/neat/legacy/rules/models/_base.py +0 -151
  96. cognite/neat/legacy/rules/models/raw_rules.py +0 -316
  97. cognite/neat/legacy/rules/models/rdfpath.py +0 -237
  98. cognite/neat/legacy/rules/models/rules.py +0 -1289
  99. cognite/neat/legacy/rules/models/tables.py +0 -9
  100. cognite/neat/legacy/rules/models/value_types.py +0 -118
  101. cognite/neat/legacy/workflows/examples/Export_DMS/workflow.yaml +0 -89
  102. cognite/neat/legacy/workflows/examples/Export_Rules_to_Ontology/workflow.yaml +0 -152
  103. cognite/neat/legacy/workflows/examples/Extract_DEXPI_Graph_and_Export_Rules/workflow.yaml +0 -139
  104. cognite/neat/legacy/workflows/examples/Extract_RDF_Graph_and_Generate_Assets/workflow.yaml +0 -270
  105. cognite/neat/legacy/workflows/examples/Import_DMS/workflow.yaml +0 -65
  106. cognite/neat/legacy/workflows/examples/Ontology_to_Data_Model/workflow.yaml +0 -116
  107. cognite/neat/legacy/workflows/examples/Validate_Rules/workflow.yaml +0 -67
  108. cognite/neat/legacy/workflows/examples/Validate_Solution_Model/workflow.yaml +0 -64
  109. cognite/neat/legacy/workflows/examples/Visualize_Data_Model_Using_Mock_Graph/workflow.yaml +0 -95
  110. cognite/neat/legacy/workflows/examples/Visualize_Semantic_Data_Model/workflow.yaml +0 -111
  111. cognite/neat/workflows/examples/Extract_RDF_Graph_and_Generate_Assets/workflow.yaml +0 -270
  112. cognite/neat/workflows/migration/__init__.py +0 -0
  113. cognite/neat/workflows/migration/steps.py +0 -91
  114. cognite/neat/workflows/migration/wf_manifests.py +0 -33
  115. cognite/neat/workflows/steps/lib/legacy/__init__.py +0 -7
  116. cognite/neat/workflows/steps/lib/legacy/graph_contextualization.py +0 -82
  117. cognite/neat/workflows/steps/lib/legacy/graph_extractor.py +0 -746
  118. cognite/neat/workflows/steps/lib/legacy/graph_loader.py +0 -606
  119. cognite/neat/workflows/steps/lib/legacy/graph_store.py +0 -307
  120. cognite/neat/workflows/steps/lib/legacy/graph_transformer.py +0 -58
  121. cognite/neat/workflows/steps/lib/legacy/rules_exporter.py +0 -511
  122. cognite/neat/workflows/steps/lib/legacy/rules_importer.py +0 -612
  123. {cognite_neat-0.87.6.dist-info → cognite_neat-0.88.0.dist-info}/LICENSE +0 -0
  124. {cognite_neat-0.87.6.dist-info → cognite_neat-0.88.0.dist-info}/WHEEL +0 -0
  125. {cognite_neat-0.87.6.dist-info → cognite_neat-0.88.0.dist-info}/entry_points.txt +0 -0
@@ -1,524 +0,0 @@
1
- import sys
2
- import warnings
3
- from abc import ABC
4
- from pathlib import Path
5
- from typing import ClassVar
6
-
7
- from pydantic import BaseModel, ConfigDict, ValidationInfo, field_validator
8
- from rdflib import DCTERMS, OWL, RDF, RDFS, XSD, BNode, Graph, Literal, Namespace, URIRef
9
- from rdflib.collection import Collection as GraphCollection
10
-
11
- from cognite.neat.legacy.rules import exceptions
12
- from cognite.neat.legacy.rules.analysis import to_class_property_pairs, to_property_dict
13
- from cognite.neat.legacy.rules.exporters._base import BaseExporter
14
- from cognite.neat.legacy.rules.exporters._validation import are_properties_redefined
15
- from cognite.neat.legacy.rules.models.rules import Class, Metadata, Property, Rules
16
- from cognite.neat.legacy.rules.models.value_types import XSD_VALUE_TYPE_MAPPINGS
17
- from cognite.neat.utils.auxiliary import generate_exception_report
18
- from cognite.neat.utils.rdf_ import remove_namespace_from_uri
19
-
20
- if sys.version_info >= (3, 11):
21
- from typing import Self
22
- else:
23
- from typing_extensions import Self
24
-
25
-
26
- class GraphExporter(BaseExporter[Graph], ABC):
27
- def _export_to_file(self, filepath: Path) -> None:
28
- self.export().serialize(destination=filepath)
29
-
30
-
31
- class OWLExporter(GraphExporter):
32
- def export(self) -> Graph:
33
- return Ontology.from_rules(self.rules).as_owl()
34
-
35
-
36
- class SHACLExporter(GraphExporter):
37
- def export(self) -> Graph:
38
- return Ontology.from_rules(self.rules).as_shacl()
39
-
40
-
41
- class SemanticDataModelExporter(GraphExporter):
42
- def export(self) -> Graph:
43
- return Ontology.from_rules(self.rules).as_semantic_data_model()
44
-
45
-
46
- class OntologyModel(BaseModel):
47
- model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True, strict=False, extra="allow")
48
-
49
-
50
- class Ontology(OntologyModel):
51
- """
52
- Represents an ontology. Thi class is used to generate an OWL ontology from a set of transformation rules.
53
-
54
- Args:
55
- properties: A list of OWL properties.
56
- classes: A list of OWL classes.
57
- shapes: A list of SHACL node shapes.
58
- metadata: Metadata about the ontology.
59
- prefixes: A dictionary of prefixes and namespaces.
60
- """
61
-
62
- properties: list["OWLProperty"]
63
- classes: list["OWLClass"]
64
- shapes: list["SHACLNodeShape"]
65
- metadata: "OWLMetadata"
66
- prefixes: dict[str, Namespace]
67
-
68
- @classmethod
69
- def from_rules(cls, rules: Rules) -> Self:
70
- """
71
- Generates an ontology from a set of transformation rules.
72
-
73
- Args:
74
- transformation_rules: Instance of TransformationRules.
75
-
76
- Returns:
77
- An instance of Ontology.
78
- """
79
- properties_redefined, redefinition_warnings = are_properties_redefined(rules, return_report=True)
80
- if properties_redefined:
81
- raise exceptions.PropertiesDefinedMultipleTimes(report=generate_exception_report(redefinition_warnings))
82
-
83
- if rules.prefixes is None:
84
- raise exceptions.PrefixMissing()
85
-
86
- if rules.metadata.namespace is None:
87
- raise exceptions.MissingDataModelPrefixOrNamespace()
88
-
89
- return cls(
90
- properties=[
91
- OWLProperty.from_list_of_properties(definition, rules.metadata.namespace)
92
- for definition in to_property_dict(rules).values()
93
- ],
94
- classes=[
95
- OWLClass.from_class(definition, rules.metadata.namespace, rules.prefixes)
96
- for definition in rules.classes.values()
97
- ],
98
- shapes=[
99
- SHACLNodeShape.from_rules(
100
- rules.classes[class_],
101
- list(properties.values()),
102
- rules.metadata.namespace,
103
- )
104
- for class_, properties in to_class_property_pairs(rules).items()
105
- ],
106
- metadata=OWLMetadata(**rules.metadata.model_dump()),
107
- prefixes=rules.prefixes,
108
- )
109
-
110
- def as_shacl(self) -> Graph:
111
- """
112
- Generates a SHACL graph from the ontology.
113
-
114
- Returns:
115
- A SHACL graph.
116
- """
117
-
118
- shacl = Graph()
119
- shacl.bind(self.metadata.prefix, self.metadata.namespace)
120
- for prefix, namespace in self.prefixes.items():
121
- shacl.bind(prefix, namespace)
122
-
123
- for shape in self.shapes:
124
- for triple in shape.triples:
125
- shacl.add(triple) # type: ignore[arg-type]
126
-
127
- return shacl
128
-
129
- def as_owl(self) -> Graph:
130
- """
131
- Generates an OWL graph from the ontology.
132
-
133
- Returns:
134
- An OWL graph.
135
- """
136
- owl = Graph()
137
- owl.bind(self.metadata.prefix, self.metadata.namespace)
138
- for prefix, namespace in self.prefixes.items():
139
- owl.bind(prefix, namespace)
140
-
141
- if self.metadata.namespace is None:
142
- raise exceptions.MetadataSheetNamespaceNotDefined()
143
-
144
- owl.add((URIRef(self.metadata.namespace), RDF.type, OWL.Ontology))
145
- for property_ in self.properties:
146
- for triple in property_.triples:
147
- owl.add(triple) # type: ignore[arg-type]
148
-
149
- for class_ in self.classes:
150
- for triple in class_.triples:
151
- owl.add(triple) # type: ignore[arg-type]
152
-
153
- for triple in self.metadata.triples:
154
- owl.add(triple) # type: ignore[arg-type]
155
-
156
- return owl
157
-
158
- def as_semantic_data_model(self) -> Graph:
159
- return self.as_owl() + self.as_shacl()
160
-
161
- @property
162
- def owl_triples(self) -> list[tuple]:
163
- return list(self.as_owl())
164
-
165
- @property
166
- def shacl_triples(self) -> list[tuple]:
167
- return list(self.as_shacl())
168
-
169
- @property
170
- def triples(self) -> list[tuple]:
171
- return self.owl_triples + self.shacl_triples
172
-
173
- @property
174
- def ontology(self) -> str:
175
- return self.as_owl().serialize()
176
-
177
- @property
178
- def constraints(self) -> str:
179
- return self.as_shacl().serialize()
180
-
181
- @property
182
- def semantic_data_model(self) -> str:
183
- return (self.as_owl() + self.as_shacl()).serialize()
184
-
185
-
186
- class OWLMetadata(Metadata):
187
- @property
188
- def triples(self) -> list[tuple]:
189
- # Mandatory triples originating from Metadata mandatory fields
190
- if self.namespace is None:
191
- raise exceptions.MetadataSheetNamespaceNotDefined()
192
- triples: list[tuple] = [
193
- (URIRef(self.namespace), DCTERMS.hasVersion, Literal(self.version)),
194
- (URIRef(self.namespace), OWL.versionInfo, Literal(self.version)),
195
- (URIRef(self.namespace), RDFS.label, Literal(self.name)),
196
- (URIRef(self.namespace), DCTERMS.title, Literal(self.name)),
197
- (URIRef(self.namespace), DCTERMS.created, Literal(self.created, datatype=XSD.dateTime)),
198
- (URIRef(self.namespace), DCTERMS.description, Literal(self.description)),
199
- ]
200
- if isinstance(self.creator, list):
201
- triples.extend([(URIRef(self.namespace), DCTERMS.creator, Literal(creator)) for creator in self.creator])
202
- else:
203
- triples.append((URIRef(self.namespace), DCTERMS.creator, Literal(self.creator)))
204
-
205
- # Optional triples originating from Metadata optional fields
206
- if self.updated:
207
- triples.append((URIRef(self.namespace), DCTERMS.modified, Literal(self.updated, datatype=XSD.dateTime)))
208
- if self.rights:
209
- triples.append((URIRef(self.namespace), DCTERMS.rights, Literal(self.rights)))
210
-
211
- if self.contributor and isinstance(self.contributor, list):
212
- triples.extend(
213
- [
214
- (URIRef(self.namespace), DCTERMS.contributor, Literal(contributor))
215
- for contributor in self.contributor
216
- ]
217
- )
218
- elif self.contributor:
219
- triples.append((URIRef(self.namespace), DCTERMS.contributor, Literal(self.contributor)))
220
-
221
- return triples
222
-
223
-
224
- class OWLClass(OntologyModel):
225
- id_: URIRef
226
- type_: URIRef = OWL.Class
227
- label: str | None
228
- comment: str | None
229
- sub_class_of: list[URIRef] | None
230
- namespace: Namespace
231
-
232
- @classmethod
233
- def from_class(cls, definition: Class, namespace: Namespace, prefixes: dict) -> Self:
234
- if definition.parent_class and isinstance(definition.parent_class, list):
235
- sub_class_of = []
236
- for parent_class in definition.parent_class:
237
- try:
238
- sub_class_of.append(prefixes[parent_class.prefix][parent_class.suffix])
239
- except KeyError:
240
- sub_class_of.append(namespace[parent_class.suffix])
241
- else:
242
- sub_class_of = None
243
-
244
- return cls(
245
- id_=namespace[definition.class_id],
246
- label=definition.class_name,
247
- comment=definition.description,
248
- sub_class_of=sub_class_of,
249
- namespace=namespace,
250
- )
251
-
252
- @property
253
- def type_triples(self) -> list[tuple]:
254
- return [(self.id_, RDF.type, self.type_)]
255
-
256
- @property
257
- def label_triples(self) -> list[tuple]:
258
- return [(self.id_, RDFS.label, Literal(self.label))]
259
-
260
- @property
261
- def comment_triples(self) -> list[tuple]:
262
- return [(self.id_, RDFS.comment, Literal(self.comment))]
263
-
264
- @property
265
- def subclass_triples(self) -> list[tuple]:
266
- if self.sub_class_of:
267
- return [(self.id_, RDFS.subClassOf, sub_class_of) for sub_class_of in self.sub_class_of]
268
- else:
269
- return []
270
-
271
- @property
272
- def triples(self) -> list[tuple]:
273
- return self.type_triples + self.label_triples + self.comment_triples + self.subclass_triples
274
-
275
-
276
- class OWLProperty(OntologyModel):
277
- id_: URIRef
278
- type_: set[URIRef]
279
- label: set[str]
280
- comment: set[str]
281
- domain: set[URIRef]
282
- range_: set[URIRef]
283
- namespace: Namespace
284
-
285
- @staticmethod
286
- def same_property_id(definitions: list[Property]) -> bool:
287
- return len({definition.property_id for definition in definitions}) == 1
288
-
289
- @classmethod
290
- def from_list_of_properties(cls, definitions: list[Property], namespace: Namespace) -> "OWLProperty":
291
- """Here list of properties is a list of properties with the same id, but different definitions."""
292
-
293
- if not cls.same_property_id(definitions):
294
- raise exceptions.PropertyDefinitionsNotForSameProperty()
295
-
296
- owl_property = cls.model_construct(
297
- id_=namespace[definitions[0].property_id],
298
- namespace=namespace,
299
- label=set(),
300
- comment=set(),
301
- domain=set(),
302
- range_=set(),
303
- type_=set(),
304
- )
305
- for definition in definitions:
306
- owl_property.type_.add(OWL[definition.property_type])
307
- owl_property.range_.add(
308
- XSD[definition.expected_value_type.suffix]
309
- if definition.expected_value_type.suffix in XSD_VALUE_TYPE_MAPPINGS
310
- else namespace[definition.expected_value_type.suffix]
311
- )
312
- owl_property.domain.add(namespace[definition.class_id])
313
-
314
- if definition.property_name:
315
- owl_property.label.add(definition.property_name)
316
- if definition.description:
317
- owl_property.comment.add(definition.description)
318
-
319
- return owl_property
320
-
321
- @field_validator("type_")
322
- def is_multi_type(cls, v, info: ValidationInfo):
323
- if len(v) > 1:
324
- warnings.warn(
325
- exceptions.OntologyMultiTypeProperty(
326
- remove_namespace_from_uri(info.data["id_"]), [remove_namespace_from_uri(t) for t in v]
327
- ).message,
328
- category=exceptions.OntologyMultiTypeProperty,
329
- stacklevel=2,
330
- )
331
- return v
332
-
333
- @field_validator("range_")
334
- def is_multi_range(cls, v, info: ValidationInfo):
335
- if len(v) > 1:
336
- warnings.warn(
337
- exceptions.OntologyMultiRangeProperty(
338
- remove_namespace_from_uri(info.data["id_"]), [remove_namespace_from_uri(t) for t in v]
339
- ).message,
340
- category=exceptions.OntologyMultiRangeProperty,
341
- stacklevel=2,
342
- )
343
- return v
344
-
345
- @field_validator("domain")
346
- def is_multi_domain(cls, v, info: ValidationInfo):
347
- if len(v) > 1:
348
- warnings.warn(
349
- exceptions.OntologyMultiDomainProperty(
350
- remove_namespace_from_uri(info.data["id_"]), [remove_namespace_from_uri(t) for t in v]
351
- ).message,
352
- category=exceptions.OntologyMultiDomainProperty,
353
- stacklevel=2,
354
- )
355
- return v
356
-
357
- @field_validator("label")
358
- def has_multi_name(cls, v, info: ValidationInfo):
359
- if len(v) > 1:
360
- warnings.warn(
361
- exceptions.OntologyMultiLabeledProperty(remove_namespace_from_uri(info.data["id_"]), v).message,
362
- category=exceptions.OntologyMultiLabeledProperty,
363
- stacklevel=2,
364
- )
365
- return v
366
-
367
- @field_validator("comment")
368
- def has_multi_comment(cls, v, info: ValidationInfo):
369
- if len(v) > 1:
370
- warnings.warn(
371
- exceptions.OntologyMultiDefinitionProperty(remove_namespace_from_uri(info.data["id_"])).message,
372
- category=exceptions.OntologyMultiDefinitionProperty,
373
- stacklevel=2,
374
- )
375
- return v
376
-
377
- @property
378
- def domain_triples(self) -> list[tuple]:
379
- triples: list[tuple] = []
380
- if len(self.domain) == 1:
381
- triples.append((self.id_, RDFS.domain, next(iter(self.domain))))
382
- else:
383
- _graph = Graph()
384
- b_union = BNode()
385
- b_domain = BNode()
386
- _graph.add((self.id_, RDFS.domain, b_domain))
387
- _graph.add((b_domain, OWL.unionOf, b_union))
388
- _graph.add((b_domain, RDF.type, OWL.Class))
389
- _ = GraphCollection(_graph, b_union, list(self.domain))
390
- triples.extend(list(_graph))
391
- return triples
392
-
393
- @property
394
- def range_triples(self) -> list[tuple]:
395
- triples: list[tuple] = []
396
- if len(self.range_) == 1:
397
- triples.append((self.id_, RDFS.range, next(iter(self.range_))))
398
- else:
399
- _graph = Graph()
400
- b_union = BNode()
401
- b_range = BNode()
402
- _graph.add((self.id_, RDFS.range, b_range))
403
- _graph.add((b_range, OWL.unionOf, b_union))
404
- _graph.add((b_range, RDF.type, OWL.Class))
405
- _graph.add((b_range, OWL.unionOf, b_union))
406
- _graph.add((b_range, RDF.type, OWL.Class))
407
- _ = GraphCollection(_graph, b_union, list(self.range_))
408
- triples.extend(list(_graph))
409
- return triples
410
-
411
- @property
412
- def type_triples(self) -> list[tuple]:
413
- return [(self.id_, RDF.type, type_) for type_ in self.type_]
414
-
415
- @property
416
- def label_triples(self) -> list[tuple]:
417
- label = list(filter(None, self.label))
418
- return [(self.id_, RDFS.label, Literal(label[0] if label else self.id_))]
419
-
420
- @property
421
- def comment_triples(self) -> list[tuple]:
422
- return [(self.id_, RDFS.comment, Literal("\n".join(filter(None, self.comment))))]
423
-
424
- @property
425
- def triples(self) -> list[tuple]:
426
- return self.type_triples + self.label_triples + self.comment_triples + self.domain_triples + self.range_triples
427
-
428
-
429
- SHACL = Namespace("http://www.w3.org/ns/shacl#")
430
-
431
-
432
- class SHACLNodeShape(OntologyModel):
433
- id_: URIRef
434
- type_: URIRef = SHACL.NodeShape
435
- target_class: URIRef
436
- property_shapes: list["SHACLPropertyShape"]
437
- namespace: Namespace
438
-
439
- @property
440
- def type_triples(self) -> list[tuple]:
441
- return [(self.id_, RDF.type, self.type_)]
442
-
443
- @property
444
- def target_class_triples(self) -> list[tuple]:
445
- return [(self.id_, SHACL.targetClass, self.target_class)]
446
-
447
- @property
448
- def property_shapes_triples(self) -> list[tuple]:
449
- triples: list[tuple] = []
450
- for property_shape in self.property_shapes:
451
- triples.append((self.id_, SHACL.property, property_shape.id_))
452
- triples.extend(property_shape.triples)
453
- return triples
454
-
455
- @property
456
- def triples(self) -> list[tuple]:
457
- return self.type_triples + self.target_class_triples + self.property_shapes_triples
458
-
459
- @classmethod
460
- def from_rules(
461
- cls, class_definition: Class, property_definitions: list[Property], namespace: Namespace
462
- ) -> "SHACLNodeShape":
463
- return cls(
464
- id_=namespace[f"{class_definition.class_id}Shape"],
465
- target_class=namespace[class_definition.class_id],
466
- property_shapes=[SHACLPropertyShape.from_property(prop, namespace) for prop in property_definitions],
467
- namespace=namespace,
468
- )
469
-
470
-
471
- class SHACLPropertyShape(OntologyModel):
472
- id_: BNode
473
- type_: URIRef = SHACL.property
474
- path: URIRef # URIRef to property in OWL
475
- node_kind: URIRef # SHACL.IRI or SHACL.Literal
476
- expected_value_type: URIRef
477
- min_count: int | None
478
- max_count: int | None
479
- namespace: Namespace
480
-
481
- @property
482
- def path_triples(self) -> list[tuple]:
483
- return [(self.id_, SHACL.path, self.path)]
484
-
485
- @property
486
- def node_kind_triples(self) -> list[tuple]:
487
- triples: list[tuple] = [(self.id_, SHACL.nodeKind, self.node_kind)]
488
-
489
- if self.node_kind == SHACL.Literal:
490
- triples.append((self.id_, SHACL.datatype, self.expected_value_type))
491
- else:
492
- triples.append((self.id_, SHACL.node, self.expected_value_type))
493
-
494
- return triples
495
-
496
- @property
497
- def cardinality_triples(self) -> list[tuple]:
498
- triples: list[tuple] = []
499
- if self.min_count:
500
- triples.append((self.id_, SHACL.minCount, Literal(self.min_count)))
501
- if self.max_count:
502
- triples.append((self.id_, SHACL.maxCount, Literal(self.max_count)))
503
-
504
- return triples
505
-
506
- @property
507
- def triples(self) -> list[tuple]:
508
- return self.path_triples + self.node_kind_triples + self.cardinality_triples
509
-
510
- @classmethod
511
- def from_property(cls, definition: Property, namespace: Namespace) -> "SHACLPropertyShape":
512
- return cls(
513
- id_=BNode(),
514
- path=namespace[definition.property_id],
515
- node_kind=SHACL.IRI if definition.property_type == "ObjectProperty" else SHACL.Literal,
516
- expected_value_type=(
517
- namespace[f"{definition.expected_value_type.suffix}Shape"]
518
- if definition.property_type == "ObjectProperty"
519
- else XSD[definition.expected_value_type.suffix]
520
- ),
521
- min_count=definition.min_count,
522
- max_count=definition.max_count,
523
- namespace=namespace,
524
- )