88from __future__ import annotations
99
1010from numbers import Real
11- from typing import Union , Any , Literal
11+ from typing import Union , Any , Literal , Annotated
1212
13- from pydantic import BaseModel , Field , field_validator , SerializeAsAny
13+ from pydantic import BaseModel , ConfigDict , Field , field_validator , SerializeAsAny
1414
1515from .csapi4py .constants import GeometryTypes
1616from .api_utils import UCUMCode , URI
3131
3232
3333class AnyComponentSchema (BaseModel ):
34+ model_config = ConfigDict (populate_by_name = True )
3435 type : str = Field (...)
3536 id : str = Field (None )
3637 label : str = Field (None )
@@ -42,33 +43,39 @@ class AnyComponentSchema(BaseModel):
4243
4344class DataRecordSchema (AnyComponentSchema ):
4445 type : Literal ["DataRecord" ] = "DataRecord"
45- fields : SerializeAsAny [list [AnyComponentSchema ]] = Field (...)
46+ # `name` is not part of AbstractDataComponent in SWE Common 3 — it belongs to
47+ # the SoftNamedProperty wrapper that binds a component as a record field. We
48+ # accept it here only because the OSH server emits `name` at the root-level
49+ # DataRecord of a datastream's recordSchema/resultSchema. See
50+ # docs/osh_spec_deviations.md (root-component-name).
51+ name : str = Field (None )
52+ fields : list ["AnyComponent" ] = Field (...)
4653
4754
4855class VectorSchema (AnyComponentSchema ):
4956 label : str = Field (...)
5057 name : str = Field (...)
5158 type : Literal ["Vector" ] = "Vector"
5259 definition : str = Field (...)
53- reference_frame : str = Field (..., serialization_alias = 'referenceFrame' )
54- local_frame : str = Field (None , serialization_alias = 'localFrame' )
60+ reference_frame : str = Field (..., alias = 'referenceFrame' )
61+ local_frame : str = Field (None , alias = 'localFrame' )
5562 # TODO: VERIFY might need to be moved further down when these are defined
5663 coordinates : SerializeAsAny [Union [list [CountSchema ], list [QuantitySchema ], list [TimeSchema ]]] = Field (...)
5764
5865
5966class DataArraySchema (AnyComponentSchema ):
6067 type : Literal ["DataArray" ] = "DataArray"
6168 name : str = Field (...)
62- element_count : dict | str | CountSchema = Field (..., serialization_alias = 'elementCount' ) # Should type of Count
63- element_type : SerializeAsAny [ AnyComponentSchema ] = Field (..., serialization_alias = 'elementType' )
69+ element_count : dict | str | CountSchema = Field (..., alias = 'elementCount' ) # Should type of Count
70+ element_type : "AnyComponent" = Field (..., alias = 'elementType' )
6471 encoding : str = Field (...) # TODO: implement an encodings class
6572 values : list = Field (None )
6673
6774
6875class MatrixSchema (AnyComponentSchema ):
6976 type : Literal ["Matrix" ] = "Matrix"
70- element_count : dict | str | CountSchema = Field (..., serialization_alias = 'elementCount' ) # Should be type of Count
71- element_type : SerializeAsAny [ list [AnyComponentSchema ]] = Field (..., serialization_alias = 'elementType' )
77+ element_count : dict | str | CountSchema = Field (..., alias = 'elementCount' ) # Should be type of Count
78+ element_type : list ["AnyComponent" ] = Field (..., alias = 'elementType' )
7279 encoding : str = Field (...) # TODO: implement an encodings class
7380 values : list = Field (None )
7481 reference_frame : str = Field (None )
@@ -79,8 +86,8 @@ class DataChoiceSchema(AnyComponentSchema):
7986 type : Literal ["DataChoice" ] = "DataChoice"
8087 updatable : bool = Field (False )
8188 optional : bool = Field (False )
82- choice_value : CategorySchema = Field (..., serialization_alias = 'choiceValue' ) # TODO: Might be called "choiceValues"
83- items : SerializeAsAny [ list [AnyComponentSchema ] ] = Field (...)
89+ choice_value : CategorySchema = Field (..., alias = 'choiceValue' ) # TODO: Might be called "choiceValues"
90+ items : list ["AnyComponent" ] = Field (...)
8491
8592
8693class GeometrySchema (AnyComponentSchema ):
@@ -99,7 +106,7 @@ class GeometrySchema(AnyComponentSchema):
99106 GeometryTypes .MULTI_POLYGON .value
100107 ]
101108 })
102- nil_values : list = Field (None , serialization_alias = 'nilValues' )
109+ nil_values : list = Field (None , alias = 'nilValues' )
103110 srs : str = Field (...)
104111 value : Geometry = Field (None )
105112
@@ -111,11 +118,13 @@ class AnySimpleComponentSchema(AnyComponentSchema):
111118 updatable : bool = Field (False )
112119 optional : bool = Field (False )
113120 definition : str = Field (...)
114- reference_frame : str = Field (None , serialization_alias = 'referenceFrame' )
115- axis_id : str = Field (None , serialization_alias = 'axisID' )
116- quality : list [Union [QuantitySchema , QuantityRangeSchema , CategorySchema , TextSchema ]] = Field (
117- None ) # TODO: Union[Quantity, QuantityRange, Category, Text]
118- nil_values : list = Field (None , serialization_alias = 'nilValues' )
121+ reference_frame : str = Field (None , alias = 'referenceFrame' )
122+ axis_id : str = Field (None , alias = 'axisID' )
123+ quality : list [Annotated [
124+ Union [QuantitySchema , QuantityRangeSchema , CategorySchema , TextSchema ],
125+ Field (discriminator = 'type' ),
126+ ]] = Field (None )
127+ nil_values : list = Field (None , alias = 'nilValues' )
119128 constraint : Any = Field (None )
120129 value : Any = Field (None )
121130 name : str = Field (...)
@@ -165,15 +174,15 @@ def validate_value(cls, v):
165174class TimeSchema (AnyScalarComponentSchema ):
166175 type : Literal ["Time" ] = "Time"
167176 value : str = Field (None )
168- reference_time : str = Field (None , serialization_alias = 'referenceTime' )
177+ reference_time : str = Field (None , alias = 'referenceTime' )
169178 local_frame : str = Field (None )
170179 uom : Union [UCUMCode , URI ] = Field (...)
171180
172181
173182class CategorySchema (AnyScalarComponentSchema ):
174183 type : Literal ["Category" ] = "Category"
175184 value : str = Field (None )
176- code_space : str = Field (None , serialization_alias = 'codeSpace' )
185+ code_space : str = Field (None , alias = 'codeSpace' )
177186
178187
179188class TextSchema (AnyScalarComponentSchema ):
@@ -196,12 +205,24 @@ class QuantityRangeSchema(AnySimpleComponentSchema):
196205class TimeRangeSchema (AnySimpleComponentSchema ):
197206 type : Literal ["TimeRange" ] = "TimeRange"
198207 value : list [str ] = Field (None )
199- reference_time : str = Field (None , serialization_alias = 'referenceTime' )
208+ reference_time : str = Field (None , alias = 'referenceTime' )
200209 local_frame : str = Field (None )
201210 uom : Union [UCUMCode , URI ] = Field (...)
202211
203212
204213class CategoryRangeSchema (AnySimpleComponentSchema ):
205214 type : Literal ["CategoryRange" ] = "CategoryRange"
206215 value : list [str ] = Field (None )
207- code_space : str = Field (None , serialization_alias = 'codeSpace' )
216+ code_space : str = Field (None , alias = 'codeSpace' )
217+
218+
219+ AnyComponent = Annotated [
220+ Union [
221+ DataRecordSchema , VectorSchema , DataArraySchema , MatrixSchema ,
222+ DataChoiceSchema , GeometrySchema ,
223+ BooleanSchema , CountSchema , QuantitySchema , TimeSchema ,
224+ CategorySchema , TextSchema ,
225+ CountRangeSchema , QuantityRangeSchema , TimeRangeSchema , CategoryRangeSchema ,
226+ ],
227+ Field (discriminator = "type" ),
228+ ]
0 commit comments