crossbario / crossbario/autobahn-python

Automatic marshalling decorators

Open
#624 1 comment 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

feature needs-discussion wamp
Dominant language
Python
Stars
2.5k
Forks
768
PR merge metrics
No merged PRs in 30d

Description

This is an enhancement suggestion for automatic marshalling of native objects (see this thread).

Elevator pitch: allow WAMP handlers to directly receive native objects instead of primitive values only. The marshalling is handled behind the scenes between unserialising the message from the wire and before calling the handler.

My current primitive prototype relies on a custom serialiser to do that:

from abc import ABC, abstractmethod

class RepresentableAsPrimitive(ABC):
    @classmethod
    @abstractmethod
    def from_primitive_representation(cls, primitive):
        pass

    @property
    @abstractmethod
    def primitive_representation(self):
        pass

I then subclass autobahn.wamp.serializer.JsonObjectSerializer, override serialize and unserialize and use some ugly wrapping to identify types to unserialise (e.g. {"__type": ..., "payload": {...}}). My business objects implement RepresentableAsPrimitve, and any such objects are automatically being serialised. It's not pretty, but does the job.

I'm currently refactoring this into decorators so I can get rid of the wrapping on the wire. My idea for the moment is something like this:

@register('com.example.foo')
@param('bar', unserializer=Bar.fromDict)  # using the @classmethod fromDict
@returnval(serializer=operator.methodcaller('toDict'))  # using the instance method toDict
def foo(self, bar):
    return Baz(bar.bacon)

The param decorator would use the specified unserializer to convert the dict representation into a native object, and the returnval decorator would do the reverse. Note that it would not serialise to JSON directly, but to an intermediate primitive representation like a dict.

Using Python 3.4 type hinting and a defined interface like above, this could be made even more concise:

@register('com.example.foo')
@automarshall
def foo(self, bar: Bar) -> Baz:
    return Baz(bar.bacon)

automarshall can inspect the method signature and derive the used classes itself; it would require Bar and Baz to implement the RepresentableAsPrimitive interface. Any combination of explicitly using @param and @automarshall should work as well.

If I get around to a presentable prototype I'll post it here, but let this be a starter for discussions for now.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing the existing JsonObjectSerializer serialize and unserialize flow and how WAMP handlers are registered and invoked. Compare the proposed @param, @returnval, and @automarshall decorators with the prototype; done would mean native handler parameters and return values are converted through primitive representations without wire-format type wrappers.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend-api-design
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
20/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.