Repository navigation
Conversation
All `$value` routes previously responded with `501 Not Implemented`.
The specification leaves some points open, which are resolved as
follows:
- Property values are mapped to the JSON type of their `valueType`, so
booleans and numbers are not quoted. Values without a JSON literal
are returned as their XSD representation.
`xs:integer` is unbounded in both Python and JSON and is
therefore passed on as it is.
- Elements without a value are omitted from Submodels, collections and
Entity statements, but kept as `null` within a SubmodelElementList, as
omitting them would shift the indices of the remaining elements.
- Operations and Capabilities have no ValueOnly representation. They are
skipped in containers and result in `400 Bad Request` when requested
directly, which is how the `$metadata` route handles them.
- `level=core` returns the direct children of the requested resource and
their nested containers as empty, matching the examples of the
specification.
- The entries of `GET /submodels/{id}/submodel-elements/$value` are
mapped by idShort, as a bare `SubmodelElementValue` would lose the
association between a value and its element. Submodels are returned
as-is, since their entries are already named.
- The languages of a MultiLanguageProperty are sorted, to keep the order
of the response deterministic.
The ValueOnly serialization is only defined for JSON, so the routes
respond with `406 Not Acceptable` if XML is requested. `extent` remains
unimplemented, as on all other routes. `PATCH …/$value`, the `$path`
routes and the operation invocation routes are not part of this change.
Fixes eclipse-basyx#446
Previously, the ValueOnly serialization was method based in the server package. These changes shift the code from serve package to the sdk, as ValueOnly serialiaztion is defined in Part 1 of the spec. Additionally, I restructured the code to live inside a `JSONEncoder` subclass, so it can be used the same way as `AASToJsonEncoder`. Still TODO: - Implement `level=core` serialization - Integrate this serialiazer into the server
Functionality follows eclipse-basyx#649
Showcases collapse of rules and handler methods using converter and modifiers
hpoeche
left a comment
There was a problem hiding this comment.
I really like the idea of the ContentModifierConverter for the endpoint definition! I found some small things we should discuss, so I can mirror them for the ValueOnly encoder.
| return Modifiers(content=resolved, deep=deep, with_blob=with_blob) | ||
|
|
||
|
|
||
| def _parse_level(request: Request, content: Content) -> bool: |
There was a problem hiding this comment.
Could you rename the method, so it identifies the state that a True value would encode (e.g. _is_deep_request())? In general, it is good style to name all functions and variables of type bool starting with is.
There was a problem hiding this comment.
Yes, way cleaner. Have adjusted hopefully everything surrounding deep and blob values
| return raw == "deep" | ||
|
|
||
|
|
||
| def _parse_extent(request: Request, content: Content) -> bool: |
There was a problem hiding this comment.
Same as fro _parse_level() ;) Maybe, you can also add a comment for the default case.
| (matches ``?level=core``). | ||
| """ | ||
|
|
||
| deep: bool = False |
There was a problem hiding this comment.
We should consider, setting this class variable not via overwriting in subclass but rather to pass it in via the __init__() method. This halves the amount of classes we have to define. Is their anything from your side that speaks against this?
| serializers = super()._get_aas_class_serializers() | ||
| serializers.update( | ||
| { | ||
| model.Submodel: cls._submodel_to_path, | ||
| model.SubmodelElementCollection: cls._submodel_element_collection_to_path, | ||
| model.SubmodelElementList: cls._submodel_element_list_to_path, | ||
| model.Entity: cls._entity_to_path, | ||
| model.AnnotatedRelationshipElement: cls._annotated_relationship_element_to_path, | ||
| model.Property: cls._leaf_to_path, | ||
| model.MultiLanguageProperty: cls._leaf_to_path, | ||
| model.Range: cls._leaf_to_path, | ||
| model.Blob: cls._leaf_to_path, | ||
| model.File: cls._leaf_to_path, | ||
| model.ReferenceElement: cls._leaf_to_path, | ||
| model.RelationshipElement: cls._leaf_to_path, | ||
| model.BasicEventElement: cls._leaf_to_path, | ||
| model.Capability: cls._leaf_to_path, | ||
| model.Operation: cls._leaf_to_path, | ||
| } | ||
| ) | ||
| return serializers |
There was a problem hiding this comment.
I think updating the serializers dict might lead to unexpected behavior. If someone would apply this serializer class to a model.AssetInformation object, this would class the matching method from the AASToJsonEncoder, leading to a normal JSON serialization.
Instead a user should be confronted with an error message. We can choose to either replace serializers with the new path-serializer mapping (this would lead to a general TypeError of json.JSONEncoder) or we explicitly throw errors here for all objects that do not have a path serialization.
Previously, `PathJsonEncoder` carried `deep` as a class variable and the `?level=core` variant was expressed by a dedicated `ShallowPathJsonEncoder` subclass that flipped it to `False`. Composing this axis with other content modes required another `Shallow*` sibling per encoder, so the class count scaled with the Cartesian product of axes. With this change, `deep` is passed to `PathJsonEncoder.__init__` as a keyword argument and stored on the instance. The encoder uses `default()` directly instead of extending the classmethod- based `_get_aas_class_serializers` dispatch, which avoids `cls`/`self` mismatches along the MRO when carrying per-request state. On the server side, `pick_encoder` now returns `(cls, kwargs)` and `JsonResponse.serialize` forwards the kwargs through `json.dumps` into the encoder constructor; `ResultShallowPathJsonEncoder` is removed since the single `ResultPathJsonEncoder` now covers both levels via the kwarg.
This is WIP to implement and correct the missing serialization formats of the JSON serialization (defined in Part 1) as well as the modifiers that the server needs to offer (defined in Part 2).
AASToJsonEncoder(Henri)AASToJsonEncoder(Henri)