Pydantic: Error when serialize a dynamically created BaseModel (using method create_model)

Created on 19 Dec 2020  路  3Comments  路  Source: samuelcolvin/pydantic

Bug

When to try to serialize a BaseModel dynamically created with create_model this error raises:

TypeError: Object of type ModelMetaclass is not JSON serializable

pydantic version: 1.7.3
python version: 3.8.6

ps: I found this when using a dynamically created BaseModel on the parameter response_model of FastAPI method.

A way to reproduce:

```py
In [1]: from pydantic import create_model

In [2]: import json

In [3]: json.dumps(create_model('BarModel', a='b', c='d'))

TypeError Traceback (most recent call last)
in
----> 1 json.dumps(create_model('BarModel', a='b', c='d'))

/usr/lib/python3.8/json/__init__.py in dumps(obj, skipkeys, ensure_ascii, check_circular, allow_nan, cls, indent, separators, default, sort_keys, **kw)
229 cls is None and indent is None and separators is None and
230 default is None and not sort_keys and not kw):
--> 231 return _default_encoder.encode(obj)
232 if cls is None:
233 cls = JSONEncoder

/usr/lib/python3.8/json/encoder.py in encode(self, o)
197 # exceptions aren't as detailed. The list call should be roughly
198 # equivalent to the PySequence_Fast that ''.join() would do.
--> 199 chunks = self.iterencode(o, _one_shot=True)
200 if not isinstance(chunks, (list, tuple)):
201 chunks = list(chunks)

/usr/lib/python3.8/json/encoder.py in iterencode(self, o, _one_shot)
255 self.key_separator, self.item_separator, self.sort_keys,
256 self.skipkeys, _one_shot)
--> 257 return _iterencode(o, 0)
258
259 def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,

/usr/lib/python3.8/json/encoder.py in default(self, o)
177
178 """
--> 179 raise TypeError(f'Object of type {o.__class__.__name__} '
180 f'is not JSON serializable')
181

TypeError: Object of type ModelMetaclass is not JSON serializable

In [4]:

...

bug

Most helpful comment

Hi @trongbq and happy new year!
In this case it's beyond _pydantic_ scope. I also use celery for data pipelines and it's quite common to use a custom encoder for json for example.
In your case you could go with something like this

import json
from pydantic import BaseModel

class BarModel(BaseModel):
    a = 'b'
    c = 'd'

class CustomEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, BaseModel):
            return obj.dict()
        return super().default(obj)


print(json.dumps(BarModel(), cls=CustomEncoder))
# {"a": "b", "c": "d"}

Hope it helps

All 3 comments

Hi @berlotto
When you define a model, you need to use the json method on an instance (not the class!)

class BarModel(BaseModel):
    a = 'b'
    c = 'd'

print(BarModel().json())
# {"a": "b", "c": "d"}

So when you define you class dynamically, remember that create_model('BarModel', a='b', c='d') returns the class!
You hence need to do create_model('BarModel', a='b', c='d')().json()

Hope it helps!

I would like to add a case when an instance of a class is passed to an external library and this library uses json package to serialize data, then we can not force that library to use model's #json() method.
For example, I got a case when using celery, if I pass pydatic model Event to a celery task, error message like Object of type Event is not JSON serializable will appear.

Hi @trongbq and happy new year!
In this case it's beyond _pydantic_ scope. I also use celery for data pipelines and it's quite common to use a custom encoder for json for example.
In your case you could go with something like this

import json
from pydantic import BaseModel

class BarModel(BaseModel):
    a = 'b'
    c = 'd'

class CustomEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, BaseModel):
            return obj.dict()
        return super().default(obj)


print(json.dumps(BarModel(), cls=CustomEncoder))
# {"a": "b", "c": "d"}

Hope it helps

Was this page helpful?
0 / 5 - 0 ratings

Related issues

demospace picture demospace  路  26Comments

chopraaa picture chopraaa  路  18Comments

MrMrRobat picture MrMrRobat  路  22Comments

jaheba picture jaheba  路  25Comments

Yolley picture Yolley  路  18Comments