Skip to content

Commit

Permalink
Add support for field alias in dataclass signature (#8387)
Browse files Browse the repository at this point in the history
  • Loading branch information
NeevCohen committed Dec 20, 2023
1 parent c765f87 commit 19fa86c
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 6 deletions.
25 changes: 20 additions & 5 deletions pydantic/_internal/_constructor_signature_generators.py
Expand Up @@ -10,6 +10,21 @@
from ..fields import FieldInfo


def _field_name_or_alias(field_name: str, field_info: FieldInfo) -> str:
"""Extract the correct name to use for the field when generating a signature.
If it has a valid alias then returns its alais, else returns its name
Args:
field_name: The name of the field
field_info: The field
Returns:
The correct name to use when generating a signature.
"""
return (
field_info.alias if isinstance(field_info.alias, str) and is_valid_identifier(field_info.alias) else field_name
)


def generate_pydantic_signature(
init: Callable[..., None],
fields: dict[str, FieldInfo],
Expand Down Expand Up @@ -37,6 +52,9 @@ def generate_pydantic_signature(
for param in islice(present_params, 1, None): # skip self arg
# inspect does "clever" things to show annotations as strings because we have
# `from __future__ import annotations` in main, we don't want that
if fields.get(param.name):
param_name = _field_name_or_alias(param.name, fields[param.name])
param = param.replace(name=param_name)
if param.annotation == 'Any':
param = param.replace(annotation=Any)
if param.kind is param.VAR_KEYWORD:
Expand All @@ -48,16 +66,13 @@ def generate_pydantic_signature(
allow_names = config_wrapper.populate_by_name
for field_name, field in fields.items():
# when alias is a str it should be used for signature generation
if isinstance(field.alias, str):
param_name = field.alias
else:
param_name = field_name
param_name = _field_name_or_alias(field_name, field)

if field_name in merged_params or param_name in merged_params:
continue

if not is_valid_identifier(param_name):
if allow_names and is_valid_identifier(field_name):
if allow_names:
param_name = field_name
else:
use_var_kw = True
Expand Down
3 changes: 2 additions & 1 deletion tests/test_dataclasses.py
Expand Up @@ -2487,9 +2487,10 @@ class Model:
a: float = dataclasses.field(default_factory=float)
b: float = Field(default=1.0)
c: float = Field(default_factory=float)
d: int = dataclasses.field(metadata={'alias': 'dd'}, default=1)

assert str(inspect.signature(Model)) == (
"(x: int, y: str = 'y', z: float = 1.0, a: float = <factory>, b: float = 1.0, c: float = <factory>) -> None"
"(x: int, y: str = 'y', z: float = 1.0, a: float = <factory>, b: float = 1.0, c: float = <factory>, dd: int = 1) -> None"
)


Expand Down

0 comments on commit 19fa86c

Please sign in to comment.