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

Use generated alias for aliases that are not specified otherwise #7802

Merged
merged 3 commits into from Oct 16, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
16 changes: 12 additions & 4 deletions pydantic/_internal/_generate_schema.py
Expand Up @@ -996,14 +996,22 @@ def json_schema_update_func(schema: CoreSchemaOrField, handler: GetJsonSchemaHan

# apply alias generator
alias_generator = self._config_wrapper.alias_generator
if alias_generator and (field_info.alias_priority is None or field_info.alias_priority <= 1):
if alias_generator and (
field_info.alias_priority is None or field_info.alias_priority <= 1 or field_info.alias is None
):
alias = alias_generator(name)
if not isinstance(alias, str):
raise TypeError(f'alias_generator {alias_generator} must return str, not {alias.__class__}')
if field_info.alias is None:
if field_info.serialization_alias is None:
field_info.serialization_alias = alias
if field_info.validation_alias is None:
field_info.validation_alias = alias
else:
field_info.serialization_alias = alias
field_info.validation_alias = alias
field_info.alias_priority = 1
field_info.alias = alias
field_info.validation_alias = alias
field_info.serialization_alias = alias
field_info.alias_priority = 1

if isinstance(field_info.validation_alias, (AliasChoices, AliasPath)):
validation_alias = field_info.validation_alias.convert_to_aliases()
Expand Down
58 changes: 58 additions & 0 deletions tests/test_aliases.py
Expand Up @@ -216,6 +216,64 @@ class Child(Parent):
assert [f.alias for f in Child.model_fields.values()] == ['abc', 'Y', 'Z']


def test_alias_generator_used_by_default():
class Model(BaseModel):
model_config = ConfigDict(alias_generator=lambda x: x.upper())

a: str
b: str = Field(..., alias='b_alias')
c: str = Field(..., validation_alias='c_val_alias')
d: str = Field(..., serialization_alias='d_ser_alias')
e: str = Field(..., alias='e_alias', validation_alias='e_val_alias')
f: str = Field(..., alias='f_alias', serialization_alias='f_ser_alias')
g: str = Field(..., alias='g_alias', validation_alias='g_val_alias', serialization_alias='g_ser_alias')

assert {
name: {k: getattr(f, k) for k in ('alias', 'validation_alias', 'serialization_alias')}
for name, f in Model.model_fields.items()
} == {
# Validation/serialization aliases should be:
# 1. The specific alias, if specified, or
# 2. The alias, if specified, or
# 3. The generated alias (i.e. the field name in upper case)
'a': {
'alias': 'A',
'validation_alias': 'A',
'serialization_alias': 'A',
},
'b': {
'alias': 'b_alias',
'validation_alias': 'b_alias',
'serialization_alias': 'b_alias',
},
'c': {
'alias': 'C',
'validation_alias': 'c_val_alias',
'serialization_alias': 'C',
},
'd': {
'alias': 'D',
'validation_alias': 'D',
'serialization_alias': 'd_ser_alias',
},
'e': {
'alias': 'e_alias',
'validation_alias': 'e_val_alias',
'serialization_alias': 'e_alias',
},
'f': {
'alias': 'f_alias',
'validation_alias': 'f_alias',
'serialization_alias': 'f_ser_alias',
},
'g': {
'alias': 'g_alias',
'validation_alias': 'g_val_alias',
'serialization_alias': 'g_ser_alias',
},
}


def test_low_priority_alias():
class Parent(BaseModel):
w: bool = Field(..., alias='w_', validation_alias='w_val_alias', serialization_alias='w_ser_alias')
Expand Down