10
10
from abc import ABC , abstractmethod
11
11
from argparse import SUPPRESS , ArgumentParser , HelpFormatter , Namespace , _SubParsersAction
12
12
from collections import deque
13
- from dataclasses import is_dataclass
13
+ from dataclasses import asdict , is_dataclass
14
14
from enum import Enum
15
15
from pathlib import Path
16
16
from types import FunctionType
17
17
from typing import (
18
18
TYPE_CHECKING ,
19
19
Any ,
20
20
Callable ,
21
+ Dict ,
21
22
Generic ,
22
23
Iterator ,
23
24
List ,
34
35
35
36
import typing_extensions
36
37
from dotenv import dotenv_values
37
- from pydantic import AliasChoices , AliasPath , BaseModel , Json
38
+ from pydantic import AliasChoices , AliasPath , BaseModel , Json , TypeAdapter
38
39
from pydantic ._internal ._repr import Representation
40
+ from pydantic ._internal ._signature import _field_name_for_signature
39
41
from pydantic ._internal ._typing_extra import WithArgsTypes , origin_is_union , typing_base
40
42
from pydantic ._internal ._utils import deep_update , is_model_class , lenient_issubclass
41
43
from pydantic .dataclasses import is_pydantic_dataclass
@@ -248,55 +250,23 @@ def __call__(self) -> dict[str, Any]:
248
250
249
251
class DefaultSettingsSource (PydanticBaseSettingsSource ):
250
252
"""
251
- Source class for loading default values.
253
+ Source class for loading default object values.
252
254
"""
253
255
254
- def __init__ (self , settings_cls : type [BaseSettings ]):
256
+ def __init__ (self , settings_cls : type [BaseSettings ], default_objects_copy_by_value : bool | None = None ):
255
257
super ().__init__ (settings_cls )
256
- self .defaults = self ._get_defaults (settings_cls )
257
-
258
- def _get_defaults (self , settings_cls : type [BaseSettings ]) -> dict [str , Any ]:
259
- defaults : dict [str , Any ] = {}
260
- if self .config .get ('validate_default' ):
261
- fields = (
262
- settings_cls .__pydantic_fields__ if is_pydantic_dataclass (settings_cls ) else settings_cls .model_fields
263
- )
264
- for field_name , field_info in fields .items ():
265
- if field_info .validate_default is not False :
266
- resolved_name = self ._get_resolved_name (field_name , field_info )
267
- if field_info .default not in (PydanticUndefined , None ):
268
- defaults [resolved_name ] = field_info .default
269
- elif field_info .default_factory is not None :
270
- defaults [resolved_name ] = field_info .default_factory
271
- return defaults
272
-
273
- def _get_resolved_name (self , field_name : str , field_info : FieldInfo ) -> str :
274
- if not any ((field_info .alias , field_info .validation_alias )):
275
- return field_name
276
-
277
- resolved_names : list [str ] = []
278
- is_alias_path_only : bool = True
279
- new_alias_paths : list [AliasPath ] = []
280
- for alias in (field_info .alias , field_info .validation_alias ):
281
- if alias is None :
282
- continue
283
- elif isinstance (alias , str ):
284
- resolved_names .append (alias )
285
- is_alias_path_only = False
286
- elif isinstance (alias , AliasChoices ):
287
- for name in alias .choices :
288
- if isinstance (name , str ):
289
- resolved_names .append (name )
290
- is_alias_path_only = False
291
- else :
292
- new_alias_paths .append (name )
293
- else :
294
- new_alias_paths .append (alias )
295
- for alias_path in new_alias_paths :
296
- name = cast (str , alias_path .path [0 ])
297
- if not resolved_names and is_alias_path_only :
298
- resolved_names .append (name )
299
- return tuple (dict .fromkeys (resolved_names ))[0 ]
258
+ self .defaults : dict [str , Any ] = {}
259
+ self .default_objects_copy_by_value = (
260
+ default_objects_copy_by_value
261
+ if default_objects_copy_by_value is not None
262
+ else self .config .get ('default_objects_copy_by_value' , False )
263
+ )
264
+ if self .default_objects_copy_by_value :
265
+ for field_name , field_info in settings_cls .model_fields .items ():
266
+ if is_dataclass (type (field_info .default )):
267
+ self .defaults [_field_name_for_signature (field_name , field_info )] = asdict (field_info .default )
268
+ elif is_model_class (type (field_info .default )):
269
+ self .defaults [_field_name_for_signature (field_name , field_info )] = field_info .default .model_dump ()
300
270
301
271
def get_field_value (self , field : FieldInfo , field_name : str ) -> tuple [Any , str , bool ]:
302
272
# Nothing to do here. Only implement the return statement to make mypy happy
@@ -306,27 +276,44 @@ def __call__(self) -> dict[str, Any]:
306
276
return self .defaults
307
277
308
278
def __repr__ (self ) -> str :
309
- return 'DefaultSettingsSource()'
279
+ return f 'DefaultSettingsSource(default_objects_copy_by_value= { self . default_objects_copy_by_value } )'
310
280
311
281
312
282
class InitSettingsSource (PydanticBaseSettingsSource ):
313
283
"""
314
284
Source class for loading values provided during settings class initialization.
315
285
"""
316
286
317
- def __init__ (self , settings_cls : type [BaseSettings ], init_kwargs : dict [str , Any ]):
287
+ def __init__ (
288
+ self ,
289
+ settings_cls : type [BaseSettings ],
290
+ init_kwargs : dict [str , Any ],
291
+ default_objects_copy_by_value : bool | None = None ,
292
+ ):
318
293
self .init_kwargs = init_kwargs
319
294
super ().__init__ (settings_cls )
295
+ self .default_objects_copy_by_value = (
296
+ default_objects_copy_by_value
297
+ if default_objects_copy_by_value is not None
298
+ else self .config .get ('default_objects_copy_by_value' , False )
299
+ )
320
300
321
301
def get_field_value (self , field : FieldInfo , field_name : str ) -> tuple [Any , str , bool ]:
322
302
# Nothing to do here. Only implement the return statement to make mypy happy
323
303
return None , '' , False
324
304
325
305
def __call__ (self ) -> dict [str , Any ]:
326
- return self .init_kwargs
306
+ return (
307
+ TypeAdapter (Dict [str , Any ]).dump_python (self .init_kwargs )
308
+ if self .default_objects_copy_by_value
309
+ else self .init_kwargs
310
+ )
327
311
328
312
def __repr__ (self ) -> str :
329
- return f'InitSettingsSource(init_kwargs={ self .init_kwargs !r} )'
313
+ return (
314
+ f'InitSettingsSource(init_kwargs={ self .init_kwargs !r} , '
315
+ f'default_objects_copy_by_value={ self .default_objects_copy_by_value } )'
316
+ )
330
317
331
318
332
319
class PydanticBaseEnvSettingsSource (PydanticBaseSettingsSource ):
0 commit comments