Skip to content

CliApp does not recognize argument with discriminated union #487

@klieret

Description

@klieret

CliApp fails to run with if a model contains a discriminated union with a Discriminator object, i.e., something like this:

Poly = Annotated[
    Annotated[PolyA, Tag("a")]
    | Annotated[PolyB, Tag("b")],
    Discriminator(_get_type)
]

Full reproduction:

from typing import Literal, Union, Annotated
from pydantic import BaseModel, Field, Tag, Discriminator
from pydantic_settings import BaseSettings,  CliApp


class PolyA(BaseModel):
    a: int = 1
    type: Literal["a"] = "a"

class PolyB(BaseModel):
    b: str = "2"
    type: Literal["b"] = "b"

def _get_type(model: BaseModel | dict) -> str:
    if isinstance(model, dict):
        return model.get("type", "a")
    return model.type  # type: ignore

Poly = Annotated[
    Annotated[PolyA, Tag("a")]
    | Annotated[PolyB, Tag("b")],
    Discriminator(_get_type)
]

PolyStrDiscriminator = Annotated[
    PolyA | PolyB,
    Discriminator("type")
]

PolyUndiscriminated = PolyA | PolyB


class WithUnion(BaseSettings):
    poly: Poly

class WithUnionStrDiscriminator(BaseSettings):
    poly: PolyStrDiscriminator

class WithUnionUndiscriminated(BaseSettings):
    poly: PolyUndiscriminated


if __name__ == "__main__":
    # the union with `Discriminator` object works without CLI
    print(WithUnion.model_validate({"poly": {"type": "a"}}))
    # the CLI works for union without discriminator
    print(CliApp.run(WithUnionUndiscriminated, ["--poly.type=a"]))
    # the CLI works for union with str discriminator
    print(CliApp.run(WithUnionStrDiscriminator, ["--poly.type=a"]))
    # the CLI does NOT work with `Discriminator` object
    print(CliApp.run(WithUnion, ["--poly.type=a"]))

Here's the output

poly=PolyA(a=1, type='a')
poly=PolyA(a=1, type='a')
poly=PolyA(a=1, type='a')
usage: pydantic_main_discriminated_union.py [-h] [--poly JSON]
pydantic_main_discriminated_union.py: error: unrecognized arguments: --poly.type=a

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions