From c82d286ae55039acc4f430ddb4a50be6bda46cff Mon Sep 17 00:00:00 2001 From: Sergey Tsaplin Date: Tue, 19 Jul 2022 13:09:23 +0200 Subject: [PATCH 1/3] Empty string is a valid JSON-key Signed-off-by: Sergey Tsaplin --- changes/4253-sergeytsaplin.md | 1 + pydantic/fields.py | 4 ++-- tests/test_aliases.py | 10 ++++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 changes/4253-sergeytsaplin.md diff --git a/changes/4253-sergeytsaplin.md b/changes/4253-sergeytsaplin.md new file mode 100644 index 0000000000..ba6dae6cb2 --- /dev/null +++ b/changes/4253-sergeytsaplin.md @@ -0,0 +1 @@ +Field aliases are compared with None instead of simple `bool(alias)` because an empty string is a valid JSON attribute name. diff --git a/pydantic/fields.py b/pydantic/fields.py index 600ee53644..ca3a05cfd3 100644 --- a/pydantic/fields.py +++ b/pydantic/fields.py @@ -148,7 +148,7 @@ def __init__(self, default: Any = Undefined, **kwargs: Any) -> None: self.default = default self.default_factory = kwargs.pop('default_factory', None) self.alias = kwargs.pop('alias', None) - self.alias_priority = kwargs.pop('alias_priority', 2 if self.alias else None) + self.alias_priority = kwargs.pop('alias_priority', 2 if self.alias is not None else None) self.title = kwargs.pop('title', None) self.description = kwargs.pop('description', None) self.exclude = kwargs.pop('exclude', None) @@ -395,7 +395,7 @@ def __init__( self.name: str = name self.has_alias: bool = bool(alias) - self.alias: str = alias or name + self.alias: str = alias if alias is not None else name self.type_: Any = convert_generics(type_) self.outer_type_: Any = type_ self.class_validators = class_validators or {} diff --git a/tests/test_aliases.py b/tests/test_aliases.py index 24caa9ed62..53a08dc0a1 100644 --- a/tests/test_aliases.py +++ b/tests/test_aliases.py @@ -335,3 +335,13 @@ def alias_generator(x): 'd_config_parent', 'e_generator_child', ] + + +def test_empty_string_alias(): + class Model(BaseModel): + empty_string_key: int = Field(alias='') + + data = {'': 123} + m = Model(**data) + assert m.empty_string_key == 123 + assert m.dict(by_alias=True) == data From 5f7f8c3a4387f6897704658046353ec5d185f3e8 Mon Sep 17 00:00:00 2001 From: Sergey Tsaplin Date: Tue, 19 Jul 2022 13:50:49 +0200 Subject: [PATCH 2/3] Update changes/4253-sergeytsaplin.md Co-authored-by: Samuel Colvin --- changes/4253-sergeytsaplin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changes/4253-sergeytsaplin.md b/changes/4253-sergeytsaplin.md index ba6dae6cb2..6cdee03ca6 100644 --- a/changes/4253-sergeytsaplin.md +++ b/changes/4253-sergeytsaplin.md @@ -1 +1 @@ -Field aliases are compared with None instead of simple `bool(alias)` because an empty string is a valid JSON attribute name. +Allow empty string aliases by using a `alias is not None` check, rather than `bool(alias)` From b503363000ec10c3ab436e425c264a2eae895e6b Mon Sep 17 00:00:00 2001 From: Sergey Tsaplin Date: Tue, 19 Jul 2022 14:03:34 +0200 Subject: [PATCH 3/3] has_alias attribute of the ModelField also should be a result of comparison with None Signed-off-by: Sergey Tsaplin --- pydantic/fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pydantic/fields.py b/pydantic/fields.py index ca3a05cfd3..7b55bcf637 100644 --- a/pydantic/fields.py +++ b/pydantic/fields.py @@ -394,7 +394,7 @@ def __init__( ) -> None: self.name: str = name - self.has_alias: bool = bool(alias) + self.has_alias: bool = alias is not None self.alias: str = alias if alias is not None else name self.type_: Any = convert_generics(type_) self.outer_type_: Any = type_