diff --git a/changes/4192-kylebamos.md b/changes/4192-kylebamos.md new file mode 100644 index 0000000..daa518d --- /dev/null +++ b/changes/4192-kylebamos.md @@ -0,0 +1 @@ +Update BaseModel.construct to work with aliased Fields \ No newline at end of file diff --git a/pydantic/main.py b/pydantic/main.py index 5ce2674..fddacd9 100644 --- a/pydantic/main.py +++ b/pydantic/main.py @@ -588,7 +588,9 @@ class BaseModel(Representation, metaclass=ModelMetaclass): m = cls.__new__(cls) fields_values: Dict[str, Any] = {} for name, field in cls.__fields__.items(): - if name in values: + if field.alt_alias and field.alias in values: + fields_values[name] = values[field.alias] + elif name in values: fields_values[name] = values[name] elif not field.required: fields_values[name] = field.get_default() diff --git a/tests/test_aliases.py b/tests/test_aliases.py index 53a08dc..f37daf1 100644 --- a/tests/test_aliases.py +++ b/tests/test_aliases.py @@ -1,5 +1,6 @@ import re -from typing import Any, List, Optional +from contextlib import nullcontext as does_not_raise +from typing import Any, ContextManager, List, Optional import pytest @@ -345,3 +346,39 @@ def test_empty_string_alias(): m = Model(**data) assert m.empty_string_key == 123 assert m.dict(by_alias=True) == data + + +@pytest.mark.parametrize( + 'use_construct, allow_population_by_field_name_config, arg_name, expectation', + [ + [False, True, 'bar', does_not_raise()], + [False, True, 'bar_', does_not_raise()], + [False, False, 'bar', does_not_raise()], + [False, False, 'bar_', pytest.raises(ValueError)], + [True, True, 'bar', does_not_raise()], + [True, True, 'bar_', does_not_raise()], + [True, False, 'bar', does_not_raise()], + [True, False, 'bar_', does_not_raise()], + ], +) +def test_allow_population_by_field_name_config( + use_construct: bool, + allow_population_by_field_name_config: bool, + arg_name: str, + expectation: ContextManager, +): + expected_value: int = 7 + + class Foo(BaseModel): + bar_: int = Field(..., alias='bar') + + class Config(BaseConfig): + allow_population_by_field_name = allow_population_by_field_name_config + + with expectation: + if use_construct: + f = Foo.construct(**{arg_name: expected_value}) + else: + f = Foo(**{arg_name: expected_value}) + + assert f.bar_ == expected_value