admin管理员组文章数量:1404924
I'd like to serialize and deserialize an object holding a polymorphic member.
If the class was polymorphic, I would use a correct concrete type with TypeAdapter
. The question is, how to do the same when a member is polymorphic. Here's a minimal example of what I mean:
from abc import ABC, abstractmethod
from pydantic import BaseModel, TypeAdapter
class I_Widget(ABC, BaseModel):
@abstractmethod
def do_stuff(self): ...
class WidgetHolder(BaseModel):
widget: I_Widget
class ActualWidget(I_Widget):
value: int
def do_stuff(self):
print('Doing stuff')
if __name__ == '__main__':
w = ActualWidget(value=42)
wh = WidgetHolder(widget=w)
# Serializes:
json = wh.json()
# Deserializes:
wh2 = TypeAdapter(WidgetHolder).validate_json(json) # Throws an error
When I run it, I get:
File "/home/adam/.cache/pypoetry/virtualenvs/poc-py3.12/lib/python3.12/site-packages/pydantic/type_adapter.py", line 446, in validate_json
return self.validator.validate_json(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: Can't instantiate abstract class I_Widget without an implementation for abstract method 'do_stuff'
I'd like to serialize and deserialize an object holding a polymorphic member.
If the class was polymorphic, I would use a correct concrete type with TypeAdapter
. The question is, how to do the same when a member is polymorphic. Here's a minimal example of what I mean:
from abc import ABC, abstractmethod
from pydantic import BaseModel, TypeAdapter
class I_Widget(ABC, BaseModel):
@abstractmethod
def do_stuff(self): ...
class WidgetHolder(BaseModel):
widget: I_Widget
class ActualWidget(I_Widget):
value: int
def do_stuff(self):
print('Doing stuff')
if __name__ == '__main__':
w = ActualWidget(value=42)
wh = WidgetHolder(widget=w)
# Serializes:
json = wh.json()
# Deserializes:
wh2 = TypeAdapter(WidgetHolder).validate_json(json) # Throws an error
When I run it, I get:
File "/home/adam/.cache/pypoetry/virtualenvs/poc-py3.12/lib/python3.12/site-packages/pydantic/type_adapter.py", line 446, in validate_json
return self.validator.validate_json(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: Can't instantiate abstract class I_Widget without an implementation for abstract method 'do_stuff'
Share
Improve this question
edited Mar 22 at 17:10
mkrieger1
23.5k7 gold badges64 silver badges82 bronze badges
asked Mar 22 at 15:36
Adam RyczkowskiAdam Ryczkowski
8,08414 gold badges50 silver badges73 bronze badges
2
|
2 Answers
Reset to default 1Another possibility would be using a discriminator
:
from abc import ABC, abstractmethod
from pydantic import BaseModel, TypeAdapter, Field
from typing import Literal, Union
class I_Widget(ABC, BaseModel):
type: str
@abstractmethod
def do_stuff(self): ...
class ActualWidget(I_Widget):
type: Literal["actual"] = "actual" # Discriminator field
value: int
def do_stuff(self):
print("Doing stuff")
class WidgetHolder(BaseModel):
widget: Union[ActualWidget] # Use Union to list all possible widget types
if __name__ == "__main__":
w = ActualWidget(value=42)
wh = WidgetHolder(widget=w)
json = wh.model_dump_json()
print("Serialized JSON:", json)
wh2 = TypeAdapter(WidgetHolder).validate_json(json)
assert wh2.widget.value == 42
I found one way around using a widget factory method.
It is not as clear and readable as I would hope for, but good enough to be proposed here.
Please, bring in alternative solutions...
from abc import ABC, abstractmethod
from pydantic import BaseModel, TypeAdapter
from typing import Type
class I_Widget(ABC, BaseModel):
@abstractmethod
def do_stuff(self): ...
class WidgetHolder(BaseModel):
widget: I_Widget
class ActualWidget(I_Widget):
value: int
def do_stuff(self):
print('Doing stuff')
def WidgetHolder_factory(widget_type: Type[I_Widget]):
class _WidgetHolder(WidgetHolder):
widget: widget_type
return _WidgetHolder
if __name__ == '__main__':
w = ActualWidget(value=42)
wh = WidgetHolder_factory(ActualWidget)(widget=w)
json = wh.json()
wh2 = TypeAdapter(WidgetHolder_factory(ActualWidget)).validate_json(json)
assert wh2.widget.value == 42
本文标签: pythonHow to specify actual class in Pydantic memberStack Overflow
版权声明:本文标题:python - How to specify actual class in Pydantic member - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744309918a2599977.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
wh
correctly in the first place; the resulting JSON just has an emptydict
for thewidget
key, not anything that could be deserialized as anActualWidget
. I think this matters because what kind ofI_Widget
is the JSON supposed to be validated against? – chepner Commented Mar 22 at 17:10