dash icon indicating copy to clipboard operation
dash copied to clipboard

[Feature Request] Add the ability to use a custom JSON encoder

Open mfreeborn opened this issue 4 years ago • 4 comments

Describe the Feature My use case is that I have a very simple custom type which stores a value in a standardised way ("aaabbbccc"), but displays the value in a prettier way ("aaa bbb ccc").

This is implemented simply like this:

class CustomType:
    def __init__(self, value):
        self.value = "".join(value.split())

    def __str__(self):
        return f"{self.value[:3]} {self.value[3:6]} {self.value[6:]}"

However, if I try and return this to the front end dashboard, I get:

component <X>
returned a value which is not JSON serializable.

In general, Dash properties can only be dash components, strings,
dictionaries, numbers, None, or lists of those.

Describe the solution you'd like I would like to be able to override plotly.utils.PlotlyJSONEncoder by doing something like this:

from plotly.utils import PlotlyJSONEncoder

from utils import CustomType

class CustomJSONEncoder(PlotlyJSONEncoder):
    def default(self, obj):
        if isinstance(obj, CustomType):
            return str(obj)
        return PlotlyJSONEncoder.default(self, obj)

app = Dash(__name__, json_encoder=CustomJSONEncoder)

Additional context As an example of how it could look, Flask gives the user the ability to override the default json encoder. Snippet.

mfreeborn avatar May 22 '20 15:05 mfreeborn

An alternative method would be to implement a to_plotly_json method within your class: https://github.com/plotly/plotly.py/blob/7fcb95ce94652a48b744a06460d17c50a932c8a2/packages/python/plotly/_plotly_utils/utils.py#L99-L123

This works for classes that you have control over, doesn't work as well for classes that you don't have control over.

chriddyp avatar May 22 '20 16:05 chriddyp

That's interesting - hadn't found that. I just had a quick look and I can't see it in the docs anywhere. That would certainly work for my use case, my only thought would be that it isn't very obvious at present. Coming from a Flask background, I expected to be able to provide my own custom encoder.

mfreeborn avatar May 22 '20 16:05 mfreeborn

Hello! I have proposed a more flexible solution in another ticket: https://github.com/plotly/plotly.py/issues/2475

merwok avatar May 22 '20 21:05 merwok

This seems to be needed to properly work with lazy_gettext objects from Flask-Babel (for translation). See https://github.com/python-babel/flask-babel/issues/31

UPDATE: using a custom JSONEncoder wont be enough, since dash validates callback output in a strict way (_validate_value). (which precludes the values from being LazyStrings)

Maybe a reasonable "protocol" would be to accept UserString objects and threat these the same way as any regular string in the validation and the serialization code? Then it would be easy to make the LazyString usable.

olejorgenb avatar Sep 05 '23 13:09 olejorgenb