Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Raise ValidationError for unhashable discriminator values #5132

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/4773-kurtmckee.md
@@ -0,0 +1 @@
Raise `ValidationError`, not `ConfigError`, when a discriminator value is unhashable.
11 changes: 7 additions & 4 deletions pydantic/fields.py
Expand Up @@ -1117,15 +1117,18 @@ def _validate_discriminated_union(
except (AttributeError, TypeError):
return v, ErrorWrapper(MissingDiscriminator(discriminator_key=self.discriminator_key), loc)

try:
sub_field = self.sub_fields_mapping[discriminator_value] # type: ignore[index]
except TypeError:
if self.sub_fields_mapping is None:
assert cls is not None
raise ConfigError(
f'field "{self.name}" not yet prepared so type is still a ForwardRef, '
f'you might need to call {cls.__name__}.update_forward_refs().'
)
except KeyError:

try:
sub_field = self.sub_fields_mapping[discriminator_value] # type: ignore[index]
hramezani marked this conversation as resolved.
Show resolved Hide resolved
except (KeyError, TypeError):
# KeyError: `discriminator_value` is not in the dictionary.
# TypeError: `discriminator_value` is unhashable.
assert self.sub_fields_mapping is not None
return v, ErrorWrapper(
InvalidDiscriminator(
Expand Down
18 changes: 18 additions & 0 deletions tests/test_discrimated_union.py
Expand Up @@ -423,3 +423,21 @@ class Container(GenericModel, Generic[T]):

# coercion is done properly
assert Container[str].parse_obj({'result': {'type': 'Success', 'data': 1}}).result.data == '1'


def test_discriminator_with_unhashable_type():
"""Verify an unhashable discriminator value raises a ValidationError."""

class Model1(BaseModel):
target: Literal['t1']
a: int

class Model2(BaseModel):
target: Literal['t2']
b: int

class Foo(BaseModel):
foo: Union[Model1, Model2] = Field(discriminator='target')

with pytest.raises(ValidationError, match=re.escape("No match for discriminator 'target' and value {}")):
Foo(**{'foo': {'target': {}}})