Skip to content

Commit

Permalink
Change alias precedence to prefer child models (#904)
Browse files Browse the repository at this point in the history
* Change alias precedence to prefer child models

* add docs about alias precedence

* correct change
  • Loading branch information
samuelcolvin committed Oct 17, 2019
1 parent 87fb5cc commit ed7b216
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 6 deletions.
2 changes: 2 additions & 0 deletions changes/904-samuelcolvin.md
@@ -0,0 +1,2 @@
**Breaking Change:** Change the precedence of aliases so child model aliases override parent aliases,
including using `alias_generator`
3 changes: 1 addition & 2 deletions docs/examples/alias_generator_config.py
Expand Up @@ -5,12 +5,11 @@ def to_camel(string: str) -> str:

class Voice(BaseModel):
name: str
gender: str
language_code: str

class Config:
alias_generator = to_camel

voice = Voice(Name='Filiz', Gender='Female', LanguageCode='tr-TR')
voice = Voice(Name='Filiz', LanguageCode='tr-TR')
print(voice.language_code)
print(voice.dict(by_alias=True))
21 changes: 21 additions & 0 deletions docs/examples/alias_precedence.py
@@ -0,0 +1,21 @@
from pydantic import BaseModel

class Voice(BaseModel):
name: str
language_code: str

class Config:
@classmethod
def alias_generator(cls, string: str) -> str:
# this is the same as `alias_generator = to_camel` above
return ''.join(word.capitalize() for word in string.split('_'))

class Character(Voice):
mood: str

class Config:
fields = {'mood': 'Mood', 'language_code': 'lang'}

c = Character(Mood='happy', Name='Filiz', lang='tr-TR')
print(c)
print(c.dict(by_alias=True))
13 changes: 13 additions & 0 deletions docs/usage/model_config.md
Expand Up @@ -98,3 +98,16 @@ you can automatically generate aliases using `alias_generator`:
{!.tmp_examples/alias_generator_config.py!}
```
_(This script is complete, it should run "as is")_


## Alias Precedence

Aliases defined on the `Config` class of child models will take priority over any aliases defined on `Config` of a
parent model:

```py
{!.tmp_examples/alias_precedence.py!}
```
_(This script is complete, it should run "as is")_

This includes when a child model uses `alias_generator` where the aliases of all parent model fields will be updated.
2 changes: 1 addition & 1 deletion mkdocs.yml
Expand Up @@ -29,7 +29,7 @@ nav:
- usage/models.md
- 'Field Types': usage/types.md
- usage/validators.md
- usage/model_config.md
- 'Model Config': usage/model_config.md
- usage/schema.md
- usage/exporting_models.md
- usage/dataclasses.md
Expand Down
6 changes: 3 additions & 3 deletions pydantic/fields.py
Expand Up @@ -263,10 +263,10 @@ def infer(

def set_config(self, config: Type['BaseConfig']) -> None:
self.model_config = config
schema_from_config = config.get_field_info(self.name)
if schema_from_config:
info_from_config = config.get_field_info(self.name)
if info_from_config:
self.field_info = cast(FieldInfo, self.field_info)
self.field_info.alias = self.field_info.alias or schema_from_config.get('alias') or self.name
self.field_info.alias = info_from_config.get('alias') or self.field_info.alias or self.name
self.alias = cast(str, self.field_info.alias)

@property
Expand Down
40 changes: 40 additions & 0 deletions tests/test_edge_cases.py
Expand Up @@ -1079,3 +1079,43 @@ class Model(BaseModel):

assert Model().__fields__.keys() == {'v'}
assert Model.__fields__.keys() == {'v'}


def test_alias_child_precedence():
class Parent(BaseModel):
x: int

class Config:
fields = {'x': 'x1'}

class Child(Parent):
y: int

class Config:
fields = {'y': 'y2', 'x': 'x2'}

assert Child.__fields__['y'].alias == 'y2'
assert Child.__fields__['x'].alias == 'x2'


def test_alias_generator_parent():
class Parent(BaseModel):
x: int

class Config:
allow_population_by_field_name = True

@classmethod
def alias_generator(cls, f_name):
return f_name + '1'

class Child(Parent):
y: int

class Config:
@classmethod
def alias_generator(cls, f_name):
return f_name + '2'

assert Child.__fields__['y'].alias == 'y2'
assert Child.__fields__['x'].alias == 'x2'

0 comments on commit ed7b216

Please sign in to comment.