Search code examples
pythonlistunionpython-typingpydantic

List of Union only accepts first type of union with Pydantic


With the following python type definitions:

import pydantic
from typing import List, Union
import sys
import pprint

class TypeA(pydantic.BaseModel):
    name:str = "Type A"
    type_a_spesific:float = 1337

class TypeB(pydantic.BaseModel):
    name:str = "Type B"
    type_b_spesific:str = "bob"


class ReturnObject(pydantic.BaseModel):
    parameters:List[Union[TypeA, TypeB] ]

parameters = list()
parameters.append(TypeA(name="item 1", type_a_spesific=69))
parameters.append(TypeB(name="item 2", type_b_spesific="lol"))

ret = ReturnObject(parameters = parameters)

print(f"Python version: {pprint.pformat(sys.version_info)}")
print(f"Pydantic version: {pydantic.__version__}")
print(ret.json(indent=3))
print(ret)

The version output looks like this:

Python version: sys.version_info(major=3, minor=11, micro=5, releaselevel='final', serial=0)
Pydantic version: 1.10.11

I would expect the parameter list to contain two objects with different type like this:

Expected

{
    "parameters": [
        {
            "name": "item 1",
            "type_a_spesific": 69
        },
        {
            "name": "item 2",
            "type_b_spesific": "lol"
        }
    ]
}

parameters=[TypeA(name='item 1', type_a_spesific=69.0), TypeB(name='item 2', type_b_spesific="lol")]

However what comes out instead is this:

Actual

{
   "parameters": [
      {
         "name": "item 1",
         "type_a_spesific": 69.0
      },
      {
         "name": "item 2",
         "type_a_spesific": 1337
      }
   ]
}

parameters=[TypeA(name='item 1', type_a_spesific=69.0), TypeA(name='item 2', type_a_spesific=1337)]

For some reason the List[ Union[ TypeA, TypeB ]] does not work. What gives?


Solution

  • Thanks to comments by @juanpa.arrivillaga I found the answer myself;

    This is a bug(feature?) of Pydantic 1.x. If I upgrade to use Pydantic 2.x then it behaves as expected.