Generate a mapping of parameter names to Parameter objects for a pydantic BaseModel or dataclass.
( # noqa: C901 (ignore complexity, could use a refactor)
init: Callable[..., None],
fields: dict[str, FieldInfo],
validate_by_name: bool,
extra: ExtraValues | None,
)
| 79 | |
| 80 | |
| 81 | def _generate_signature_parameters( # noqa: C901 (ignore complexity, could use a refactor) |
| 82 | init: Callable[..., None], |
| 83 | fields: dict[str, FieldInfo], |
| 84 | validate_by_name: bool, |
| 85 | extra: ExtraValues | None, |
| 86 | ) -> dict[str, Parameter]: |
| 87 | """Generate a mapping of parameter names to Parameter objects for a pydantic BaseModel or dataclass.""" |
| 88 | from itertools import islice |
| 89 | |
| 90 | present_params = signature_no_eval(init).parameters.values() |
| 91 | merged_params: dict[str, Parameter] = {} |
| 92 | var_kw = None |
| 93 | use_var_kw = False |
| 94 | |
| 95 | for param in islice(present_params, 1, None): # skip self arg |
| 96 | # inspect does "clever" things to show annotations as strings because we have |
| 97 | # `from __future__ import annotations` in main, we don't want that |
| 98 | if fields.get(param.name): |
| 99 | # exclude params with init=False |
| 100 | if getattr(fields[param.name], 'init', True) is False: |
| 101 | continue |
| 102 | param = param.replace(name=_field_name_for_signature(param.name, fields[param.name])) |
| 103 | if param.annotation == 'Any': |
| 104 | param = param.replace(annotation=Any) |
| 105 | if param.kind is param.VAR_KEYWORD: |
| 106 | var_kw = param |
| 107 | continue |
| 108 | merged_params[param.name] = param |
| 109 | |
| 110 | if var_kw: # if custom init has no var_kw, fields which are not declared in it cannot be passed through |
| 111 | allow_names = validate_by_name |
| 112 | for field_name, field in fields.items(): |
| 113 | # when alias is a str it should be used for signature generation |
| 114 | param_name = _field_name_for_signature(field_name, field) |
| 115 | |
| 116 | if field_name in merged_params or param_name in merged_params: |
| 117 | continue |
| 118 | |
| 119 | if not is_valid_identifier(param_name): |
| 120 | if allow_names: |
| 121 | param_name = field_name |
| 122 | else: |
| 123 | use_var_kw = True |
| 124 | continue |
| 125 | |
| 126 | if field.is_required(): |
| 127 | default = Parameter.empty |
| 128 | elif field.default_factory is not None: |
| 129 | # Mimics stdlib dataclasses: |
| 130 | default = _HAS_DEFAULT_FACTORY |
| 131 | else: |
| 132 | default = field.default |
| 133 | merged_params[param_name] = Parameter( |
| 134 | param_name, |
| 135 | Parameter.KEYWORD_ONLY, |
| 136 | annotation=field.rebuild_annotation(), |
| 137 | default=default, |
| 138 | ) |
no test coverage detected