plotly / dash

Data Apps & Dashboards for Python. No JavaScript Required.
https://plotly.com/dash
MIT License
21.45k stars 2.07k forks source link

Define JSON serialization on Dash component level #1786

Open anders-kiaer opened 3 years ago

anders-kiaer commented 3 years ago

Especially for advanced Dash components, it would be useful if the Dash component author could do serialization/deserialization for the Dash app developer, in order to make an easy component API. Today the component authors are limited to accepting directly JSON-serializable Python objects, and can't e.g. accept instances of custom Python data objects / classes.

One way of achieving this feature could perhaps be roughly along these lines:

1) In dash.development.base_component.Component add @classmethods serialize and deserialize:

    class Component:
        @classmethod
        def serialize(prop_name, value):
            return to_json(value)

        @classmethod
        def deserialize(prop_name, value):
            return from_json(value)
For all Dash components that don't need any other serialization/deserialization than what is offered today, no change is necessary since they will inherit the default serialization functions from `Component`. For Dash component authors that want to support some other serialization function, they simply override them as usual:

2) ```python from dash.development.base_component import Component

class SomeDashComponent(Component):    
    @classmethod
    def serialize(prop_name, value):
        # component author defines serialization logic

    @classmethod
    def deserialize(prop_name, value):
        # component author defines deserialization logic

3) In Dash core, call SomeDashComponent.(de)serialize when input/output data for a prop is to be serialized/deserialized.

Features possible with this:


*The typing module in Python 3+ opens up possibilities for libraries to accomplish all these at the same time:

Taken down to the context in this issue, type hint annotations could be introduced without breaking change at a later point following something along these lines:

from typing import overload, Literal, List

from dash.development.base_component import Component
import pandas as pd

# Using typing.overload and typing.Literal, two standard features in Python std.lib
# we can annotate the component with expected data input format for different
# props using standard conventions.
class SomeDashComponent(Component):
    @overload
    @classmethod
    def serialize(prop_name: Literal["some_prop"], value: pd.DataFrame):
        ...
    @overload
    @classmethod
    def serialize(prop_name: Literal["some_other_prop1", "some_other_prop2"], value: List[int]):
        ...
    @classmethod 
    def serialize(prop_name, value):
        if prop_name == "some_prop":
            return some_serialization_logic(value)
       # The other props are e.g. serialized using standard function
       return to_json(value)

    # @overload
    # @classmethod
    # def deserialize(...same setup as for serialize

The last point here on type hinting is related to https://github.com/plotly/dash/issues/719#issuecomment-844406378 and #1748.

anders-kiaer commented 2 years ago

There are other input on this issue in #1784, specically:

https://github.com/plotly/dash/pull/1784#issuecomment-931620245 https://github.com/plotly/dash/pull/1784#issuecomment-932584610 https://github.com/plotly/dash/pull/1784#issuecomment-937927584

emilhe commented 2 years ago

As a side note, this is already supported by the serverside outputs in dash-extensions.