cognite-neat 0.123.2__py3-none-any.whl → 0.123.4__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 +1 -1
- cognite/neat/core/_data_model/importers/__init__.py +2 -12
- cognite/neat/core/_data_model/importers/_rdf/__init__.py +1 -2
- cognite/neat/session/_read.py +0 -23
- {cognite_neat-0.123.2.dist-info → cognite_neat-0.123.4.dist-info}/METADATA +1 -1
- {cognite_neat-0.123.2.dist-info → cognite_neat-0.123.4.dist-info}/RECORD +8 -14
- cognite/neat/core/_data_model/importers/_dtdl2data_model/__init__.py +0 -3
- cognite/neat/core/_data_model/importers/_dtdl2data_model/_unit_lookup.py +0 -224
- cognite/neat/core/_data_model/importers/_dtdl2data_model/dtdl_converter.py +0 -320
- cognite/neat/core/_data_model/importers/_dtdl2data_model/dtdl_importer.py +0 -155
- cognite/neat/core/_data_model/importers/_dtdl2data_model/spec.py +0 -363
- cognite/neat/core/_data_model/importers/_rdf/_imf2data_model.py +0 -98
- {cognite_neat-0.123.2.dist-info → cognite_neat-0.123.4.dist-info}/WHEEL +0 -0
- {cognite_neat-0.123.2.dist-info → cognite_neat-0.123.4.dist-info}/licenses/LICENSE +0 -0
cognite/neat/_version.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
__version__ = "0.123.
|
|
1
|
+
__version__ = "0.123.4"
|
|
2
2
|
__engine__ = "^2.0.4"
|
|
@@ -1,31 +1,21 @@
|
|
|
1
1
|
from ._base import BaseImporter
|
|
2
2
|
from ._dict2data_model import DictImporter
|
|
3
3
|
from ._dms2data_model import DMSImporter
|
|
4
|
-
from .
|
|
5
|
-
from ._rdf import IMFImporter, InferenceImporter, OWLImporter, SubclassInferenceImporter
|
|
4
|
+
from ._rdf import InferenceImporter, OWLImporter, SubclassInferenceImporter
|
|
6
5
|
from ._spreadsheet2data_model import ExcelImporter
|
|
7
6
|
|
|
8
7
|
__all__ = [
|
|
9
8
|
"BaseImporter",
|
|
10
9
|
"DMSImporter",
|
|
11
|
-
"DTDLImporter",
|
|
12
10
|
"DictImporter",
|
|
13
11
|
"ExcelImporter",
|
|
14
|
-
"IMFImporter",
|
|
15
12
|
"InferenceImporter",
|
|
16
13
|
"OWLImporter",
|
|
17
14
|
"SubclassInferenceImporter",
|
|
18
15
|
]
|
|
19
16
|
|
|
20
17
|
DataModelImporters = (
|
|
21
|
-
OWLImporter
|
|
22
|
-
| IMFImporter
|
|
23
|
-
| DMSImporter
|
|
24
|
-
| ExcelImporter
|
|
25
|
-
| DTDLImporter
|
|
26
|
-
| DictImporter
|
|
27
|
-
| InferenceImporter
|
|
28
|
-
| SubclassInferenceImporter
|
|
18
|
+
OWLImporter | DMSImporter | ExcelImporter | DictImporter | InferenceImporter | SubclassInferenceImporter
|
|
29
19
|
)
|
|
30
20
|
|
|
31
21
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
from ._imf2data_model import IMFImporter
|
|
2
1
|
from ._inference2rdata_model import InferenceImporter, SubclassInferenceImporter
|
|
3
2
|
from ._owl2data_model import OWLImporter
|
|
4
3
|
|
|
5
|
-
__all__ = ["
|
|
4
|
+
__all__ = ["InferenceImporter", "OWLImporter", "SubclassInferenceImporter"]
|
cognite/neat/session/_read.py
CHANGED
|
@@ -826,29 +826,6 @@ class RDFReadAPI(BaseReadAPI):
|
|
|
826
826
|
importer = importers.OWLImporter.from_file(reader.materialize_path(), source_name=f"file {reader!s}")
|
|
827
827
|
return self._state.data_model_import(importer)
|
|
828
828
|
|
|
829
|
-
def imf(self, io: Any) -> IssueList:
|
|
830
|
-
"""Reads IMF Types provided as SHACL shapes into NeatSession.
|
|
831
|
-
|
|
832
|
-
Args:
|
|
833
|
-
io: file path or url to the IMF file
|
|
834
|
-
|
|
835
|
-
Example:
|
|
836
|
-
```python
|
|
837
|
-
neat.read.rdf.imf("url_or_path_to_imf_source")
|
|
838
|
-
```
|
|
839
|
-
"""
|
|
840
|
-
warnings.filterwarnings("default")
|
|
841
|
-
ExperimentalFlags.imf_read.warn()
|
|
842
|
-
|
|
843
|
-
self._state._raise_exception_if_condition_not_met(
|
|
844
|
-
"Read IMF file",
|
|
845
|
-
empty_data_model_store_required=True,
|
|
846
|
-
)
|
|
847
|
-
|
|
848
|
-
reader = NeatReader.create(io)
|
|
849
|
-
importer = importers.IMFImporter.from_file(reader.materialize_path(), source_name=f"file {reader!s}")
|
|
850
|
-
return self._state.data_model_import(importer)
|
|
851
|
-
|
|
852
829
|
def instances(self, io: Any) -> IssueList:
|
|
853
830
|
self._state._raise_exception_if_condition_not_met(
|
|
854
831
|
"Read RDF Instances",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
cognite/neat/__init__.py,sha256=12StS1dzH9_MElqxGvLWrNsxCJl9Hv8A2a9D0E5OD_U,193
|
|
2
|
-
cognite/neat/_version.py,sha256=
|
|
2
|
+
cognite/neat/_version.py,sha256=8hU8Ii91v2mPVi02JvAjqdizS1HMfV4lF6LA_zsFYGc,46
|
|
3
3
|
cognite/neat/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
cognite/neat/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
cognite/neat/core/_config.py,sha256=WT1BS8uADcFvGoUYOOfwFOVq_VBl472TisdoA3wLick,280
|
|
@@ -34,20 +34,14 @@ cognite/neat/core/_data_model/exporters/_data_model2excel.py,sha256=mRVJzUCEWfm2
|
|
|
34
34
|
cognite/neat/core/_data_model/exporters/_data_model2instance_template.py,sha256=9k8A70b1paeOHjvJRtbl6Xror1GD8AIMdo3cCx5aejE,6103
|
|
35
35
|
cognite/neat/core/_data_model/exporters/_data_model2ontology.py,sha256=YrLTwPAvOOyLFHFJaNs4I82HCp1llJnkF1BRdoIQMck,23409
|
|
36
36
|
cognite/neat/core/_data_model/exporters/_data_model2yaml.py,sha256=1dlb-v4sV8BArnX_6J4wpjQT7r-FinFAvoPDoMNkHYw,3284
|
|
37
|
-
cognite/neat/core/_data_model/importers/__init__.py,sha256=
|
|
37
|
+
cognite/neat/core/_data_model/importers/__init__.py,sha256=5KqFRDz69FlXRcmqu7ejQl3YVXrpLXx-Q-HpwAeDbfA,1184
|
|
38
38
|
cognite/neat/core/_data_model/importers/_base.py,sha256=pKe2OK86Wdj6CTj5bUgjY33ejZhRfD2eJbjcCapHD58,2013
|
|
39
39
|
cognite/neat/core/_data_model/importers/_base_file_reader.py,sha256=m7CwMujEybYMfHWbTQOb7wBvLl2X1TmROkPelJMSaDA,1621
|
|
40
40
|
cognite/neat/core/_data_model/importers/_dict2data_model.py,sha256=-1zmo8JkxJ9qiWuC7sUH7oSlpnPPKTMxZtm4WrRPO5A,4709
|
|
41
41
|
cognite/neat/core/_data_model/importers/_dms2data_model.py,sha256=1luEyqEu51rNcFcEh-MjTnUY_5mnQU0761MDVHOuteo,29132
|
|
42
42
|
cognite/neat/core/_data_model/importers/_spreadsheet2data_model.py,sha256=2QqrxQ9AI3LT9toH_gryIR52UecMsR-v44ljXedDCp4,11972
|
|
43
|
-
cognite/neat/core/_data_model/importers/
|
|
44
|
-
cognite/neat/core/_data_model/importers/_dtdl2data_model/_unit_lookup.py,sha256=wW4saKva61Q_i17guY0dc4OseJDQfqHy_QZBtm0OD6g,12134
|
|
45
|
-
cognite/neat/core/_data_model/importers/_dtdl2data_model/dtdl_converter.py,sha256=mjouy5XQCJoybUkCnEoZFrFtWBQrBQRPIM4DwfMDUkw,11879
|
|
46
|
-
cognite/neat/core/_data_model/importers/_dtdl2data_model/dtdl_importer.py,sha256=t5EkawmYPuQ-dJ1J-IhqhdX_CkaCwQLQDAcpmx7QdS0,6288
|
|
47
|
-
cognite/neat/core/_data_model/importers/_dtdl2data_model/spec.py,sha256=HnKUZbp42pl4DSexo0N6t_20tsvlsxyHHnNak5SVgzg,12182
|
|
48
|
-
cognite/neat/core/_data_model/importers/_rdf/__init__.py,sha256=CYZd6Oj5PR2wv-eh4DYvKt4SDQgYRf1zW5QhN1Rg9AU,255
|
|
43
|
+
cognite/neat/core/_data_model/importers/_rdf/__init__.py,sha256=1yOjV2PKCxwH7uCTXVZhSdxtn5etmFX40cksvwtKcZ8,199
|
|
49
44
|
cognite/neat/core/_data_model/importers/_rdf/_base.py,sha256=FKceKumKmhEGpMZvo1BwEewnUvfAsTF3Ax9fo1nxsGE,6020
|
|
50
|
-
cognite/neat/core/_data_model/importers/_rdf/_imf2data_model.py,sha256=f5kAkv7-d5DtqzaACkyA-vLXrQ2xArwEd9zg7yX-MfA,3777
|
|
51
45
|
cognite/neat/core/_data_model/importers/_rdf/_inference2rdata_model.py,sha256=PCgM9-qGSLlupN7tYCFLHjivgICtMiahNry1ub8JCYk,28934
|
|
52
46
|
cognite/neat/core/_data_model/importers/_rdf/_owl2data_model.py,sha256=WmncZNpELeZnt6mdw6X8yWnr7XsFXZGfoVe5wTd0HH4,3438
|
|
53
47
|
cognite/neat/core/_data_model/importers/_rdf/_shared.py,sha256=yB4BkupiPhizWSHNKdaspj3xE_6pKDiNG-_IHtTN1gI,5961
|
|
@@ -177,7 +171,7 @@ cognite/neat/session/_inspect.py,sha256=AESQd2SOidR_pDTFk5B_JdPnKZ5PNNskdAQBepH2
|
|
|
177
171
|
cognite/neat/session/_mapping.py,sha256=ItEXhXo_8V3069hktHMxdpBsLNeTck3gZBvhlm12Oxw,2895
|
|
178
172
|
cognite/neat/session/_plugin.py,sha256=diFvZUFRvY037iVy_HxnIGMSfrauOpwYCSvFEPOzchQ,2282
|
|
179
173
|
cognite/neat/session/_prepare.py,sha256=pskEVNgcnVJVRvYKk5xI55V89vKDO_kgjszj5flY8Zs,12778
|
|
180
|
-
cognite/neat/session/_read.py,sha256=
|
|
174
|
+
cognite/neat/session/_read.py,sha256=rd1MeXPt_fS50WYrpM6UqDTKOQkDrOIn8TPS0WOVoSw,34607
|
|
181
175
|
cognite/neat/session/_set.py,sha256=PU4lKI-LGtKFVyvdtfZkk-zLw9e_rnFHzuV9IyrOrTM,4593
|
|
182
176
|
cognite/neat/session/_show.py,sha256=YLt6K4ukG1s_I_FhuVrIVPtw_btvvOL50Rwrx-vo7VQ,10743
|
|
183
177
|
cognite/neat/session/_state.py,sha256=DLEm9wn3GtOuTGhy5-M1IK2v9qvLnTYEruWPidzAP_Q,6580
|
|
@@ -191,7 +185,7 @@ cognite/neat/session/engine/__init__.py,sha256=D3MxUorEs6-NtgoICqtZ8PISQrjrr4dvc
|
|
|
191
185
|
cognite/neat/session/engine/_import.py,sha256=1QxA2_EK613lXYAHKQbZyw2yjo5P9XuiX4Z6_6-WMNQ,169
|
|
192
186
|
cognite/neat/session/engine/_interface.py,sha256=3W-cYr493c_mW3P5O6MKN1xEQg3cA7NHR_ev3zdF9Vk,533
|
|
193
187
|
cognite/neat/session/engine/_load.py,sha256=g52uYakQM03VqHt_RDHtpHso1-mFFifH5M4T2ScuH8A,5198
|
|
194
|
-
cognite_neat-0.123.
|
|
195
|
-
cognite_neat-0.123.
|
|
196
|
-
cognite_neat-0.123.
|
|
197
|
-
cognite_neat-0.123.
|
|
188
|
+
cognite_neat-0.123.4.dist-info/METADATA,sha256=PxEsDokXeHFbmzASWwu40eFyMdFDUNDEqOw0X2zQ8Co,9171
|
|
189
|
+
cognite_neat-0.123.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
190
|
+
cognite_neat-0.123.4.dist-info/licenses/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
|
|
191
|
+
cognite_neat-0.123.4.dist-info/RECORD,,
|
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
@dataclass
|
|
5
|
-
class UnitEntry:
|
|
6
|
-
semantic_type: str
|
|
7
|
-
unit_type: str
|
|
8
|
-
unit: str
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
_UNIT_ENTRIES = [
|
|
12
|
-
UnitEntry("Acceleration", "AccelerationUnit", "centimetrePerSecondSquared"),
|
|
13
|
-
UnitEntry("Acceleration", "AccelerationUnit", "gForce"),
|
|
14
|
-
UnitEntry("Acceleration", "AccelerationUnit", "metrePerSecondSquared"),
|
|
15
|
-
UnitEntry("Angle", "AngleUnit", "degreeOfArc"),
|
|
16
|
-
UnitEntry("Angle", "AngleUnit", "minuteOfArc"),
|
|
17
|
-
UnitEntry("Angle", "AngleUnit", "radian"),
|
|
18
|
-
UnitEntry("Angle", "AngleUnit", "secondOfArc"),
|
|
19
|
-
UnitEntry("Angle", "AngleUnit", "turn"),
|
|
20
|
-
UnitEntry("AngularAcceleration", "AngularAccelerationUnit", "radianPerSecondSquared"),
|
|
21
|
-
UnitEntry("AngularVelocity", "AngularVelocityUnit", "degreePerSecond"),
|
|
22
|
-
UnitEntry("AngularVelocity", "AngularVelocityUnit", "radianPerSecond"),
|
|
23
|
-
UnitEntry("AngularVelocity", "AngularVelocityUnit", "revolutionPerMinute"),
|
|
24
|
-
UnitEntry("AngularVelocity", "AngularVelocityUnit", "revolutionPerSecond"),
|
|
25
|
-
UnitEntry("Area", "AreaUnit", "acre"),
|
|
26
|
-
UnitEntry("Area", "AreaUnit", "hectare"),
|
|
27
|
-
UnitEntry("Area", "AreaUnit", "squareCentimetre"),
|
|
28
|
-
UnitEntry("Area", "AreaUnit", "squareFoot"),
|
|
29
|
-
UnitEntry("Area", "AreaUnit", "squareInch"),
|
|
30
|
-
UnitEntry("Area", "AreaUnit", "squareKilometre"),
|
|
31
|
-
UnitEntry("Area", "AreaUnit", "squareMetre"),
|
|
32
|
-
UnitEntry("Area", "AreaUnit", "squareMillimetre"),
|
|
33
|
-
UnitEntry("Capacitance", "CapacitanceUnit", "farad"),
|
|
34
|
-
UnitEntry("Capacitance", "CapacitanceUnit", "microfarad"),
|
|
35
|
-
UnitEntry("Capacitance", "CapacitanceUnit", "millifarad"),
|
|
36
|
-
UnitEntry("Capacitance", "CapacitanceUnit", "nanofarad"),
|
|
37
|
-
UnitEntry("Capacitance", "CapacitanceUnit", "picofarad"),
|
|
38
|
-
UnitEntry("Current", "CurrentUnit", "ampere"),
|
|
39
|
-
UnitEntry("Current", "CurrentUnit", "microampere"),
|
|
40
|
-
UnitEntry("Current", "CurrentUnit", "milliampere"),
|
|
41
|
-
UnitEntry("DataRate", "DataRateUnit", "bitPerSecond"),
|
|
42
|
-
UnitEntry("DataRate", "DataRateUnit", "bytePerSecond"),
|
|
43
|
-
UnitEntry("DataRate", "DataRateUnit", "exbibitPerSecond"),
|
|
44
|
-
UnitEntry("DataRate", "DataRateUnit", "exbibytePerSecond"),
|
|
45
|
-
UnitEntry("DataRate", "DataRateUnit", "gibibitPerSecond"),
|
|
46
|
-
UnitEntry("DataRate", "DataRateUnit", "gibibytePerSecond"),
|
|
47
|
-
UnitEntry("DataRate", "DataRateUnit", "kibibitPerSecond"),
|
|
48
|
-
UnitEntry("DataRate", "DataRateUnit", "kibibytePerSecond"),
|
|
49
|
-
UnitEntry("DataRate", "DataRateUnit", "mebibitPerSecond"),
|
|
50
|
-
UnitEntry("DataRate", "DataRateUnit", "mebibytePerSecond"),
|
|
51
|
-
UnitEntry("DataRate", "DataRateUnit", "tebibitPerSecond"),
|
|
52
|
-
UnitEntry("DataRate", "DataRateUnit", "tebibytePerSecond"),
|
|
53
|
-
UnitEntry("DataRate", "DataRateUnit", "yobibitPerSecond"),
|
|
54
|
-
UnitEntry("DataRate", "DataRateUnit", "yobibytePerSecond"),
|
|
55
|
-
UnitEntry("DataRate", "DataRateUnit", "zebibitPerSecond"),
|
|
56
|
-
UnitEntry("DataRate", "DataRateUnit", "zebibytePerSecond"),
|
|
57
|
-
UnitEntry("DataSize", "DataSizeUnit", "bit"),
|
|
58
|
-
UnitEntry("DataSize", "DataSizeUnit", "byte"),
|
|
59
|
-
UnitEntry("DataSize", "DataSizeUnit", "exbibit"),
|
|
60
|
-
UnitEntry("DataSize", "DataSizeUnit", "exbibyte"),
|
|
61
|
-
UnitEntry("DataSize", "DataSizeUnit", "gibibit"),
|
|
62
|
-
UnitEntry("DataSize", "DataSizeUnit", "gibibyte"),
|
|
63
|
-
UnitEntry("DataSize", "DataSizeUnit", "kibibit"),
|
|
64
|
-
UnitEntry("DataSize", "DataSizeUnit", "kibibyte"),
|
|
65
|
-
UnitEntry("DataSize", "DataSizeUnit", "mebibit"),
|
|
66
|
-
UnitEntry("DataSize", "DataSizeUnit", "mebibyte"),
|
|
67
|
-
UnitEntry("DataSize", "DataSizeUnit", "tebibit"),
|
|
68
|
-
UnitEntry("DataSize", "DataSizeUnit", "tebibyte"),
|
|
69
|
-
UnitEntry("DataSize", "DataSizeUnit", "yobibit"),
|
|
70
|
-
UnitEntry("DataSize", "DataSizeUnit", "yobibyte"),
|
|
71
|
-
UnitEntry("DataSize", "DataSizeUnit", "zebibit"),
|
|
72
|
-
UnitEntry("DataSize", "DataSizeUnit", "zebibyte"),
|
|
73
|
-
UnitEntry("Density", "DensityUnit", "gramPerCubicMetre"),
|
|
74
|
-
UnitEntry("Density", "DensityUnit", "kilogramPerCubicMetre"),
|
|
75
|
-
UnitEntry("Distance", "LengthUnit", "astronomicalUnit"),
|
|
76
|
-
UnitEntry("Distance", "LengthUnit", "centimetre"),
|
|
77
|
-
UnitEntry("Distance", "LengthUnit", "foot"),
|
|
78
|
-
UnitEntry("Distance", "LengthUnit", "inch"),
|
|
79
|
-
UnitEntry("Distance", "LengthUnit", "kilometre"),
|
|
80
|
-
UnitEntry("Distance", "LengthUnit", "metre"),
|
|
81
|
-
UnitEntry("Distance", "LengthUnit", "micrometre"),
|
|
82
|
-
UnitEntry("Distance", "LengthUnit", "mile"),
|
|
83
|
-
UnitEntry("Distance", "LengthUnit", "millimetre"),
|
|
84
|
-
UnitEntry("Distance", "LengthUnit", "nanometre"),
|
|
85
|
-
UnitEntry("Distance", "LengthUnit", "nauticalMile"),
|
|
86
|
-
UnitEntry("ElectricCharge", "ChargeUnit", "coulomb"),
|
|
87
|
-
UnitEntry("Energy", "EnergyUnit", "electronvolt"),
|
|
88
|
-
UnitEntry("Energy", "EnergyUnit", "gigajoule"),
|
|
89
|
-
UnitEntry("Energy", "EnergyUnit", "joule"),
|
|
90
|
-
UnitEntry("Energy", "EnergyUnit", "kilojoule"),
|
|
91
|
-
UnitEntry("Energy", "EnergyUnit", "kilowattHour"),
|
|
92
|
-
UnitEntry("Energy", "EnergyUnit", "megaelectronvolt"),
|
|
93
|
-
UnitEntry("Energy", "EnergyUnit", "megajoule"),
|
|
94
|
-
UnitEntry("Force", "ForceUnit", "newton"),
|
|
95
|
-
UnitEntry("Force", "ForceUnit", "ounce"),
|
|
96
|
-
UnitEntry("Force", "ForceUnit", "pound"),
|
|
97
|
-
UnitEntry("Force", "ForceUnit", "ton"),
|
|
98
|
-
UnitEntry("Frequency", "FrequencyUnit", "gigahertz"),
|
|
99
|
-
UnitEntry("Frequency", "FrequencyUnit", "hertz"),
|
|
100
|
-
UnitEntry("Frequency", "FrequencyUnit", "kilohertz"),
|
|
101
|
-
UnitEntry("Frequency", "FrequencyUnit", "megahertz"),
|
|
102
|
-
UnitEntry("Humidity", "DensityUnit", "gramPerCubicMetre"),
|
|
103
|
-
UnitEntry("Humidity", "DensityUnit", "kilogramPerCubicMetre"),
|
|
104
|
-
UnitEntry("Illuminance", "IlluminanceUnit", "footcandle"),
|
|
105
|
-
UnitEntry("Illuminance", "IlluminanceUnit", "lux"),
|
|
106
|
-
UnitEntry("Inductance", "InductanceUnit", "henry"),
|
|
107
|
-
UnitEntry("Inductance", "InductanceUnit", "microhenry"),
|
|
108
|
-
UnitEntry("Inductance", "InductanceUnit", "millihenry"),
|
|
109
|
-
UnitEntry("Latitude", "AngleUnit", "degreeOfArc"),
|
|
110
|
-
UnitEntry("Latitude", "AngleUnit", "minuteOfArc"),
|
|
111
|
-
UnitEntry("Latitude", "AngleUnit", "radian"),
|
|
112
|
-
UnitEntry("Latitude", "AngleUnit", "secondOfArc"),
|
|
113
|
-
UnitEntry("Latitude", "AngleUnit", "turn"),
|
|
114
|
-
UnitEntry("Length", "LengthUnit", "astronomicalUnit"),
|
|
115
|
-
UnitEntry("Length", "LengthUnit", "centimetre"),
|
|
116
|
-
UnitEntry("Length", "LengthUnit", "foot"),
|
|
117
|
-
UnitEntry("Length", "LengthUnit", "inch"),
|
|
118
|
-
UnitEntry("Length", "LengthUnit", "kilometre"),
|
|
119
|
-
UnitEntry("Length", "LengthUnit", "metre"),
|
|
120
|
-
UnitEntry("Length", "LengthUnit", "micrometre"),
|
|
121
|
-
UnitEntry("Length", "LengthUnit", "mile"),
|
|
122
|
-
UnitEntry("Length", "LengthUnit", "millimetre"),
|
|
123
|
-
UnitEntry("Length", "LengthUnit", "nanometre"),
|
|
124
|
-
UnitEntry("Length", "LengthUnit", "nauticalMile"),
|
|
125
|
-
UnitEntry("Longitude", "AngleUnit", "degreeOfArc"),
|
|
126
|
-
UnitEntry("Longitude", "AngleUnit", "minuteOfArc"),
|
|
127
|
-
UnitEntry("Longitude", "AngleUnit", "radian"),
|
|
128
|
-
UnitEntry("Longitude", "AngleUnit", "secondOfArc"),
|
|
129
|
-
UnitEntry("Longitude", "AngleUnit", "turn"),
|
|
130
|
-
UnitEntry("Luminance", "LuminanceUnit", "candelaPerSquareMetre"),
|
|
131
|
-
UnitEntry("Luminosity", "PowerUnit", "gigawatt"),
|
|
132
|
-
UnitEntry("Luminosity", "PowerUnit", "horsepower"),
|
|
133
|
-
UnitEntry("Luminosity", "PowerUnit", "kilowatt"),
|
|
134
|
-
UnitEntry("Luminosity", "PowerUnit", "kilowattHourPerYear"),
|
|
135
|
-
UnitEntry("Luminosity", "PowerUnit", "megawatt"),
|
|
136
|
-
UnitEntry("Luminosity", "PowerUnit", "microwatt"),
|
|
137
|
-
UnitEntry("Luminosity", "PowerUnit", "milliwatt"),
|
|
138
|
-
UnitEntry("Luminosity", "PowerUnit", "watt"),
|
|
139
|
-
UnitEntry("LuminousFlux", "LuminousFluxUnit", "lumen"),
|
|
140
|
-
UnitEntry("LuminousIntensity", "LuminousIntensityUnit", "candela"),
|
|
141
|
-
UnitEntry("MagneticFlux", "MagneticFluxUnit", "maxwell"),
|
|
142
|
-
UnitEntry("MagneticFlux", "MagneticFluxUnit", "weber"),
|
|
143
|
-
UnitEntry("MagneticInduction", "MagneticInductionUnit", "tesla"),
|
|
144
|
-
UnitEntry("Mass", "MassUnit", "gram"),
|
|
145
|
-
UnitEntry("Mass", "MassUnit", "kilogram"),
|
|
146
|
-
UnitEntry("Mass", "MassUnit", "microgram"),
|
|
147
|
-
UnitEntry("Mass", "MassUnit", "milligram"),
|
|
148
|
-
UnitEntry("Mass", "MassUnit", "slug"),
|
|
149
|
-
UnitEntry("Mass", "MassUnit", "tonne"),
|
|
150
|
-
UnitEntry("MassFlowRate", "MassFlowRateUnit", "gramPerHour"),
|
|
151
|
-
UnitEntry("MassFlowRate", "MassFlowRateUnit", "gramPerSecond"),
|
|
152
|
-
UnitEntry("MassFlowRate", "MassFlowRateUnit", "kilogramPerHour"),
|
|
153
|
-
UnitEntry("MassFlowRate", "MassFlowRateUnit", "kilogramPerSecond"),
|
|
154
|
-
UnitEntry("Power", "PowerUnit", "gigawatt"),
|
|
155
|
-
UnitEntry("Power", "PowerUnit", "horsepower"),
|
|
156
|
-
UnitEntry("Power", "PowerUnit", "kilowatt"),
|
|
157
|
-
UnitEntry("Power", "PowerUnit", "kilowattHour"),
|
|
158
|
-
UnitEntry("Power", "PowerUnit", "megawatt"),
|
|
159
|
-
UnitEntry("Power", "PowerUnit", "microwatt"),
|
|
160
|
-
UnitEntry("Power", "PowerUnit", "milliwatt"),
|
|
161
|
-
UnitEntry("Power", "PowerUnit", "watt"),
|
|
162
|
-
UnitEntry("Pressure", "PressureUnit", "bar"),
|
|
163
|
-
UnitEntry("Pressure", "PressureUnit", "inchesOfMercury"),
|
|
164
|
-
UnitEntry("Pressure", "PressureUnit", "inchesOfWater"),
|
|
165
|
-
UnitEntry("Pressure", "PressureUnit", "kilopascal"),
|
|
166
|
-
UnitEntry("Pressure", "PressureUnit", "millibar"),
|
|
167
|
-
UnitEntry("Pressure", "PressureUnit", "millimetresOfMercury"),
|
|
168
|
-
UnitEntry("Pressure", "PressureUnit", "pascal"),
|
|
169
|
-
UnitEntry("Pressure", "PressureUnit", "poundPerSquareInch"),
|
|
170
|
-
UnitEntry("RelativeHumidity", "Unitless", "percent"),
|
|
171
|
-
UnitEntry("RelativeHumidity", "Unitless", "unity"),
|
|
172
|
-
UnitEntry("Resistance", "ResistanceUnit", "kiloohm"),
|
|
173
|
-
UnitEntry("Resistance", "ResistanceUnit", "megaohm"),
|
|
174
|
-
UnitEntry("Resistance", "ResistanceUnit", "milliohm"),
|
|
175
|
-
UnitEntry("Resistance", "ResistanceUnit", "ohm"),
|
|
176
|
-
UnitEntry("SoundPressure", "SoundPressureUnit", "bel"),
|
|
177
|
-
UnitEntry("SoundPressure", "SoundPressureUnit", "decibel"),
|
|
178
|
-
UnitEntry("Temperature", "TemperatureUnit", "degreeCelsius"),
|
|
179
|
-
UnitEntry("Temperature", "TemperatureUnit", "degreeFahrenheit"),
|
|
180
|
-
UnitEntry("Temperature", "TemperatureUnit", "kelvin"),
|
|
181
|
-
UnitEntry("Thrust", "ForceUnit", "newton"),
|
|
182
|
-
UnitEntry("Thrust", "ForceUnit", "ounce"),
|
|
183
|
-
UnitEntry("Thrust", "ForceUnit", "pound"),
|
|
184
|
-
UnitEntry("Thrust", "ForceUnit", "ton"),
|
|
185
|
-
UnitEntry("TimeSpan", "TimeUnit", "day"),
|
|
186
|
-
UnitEntry("TimeSpan", "TimeUnit", "hour"),
|
|
187
|
-
UnitEntry("TimeSpan", "TimeUnit", "microsecond"),
|
|
188
|
-
UnitEntry("TimeSpan", "TimeUnit", "millisecond"),
|
|
189
|
-
UnitEntry("TimeSpan", "TimeUnit", "minute"),
|
|
190
|
-
UnitEntry("TimeSpan", "TimeUnit", "nanosecond"),
|
|
191
|
-
UnitEntry("TimeSpan", "TimeUnit", "second"),
|
|
192
|
-
UnitEntry("TimeSpan", "TimeUnit", "year"),
|
|
193
|
-
UnitEntry("Torque", "TorqueUnit", "newtonMetre"),
|
|
194
|
-
UnitEntry("Velocity", "VelocityUnit", "centimetrePerSecond"),
|
|
195
|
-
UnitEntry("Velocity", "VelocityUnit", "kilometrePerHour"),
|
|
196
|
-
UnitEntry("Velocity", "VelocityUnit", "kilometrePerSecond"),
|
|
197
|
-
UnitEntry("Velocity", "VelocityUnit", "knot"),
|
|
198
|
-
UnitEntry("Velocity", "VelocityUnit", "metrePerHour"),
|
|
199
|
-
UnitEntry("Velocity", "VelocityUnit", "metrePerSecond"),
|
|
200
|
-
UnitEntry("Velocity", "VelocityUnit", "milePerHour"),
|
|
201
|
-
UnitEntry("Velocity", "VelocityUnit", "milePerSecond"),
|
|
202
|
-
UnitEntry("Voltage", "VoltageUnit", "kilovolt"),
|
|
203
|
-
UnitEntry("Voltage", "VoltageUnit", "megavolt"),
|
|
204
|
-
UnitEntry("Voltage", "VoltageUnit", "microvolt"),
|
|
205
|
-
UnitEntry("Voltage", "VoltageUnit", "millivolt"),
|
|
206
|
-
UnitEntry("Voltage", "VoltageUnit", "volt"),
|
|
207
|
-
UnitEntry("Volume", "VolumeUnit", "cubicCentimetre"),
|
|
208
|
-
UnitEntry("Volume", "VolumeUnit", "cubicFoot"),
|
|
209
|
-
UnitEntry("Volume", "VolumeUnit", "cubicInch"),
|
|
210
|
-
UnitEntry("Volume", "VolumeUnit", "cubicMetre"),
|
|
211
|
-
UnitEntry("Volume", "VolumeUnit", "fluidOunce"),
|
|
212
|
-
UnitEntry("Volume", "VolumeUnit", "gallon"),
|
|
213
|
-
UnitEntry("Volume", "VolumeUnit", "litre"),
|
|
214
|
-
UnitEntry("Volume", "VolumeUnit", "millilitre"),
|
|
215
|
-
UnitEntry("VolumeFlowRate", "VolumeFlowRateUnit", "litrePerHour"),
|
|
216
|
-
UnitEntry("VolumeFlowRate", "VolumeFlowRateUnit", "litrePerSecond"),
|
|
217
|
-
UnitEntry("VolumeFlowRate", "VolumeFlowRateUnit", "millilitrePerHour"),
|
|
218
|
-
UnitEntry("VolumeFlowRate", "VolumeFlowRateUnit", "millilitrePerSecond"),
|
|
219
|
-
]
|
|
220
|
-
|
|
221
|
-
UNIT_TYPE_BY_SEMANTIC_TYPE = {entry.semantic_type: entry.unit_type for entry in _UNIT_ENTRIES}
|
|
222
|
-
# This is a bit dangerous, as unit names are not unique across types
|
|
223
|
-
# It is only used as a backup in the parsing of units.
|
|
224
|
-
ENTRY_BY_UNIT = {entry.unit: entry for entry in _UNIT_ENTRIES}
|
|
@@ -1,320 +0,0 @@
|
|
|
1
|
-
from collections import Counter
|
|
2
|
-
from collections.abc import Callable, Sequence
|
|
3
|
-
|
|
4
|
-
from cognite.neat.core._data_model.importers._dtdl2data_model.spec import (
|
|
5
|
-
DTMI,
|
|
6
|
-
Command,
|
|
7
|
-
CommandV2,
|
|
8
|
-
Component,
|
|
9
|
-
DTDLBase,
|
|
10
|
-
DTDLBaseWithName,
|
|
11
|
-
Enum,
|
|
12
|
-
Interface,
|
|
13
|
-
Object,
|
|
14
|
-
Property,
|
|
15
|
-
PropertyV2,
|
|
16
|
-
Relationship,
|
|
17
|
-
Schema,
|
|
18
|
-
Telemetry,
|
|
19
|
-
TelemetryV2,
|
|
20
|
-
)
|
|
21
|
-
from cognite.neat.core._data_model.models.conceptual import (
|
|
22
|
-
UnverifiedConcept,
|
|
23
|
-
UnverifiedConceptualProperty,
|
|
24
|
-
)
|
|
25
|
-
from cognite.neat.core._data_model.models.data_types import (
|
|
26
|
-
_DATA_TYPE_BY_NAME,
|
|
27
|
-
DataType,
|
|
28
|
-
Json,
|
|
29
|
-
String,
|
|
30
|
-
)
|
|
31
|
-
from cognite.neat.core._data_model.models.entities import ConceptEntity
|
|
32
|
-
from cognite.neat.core._issues import IssueList
|
|
33
|
-
from cognite.neat.core._issues.errors import (
|
|
34
|
-
PropertyTypeNotSupportedError,
|
|
35
|
-
ResourceMissingIdentifierError,
|
|
36
|
-
ResourceNotFoundError,
|
|
37
|
-
)
|
|
38
|
-
from cognite.neat.core._issues.warnings import (
|
|
39
|
-
PropertyTypeNotSupportedWarning,
|
|
40
|
-
ResourceTypeNotSupportedWarning,
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
class _DTDLConverter:
|
|
45
|
-
def __init__(self, issues: IssueList | None = None) -> None:
|
|
46
|
-
self.issues = IssueList(issues or [])
|
|
47
|
-
self.properties: list[UnverifiedConceptualProperty] = []
|
|
48
|
-
self.classes: list[UnverifiedConcept] = []
|
|
49
|
-
self._item_by_id: dict[DTMI, DTDLBase] = {}
|
|
50
|
-
|
|
51
|
-
self._method_by_type = {
|
|
52
|
-
Interface: self.convert_interface, # type: ignore[dict-item]
|
|
53
|
-
Property: self.convert_property, # type: ignore[dict-item]
|
|
54
|
-
PropertyV2: self.convert_property, # type: ignore[dict-item]
|
|
55
|
-
Relationship: self.convert_relationship, # type: ignore[dict-item]
|
|
56
|
-
Object: self.convert_object, # type: ignore[dict-item]
|
|
57
|
-
Telemetry: self.convert_telemetry, # type: ignore[dict-item]
|
|
58
|
-
TelemetryV2: self.convert_telemetry, # type: ignore[dict-item]
|
|
59
|
-
Command: self.convert_command, # type: ignore[dict-item]
|
|
60
|
-
CommandV2: self.convert_command, # type: ignore[dict-item]
|
|
61
|
-
Component: self.convert_component, # type: ignore[dict-item]
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
def get_most_common_prefix(self) -> str:
|
|
65
|
-
if not self.classes:
|
|
66
|
-
raise ValueError("No classes found")
|
|
67
|
-
counted = Counter(
|
|
68
|
-
class_.prefix
|
|
69
|
-
for class_ in (cls_.concept for cls_ in self.classes)
|
|
70
|
-
if isinstance(class_, ConceptEntity) and isinstance(class_.prefix, str)
|
|
71
|
-
)
|
|
72
|
-
if not counted:
|
|
73
|
-
raise ValueError("No prefixes found")
|
|
74
|
-
return counted.most_common(1)[0][0]
|
|
75
|
-
|
|
76
|
-
def convert(self, items: Sequence[DTDLBase]) -> None:
|
|
77
|
-
self._item_by_id.update({item.id_: item for item in items if item.id_ is not None})
|
|
78
|
-
# Update schema objects which are reusable
|
|
79
|
-
self._item_by_id.update(
|
|
80
|
-
{
|
|
81
|
-
schema.id_: schema
|
|
82
|
-
for item in items
|
|
83
|
-
if isinstance(item, Interface)
|
|
84
|
-
for schema in item.schemas or []
|
|
85
|
-
if isinstance(schema.id_, DTMI) and isinstance(schema, DTDLBase)
|
|
86
|
-
}
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
for item in items:
|
|
90
|
-
self.convert_item(item)
|
|
91
|
-
|
|
92
|
-
def convert_item(self, item: DTDLBase, parent: str | None = None) -> None:
|
|
93
|
-
# Bug in mypy https://github.com/python/mypy/issues/17478
|
|
94
|
-
convert_method: Callable[[DTDLBase, str | None], None] | None = self._method_by_type.get(type(item)) # type: ignore[assignment]
|
|
95
|
-
if convert_method is not None:
|
|
96
|
-
convert_method(item, parent)
|
|
97
|
-
else:
|
|
98
|
-
self.issues.append(
|
|
99
|
-
ResourceTypeNotSupportedWarning(
|
|
100
|
-
item.identifier_with_fallback,
|
|
101
|
-
item.type,
|
|
102
|
-
),
|
|
103
|
-
)
|
|
104
|
-
|
|
105
|
-
def convert_interface(self, item: Interface, _: str | None) -> None:
|
|
106
|
-
class_ = UnverifiedConcept(
|
|
107
|
-
concept=item.id_.as_concept_entity(),
|
|
108
|
-
name=item.display_name,
|
|
109
|
-
description=item.description,
|
|
110
|
-
implements=[parent.as_concept_entity() for parent in item.extends or []] or None,
|
|
111
|
-
)
|
|
112
|
-
self.classes.append(class_)
|
|
113
|
-
for sub_item_or_id in item.contents or []:
|
|
114
|
-
if isinstance(sub_item_or_id, DTMI) and sub_item_or_id not in self._item_by_id:
|
|
115
|
-
self.issues.append(
|
|
116
|
-
PropertyTypeNotSupportedWarning(
|
|
117
|
-
item.id_.model_dump() or item.display_name or "missing",
|
|
118
|
-
item.type,
|
|
119
|
-
sub_item_or_id.path[-1],
|
|
120
|
-
".".join(sub_item_or_id.path),
|
|
121
|
-
)
|
|
122
|
-
)
|
|
123
|
-
elif isinstance(sub_item_or_id, DTMI):
|
|
124
|
-
sub_item = self._item_by_id[sub_item_or_id]
|
|
125
|
-
self.convert_item(sub_item, class_.concept_str)
|
|
126
|
-
else:
|
|
127
|
-
self.convert_item(sub_item_or_id, class_.concept_str)
|
|
128
|
-
# interface.schema objects are handled in the convert method
|
|
129
|
-
|
|
130
|
-
def convert_property(
|
|
131
|
-
self, item: Property | Telemetry, parent: str | None, min_count: int | None = 0, max_count: int | None = 1
|
|
132
|
-
) -> None:
|
|
133
|
-
if parent is None:
|
|
134
|
-
self._missing_parent_warning(item)
|
|
135
|
-
return None
|
|
136
|
-
value_type = self.schema_to_value_type(item.schema_, item)
|
|
137
|
-
if value_type is None:
|
|
138
|
-
return None
|
|
139
|
-
|
|
140
|
-
prop = UnverifiedConceptualProperty(
|
|
141
|
-
concept=ConceptEntity.load(parent),
|
|
142
|
-
property_=item.name,
|
|
143
|
-
name=item.display_name,
|
|
144
|
-
description=item.description,
|
|
145
|
-
value_type=value_type,
|
|
146
|
-
min_count=min_count,
|
|
147
|
-
max_count=max_count,
|
|
148
|
-
)
|
|
149
|
-
self.properties.append(prop)
|
|
150
|
-
|
|
151
|
-
def _missing_parent_warning(self, item: DTDLBaseWithName) -> None:
|
|
152
|
-
self.issues.append(
|
|
153
|
-
ResourceNotFoundError(
|
|
154
|
-
"UNKNOWN",
|
|
155
|
-
"parent",
|
|
156
|
-
item.identifier_with_fallback,
|
|
157
|
-
item.type,
|
|
158
|
-
)
|
|
159
|
-
)
|
|
160
|
-
|
|
161
|
-
def convert_telemetry(self, item: Telemetry, parent: str | None) -> None:
|
|
162
|
-
return self.convert_property(
|
|
163
|
-
item,
|
|
164
|
-
parent,
|
|
165
|
-
)
|
|
166
|
-
|
|
167
|
-
def convert_command(self, item: Command | CommandV2, parent: str | None) -> None:
|
|
168
|
-
if parent is None:
|
|
169
|
-
self._missing_parent_warning(item)
|
|
170
|
-
return None
|
|
171
|
-
if item.request is None:
|
|
172
|
-
self.issues.append(
|
|
173
|
-
ResourceTypeNotSupportedWarning[str](
|
|
174
|
-
item.identifier_with_fallback,
|
|
175
|
-
f"{item.type}.request",
|
|
176
|
-
),
|
|
177
|
-
)
|
|
178
|
-
return None
|
|
179
|
-
if item.response is not None:
|
|
180
|
-
# Currently, we do not know how to handle response
|
|
181
|
-
self.issues.append(ResourceTypeNotSupportedWarning[str](f"{parent}.response", "Command.Response"))
|
|
182
|
-
value_type = self.schema_to_value_type(item.request.schema_, item)
|
|
183
|
-
if value_type is None:
|
|
184
|
-
return
|
|
185
|
-
prop = UnverifiedConceptualProperty(
|
|
186
|
-
concept=ConceptEntity.load(parent),
|
|
187
|
-
property_=item.name,
|
|
188
|
-
name=item.display_name,
|
|
189
|
-
description=item.description,
|
|
190
|
-
value_type=value_type,
|
|
191
|
-
min_count=0,
|
|
192
|
-
max_count=1,
|
|
193
|
-
)
|
|
194
|
-
self.properties.append(prop)
|
|
195
|
-
|
|
196
|
-
def convert_component(self, item: Component, parent: str | None) -> None:
|
|
197
|
-
if parent is None:
|
|
198
|
-
self._missing_parent_warning(item)
|
|
199
|
-
return None
|
|
200
|
-
|
|
201
|
-
value_type = self.schema_to_value_type(item.schema_, item)
|
|
202
|
-
if value_type is None:
|
|
203
|
-
return
|
|
204
|
-
prop = UnverifiedConceptualProperty(
|
|
205
|
-
concept=ConceptEntity.load(parent),
|
|
206
|
-
property_=item.name,
|
|
207
|
-
name=item.display_name,
|
|
208
|
-
description=item.description,
|
|
209
|
-
value_type=value_type,
|
|
210
|
-
min_count=0,
|
|
211
|
-
max_count=1,
|
|
212
|
-
)
|
|
213
|
-
self.properties.append(prop)
|
|
214
|
-
|
|
215
|
-
def convert_relationship(self, item: Relationship, parent: str | None) -> None:
|
|
216
|
-
if parent is None:
|
|
217
|
-
self._missing_parent_warning(item)
|
|
218
|
-
return None
|
|
219
|
-
if item.target is not None:
|
|
220
|
-
value_type: DataType | ConceptEntity
|
|
221
|
-
if item.target in self._item_by_id:
|
|
222
|
-
value_type = item.target.as_concept_entity()
|
|
223
|
-
else:
|
|
224
|
-
# Falling back to json
|
|
225
|
-
self.issues.append(
|
|
226
|
-
ResourceMissingIdentifierError(
|
|
227
|
-
"unknown",
|
|
228
|
-
item.target.model_dump(),
|
|
229
|
-
)
|
|
230
|
-
)
|
|
231
|
-
value_type = Json()
|
|
232
|
-
|
|
233
|
-
prop = UnverifiedConceptualProperty(
|
|
234
|
-
concept=ConceptEntity.load(parent),
|
|
235
|
-
property_=item.name,
|
|
236
|
-
name=item.display_name,
|
|
237
|
-
description=item.description,
|
|
238
|
-
min_count=item.min_multiplicity or 0,
|
|
239
|
-
max_count=item.max_multiplicity or 1,
|
|
240
|
-
value_type=value_type,
|
|
241
|
-
)
|
|
242
|
-
self.properties.append(prop)
|
|
243
|
-
elif item.properties is not None:
|
|
244
|
-
for prop_ in item.properties or []:
|
|
245
|
-
self.convert_property(prop_, parent, item.min_multiplicity, item.max_multiplicity)
|
|
246
|
-
|
|
247
|
-
def convert_object(self, item: Object, _: str | None) -> None:
|
|
248
|
-
if item.id_ is None:
|
|
249
|
-
self.issues.append(
|
|
250
|
-
ResourceMissingIdentifierError(
|
|
251
|
-
resource_type=item.type,
|
|
252
|
-
name=item.display_name,
|
|
253
|
-
)
|
|
254
|
-
)
|
|
255
|
-
return None
|
|
256
|
-
|
|
257
|
-
class_ = UnverifiedConcept(
|
|
258
|
-
concept=item.id_.as_concept_entity(),
|
|
259
|
-
name=item.display_name,
|
|
260
|
-
description=item.description,
|
|
261
|
-
)
|
|
262
|
-
self.classes.append(class_)
|
|
263
|
-
|
|
264
|
-
for field_ in item.fields or []:
|
|
265
|
-
value_type = self.schema_to_value_type(field_.schema_, item)
|
|
266
|
-
if value_type is None:
|
|
267
|
-
continue
|
|
268
|
-
prop = UnverifiedConceptualProperty(
|
|
269
|
-
concept=class_.concept,
|
|
270
|
-
name=field_.name,
|
|
271
|
-
description=field_.description,
|
|
272
|
-
property_=field_.name,
|
|
273
|
-
value_type=value_type,
|
|
274
|
-
min_count=0,
|
|
275
|
-
max_count=1,
|
|
276
|
-
)
|
|
277
|
-
self.properties.append(prop)
|
|
278
|
-
|
|
279
|
-
def schema_to_value_type(
|
|
280
|
-
self, schema: Schema | Interface | DTMI | None, item: DTDLBase
|
|
281
|
-
) -> DataType | ConceptEntity | None:
|
|
282
|
-
input_type = self._item_by_id.get(schema) if isinstance(schema, DTMI) else schema
|
|
283
|
-
|
|
284
|
-
if isinstance(input_type, Enum):
|
|
285
|
-
return String()
|
|
286
|
-
elif isinstance(input_type, str) and input_type.casefold() in _DATA_TYPE_BY_NAME:
|
|
287
|
-
return _DATA_TYPE_BY_NAME[input_type.casefold()]()
|
|
288
|
-
elif isinstance(input_type, str):
|
|
289
|
-
self.issues.append(
|
|
290
|
-
PropertyTypeNotSupportedError(
|
|
291
|
-
item.identifier_with_fallback,
|
|
292
|
-
item.type,
|
|
293
|
-
"schema",
|
|
294
|
-
input_type,
|
|
295
|
-
)
|
|
296
|
-
)
|
|
297
|
-
return None
|
|
298
|
-
elif isinstance(input_type, Object | Interface):
|
|
299
|
-
if input_type.id_ is None:
|
|
300
|
-
self.issues.append(
|
|
301
|
-
ResourceMissingIdentifierError(
|
|
302
|
-
input_type.type,
|
|
303
|
-
input_type.display_name,
|
|
304
|
-
)
|
|
305
|
-
)
|
|
306
|
-
return Json()
|
|
307
|
-
else:
|
|
308
|
-
if isinstance(input_type, Object):
|
|
309
|
-
self.convert_object(input_type, None)
|
|
310
|
-
return input_type.id_.as_concept_entity()
|
|
311
|
-
else:
|
|
312
|
-
self.issues.append(
|
|
313
|
-
PropertyTypeNotSupportedWarning(
|
|
314
|
-
item.identifier_with_fallback,
|
|
315
|
-
item.type, # type: ignore[arg-type]
|
|
316
|
-
"schema",
|
|
317
|
-
input_type.type if input_type else "missing",
|
|
318
|
-
)
|
|
319
|
-
)
|
|
320
|
-
return None
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import zipfile
|
|
3
|
-
from collections.abc import Iterable, Sequence
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
|
|
6
|
-
from pydantic import ValidationError
|
|
7
|
-
|
|
8
|
-
from cognite.neat.core._data_model._shared import ImportedDataModel
|
|
9
|
-
from cognite.neat.core._data_model.importers._base import BaseImporter
|
|
10
|
-
from cognite.neat.core._data_model.importers._dtdl2data_model.dtdl_converter import _DTDLConverter
|
|
11
|
-
from cognite.neat.core._data_model.importers._dtdl2data_model.spec import (
|
|
12
|
-
DTDL_CLS_BY_TYPE_BY_SPEC,
|
|
13
|
-
DTDLBase,
|
|
14
|
-
Interface,
|
|
15
|
-
)
|
|
16
|
-
from cognite.neat.core._data_model.models import UnverifiedConceptualDataModel
|
|
17
|
-
from cognite.neat.core._data_model.models.conceptual import UnverifiedConceptualMetadata
|
|
18
|
-
from cognite.neat.core._issues import IssueList, MultiValueError, NeatIssue
|
|
19
|
-
from cognite.neat.core._issues.warnings import (
|
|
20
|
-
FileItemNotSupportedWarning,
|
|
21
|
-
FileMissingRequiredFieldWarning,
|
|
22
|
-
FileReadWarning,
|
|
23
|
-
FileTypeUnexpectedWarning,
|
|
24
|
-
NeatValueWarning,
|
|
25
|
-
)
|
|
26
|
-
from cognite.neat.core._utils.text import humanize_collection, to_pascal_case
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
class DTDLImporter(BaseImporter[UnverifiedConceptualDataModel]):
|
|
30
|
-
"""Importer from Azure Digital Twin - DTDL (Digital Twin Definition Language).
|
|
31
|
-
|
|
32
|
-
This importer supports DTDL v2.0 and v3.0.
|
|
33
|
-
|
|
34
|
-
It is recommended to use the class methods `from_directory` and `from_zip` to create an instance of this class.
|
|
35
|
-
|
|
36
|
-
Args:
|
|
37
|
-
items (Sequence[DTDLBase]): A sequence of DTDLBase objects.
|
|
38
|
-
name (str, optional): Name of the data model. Defaults to None.
|
|
39
|
-
read_issues (list[ValidationIssue], optional): A list of issues that occurred during reading. Defaults to None.
|
|
40
|
-
schema (SchemaCompleteness, optional): Schema completeness. Defaults to SchemaCompleteness.partial.
|
|
41
|
-
|
|
42
|
-
"""
|
|
43
|
-
|
|
44
|
-
def __init__(
|
|
45
|
-
self,
|
|
46
|
-
items: Sequence[DTDLBase],
|
|
47
|
-
name: str | None = None,
|
|
48
|
-
read_issues: list[NeatIssue] | None = None,
|
|
49
|
-
) -> None:
|
|
50
|
-
self._items = items
|
|
51
|
-
self.name = name
|
|
52
|
-
self._read_issues = IssueList(read_issues)
|
|
53
|
-
|
|
54
|
-
@classmethod
|
|
55
|
-
def _from_file_content(cls, file_content: str, filepath: Path) -> Iterable[DTDLBase | NeatIssue]:
|
|
56
|
-
raw = json.loads(file_content)
|
|
57
|
-
if isinstance(raw, dict):
|
|
58
|
-
if (context := raw.get("@context")) is None:
|
|
59
|
-
yield FileMissingRequiredFieldWarning(filepath, "@context", "Missing '@context' key.")
|
|
60
|
-
return
|
|
61
|
-
raw_list = [raw]
|
|
62
|
-
elif isinstance(raw, list):
|
|
63
|
-
context = next(
|
|
64
|
-
(entry["@context"] for entry in raw if isinstance(entry, dict) and "@context" in entry), None
|
|
65
|
-
)
|
|
66
|
-
if context is None:
|
|
67
|
-
yield FileMissingRequiredFieldWarning(filepath, "@context", "Missing '@context' key.")
|
|
68
|
-
return
|
|
69
|
-
raw_list = raw
|
|
70
|
-
else:
|
|
71
|
-
yield FileTypeUnexpectedWarning(filepath, frozenset(["dict", "list"]), "Content is not an object or array.")
|
|
72
|
-
return
|
|
73
|
-
|
|
74
|
-
if isinstance(context, list):
|
|
75
|
-
context = context[0]
|
|
76
|
-
Interface.default_context = context
|
|
77
|
-
spec_version = context.split(";")[1]
|
|
78
|
-
try:
|
|
79
|
-
cls_by_type = DTDL_CLS_BY_TYPE_BY_SPEC[spec_version]
|
|
80
|
-
except KeyError:
|
|
81
|
-
yield NeatValueWarning(
|
|
82
|
-
f"Unsupported DTDL spec version: {spec_version} in {filepath}. "
|
|
83
|
-
f"Supported versions are {humanize_collection(DTDL_CLS_BY_TYPE_BY_SPEC.keys())}."
|
|
84
|
-
" The file will be skipped."
|
|
85
|
-
)
|
|
86
|
-
return
|
|
87
|
-
|
|
88
|
-
for item in raw_list:
|
|
89
|
-
if not (type_ := item.get("@type")):
|
|
90
|
-
yield FileMissingRequiredFieldWarning(filepath, "@type", "Missing '@type' key.")
|
|
91
|
-
continue
|
|
92
|
-
cls_ = cls_by_type.get(type_)
|
|
93
|
-
if cls_ is None:
|
|
94
|
-
yield FileItemNotSupportedWarning(f"Unknown '@type' {type_}.", filepath=filepath)
|
|
95
|
-
continue
|
|
96
|
-
try:
|
|
97
|
-
yield cls_.model_validate(item)
|
|
98
|
-
except ValidationError as e:
|
|
99
|
-
yield FileTypeUnexpectedWarning(filepath, frozenset([cls.__name__]), str(e))
|
|
100
|
-
except Exception as e:
|
|
101
|
-
yield FileReadWarning(filepath=filepath, reason=str(e))
|
|
102
|
-
|
|
103
|
-
@classmethod
|
|
104
|
-
def from_directory(cls, directory: Path) -> "DTDLImporter":
|
|
105
|
-
items: list[DTDLBase] = []
|
|
106
|
-
issues: list[NeatIssue] = []
|
|
107
|
-
for filepath in directory.glob("**/*.json"):
|
|
108
|
-
for item in cls._from_file_content(filepath.read_text(), filepath):
|
|
109
|
-
if isinstance(item, NeatIssue):
|
|
110
|
-
issues.append(item)
|
|
111
|
-
else:
|
|
112
|
-
items.append(item)
|
|
113
|
-
return cls(items, directory.stem, read_issues=issues)
|
|
114
|
-
|
|
115
|
-
@classmethod
|
|
116
|
-
def from_zip(cls, zip_file: Path) -> "DTDLImporter":
|
|
117
|
-
items: list[DTDLBase] = []
|
|
118
|
-
issues: list[NeatIssue] = []
|
|
119
|
-
with zipfile.ZipFile(zip_file) as z:
|
|
120
|
-
for filepath in z.namelist():
|
|
121
|
-
if filepath.endswith(".json"):
|
|
122
|
-
for item in cls._from_file_content(z.read(filepath).decode(), Path(filepath)):
|
|
123
|
-
if isinstance(item, NeatIssue):
|
|
124
|
-
issues.append(item)
|
|
125
|
-
else:
|
|
126
|
-
items.append(item)
|
|
127
|
-
return cls(items, zip_file.stem, read_issues=issues)
|
|
128
|
-
|
|
129
|
-
def to_data_model(self) -> ImportedDataModel[UnverifiedConceptualDataModel]:
|
|
130
|
-
converter = _DTDLConverter(self._read_issues)
|
|
131
|
-
|
|
132
|
-
converter.convert(self._items)
|
|
133
|
-
|
|
134
|
-
metadata = self._default_metadata()
|
|
135
|
-
|
|
136
|
-
if self.name:
|
|
137
|
-
metadata["name"] = to_pascal_case(self.name)
|
|
138
|
-
try:
|
|
139
|
-
most_common_prefix = converter.get_most_common_prefix()
|
|
140
|
-
except ValueError:
|
|
141
|
-
# No prefixes are defined so we just use the default prefix...
|
|
142
|
-
...
|
|
143
|
-
else:
|
|
144
|
-
metadata["space"] = most_common_prefix
|
|
145
|
-
|
|
146
|
-
data_model = UnverifiedConceptualDataModel(
|
|
147
|
-
metadata=UnverifiedConceptualMetadata.load(metadata),
|
|
148
|
-
properties=converter.properties,
|
|
149
|
-
concepts=converter.classes,
|
|
150
|
-
)
|
|
151
|
-
converter.issues.trigger_warnings()
|
|
152
|
-
if converter.issues.has_errors:
|
|
153
|
-
raise MultiValueError(converter.issues.errors)
|
|
154
|
-
|
|
155
|
-
return ImportedDataModel(data_model, {})
|
|
@@ -1,363 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
This is a pydantic validation implementation of the DTDL v2 and v3 specifications.
|
|
3
|
-
|
|
4
|
-
The specs are taken from:
|
|
5
|
-
|
|
6
|
-
* Spec v2: https://github.com/Azure/opendigitaltwins-dtdl/blob/master/DTDL/v2/DTDL.v2.md
|
|
7
|
-
* Spec v3: https://github.com/Azure/opendigitaltwins-dtdl/blob/master/DTDL/v3/DTDL.v3.md
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
import re
|
|
11
|
-
import warnings
|
|
12
|
-
from abc import ABC
|
|
13
|
-
from typing import TYPE_CHECKING, Any, ClassVar, Literal, TypeAlias
|
|
14
|
-
|
|
15
|
-
from pydantic import BaseModel, Field, field_validator, model_serializer, model_validator
|
|
16
|
-
from pydantic.fields import FieldInfo
|
|
17
|
-
|
|
18
|
-
from cognite.neat.core._data_model.models.entities import ConceptEntity
|
|
19
|
-
|
|
20
|
-
if TYPE_CHECKING:
|
|
21
|
-
from pydantic.type_adapter import IncEx
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
# Regex is from the spec: https://github.com/Azure/opendigitaltwins-dtdl/blob/master/DTMI/README.md#validation-regular-expressions
|
|
25
|
-
_DTMI_REGEX = (
|
|
26
|
-
r"^dtmi:(?:_+[A-Za-z0-9]|[A-Za-z])(?:[A-Za-z0-9_]*[A-Za-z0-9])?(?::(?:_+[A-Za-z0-9]|[A-Za-z])"
|
|
27
|
-
r"(?:[A-Za-z0-9_]*[A-Za-z0-9])?)*(?:;[1-9][0-9]{0,8}(?:\.[1-9][0-9]{0,5})?)?$"
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
_DTMI_COMPILED = re.compile(_DTMI_REGEX)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class DTMI(BaseModel):
|
|
34
|
-
scheme: ClassVar[str] = "dtmi"
|
|
35
|
-
path: list[str]
|
|
36
|
-
version: str
|
|
37
|
-
|
|
38
|
-
def as_concept_entity(self) -> ConceptEntity:
|
|
39
|
-
return ConceptEntity(prefix="_".join(self.path[:-1]), suffix=self.path[-1], version=self.version)
|
|
40
|
-
|
|
41
|
-
def __hash__(self) -> int:
|
|
42
|
-
return hash(self.to_string())
|
|
43
|
-
|
|
44
|
-
def __repr__(self) -> str:
|
|
45
|
-
return self.to_string()
|
|
46
|
-
|
|
47
|
-
@model_validator(mode="before")
|
|
48
|
-
def from_string(cls, value: Any) -> Any:
|
|
49
|
-
if not isinstance(value, str):
|
|
50
|
-
return value
|
|
51
|
-
if not _DTMI_COMPILED.match(value):
|
|
52
|
-
raise ValueError(f"Invalid DTMI {value}")
|
|
53
|
-
value = value.removeprefix(cls.scheme + ":")
|
|
54
|
-
path_str, version = value.split(";", 1)
|
|
55
|
-
return dict(path=path_str.split(":"), version=version)
|
|
56
|
-
|
|
57
|
-
@model_serializer
|
|
58
|
-
def to_string(self) -> str:
|
|
59
|
-
return f"{self.scheme}:{':'.join(self.path)};{self.version}"
|
|
60
|
-
|
|
61
|
-
if TYPE_CHECKING:
|
|
62
|
-
# Ensure type checkers works correctly, ref
|
|
63
|
-
# https://docs.pydantic.dev/latest/concepts/serialization/#overriding-the-return-type-when-dumping-a-model
|
|
64
|
-
def model_dump( # type: ignore[override]
|
|
65
|
-
self,
|
|
66
|
-
*,
|
|
67
|
-
mode: Literal["json", "python"] | str = "python",
|
|
68
|
-
include: IncEx | None = None,
|
|
69
|
-
exclude: IncEx | None = None,
|
|
70
|
-
by_alias: bool = False,
|
|
71
|
-
exclude_unset: bool = False,
|
|
72
|
-
exclude_defaults: bool = False,
|
|
73
|
-
exclude_none: bool = False,
|
|
74
|
-
round_trip: bool = False,
|
|
75
|
-
warnings: bool = True,
|
|
76
|
-
) -> str: ...
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
IRI: TypeAlias = str
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
class Unit(BaseModel, ABC):
|
|
83
|
-
value: str
|
|
84
|
-
semantic_type: str | None = Field(None, alias="semanticType")
|
|
85
|
-
unit_type: str | None = Field(None, alias="unitType")
|
|
86
|
-
|
|
87
|
-
def __hash__(self) -> int:
|
|
88
|
-
return hash(self.to_string())
|
|
89
|
-
|
|
90
|
-
def __repr__(self) -> str:
|
|
91
|
-
return self.to_string()
|
|
92
|
-
|
|
93
|
-
@model_validator(mode="before")
|
|
94
|
-
def from_string(cls, value: Any) -> Any:
|
|
95
|
-
if not isinstance(value, str):
|
|
96
|
-
return value
|
|
97
|
-
from ._unit_lookup import ENTRY_BY_UNIT
|
|
98
|
-
|
|
99
|
-
if value not in ENTRY_BY_UNIT:
|
|
100
|
-
return dict(unit=value)
|
|
101
|
-
entry = ENTRY_BY_UNIT[value]
|
|
102
|
-
return dict(
|
|
103
|
-
value=value,
|
|
104
|
-
semanticType=entry.semantic_type,
|
|
105
|
-
unitType=entry.unit_type,
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
@model_serializer
|
|
109
|
-
def to_string(self) -> str:
|
|
110
|
-
return self.value
|
|
111
|
-
|
|
112
|
-
if TYPE_CHECKING:
|
|
113
|
-
# Ensure type checkers works correctly, ref
|
|
114
|
-
# https://docs.pydantic.dev/latest/concepts/serialization/#overriding-the-return-type-when-dumping-a-model
|
|
115
|
-
def model_dump( # type: ignore[override]
|
|
116
|
-
self,
|
|
117
|
-
*,
|
|
118
|
-
mode: Literal["json", "python"] | str = "python",
|
|
119
|
-
include: IncEx | None = None,
|
|
120
|
-
exclude: IncEx | None = None,
|
|
121
|
-
by_alias: bool = False,
|
|
122
|
-
exclude_unset: bool = False,
|
|
123
|
-
exclude_defaults: bool = False,
|
|
124
|
-
exclude_none: bool = False,
|
|
125
|
-
round_trip: bool = False,
|
|
126
|
-
warnings: bool = True,
|
|
127
|
-
) -> str: ...
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
class DTDLBase(BaseModel, ABC):
|
|
131
|
-
type: ClassVar[str]
|
|
132
|
-
spec_version: ClassVar[frozenset[str]]
|
|
133
|
-
id_: DTMI | None = Field(None, alias="@id")
|
|
134
|
-
comment: str | None = None
|
|
135
|
-
display_name: str | None = Field(None, alias="displayName")
|
|
136
|
-
description: str | None = None
|
|
137
|
-
|
|
138
|
-
@property
|
|
139
|
-
def identifier_with_fallback(self) -> str:
|
|
140
|
-
return (self.id_.model_dump() if self.id_ else self.display_name) or "MISSING"
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
PrimitiveSchema: TypeAlias = Literal[
|
|
144
|
-
"boolean", "date", "dateTime", "double", "duration", "float", "integer", "long", "string", "time"
|
|
145
|
-
]
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
class DTDLBaseWithName(DTDLBase, ABC):
|
|
149
|
-
name: str
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
class DTDLBaseWithSchema(DTDLBaseWithName, ABC):
|
|
153
|
-
schema_: "Schema | DTMI | None" = Field(None, alias="schema") # type: ignore[assignment]
|
|
154
|
-
|
|
155
|
-
@field_validator("schema_", mode="before")
|
|
156
|
-
def select_schema_type(cls, value: Any) -> Any:
|
|
157
|
-
if isinstance(value, dict) and (type_ := value.get("@type")):
|
|
158
|
-
context = Interface.default_context
|
|
159
|
-
spec_version = context.rsplit(";", maxsplit=1)[1]
|
|
160
|
-
try:
|
|
161
|
-
cls_by_type = DTDL_CLS_BY_TYPE_BY_SPEC[spec_version]
|
|
162
|
-
except KeyError:
|
|
163
|
-
raise ValueError(f"DTDL Spec v{spec_version} is not supported: {context}") from None
|
|
164
|
-
if isinstance(type_, str) and (cls_ := cls_by_type.get(type_)) is not None:
|
|
165
|
-
return cls_.model_validate(value)
|
|
166
|
-
elif isinstance(type_, list) and len(type_) == 2 and (cls_ := cls_by_type.get(type_[0])) is not None:
|
|
167
|
-
# In the spec v2, the type of Telemetry and Property can be a list of two strings,
|
|
168
|
-
# [[Telemetry|Property, "Semantic Type"].
|
|
169
|
-
from ._unit_lookup import UNIT_TYPE_BY_SEMANTIC_TYPE
|
|
170
|
-
|
|
171
|
-
if unit_type := UNIT_TYPE_BY_SEMANTIC_TYPE.get(type_[1]) and "unit" in value:
|
|
172
|
-
value["unit"] = {
|
|
173
|
-
"value": value["unit"],
|
|
174
|
-
"semanticType": type_[1],
|
|
175
|
-
"unitType": unit_type,
|
|
176
|
-
}
|
|
177
|
-
return cls_.model_validate(value)
|
|
178
|
-
return value
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
class DTDLField(DTDLBaseWithSchema):
|
|
182
|
-
type = "Field"
|
|
183
|
-
spec_version = frozenset(["2", "3"])
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
class Object(DTDLBase):
|
|
187
|
-
type = "Object"
|
|
188
|
-
spec_version = frozenset(["2", "3"])
|
|
189
|
-
fields: list[DTDLField] | None = None
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
class MapKey(DTDLBaseWithName):
|
|
193
|
-
type = "MapKey"
|
|
194
|
-
spec_version = frozenset(["2", "3"])
|
|
195
|
-
schema_: str = Field(alias="schema")
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
class MapValue(DTDLBaseWithSchema):
|
|
199
|
-
type = "MapValue"
|
|
200
|
-
spec_version = frozenset(["2", "3"])
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
class Map(DTDLBase):
|
|
204
|
-
type = "Map"
|
|
205
|
-
spec_version = frozenset(["2", "3"])
|
|
206
|
-
map_key: MapKey = Field(alias="mapKey")
|
|
207
|
-
map_value: MapValue = Field(alias="mapValue")
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
class EnumValue(DTDLBaseWithName):
|
|
211
|
-
type = "EnumValue"
|
|
212
|
-
spec_version = frozenset(["2", "3"])
|
|
213
|
-
enum_value: str = Field(alias="enumValue")
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
class Enum(DTDLBase):
|
|
217
|
-
type = "Enum"
|
|
218
|
-
spec_version = frozenset(["2", "3"])
|
|
219
|
-
enum_values: list[EnumValue] = Field(alias="enumValues")
|
|
220
|
-
value_schema: PrimitiveSchema = Field(alias="valueSchema")
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
class Array(DTDLBase):
|
|
224
|
-
type = "Array"
|
|
225
|
-
spec_version = frozenset(["2", "3"])
|
|
226
|
-
element_schema: "Schema" = Field(alias="elementSchema")
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
ComplexSchema: TypeAlias = Array | Enum | Map | Object
|
|
230
|
-
|
|
231
|
-
Schema: TypeAlias = PrimitiveSchema | ComplexSchema
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
class Component(DTDLBaseWithSchema):
|
|
235
|
-
type = "Component"
|
|
236
|
-
spec_version = frozenset(["2", "3"])
|
|
237
|
-
schema_: "Interface | DTMI" = Field(alias="schema") # type: ignore[assignment]
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
class Property(DTDLBaseWithSchema):
|
|
241
|
-
type = "Property"
|
|
242
|
-
spec_version = frozenset(["3"])
|
|
243
|
-
writable: bool | None = None
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
class PropertyV2(Property):
|
|
247
|
-
spec_version = frozenset(["2"])
|
|
248
|
-
unit: Unit | None = None
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
class Relationship(DTDLBaseWithName):
|
|
252
|
-
type = "Relationship"
|
|
253
|
-
spec_version = frozenset(["2", "3"])
|
|
254
|
-
min_multiplicity: int | None = Field(None, alias="minMultiplicity", le=0, ge=0)
|
|
255
|
-
max_multiplicity: int | None = Field(None, alias="maxMultiplicity", ge=1)
|
|
256
|
-
properties: list[Property] | None = None
|
|
257
|
-
target: DTMI | None = None
|
|
258
|
-
writable: bool | None = None
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
class CommandRequest(DTDLBaseWithSchema):
|
|
262
|
-
type = "CommandRequest"
|
|
263
|
-
spec_version = frozenset(["3"])
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
class CommandResponse(DTDLBaseWithSchema):
|
|
267
|
-
type = "CommandResponse"
|
|
268
|
-
spec_version = frozenset(["3"])
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
class CommandPayload(DTDLBaseWithSchema):
|
|
272
|
-
type = "CommandPayload"
|
|
273
|
-
spec_version = frozenset(["2"])
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
class Command(DTDLBaseWithSchema):
|
|
277
|
-
type = "Command"
|
|
278
|
-
spec_version = frozenset(["3"])
|
|
279
|
-
request: CommandRequest | None = None
|
|
280
|
-
response: CommandResponse | None = None
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
class CommandV2(DTDLBaseWithSchema):
|
|
284
|
-
type = "Command"
|
|
285
|
-
spec_version = frozenset(["2"])
|
|
286
|
-
request: CommandPayload | None = None
|
|
287
|
-
response: CommandPayload | None = None
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
class Telemetry(DTDLBaseWithSchema):
|
|
291
|
-
type = "Telemetry"
|
|
292
|
-
spec_version = frozenset(["3"])
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
class TelemetryV2(Telemetry):
|
|
296
|
-
spec_version = frozenset(["2"])
|
|
297
|
-
unit: Unit | None = None
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
class Interface(DTDLBase):
|
|
301
|
-
type = "Interface"
|
|
302
|
-
spec_version = frozenset(["2", "3"])
|
|
303
|
-
default_context: ClassVar[IRI] = Field(
|
|
304
|
-
"dtmi:dtdl:context;3",
|
|
305
|
-
description="This can be set directly on the class to change the default context used when parsing a document.",
|
|
306
|
-
)
|
|
307
|
-
id_: DTMI = Field(alias="@id") # type: ignore[assignment]
|
|
308
|
-
context: IRI | None = Field(alias="@context")
|
|
309
|
-
extends: list[DTMI] | None = None
|
|
310
|
-
contents: list[Command | Component | Property | Relationship | Telemetry | DTMI | CommandV2] | None = None
|
|
311
|
-
schemas: list[Array | Enum | Map | Object] | None = None
|
|
312
|
-
|
|
313
|
-
@field_validator("context", mode="before")
|
|
314
|
-
def list_to_string(cls, value: Any) -> Any:
|
|
315
|
-
if isinstance(value, list) and len(value) == 1:
|
|
316
|
-
return value[0]
|
|
317
|
-
return value
|
|
318
|
-
|
|
319
|
-
@field_validator("contents", "schemas", mode="before")
|
|
320
|
-
def select_content_type(cls, value: Any, info: Any) -> Any:
|
|
321
|
-
if not isinstance(value, list):
|
|
322
|
-
return value
|
|
323
|
-
context = info.data.get("@context", cls.default_context)
|
|
324
|
-
if isinstance(context, FieldInfo):
|
|
325
|
-
context = context.default
|
|
326
|
-
spec_version = context.rsplit(";", maxsplit=1)[1]
|
|
327
|
-
try:
|
|
328
|
-
cls_by_type = DTDL_CLS_BY_TYPE_BY_SPEC[spec_version]
|
|
329
|
-
except KeyError:
|
|
330
|
-
raise ValueError(f"DTDL Spec v{spec_version} is not supported: {context}") from None
|
|
331
|
-
output: list[DTDLBase] = []
|
|
332
|
-
for item in value:
|
|
333
|
-
if isinstance(item, dict) and (type_ := item.get("@type")):
|
|
334
|
-
if isinstance(type_, str) and (cls_ := cls_by_type.get(type_)) is not None:
|
|
335
|
-
item = cls_.model_validate(item)
|
|
336
|
-
elif isinstance(type_, list) and len(type_) == 2 and (cls_ := cls_by_type.get(type_[0])) is not None:
|
|
337
|
-
# In the spec v2, the type of Telemetry and Property can be a list of two strings,
|
|
338
|
-
# [[Telemetry|Property, "Semantic Type"].
|
|
339
|
-
from ._unit_lookup import UNIT_TYPE_BY_SEMANTIC_TYPE
|
|
340
|
-
|
|
341
|
-
if (unit_type := UNIT_TYPE_BY_SEMANTIC_TYPE.get(type_[1])) and (unit := item.get("unit")):
|
|
342
|
-
item["unit"] = {
|
|
343
|
-
"value": unit,
|
|
344
|
-
"semanticType": type_[1],
|
|
345
|
-
"unitType": unit_type,
|
|
346
|
-
}
|
|
347
|
-
item = cls_.model_validate(item)
|
|
348
|
-
else:
|
|
349
|
-
warnings.warn(f"Invalid item {item} in {cls.__name__}.contents", stacklevel=2)
|
|
350
|
-
output.append(item)
|
|
351
|
-
return output
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
DTDL_CLS_BY_TYPE_BY_SPEC: dict[str, dict[str, type[DTDLBase]]] = {}
|
|
355
|
-
to_check = list(DTDLBase.__subclasses__())
|
|
356
|
-
while to_check:
|
|
357
|
-
cls = to_check.pop()
|
|
358
|
-
to_check.extend(cls.__subclasses__())
|
|
359
|
-
if ABC in cls.__bases__:
|
|
360
|
-
continue
|
|
361
|
-
for spec in cls.spec_version:
|
|
362
|
-
DTDL_CLS_BY_TYPE_BY_SPEC.setdefault(spec, {})[cls.type] = cls
|
|
363
|
-
del cls, to_check, spec
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
"""This module performs importing of various formats to one of serializations for which
|
|
2
|
-
there are loaders to data model pydantic class."""
|
|
3
|
-
|
|
4
|
-
from cognite.neat.core._data_model.importers._rdf._base import BaseRDFImporter
|
|
5
|
-
from cognite.neat.core._data_model.importers._rdf._shared import (
|
|
6
|
-
parse_concepts,
|
|
7
|
-
parse_properties,
|
|
8
|
-
)
|
|
9
|
-
|
|
10
|
-
CLASSES_QUERY = """
|
|
11
|
-
SELECT ?concept ?name ?description ?implements
|
|
12
|
-
WHERE {{
|
|
13
|
-
VALUES ?type {{ imf:BlockType imf:TerminalType imf:AttributeType }}
|
|
14
|
-
?concept a ?type .
|
|
15
|
-
|
|
16
|
-
OPTIONAL {{?concept rdfs:subClassOf ?parent }}.
|
|
17
|
-
OPTIONAL {{?concept rdfs:label|skos:prefLabel ?name }}.
|
|
18
|
-
OPTIONAL {{?concept rdfs:comment|skos:definition ?description}}.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
# Add imf:Attribute as parent class when no parent is found
|
|
22
|
-
BIND(IF(!bound(?parent) && ?type = imf:AttributeType, imf:Attribute, ?parent) AS ?implements)
|
|
23
|
-
|
|
24
|
-
# FILTERS
|
|
25
|
-
FILTER (!isBlank(?concept))
|
|
26
|
-
FILTER (!bound(?implements) || !isBlank(?implements))
|
|
27
|
-
|
|
28
|
-
FILTER (!bound(?name) || LANG(?name) = "" || LANGMATCHES(LANG(?name), "{language}"))
|
|
29
|
-
FILTER (!bound(?description) || LANG(?description) = "" || LANGMATCHES(LANG(?description), "{language}"))
|
|
30
|
-
}}
|
|
31
|
-
"""
|
|
32
|
-
|
|
33
|
-
PROPERTIES_QUERY = """
|
|
34
|
-
SELECT ?concept ?property_ ?name ?description ?value_type ?min_count ?max_count ?default
|
|
35
|
-
WHERE
|
|
36
|
-
{{
|
|
37
|
-
# CASE 1: Handling Blocks and Terminals
|
|
38
|
-
{{
|
|
39
|
-
VALUES ?type {{ imf:BlockType imf:TerminalType }}
|
|
40
|
-
?concept a ?type ;
|
|
41
|
-
sh:property ?propertyShape .
|
|
42
|
-
?propertyShape sh:path ?property_ .
|
|
43
|
-
|
|
44
|
-
OPTIONAL {{ ?property_ skos:prefLabel ?name . }}
|
|
45
|
-
OPTIONAL {{ ?property_ skos:definition ?description . }}
|
|
46
|
-
OPTIONAL {{ ?property_ rdfs:range ?range . }}
|
|
47
|
-
|
|
48
|
-
OPTIONAL {{ ?propertyShape sh:minCount ?min_count . }}
|
|
49
|
-
OPTIONAL {{ ?propertyShape sh:maxCount ?max_count . }}
|
|
50
|
-
OPTIONAL {{ ?propertyShape sh:hasValue ?default . }}
|
|
51
|
-
OPTIONAL {{ ?propertyShape sh:class | sh:qualifiedValueShape/sh:class ?valueShape . }}
|
|
52
|
-
}}
|
|
53
|
-
|
|
54
|
-
UNION
|
|
55
|
-
|
|
56
|
-
# CASE 2: Handling Attributes
|
|
57
|
-
{{
|
|
58
|
-
?concept a imf:AttributeType .
|
|
59
|
-
BIND(xsd:anyURI AS ?valueShape)
|
|
60
|
-
BIND(imf:predicate AS ?property_)
|
|
61
|
-
?concept ?property_ ?defaultURI .
|
|
62
|
-
BIND(STR(?defaultURI) AS ?default)
|
|
63
|
-
|
|
64
|
-
}}
|
|
65
|
-
|
|
66
|
-
# Set the value type for the property based on sh:class, sh:qualifiedValueType or rdfs:range
|
|
67
|
-
BIND(IF(BOUND(?valueShape), ?valueShape, IF(BOUND(?range) , ?range , ?valueShape)) AS ?value_type)
|
|
68
|
-
|
|
69
|
-
FILTER (!isBlank(?property_))
|
|
70
|
-
FILTER (!bound(?concept) || !isBlank(?concept))
|
|
71
|
-
FILTER (!bound(?name) || LANG(?name) = "" || LANGMATCHES(LANG(?name), "{language}"))
|
|
72
|
-
FILTER (!bound(?description) || LANG(?description) = "" || LANGMATCHES(LANG(?description), "{language}"))
|
|
73
|
-
}}
|
|
74
|
-
"""
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
class IMFImporter(BaseRDFImporter):
|
|
78
|
-
"""Convert IMF Types provided as SHACL shapes to unverified data model."""
|
|
79
|
-
|
|
80
|
-
@property
|
|
81
|
-
def description(self) -> str:
|
|
82
|
-
return f"IMF Types {self.source_name} read as unverified data model"
|
|
83
|
-
|
|
84
|
-
def _to_data_model_components(
|
|
85
|
-
self,
|
|
86
|
-
) -> dict:
|
|
87
|
-
classes, issue_list = parse_concepts(self.graph, CLASSES_QUERY, self.language, self.issue_list)
|
|
88
|
-
self.issue_list = issue_list
|
|
89
|
-
properties, issue_list = parse_properties(self.graph, PROPERTIES_QUERY, self.language, self.issue_list)
|
|
90
|
-
self.issue_list = issue_list
|
|
91
|
-
|
|
92
|
-
components = {
|
|
93
|
-
"Metadata": self._metadata,
|
|
94
|
-
"Concepts": list(classes.values()) if classes else [],
|
|
95
|
-
"Properties": list(properties.values()) if properties else [],
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return components
|
|
File without changes
|
|
File without changes
|