From cd439a4e8d38e082d3ca7bdbdd53ebb9e7d49680 Mon Sep 17 00:00:00 2001 From: Charlie Hornsby Date: Mon, 8 Aug 2022 16:43:23 +0300 Subject: [PATCH] fix: access discriminator field on BaseModel instance using key (#3847) When validating a discriminated union where the union value has been passed as a Pydantic model instance, we should access the discriminator field value using the field name and not the field alias (whether one is set or not). --- changes/3846-chornsby.md | 1 + pydantic/fields.py | 2 +- tests/test_discrimated_union.py | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 changes/3846-chornsby.md diff --git a/changes/3846-chornsby.md b/changes/3846-chornsby.md new file mode 100644 index 0000000..f8daac8 --- /dev/null +++ b/changes/3846-chornsby.md @@ -0,0 +1 @@ +Fix validation of discriminated union fields with an alias when passing a model instance diff --git a/pydantic/fields.py b/pydantic/fields.py index 10b59fd..1c319cc 100644 --- a/pydantic/fields.py +++ b/pydantic/fields.py @@ -1105,7 +1105,7 @@ class ModelField(Representation): except TypeError: try: # BaseModel or dataclass - discriminator_value = getattr(v, self.discriminator_alias) + discriminator_value = getattr(v, self.discriminator_key) except (AttributeError, TypeError): return v, ErrorWrapper(MissingDiscriminator(discriminator_key=self.discriminator_key), loc) diff --git a/tests/test_discrimated_union.py b/tests/test_discrimated_union.py index a4dd501..a099fca 100644 --- a/tests/test_discrimated_union.py +++ b/tests/test_discrimated_union.py @@ -267,6 +267,24 @@ def test_discriminated_union_basemodel_instance_value(): assert isinstance(t, Top) +def test_discriminated_union_basemodel_instance_value_with_alias(): + class A(BaseModel): + literal: Literal['a'] = Field(alias='lit') + + class B(BaseModel): + literal: Literal['b'] = Field(alias='lit') + + class Config: + allow_population_by_field_name = True + + class Top(BaseModel): + sub: Union[A, B] = Field(..., discriminator='literal') + + assert Top(sub=A(lit='a')).sub.literal == 'a' + assert Top(sub=B(lit='b')).sub.literal == 'b' + assert Top(sub=B(literal='b')).sub.literal == 'b' + + def test_discriminated_union_int(): class A(BaseModel): l: Literal[1]