According to the tutorial docs for rsocket-py, an argument type named composite_metadata or an argument (with any name) annotated with the CompositeMetadata type should be passed an instance of CompositeMetadata, however the actual behaviour of the router is to pass a Payload instance in the case of the latter. The only effective way to acquire the metadata is to name the argument composite_metadata. The annotation is effectively ignored by the router.
All methods decorated by the request router accept two optional arguments:
Any argument named composite_metadata (regardless of type-hint), or type-hinted with CompositeMetadata will receive a CompositeMetadata instance containing parsed composite metadata
Any other argument without a type-hint, or type-hinted with Payload will receive the request's payload
https://rsocket.io/guides/rsocket-py/tutorial/request_routing#routing-request-handler
Behaviour
Name and type (works)
router = RequestRouter()
@router.response("example")
async def example_response(payload: Payload, composite_metadata: CompositeMetadata) -> Awaitable[Payload]:
assert isinstance(composite_metadata, CompositeMetadata) # passes
return create_response(ensure_bytes("test"))
Name without type (works)
router = RequestRouter()
@router.response("example")
async def example_response(payload: Payload, composite_metadata) -> Awaitable[Payload]:
assert isinstance(composite_metadata, CompositeMetadata) # passes
return create_response(ensure_bytes("test"))
Arbitrary name with type (should work but doesn't)
router = RequestRouter()
@router.response("example")
async def example_response(payload: Payload, arbitrary_name: CompositeMetadata) -> Awaitable[Payload]:
assert isinstance(arbitrary_metadata, CompositeMetadata) # fails
print(type(arbitrary_metadata)) # parameter_type.annotation is CompositeMetadata
return create_response(ensure_bytes("test"))
Cause and solution
This is due to the implementation of _collect_route_arguments:
|
def _collect_route_arguments(self, |
|
route_info: RouteInfo, |
|
payload: Payload, |
|
composite_metadata: CompositeMetadata): |
|
route_signature = route_info.signature |
|
route_kwargs = {} |
|
|
|
for parameter in route_signature.parameters: |
|
parameter_type = route_signature.parameters[parameter] |
|
|
|
if 'composite_metadata' == parameter or parameter_type.annotation is CompositeMetadata: |
|
route_kwargs[parameter] = composite_metadata |
|
else: |
|
payload_data = payload |
|
|
|
if parameter_type.annotation not in (Payload, parameter_type.empty): |
|
payload_data = self._payload_deserializer(parameter_type.annotation, payload) |
|
|
|
route_kwargs[parameter] = payload_data |
|
|
|
return route_kwargs |
On line 177, the check should access the annotation property of the inspect.Paramter class, but it doesn't do that. So the right hand side of the or operator. Since it checks that the Parameter instance is CompositeMetadata, it will always evaluate to false.
According to the tutorial docs for
rsocket-py, an argument type namedcomposite_metadataor an argument (with any name) annotated with theCompositeMetadatatype should be passed an instance ofCompositeMetadata, however the actual behaviour of the router is to pass aPayloadinstance in the case of the latter. The only effective way to acquire the metadata is to name the argumentcomposite_metadata. The annotation is effectively ignored by the router.Behaviour
Name and type (works)
Name without type (works)
Arbitrary name with type (should work but doesn't)
Cause and solution
This is due to the implementation of
_collect_route_arguments:rsocket-py/rsocket/routing/request_router.py
Lines 167 to 187 in a791837
On line 177, the check should access the
annotationproperty of theinspect.Paramterclass, but it doesn't do that. So the right hand side of theoroperator. Since it checks that theParameterinstance isCompositeMetadata, it will always evaluate to false.