Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pydantic/aliases.py: 46%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""Support for alias configurations."""
3from __future__ import annotations
5import dataclasses
6from collections.abc import Callable
7from typing import Any, Literal
9from pydantic_core import PydanticUndefined
11__all__ = ('AliasGenerator', 'AliasPath', 'AliasChoices')
14@dataclasses.dataclass(slots=True)
15class AliasPath:
16 """!!! abstract "Usage Documentation"
17 [`AliasPath` and `AliasChoices`](../concepts/alias.md#aliaspath-and-aliaschoices)
19 A data class used by `validation_alias` as a convenience to create aliases.
21 Attributes:
22 path: A list of string or integer aliases.
23 """
25 path: list[int | str]
27 def __init__(self, first_arg: str, *args: str | int) -> None:
28 self.path = [first_arg] + list(args)
30 def convert_to_aliases(self) -> list[str | int]:
31 """Converts arguments to a list of string or integer aliases.
33 Returns:
34 The list of aliases.
35 """
36 return self.path
38 def search_dict_for_path(self, d: dict) -> Any:
39 """Searches a dictionary for the path specified by the alias.
41 Returns:
42 The value at the specified path, or `PydanticUndefined` if the path is not found.
43 """
44 v = d
45 for k in self.path:
46 if isinstance(v, str):
47 # disallow indexing into a str, like for AliasPath('x', 0) and x='abc'
48 return PydanticUndefined
49 try:
50 v = v[k]
51 except (KeyError, IndexError, TypeError):
52 return PydanticUndefined
53 return v
56@dataclasses.dataclass(slots=True)
57class AliasChoices:
58 """!!! abstract "Usage Documentation"
59 [`AliasPath` and `AliasChoices`](../concepts/alias.md#aliaspath-and-aliaschoices)
61 A data class used by `validation_alias` as a convenience to create aliases.
63 Attributes:
64 choices: A list containing a string or `AliasPath`.
65 """
67 choices: list[str | AliasPath]
69 def __init__(self, first_choice: str | AliasPath, *choices: str | AliasPath) -> None:
70 self.choices = [first_choice] + list(choices)
72 def convert_to_aliases(self) -> list[list[str | int]]:
73 """Converts arguments to a list of lists containing string or integer aliases.
75 Returns:
76 The list of aliases.
77 """
78 aliases: list[list[str | int]] = []
79 for c in self.choices:
80 if isinstance(c, AliasPath):
81 aliases.append(c.convert_to_aliases())
82 else:
83 aliases.append([c])
84 return aliases
87@dataclasses.dataclass(slots=True)
88class AliasGenerator:
89 """!!! abstract "Usage Documentation"
90 [Using an `AliasGenerator`](../concepts/alias.md#using-an-aliasgenerator)
92 A data class used by `alias_generator` as a convenience to create various aliases.
94 Attributes:
95 alias: A callable that takes a field name and returns an alias for it.
96 validation_alias: A callable that takes a field name and returns a validation alias for it.
97 serialization_alias: A callable that takes a field name and returns a serialization alias for it.
98 """
100 alias: Callable[[str], str] | None = None
101 validation_alias: Callable[[str], str | AliasPath | AliasChoices] | None = None
102 serialization_alias: Callable[[str], str] | None = None
104 def _generate_alias(
105 self,
106 alias_kind: Literal['alias', 'validation_alias', 'serialization_alias'],
107 allowed_types: tuple[type[str] | type[AliasPath] | type[AliasChoices], ...],
108 field_name: str,
109 ) -> str | AliasPath | AliasChoices | None:
110 """Generate an alias of the specified kind. Returns None if the alias generator is None.
112 Raises:
113 TypeError: If the alias generator produces an invalid type.
114 """
115 alias = None
116 alias_generator = getattr(self, alias_kind)
118 if alias_generator is not None:
119 alias = alias_generator(field_name)
120 if alias is not None and not isinstance(alias, allowed_types):
121 raise TypeError(
122 f'Invalid `{alias_kind}` type. `{alias_kind}` generator must produce one of `{allowed_types}`'
123 )
124 return alias
126 def generate_aliases(self, field_name: str) -> tuple[str | None, str | AliasPath | AliasChoices | None, str | None]:
127 """Generate `alias`, `validation_alias`, and `serialization_alias` for a field.
129 Returns:
130 A tuple of three aliases - alias, validation, and serialization.
131 """
132 alias = self._generate_alias('alias', (str,), field_name)
133 validation_alias = self._generate_alias('validation_alias', (str, AliasChoices, AliasPath), field_name)
134 serialization_alias = self._generate_alias('serialization_alias', (str,), field_name)
136 return alias, validation_alias, serialization_alias # type: ignore