Describe the bug
Due to changes in how serialization of subclasses is handled in pydantic v2, generated models do not produce correct output when using model_dump or model_dump_json.
See issue pydantic/pydantic#7326
To Reproduce
Example schema:
paths:
/pets:
patch:
requestBody:
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/Cat'
- $ref: '#/components/schemas/Dog'
discriminator:
propertyName: pet_type
responses:
'200':
description: Updated
components:
schemas:
Animals:
type: object
properties:
pet:
$ref: '#/components/schemas/Pet'
Pet:
type: object
required:
- pet_type
properties:
pet_type:
type: string
discriminator:
propertyName: pet_type
Dog: # "Dog" is a value for the pet_type property (the discriminator value)
allOf: # Combines the main `Pet` schema with `Dog`-specific properties
- $ref: '#/components/schemas/Pet'
- type: object
# all other properties specific to a `Dog`
properties:
bark:
type: boolean
breed:
type: string
enum: [Dingo, Husky, Retriever, Shepherd]
Cat: # "Cat" is a value for the pet_type property (the discriminator value)
allOf: # Combines the main `Pet` schema with `Cat`-specific properties
- $ref: '#/components/schemas/Pet'
- type: object
# all other properties specific to a `Cat`
properties:
hunts:
type: boolean
age:
type: integer
Used commandline:
$ datamodel-codegen --input pets.yaml --output pets.py --input-file-type openapi --output-model-type pydantic_v2.BaseModel
Generated models:
# generated by datamodel-codegen:
# filename: pets.yaml
# timestamp: 2024-01-12T22:40:02+00:00
from __future__ import annotations
from enum import Enum
from typing import Optional
from pydantic import BaseModel
class Pet(BaseModel):
pet_type: str
class Breed(Enum):
Dingo = 'Dingo'
Husky = 'Husky'
Retriever = 'Retriever'
Shepherd = 'Shepherd'
class Dog(Pet):
bark: Optional[bool] = None
breed: Optional[Breed] = None
class Cat(Pet):
hunts: Optional[bool] = None
age: Optional[int] = None
class Animals(BaseModel):
pet: Optional[Pet] = None
and their usage:
import pets
animals = pets.Animals(pet=pets.Cat(pet_type='cat', hunts=True, age=2))
print(animals)
# Animals(pet=Cat(pet_type='cat', hunts=True, age=2))
print(animals.model_dump_json())
# '{"pet":{"pet_type":"cat"}}'
Expected behavior
To be able to serialize with all data from subclasses. One way to achieve this is to specify type of pet field in Animals with SerializeAsAny (docs). Another way is to specify all possible subclasses that pet field can take with union.
Version:
Pay now to fund the work behind this issue.
Get updates on progress being made.
Maintainer is rewarded once the issue is completed.
You're funding impactful open source efforts
You want to contribute to this effort
You want to get funding like this too