Skip to content

v2.0b3: Discriminator on union of models in RootModel yields TypeError #6213

@kmfarley11

Description

@kmfarley11

Initial Checks

  • I confirm that I'm using Pydantic V2 installed directly from the main branch, or equivalent

Description

If unionizing types on a RootModel, providing a discriminator seems to fail with a TypeError:

TypeError: 'definition-ref' is not a valid discriminated union variant; should be a `BaseModel` or `dataclass`

Moving the discriminator to an aggregate root model which has a list of the unionized variants seems to work just fine though.

In pydantic==2.0b2 the problematic code below worked. But now in pydantic==2.0b3 it does not.

Please let me know if this is expected for any reason. For now, I can work around it per the commented example code.

Example Code

# Usage:
#   python -m venv .venv
#   . .venv/bin/activate  # or . .\.venv\Scripts\Activate.ps1
#   pip install git+https://github.com/pydantic/pydantic.git#egg=pydantic
#   pip freeze  # confirm pydantic commit is current tip of main
#   python union_root_discriminator_issues_pydv2b3.py
# pylint: disable=all

from typing import Literal
from pydantic import RootModel, BaseModel, Field


class IdBase(BaseModel):
    kind: Literal["id"]


class IdVariant1(IdBase):
    id_str: str


class IdVariant2(IdBase):
    id_int: int


class Id(RootModel):
    root: IdVariant1 | IdVariant2


class Name(BaseModel):
    name: str
    kind: Literal["name"]


# This doesn't work, yielding this error:
#   TypeError: 'definition-ref' is not a valid discriminated union variant; should be a `BaseModel` or `dataclass`
class Item(RootModel):
    root: Name | Id = Field(..., discriminator="kind")


class Items(RootModel):
    root: list[Item]


# This does work though
# class Item(RootModel):
#     root: Name | Id
#
#
# class Items(RootModel):
#     root: list[Item] = Field(..., discriminator="kind")


def main():
    items = Items.model_validate(
        [
            {"id_str": "id1", "kind": "id"},
            {"id_int": 2, "kind": "id"},
            {"name": "number-three", "kind": "name"},
        ]
    )
    print(items)
    print(items.model_json_schema())
    print(items.model_dump_json())


if __name__ == "__main__":
    main()

Python, Pydantic & OS Version

Verified in 2 environments: The first being windows 11 with a direct install from the repo. The second being a WSL2 dev container with a direct install from pypi.

> .\.venv\Scripts\python.exe -c "import pydantic.version; print(pydantic.version.version_info())"
             pydantic version: 2.0b3
        pydantic-core version: 0.40.1 release build profile
                 install path: C:\Users\kevin.farley\Documents\my_src\pydanticv2\.venv\Lib\site-packages\pydantic
               python version: 3.11.2 (tags/v3.11.2:878ead1, Feb  7 2023, 16:38:35) [MSC v.1934 64 bit (AMD64)]
                     platform: Windows-10-10.0.22621-SP0
     optional deps. installed: ['typing-extensions']

$ python -c 'import pydantic.version; print(pydantic.version.version_info())'
             pydantic version: 2.0b3
        pydantic-core version: 0.39.0 release build profile
                 install path: /home/vscode/.local/lib/python3.11/site-packages/pydantic
               python version: 3.11.4 (main, Jun 13 2023, 15:08:32) [GCC 10.2.1 20210110]
                     platform: Linux-5.15.90.1-microsoft-standard-WSL2-x86_64-with-glibc2.31
     optional deps. installed: ['typing-extensions']

Metadata

Metadata

Assignees

Labels

bug V2Bug related to Pydantic V2

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions