Black Lives Matter. Please consider donating to Black Girls Code today.
Dash HoloViews is now available! Check out the docs.

Type not JSON serializable

I’ve seen this come up before, but so far, no answer seems to be given.

In my case, I want to use ‘type’ Objects as values for a Dropdown menu, which results in the old JSON error. Is there a way to achieve this? Maybe it would be a good addition in general, as passing type can make a lot of calls easier. Of course, I could also use type.__name__ and then have an additional if statement checking for that, but it just occured to me that a general workaround or the allowance of more value types would be nice.

Is there an outlook on this issue or any plans? Even ways to contribute?

Do you mean passing objects that are custom classes into the options list?

If so, have you considered giving your classes a property or method that just returns their relevant contents as a dictionary object? Passing myObject.d seems quite clear and clean.

It’s either that, or work out how to pass a customized superclass of jsonEncoder into the dash library, which sounds comparatively cumbersome.

I might be misunderstanding the error, but the issue occured when setting the ‘value’ of a dropdown option to a type object. This would in theory result in the type object being passed as the value of the callback to my evaluating function, where i could then call a classmethod or the constructor of that type, get the classes signature etc…

I managed to make it work passing type.__name__ instead and later evaluating that against class.__subclasses__().__name__ and calling a constructor on that subclass.

As in:

if inputValue is not None:
   for subclass in Class.__subclasses__():
      if subclass.__name__ == inputValue:
         sign = [p for p in inspect.signature(subclass.__init__).parameters]

What i would have liked to do:

if inputValue is not None:
   sign = [p for p in inspect.signature(inputValue.__init__).parameters]

Sorry, you’ve lost me a little. I can’t quite track how you want your data to be stored and where you want it to go.

Do you have a class containing a list (‘parameters’) of objects that themselves have attributes/ class variables of “label” and “value”, and you want to be able to bulk compose them into a list of dropdown options?

Yeah, there is a dash dropdown component

and mine looks like this:

                id='filter_unit_dropdown_{0}_{1}_{2}'.format(self._deviceNumber, self._servoNumber, self._filterIndex),
                className='three columns'

with self._options being

self._options = [{'label': 'None', 'value': None}]
        for filter in self._servoController.getFilterOptions():
            self._options.append({'label': filter.__name__, 'value': filter.__name__})

and getFilterOptions() works in the way I previously described:

def getFilterOptions(self):
        return [filter for filter in Filter.__subclasses__()]

As for the callback structure

def _createFieldVisibCallback(self, dropdownID, filterFieldID):
        def callback(inputValue):
            return self._servoController.filterFieldVisibility(filterFieldID, inputValue, self._deviceNumber, self._servoNumber, self._filterIndex)
        return callback

def setCallbacks(self):
        dropdown = 'some_id'.format(self._deviceNumber, self._servoNumber, self._filterIndex)
        frequencyField = 'another_id'.format(self._deviceNumber, self._servoNumber, self._filterIndex)

        dynamically_generated_function = self._createFieldVisibCallback(dropdown, frequencyField)
            Output(frequencyField, 'style'),
            [Input(dropdown, 'value')]

and lastly the functionality of

_servoController.filterFieldVisibility(xxx) is what I described in the post before.

Well, I’m tapped out for useful input then. It sure looks like in all that structure, the difference between


is the least of your worries.

Additionally, passing an object directly into the DCC renderer and having it pick to use a string representation of the object’s class’ name (if i follow what you’re describing) sounds like really non-obvious and potentially troublesome behavior.

Unfortunately this is not going to work. value needs to be a string. We don’t enforce this right now but we will in the future. We are passing this value over the network to the Dash front-end, which is why we can’t handle arbitrary python objects. The underlying component that we use in the front-end also expects a string.

If you want to keep things dynamic, then use a dictionary that maps strings to your objects:

values = {
    some_object: 'value-1',
    another_object: 'value-2'