@@ -204,7 +204,7 @@ class Settings(BaseSettings):
204
204
return values
205
205
206
206
def __call__ (self ) -> Dict [str , Any ]:
207
- d : Dict [str , Any ] = {}
207
+ data : Dict [str , Any ] = {}
208
208
209
209
for field_name , field in self .settings_cls .model_fields .items ():
210
210
try :
@@ -223,11 +223,11 @@ def __call__(self) -> Dict[str, Any]:
223
223
224
224
if field_value is not None :
225
225
if not self .config .get ('case_sensitive' , False ) and lenient_issubclass (field .annotation , BaseModel ):
226
- d [field_key ] = self ._replace_field_names_case_insensitively (field , field_value )
226
+ data [field_key ] = self ._replace_field_names_case_insensitively (field , field_value )
227
227
else :
228
- d [field_key ] = field_value
228
+ data [field_key ] = field_value
229
229
230
- return d
230
+ return data
231
231
232
232
233
233
class SecretsSettingsSource (PydanticBaseEnvSettingsSource ):
@@ -449,12 +449,7 @@ def __init__(
449
449
super ().__init__ (settings_cls , env_nested_delimiter , env_prefix_len )
450
450
451
451
def _load_env_vars (self ) -> Mapping [str , Optional [str ]]:
452
- env_vars = super ()._load_env_vars ()
453
- dotenv_vars = self ._read_env_files (self .settings_cls .model_config .get ('case_sensitive' , False ))
454
- if dotenv_vars :
455
- env_vars = {** dotenv_vars , ** env_vars }
456
-
457
- return env_vars
452
+ return self ._read_env_files (self .settings_cls .model_config .get ('case_sensitive' , False ))
458
453
459
454
def _read_env_files (self , case_sensitive : bool ) -> Mapping [str , Optional [str ]]:
460
455
env_files = self .env_file
@@ -464,7 +459,7 @@ def _read_env_files(self, case_sensitive: bool) -> Mapping[str, Optional[str]]:
464
459
if isinstance (env_files , (str , os .PathLike )):
465
460
env_files = [env_files ]
466
461
467
- dotenv_vars = {}
462
+ dotenv_vars : Dict [ str , Optional [ str ]] = {}
468
463
for env_file in env_files :
469
464
env_path = Path (env_file ).expanduser ()
470
465
if env_path .is_file ():
@@ -474,14 +469,37 @@ def _read_env_files(self, case_sensitive: bool) -> Mapping[str, Optional[str]]:
474
469
475
470
return dotenv_vars
476
471
472
+ def __call__ (self ) -> Dict [str , Any ]:
473
+ data : Dict [str , Any ] = super ().__call__ ()
474
+
475
+ data_lower_keys : List [str ] = []
476
+ if not self .settings_cls .model_config .get ('case_sensitive' , False ):
477
+ data_lower_keys = [x .lower () for x in data .keys ()]
478
+
479
+ # As `extra` config is allowed in dotenv settings source, We have to
480
+ # update data with extra env variabels from dotenv file.
481
+ for env_name , env_value in self .env_vars .items ():
482
+ if env_value is not None :
483
+ env_name_without_prefix = env_name [self .env_prefix_len :]
484
+ first_key , * _ = env_name_without_prefix .split (self .env_nested_delimiter )
485
+
486
+ if (data_lower_keys and first_key not in data_lower_keys ) or (
487
+ not data_lower_keys and first_key not in data
488
+ ):
489
+ data [first_key ] = env_value
490
+
491
+ return data
492
+
477
493
def __repr__ (self ) -> str :
478
494
return (
479
495
f'DotEnvSettingsSource(env_file={ self .env_file !r} , env_file_encoding={ self .env_file_encoding !r} , '
480
496
f'env_nested_delimiter={ self .env_nested_delimiter !r} , env_prefix_len={ self .env_prefix_len !r} )'
481
497
)
482
498
483
499
484
- def read_env_file (file_path : Path , * , encoding : str = None , case_sensitive : bool = False ) -> Dict [str , Optional [str ]]:
500
+ def read_env_file (
501
+ file_path : Path , * , encoding : Optional [str ] = None , case_sensitive : bool = False
502
+ ) -> Mapping [str , Optional [str ]]:
485
503
try :
486
504
from dotenv import dotenv_values
487
505
except ImportError as e :
0 commit comments