List of Union only accepts first type of union with Pydantic
Asked Answered
S

1

1

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?

Stoner answered 29/9, 2023 at 17:46 Comment(8)
What version of PyDantic are you on? on 2.0.3, .json no longer supports keyword arguments, and is being deprecated, but without the indent argument, it gives the output you would expectBlankly
what does print(ret) give you?Blankly
@juanpa.arrivillaga: How can I know what version I have at runtime? This is running inside a docker container so I can't readily look at pip freezeStoner
@juanpa.arrivillaga: Output of print(ret) is parameters=[TypeA(name='item 1', type_a_spesific=69.0), TypeA(name='item 2', type_a_spesific=1337)]Stoner
I noticed that if I run this outside my docker container it produces the expected output and you are correct ret.json is not supported, it wants to use ret.model_dump_json() outside docker indicating that a newer version of pydantic will solve the issueStoner
you can shell into a container, docker run -it <container> -e bash then you can use pip list, but you can also just check import pydantic; print(pydantic.__version__). Anyway, yeah, sounds like you have version lower than 2. You should probably update, 2 makes some changes though. I believe the most recent release is 2.4Blankly
Also, probably important to note, this really has nothing to do with python typing per se, but rather, how the pydantic library is handling type hints. I would edit the title to use "Pydantic" instead of "Python typing"Blankly
@juanpa.arrivillaga: I updated the question title to reflect your observation that this is in fact about Pydantic and not about python typing. Thank you.Stoner
S
1

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.

Stoner answered 29/9, 2023 at 21:21 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.