-
-
Notifications
You must be signed in to change notification settings - Fork 108
Closed
Labels
Description
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