Skip to content

Subclassed json.JSONEncoder does not respect default method for supported types #74528

Open

Description

@Xophmeister
BPO 30343
Nosy @merwok, @Xophmeister
PRs
  • bpo-30343: New API for JSON encoder to override supported types #1558
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = None
    created_at = <Date 2017-05-11.13:58:26.296>
    labels = ['type-bug', 'library']
    title = 'Subclassed json.JSONEncoder does not respect default method for supported types'
    updated_at = <Date 2020-10-19.22:32:36.651>
    user = 'https://github.com/Xophmeister'

    bugs.python.org fields:

    activity = <Date 2020-10-19.22:32:36.651>
    actor = 'eric.araujo'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = ['Library (Lib)']
    creation = <Date 2017-05-11.13:58:26.296>
    creator = 'Xophmeister'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 30343
    keywords = []
    message_count = 3.0
    messages = ['293494', '293554', '379046']
    nosy_count = 2.0
    nosy_names = ['eric.araujo', 'Xophmeister']
    pr_nums = ['1558']
    priority = 'normal'
    resolution = None
    stage = None
    status = 'open'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue30343'
    versions = ['Python 3.6']

    Activity

    1. Xophmeister commented on May 11, 2017

      Xophmeistermannequin
      MannequinAuthor

      If you subclass json.JSONEncoder to enable serialisation of custom types beyond those supported, you are meant to transform values of said type into a serialisable version within an overridden default method. For example:

          class MyJSONEncoder(json.JSONEncoder):
              def default(self, o):
                  if isinstance(o, MyType):
                      return str(o)
              # Raise TypeError when we have a type we can't serialise
              super().default(o)
      

      This, however, won't work if your custom type is an instance of one of the supported types. This is because, in Lib/json/encoder.py, the _iterencode function (defined in _make_iterencode) type checks against supported types before it delegates to the default method.

      The reason this came up is because I wanted to serialise a named tuple into a JSON object, with keys corresponding to the named tuple's field names. Ignoring the merits (or otherwise) of this desired outcome, this can't work because a named tuple is still a tuple and thus the default method is never called.

      In Python 2.7, the _iterencode method was part of the JSONEncoder class, so you could override it in a subclass; even if doing so is somewhat brittle. In Python 3, this method has been moved out into the module namespace (tested in 3.6; looking through the repo, it looks like this change was made in Python 3.1), so it can't easily be monkey-patched without it affecting other things.

      I believe this to be a bug. It seems reasonable to subclass at least named tuples, dictionaries and lists in such a way that you'd want a different JSON serialisation to their defaults.

    2. added
      stdlibStandard Library Python modules in the Lib/ directory
      type-bugAn unexpected behavior, bug, or error
      on May 11, 2017
    3. Xophmeister commented on May 12, 2017

      Xophmeistermannequin
      MannequinAuthor

      I have written a proof-of-concept implementation and submitted a pull request. See the PR for details: #1558

      (My CLA is pending; submitted around 2017-05-12T10:30:00Z+0100)

    4. merwok commented on Oct 19, 2020

      @merwok
      Member

      See also https://bugs.python.org/issue34858

      This needs a discussion on python-ideas or -dev.

    5. transferred this issue fromon Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    No one assigned

      Labels

      stdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

      Projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions