1

Why class Dict(dict) is json serializable (json.dumps(Dict) works), but class Dict(collections.UserDict)is not?

martineau
  • 119,623
  • 25
  • 170
  • 301
Joaquim
  • 111
  • 1
  • 10
  • 1
    Why should it be? – Scott Hunter Jan 18 '22 at 20:45
  • Possibly because the `json` module checks explicitly for instances of `dict` as opposed to `collections.abc.MutableMapping`. See [How to register implementation of abc.MutableMapping as a dict subclass?](https://stackoverflow.com/questions/57982946/how-to-register-implementation-of-abc-mutablemapping-as-a-dict-subclass) – martineau Jan 18 '22 at 20:59
  • 1
    Tks @martineau. I will mark buran's answer, but your link really helped. – Joaquim Jan 18 '22 at 21:24

1 Answers1

1

You can look at the source code for JSONEncoder and specifically this line. It checks for dict and collections.UserDict is not instance of dict.

The Encodersupports the following objects and types by default:

    +-------------------+---------------+
    | Python            | JSON          |
    +===================+===============+
    | dict              | object        |
    +-------------------+---------------+
    | list, tuple       | array         |
    +-------------------+---------------+
    | str               | string        |
    +-------------------+---------------+
    | int, float        | number        |
    +-------------------+---------------+
    | True              | true          |
    +-------------------+---------------+
    | False             | false         |
    +-------------------+---------------+
    | None              | null          |
    +-------------------+---------------+

You can extend it to handle collections.UserDict

buran
  • 13,682
  • 10
  • 36
  • 61
  • Thank you @buran – Joaquim Jan 18 '22 at 21:24
  • IMO you shouldn't have to extend it to handle them. It's unclear why they used `isinstance(value, dict)` instead of `isinstance(value, abc.MutableMapping)` because it's one of the main points of having abstract base classes. – martineau Jan 18 '22 at 21:26
  • What I did was define a class that extends JSONEncoder and set `def default(self,o): return o.data` on it and pass this new class as the `cls` argument of `json.dumps` – Joaquim Jan 18 '22 at 21:34
  • 1
    Alternatively you can pass function for `default` argument of `dump()`. e.g. in this case `default=dict` is enough, i.e. objects that are not supported by default will be passed to `dict()` function. – buran Jan 18 '22 at 21:43
  • What if `dumps()` is called within a dependency? Ideally you should be able to add a method to the custom class that the encoder will fall back on when the object is not an instance of `dict`. – Jonathan Biemond Aug 16 '23 at 20:17