PY-PYDA0005 · optional_variant_discriminated_union_candidate
Find optional-field models whose validator proves mutually exclusive variants.
This is a deterministic rule for python. Read its implementation.
Definition
Section titled “Definition”Inspect recognized Pydantic and house model classes. Report only an imported
@model_validator(mode="after") whose validation branch raises ValueError or
PydanticCustomError when a builtin sum of disjoint field-presence predicates exceeds one.
Every referenced field must have an optional annotation and an explicit None default. A
direct sum or one assigned immediately before the branch is accepted. The value is the number
of proven model candidates.
Evidence
Section titled “Evidence”Each finding names the model, validator, exact variant field groups, variant count, and total
participating fields. A group may combine fields with or when those fields form one variant.
The finding proposes no edit because discriminator design, variant names, and the
representation of an all-absent state remain domain decisions. The value is the number of
models whose validator proves a closed family of variants.
Exceptions
Section titled “Exceptions”Validators with custom decorators, before or wrap mode, shadowed sum, arbitrary helper calls,
generators, chained comparisons, overlapping predicates, nonoptional fields, mutable defaults,
multiple statements in the error branch, or unrecognized error types are excluded. Cross-field
invariants that do not encode a closed family of variants should remain validators.
minimum_variants is how many mutually exclusive fields a validator has to prove before the
shape is worth naming as a union, since two alternatives are the smallest set a discriminator
can help with.
Examples
Section titled “Examples”Bad
Several nullable fields encode alternatives and an imperative validator reconstructs the sumtype after parsing.
.. code-block:: python
class Credential(BaseModel): token. str | None = None username. str | None = None certificate. bytes | None = None
@model_validator(mode="after") def one_variant(self): if sum((self.token is not None, self.username is not None, self.certificate is not None)) > 1. raise ValueError("choose one credential") return self
GoodA discriminator selects one explicit model and lets Pydantic validate only that variant.
.. code-block:: python
class TokenCredential(BaseModel): kind. Literal[“token”] token. str
class UserCredential(BaseModel): kind. Literal[“user”] username. str
Credential = Annotated[TokenCredential | UserCredential, Field(discriminator=“kind”)]
References
Section titled “References”- Cites “Pydantic documentation”, discriminated unions. Open reference
- Cites “Pydantic documentation”, model validators. Open reference