Coverage for pydantic/config.py: 100.00%
116 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-08-15 13:26 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2024-08-15 13:26 +0000
1import json 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
2from enum import Enum 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
3from typing import TYPE_CHECKING, Any, Callable, Dict, ForwardRef, Optional, Tuple, Type, Union 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
5from typing_extensions import Literal, Protocol 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
7from pydantic.typing import AnyArgTCallable, AnyCallable 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
8from pydantic.utils import GetterDict 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
9from pydantic.version import compiled 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
11if TYPE_CHECKING: 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
12 from typing import overload
14 from pydantic.fields import ModelField
15 from pydantic.main import BaseModel
17 ConfigType = Type['BaseConfig']
19 class SchemaExtraCallable(Protocol):
20 @overload
21 def __call__(self, schema: Dict[str, Any]) -> None:
22 pass
24 @overload
25 def __call__(self, schema: Dict[str, Any], model_class: Type[BaseModel]) -> None:
26 pass
28else:
29 SchemaExtraCallable = Callable[..., None] 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
31__all__ = 'BaseConfig', 'ConfigDict', 'get_config', 'Extra', 'inherit_config', 'prepare_config' 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
34class Extra(str, Enum): 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
35 allow = 'allow' 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
36 ignore = 'ignore' 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
37 forbid = 'forbid' 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
40# https://github.com/cython/cython/issues/4003
41# Fixed in Cython 3 and Pydantic v1 won't support Cython 3.
42# Pydantic v2 doesn't depend on Cython at all.
43if not compiled: 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
44 from typing_extensions import TypedDict 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
46 class ConfigDict(TypedDict, total=False): 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
47 title: Optional[str] 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
48 anystr_lower: bool 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
49 anystr_strip_whitespace: bool 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
50 min_anystr_length: int 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
51 max_anystr_length: Optional[int] 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
52 validate_all: bool 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
53 extra: Extra 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
54 allow_mutation: bool 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
55 frozen: bool 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
56 allow_population_by_field_name: bool 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
57 use_enum_values: bool 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
58 fields: Dict[str, Union[str, Dict[str, str]]] 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
59 validate_assignment: bool 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
60 error_msg_templates: Dict[str, str] 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
61 arbitrary_types_allowed: bool 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
62 orm_mode: bool 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
63 getter_dict: Type[GetterDict] 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
64 alias_generator: Optional[Callable[[str], str]] 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
65 keep_untouched: Tuple[type, ...] 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
66 schema_extra: Union[Dict[str, object], 'SchemaExtraCallable'] 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
67 json_loads: Callable[[str], object] 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
68 json_dumps: AnyArgTCallable[str] 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
69 json_encoders: Dict[Type[object], AnyCallable] 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
70 underscore_attrs_are_private: bool 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
71 allow_inf_nan: bool 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
72 copy_on_model_validation: Literal['none', 'deep', 'shallow'] 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
73 # whether dataclass `__post_init__` should be run after validation
74 post_init_call: Literal['before_validation', 'after_validation'] 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
76else:
77 ConfigDict = dict # type: ignore 1QRSTU
80class BaseConfig: 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
81 title: Optional[str] = None 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
82 anystr_lower: bool = False 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
83 anystr_upper: bool = False 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
84 anystr_strip_whitespace: bool = False 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
85 min_anystr_length: int = 0 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
86 max_anystr_length: Optional[int] = None 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
87 validate_all: bool = False 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
88 extra: Extra = Extra.ignore 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
89 allow_mutation: bool = True 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
90 frozen: bool = False 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
91 allow_population_by_field_name: bool = False 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
92 use_enum_values: bool = False 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
93 fields: Dict[str, Union[str, Dict[str, str]]] = {} 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
94 validate_assignment: bool = False 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
95 error_msg_templates: Dict[str, str] = {} 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
96 arbitrary_types_allowed: bool = False 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
97 orm_mode: bool = False 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
98 getter_dict: Type[GetterDict] = GetterDict 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
99 alias_generator: Optional[Callable[[str], str]] = None 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
100 keep_untouched: Tuple[type, ...] = () 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
101 schema_extra: Union[Dict[str, Any], 'SchemaExtraCallable'] = {} 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
102 json_loads: Callable[[str], Any] = json.loads 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
103 json_dumps: Callable[..., str] = json.dumps 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
104 json_encoders: Dict[Union[Type[Any], str, ForwardRef], AnyCallable] = {} 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
105 underscore_attrs_are_private: bool = False 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
106 allow_inf_nan: bool = True 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
108 # whether inherited models as fields should be reconstructed as base model,
109 # and whether such a copy should be shallow or deep
110 copy_on_model_validation: Literal['none', 'deep', 'shallow'] = 'shallow' 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
112 # whether `Union` should check all allowed types before even trying to coerce
113 smart_union: bool = False 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
114 # whether dataclass `__post_init__` should be run before or after validation
115 post_init_call: Literal['before_validation', 'after_validation'] = 'before_validation' 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
117 @classmethod 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
118 def get_field_info(cls, name: str) -> Dict[str, Any]: 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
119 """
120 Get properties of FieldInfo from the `fields` property of the config class.
121 """
123 fields_value = cls.fields.get(name) 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
125 if isinstance(fields_value, str): 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
126 field_info: Dict[str, Any] = {'alias': fields_value} 1EFabcdefghijGHklmnopqrstQRSTUIJuvwxyzABCD
127 elif isinstance(fields_value, dict): 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
128 field_info = fields_value 1EFabcdefghijGHklmnopqrstQRSTUIJuvwxyzABCD
129 else:
130 field_info = {} 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
132 if 'alias' in field_info: 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
133 field_info.setdefault('alias_priority', 2) 1EFabcdefghijGHklmnopqrstQRSTUIJuvwxyzABCD
135 if field_info.get('alias_priority', 0) <= 1 and cls.alias_generator: 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
136 alias = cls.alias_generator(name) 1EFabcdefghijGHklmnopqrstQRSTUIJuvwxyzABCD
137 if not isinstance(alias, str): 1EFabcdefghijGHklmnopqrstQRSTUIJuvwxyzABCD
138 raise TypeError(f'Config.alias_generator must return str, not {alias.__class__}') 1EFabcdefghijGHklmnopqrstQRSTUIJuvwxyzABCD
139 field_info.update(alias=alias, alias_priority=1) 1EFabcdefghijGHklmnopqrstQRSTUIJuvwxyzABCD
140 return field_info 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
142 @classmethod 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
143 def prepare_field(cls, field: 'ModelField') -> None: 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
144 """
145 Optional hook to check or modify fields during model creation.
146 """
147 pass 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
150def get_config(config: Union[ConfigDict, Type[object], None]) -> Type[BaseConfig]: 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
151 if config is None: 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
152 return BaseConfig 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
154 else:
155 config_dict = ( 1abcdefghijklmnopqrstQRSTKLMNOPUuvwxyzABCD
156 config
157 if isinstance(config, dict)
158 else {k: getattr(config, k) for k in dir(config) if not k.startswith('__')}
159 )
161 class Config(BaseConfig): 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
162 ... 1EFabcdefghijGHklmnopqrstKLMNOPIJuvwxyzABCD
164 for k, v in config_dict.items(): 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
165 setattr(Config, k, v) 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
166 return Config 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
169def inherit_config(self_config: 'ConfigType', parent_config: 'ConfigType', **namespace: Any) -> 'ConfigType': 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
170 if not self_config: 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
171 base_classes: Tuple['ConfigType', ...] = (parent_config,) 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
172 elif self_config == parent_config: 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
173 base_classes = (self_config,) 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
174 else:
175 base_classes = self_config, parent_config 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
177 namespace['json_encoders'] = { 1abcdefghijklmnopqrstQRSTKLMNOPUuvwxyzABCD
178 **getattr(parent_config, 'json_encoders', {}),
179 **getattr(self_config, 'json_encoders', {}),
180 **namespace.get('json_encoders', {}),
181 }
183 return type('Config', base_classes, namespace) 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
186def prepare_config(config: Type[BaseConfig], cls_name: str) -> None: 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
187 if not isinstance(config.extra, Extra): 1EFabcdefghijGHklmnopqrstQRSTKLMNOPUIJuvwxyzABCD
188 try: 1EFabcdefghijGHklmnopqrstQRSTUIJuvwxyzABCD
189 config.extra = Extra(config.extra) 1EFabcdefghijGHklmnopqrstQRSTUIJuvwxyzABCD
190 except ValueError: 1EFabcdefghijGHklmnopqrstQRSTUIJuvwxyzABCD
191 raise ValueError(f'"{cls_name}": {config.extra} is not a valid value for "extra"') 1EFabcdefghijGHklmnopqrstQRSTUIJuvwxyzABCD