Skip to content

Commit 5a4a970

Browse files
Change swe components to use Literal[{type_name}]'s for the type field. added a JSONDatastreamRecordschema for testing serialization/deserialization
1 parent de14a46 commit 5a4a970

3 files changed

Lines changed: 46 additions & 20 deletions

File tree

src/oshconnect/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
QuantityRangeSchema,
3434
TimeRangeSchema,
3535
)
36-
from .schema_datamodels import SWEDatastreamRecordSchema, JSONCommandSchema
36+
from .schema_datamodels import SWEDatastreamRecordSchema, JSONDatastreamRecordSchema, JSONCommandSchema
3737

3838
# Event system
3939
from .events import EventHandler, IEventListener, CallbackListener, DefaultEventTypes, AtomicEventTypes, Event, EventBuilder
@@ -76,6 +76,7 @@
7676
"QuantityRangeSchema",
7777
"TimeRangeSchema",
7878
"SWEDatastreamRecordSchema",
79+
"JSONDatastreamRecordSchema",
7980
"JSONCommandSchema",
8081
# Event system
8182
"EventHandler",

src/oshconnect/schema_datamodels.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class SWEJSONCommandSchema(CommandSchema):
5151

5252
command_format: str = Field("application/swe+json", alias='commandFormat')
5353
encoding: SerializeAsAny[Encoding] = Field(...)
54-
record_schema: SerializeAsAny[AnyComponentSchema] = Field(..., serialization_alias='recordSchema')
54+
record_schema: SerializeAsAny[AnyComponentSchema] = Field(..., alias='recordSchema')
5555

5656

5757
class JSONCommandSchema(CommandSchema):
@@ -78,7 +78,7 @@ class DatastreamRecordSchema(BaseModel):
7878
class SWEDatastreamRecordSchema(DatastreamRecordSchema):
7979
model_config = ConfigDict(populate_by_name=True)
8080
encoding: SerializeAsAny[Encoding] = Field(...)
81-
record_schema: SerializeAsAny[AnyComponentSchema] = Field(..., serialization_alias='recordSchema')
81+
record_schema: SerializeAsAny[AnyComponentSchema] = Field(..., alias='recordSchema')
8282

8383
@field_validator('obs_format')
8484
@classmethod
@@ -89,6 +89,31 @@ def check_check_obs_format(cls, v):
8989
return v
9090

9191

92+
class JSONDatastreamRecordSchema(DatastreamRecordSchema):
93+
"""Datastream observation schema for the JSON media types
94+
(`application/json`, `application/om+json`).
95+
96+
Per CS API Part 2 §16.1.4, this form does not carry a SWE `encoding`
97+
block; structure is fully described by `resultSchema` (inline result)
98+
or `resultLink` (out-of-band). `parametersSchema` is optional.
99+
"""
100+
model_config = ConfigDict(populate_by_name=True)
101+
102+
obs_format: str = Field(ObservationFormat.JSON.value, alias='obsFormat')
103+
result_schema: SerializeAsAny[AnyComponentSchema] = Field(None, alias='resultSchema')
104+
parameters_schema: SerializeAsAny[AnyComponentSchema] = Field(None, alias='parametersSchema')
105+
result_link: dict = Field(None, alias='resultLink')
106+
107+
@field_validator('obs_format')
108+
@classmethod
109+
def _check_obs_format(cls, v):
110+
if v not in (ObservationFormat.JSON.value, "application/json"):
111+
raise ValueError(
112+
f"obsFormat must be 'application/json' or '{ObservationFormat.JSON.value}'"
113+
)
114+
return v
115+
116+
92117
class ObservationOMJSONInline(BaseModel):
93118
"""
94119
A class to represent an observation in OM-JSON format

src/oshconnect/swe_components.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from __future__ import annotations
99

1010
from numbers import Real
11-
from typing import Union, Any
11+
from typing import Union, Any, Literal
1212

1313
from pydantic import BaseModel, Field, field_validator, SerializeAsAny
1414

@@ -41,14 +41,14 @@ class AnyComponentSchema(BaseModel):
4141

4242

4343
class DataRecordSchema(AnyComponentSchema):
44-
type: str = "DataRecord"
44+
type: Literal["DataRecord"] = "DataRecord"
4545
fields: SerializeAsAny[list[AnyComponentSchema]] = Field(...)
4646

4747

4848
class VectorSchema(AnyComponentSchema):
4949
label: str = Field(...)
5050
name: str = Field(...)
51-
type: str = "Vector"
51+
type: Literal["Vector"] = "Vector"
5252
definition: str = Field(...)
5353
reference_frame: str = Field(..., serialization_alias='referenceFrame')
5454
local_frame: str = Field(None, serialization_alias='localFrame')
@@ -57,7 +57,7 @@ class VectorSchema(AnyComponentSchema):
5757

5858

5959
class DataArraySchema(AnyComponentSchema):
60-
type: str = "DataArray"
60+
type: Literal["DataArray"] = "DataArray"
6161
name: str = Field(...)
6262
element_count: dict | str | CountSchema = Field(..., serialization_alias='elementCount') # Should type of Count
6363
element_type: SerializeAsAny[AnyComponentSchema] = Field(..., serialization_alias='elementType')
@@ -66,7 +66,7 @@ class DataArraySchema(AnyComponentSchema):
6666

6767

6868
class MatrixSchema(AnyComponentSchema):
69-
type: str = "Matrix"
69+
type: Literal["Matrix"] = "Matrix"
7070
element_count: dict | str | CountSchema = Field(..., serialization_alias='elementCount') # Should be type of Count
7171
element_type: SerializeAsAny[list[AnyComponentSchema]] = Field(..., serialization_alias='elementType')
7272
encoding: str = Field(...) # TODO: implement an encodings class
@@ -76,7 +76,7 @@ class MatrixSchema(AnyComponentSchema):
7676

7777

7878
class DataChoiceSchema(AnyComponentSchema):
79-
type: str = "DataChoice"
79+
type: Literal["DataChoice"] = "DataChoice"
8080
updatable: bool = Field(False)
8181
optional: bool = Field(False)
8282
choice_value: CategorySchema = Field(..., serialization_alias='choiceValue') # TODO: Might be called "choiceValues"
@@ -85,7 +85,7 @@ class DataChoiceSchema(AnyComponentSchema):
8585

8686
class GeometrySchema(AnyComponentSchema):
8787
label: str = Field(...)
88-
type: str = "Geometry"
88+
type: Literal["Geometry"] = "Geometry"
8989
updatable: bool = Field(False)
9090
optional: bool = Field(False)
9191
definition: str = Field(...)
@@ -129,17 +129,17 @@ class AnyScalarComponentSchema(AnySimpleComponentSchema):
129129

130130

131131
class BooleanSchema(AnyScalarComponentSchema):
132-
type: str = "Boolean"
132+
type: Literal["Boolean"] = "Boolean"
133133
value: bool = Field(None)
134134

135135

136136
class CountSchema(AnyScalarComponentSchema):
137-
type: str = "Count"
137+
type: Literal["Count"] = "Count"
138138
value: int = Field(None)
139139

140140

141141
class QuantitySchema(AnyScalarComponentSchema):
142-
type: str = "Quantity"
142+
type: Literal["Quantity"] = "Quantity"
143143
value: Union[float, str] = Field(None)
144144
uom: Union[UCUMCode, URI] = Field(...)
145145

@@ -163,45 +163,45 @@ def validate_value(cls, v):
163163

164164

165165
class TimeSchema(AnyScalarComponentSchema):
166-
type: str = "Time"
166+
type: Literal["Time"] = "Time"
167167
value: str = Field(None)
168168
reference_time: str = Field(None, serialization_alias='referenceTime')
169169
local_frame: str = Field(None)
170170
uom: Union[UCUMCode, URI] = Field(...)
171171

172172

173173
class CategorySchema(AnyScalarComponentSchema):
174-
type: str = "Category"
174+
type: Literal["Category"] = "Category"
175175
value: str = Field(None)
176176
code_space: str = Field(None, serialization_alias='codeSpace')
177177

178178

179179
class TextSchema(AnyScalarComponentSchema):
180-
type: str = "Text"
180+
type: Literal["Text"] = "Text"
181181
value: str = Field(None)
182182

183183

184184
class CountRangeSchema(AnySimpleComponentSchema):
185-
type: str = "CountRange"
185+
type: Literal["CountRange"] = "CountRange"
186186
value: list[int] = Field(None)
187187
uom: Union[UCUMCode, URI] = Field(...)
188188

189189

190190
class QuantityRangeSchema(AnySimpleComponentSchema):
191-
type: str = "QuantityRange"
191+
type: Literal["QuantityRange"] = "QuantityRange"
192192
value: list[Union[float, str]] = Field(None)
193193
uom: Union[UCUMCode, URI] = Field(...)
194194

195195

196196
class TimeRangeSchema(AnySimpleComponentSchema):
197-
type: str = "TimeRange"
197+
type: Literal["TimeRange"] = "TimeRange"
198198
value: list[str] = Field(None)
199199
reference_time: str = Field(None, serialization_alias='referenceTime')
200200
local_frame: str = Field(None)
201201
uom: Union[UCUMCode, URI] = Field(...)
202202

203203

204204
class CategoryRangeSchema(AnySimpleComponentSchema):
205-
type: str = "CategoryRange"
205+
type: Literal["CategoryRange"] = "CategoryRange"
206206
value: list[str] = Field(None)
207207
code_space: str = Field(None, serialization_alias='codeSpace')

0 commit comments

Comments
 (0)