Skip to content

Pydantic Settings

BaseSettings

BaseSettings(
    __pydantic_self__,
    _case_sensitive=None,
    _env_prefix=None,
    _env_file=ENV_FILE_SENTINEL,
    _env_file_encoding=None,
    _env_ignore_empty=None,
    _env_nested_delimiter=None,
    _env_parse_none_str=None,
    _secrets_dir=None,
    **values
)

Bases: BaseModel

Base class for settings, allowing values to be overridden by environment variables.

This is useful in production for secrets you do not wish to save in code, it plays nicely with docker(-compose), Heroku and any 12 factor app design.

All the below attributes can be set via model_config.

Parameters:

Name Type Description Default
_case_sensitive bool | None

Whether environment variables names should be read with case-sensitivity. Defaults to None.

None
_env_prefix str | None

Prefix for all environment variables. Defaults to None.

None
_env_file DotenvType | None

The env file(s) to load settings values from. Defaults to Path(''), which means that the value from model_config['env_file'] should be used. You can also pass None to indicate that environment variables should not be loaded from an env file.

ENV_FILE_SENTINEL
_env_file_encoding str | None

The env file encoding, e.g. 'latin-1'. Defaults to None.

None
_env_ignore_empty bool | None

Ignore environment variables where the value is an empty string. Default to False.

None
_env_nested_delimiter str | None

The nested env values delimiter. Defaults to None.

None
_env_parse_none_str str | None

The env string value that should be parsed (e.g. "null", "void", "None", etc.) into None type(None). Defaults to None type(None), which means no parsing should occur.

None
_secrets_dir str | Path | None

The secret files directory. Defaults to None.

None
Source code in pydantic_settings/main.py
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
def __init__(
    __pydantic_self__,
    _case_sensitive: bool | None = None,
    _env_prefix: str | None = None,
    _env_file: DotenvType | None = ENV_FILE_SENTINEL,
    _env_file_encoding: str | None = None,
    _env_ignore_empty: bool | None = None,
    _env_nested_delimiter: str | None = None,
    _env_parse_none_str: str | None = None,
    _secrets_dir: str | Path | None = None,
    **values: Any,
) -> None:
    # Uses something other than `self` the first arg to allow "self" as a settable attribute
    super().__init__(
        **__pydantic_self__._settings_build_values(
            values,
            _case_sensitive=_case_sensitive,
            _env_prefix=_env_prefix,
            _env_file=_env_file,
            _env_file_encoding=_env_file_encoding,
            _env_ignore_empty=_env_ignore_empty,
            _env_nested_delimiter=_env_nested_delimiter,
            _env_parse_none_str=_env_parse_none_str,
            _secrets_dir=_secrets_dir,
        )
    )

settings_customise_sources classmethod

settings_customise_sources(
    settings_cls,
    init_settings,
    env_settings,
    dotenv_settings,
    file_secret_settings,
)

Define the sources and their order for loading the settings values.

Parameters:

Name Type Description Default
settings_cls type[BaseSettings]

The Settings class.

required
init_settings PydanticBaseSettingsSource

The InitSettingsSource instance.

required
env_settings PydanticBaseSettingsSource

The EnvSettingsSource instance.

required
dotenv_settings PydanticBaseSettingsSource

The DotEnvSettingsSource instance.

required
file_secret_settings PydanticBaseSettingsSource

The SecretsSettingsSource instance.

required

Returns:

Type Description
tuple[PydanticBaseSettingsSource, ...]

A tuple containing the sources and their order for loading the settings values.

Source code in pydantic_settings/main.py
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
@classmethod
def settings_customise_sources(
    cls,
    settings_cls: type[BaseSettings],
    init_settings: PydanticBaseSettingsSource,
    env_settings: PydanticBaseSettingsSource,
    dotenv_settings: PydanticBaseSettingsSource,
    file_secret_settings: PydanticBaseSettingsSource,
) -> tuple[PydanticBaseSettingsSource, ...]:
    """
    Define the sources and their order for loading the settings values.

    Args:
        settings_cls: The Settings class.
        init_settings: The `InitSettingsSource` instance.
        env_settings: The `EnvSettingsSource` instance.
        dotenv_settings: The `DotEnvSettingsSource` instance.
        file_secret_settings: The `SecretsSettingsSource` instance.

    Returns:
        A tuple containing the sources and their order for loading the settings values.
    """
    return init_settings, env_settings, dotenv_settings, file_secret_settings

DotEnvSettingsSource

DotEnvSettingsSource(
    settings_cls,
    env_file=ENV_FILE_SENTINEL,
    env_file_encoding=None,
    case_sensitive=None,
    env_prefix=None,
    env_nested_delimiter=None,
    env_ignore_empty=None,
    env_parse_none_str=None,
)

Bases: EnvSettingsSource

Source class for loading settings values from env files.

Source code in pydantic_settings/sources.py
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
def __init__(
    self,
    settings_cls: type[BaseSettings],
    env_file: DotenvType | None = ENV_FILE_SENTINEL,
    env_file_encoding: str | None = None,
    case_sensitive: bool | None = None,
    env_prefix: str | None = None,
    env_nested_delimiter: str | None = None,
    env_ignore_empty: bool | None = None,
    env_parse_none_str: str | None = None,
) -> None:
    self.env_file = env_file if env_file != ENV_FILE_SENTINEL else settings_cls.model_config.get('env_file')
    self.env_file_encoding = (
        env_file_encoding if env_file_encoding is not None else settings_cls.model_config.get('env_file_encoding')
    )
    super().__init__(
        settings_cls, case_sensitive, env_prefix, env_nested_delimiter, env_ignore_empty, env_parse_none_str
    )

EnvSettingsSource

EnvSettingsSource(
    settings_cls,
    case_sensitive=None,
    env_prefix=None,
    env_nested_delimiter=None,
    env_ignore_empty=None,
    env_parse_none_str=None,
)

Bases: PydanticBaseEnvSettingsSource

Source class for loading settings values from environment variables.

Source code in pydantic_settings/sources.py
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
def __init__(
    self,
    settings_cls: type[BaseSettings],
    case_sensitive: bool | None = None,
    env_prefix: str | None = None,
    env_nested_delimiter: str | None = None,
    env_ignore_empty: bool | None = None,
    env_parse_none_str: str | None = None,
) -> None:
    super().__init__(settings_cls, case_sensitive, env_prefix, env_ignore_empty, env_parse_none_str)
    self.env_nested_delimiter = (
        env_nested_delimiter if env_nested_delimiter is not None else self.config.get('env_nested_delimiter')
    )
    self.env_prefix_len = len(self.env_prefix)

    self.env_vars = self._load_env_vars()

get_field_value

get_field_value(field, field_name)

Gets the value for field from environment variables and a flag to determine whether value is complex.

Parameters:

Name Type Description Default
field FieldInfo

The field.

required
field_name str

The field name.

required

Returns:

Type Description
tuple[Any, str, bool]

A tuple contains the key, value if the file exists otherwise None, and a flag to determine whether value is complex.

Source code in pydantic_settings/sources.py
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
def get_field_value(self, field: FieldInfo, field_name: str) -> tuple[Any, str, bool]:
    """
    Gets the value for field from environment variables and a flag to determine whether value is complex.

    Args:
        field: The field.
        field_name: The field name.

    Returns:
        A tuple contains the key, value if the file exists otherwise `None`, and
            a flag to determine whether value is complex.
    """

    env_val: str | None = None
    for field_key, env_name, value_is_complex in self._extract_field_info(field, field_name):
        env_val = self.env_vars.get(env_name)
        if env_val is not None:
            break

    return env_val, field_key, value_is_complex

prepare_field_value

prepare_field_value(
    field_name, field, value, value_is_complex
)

Prepare value for the field.

  • Extract value for nested field.
  • Deserialize value to python object for complex field.

Parameters:

Name Type Description Default
field FieldInfo

The field.

required
field_name str

The field name.

required

Returns:

Type Description
Any

A tuple contains prepared value for the field.

Raises:

Type Description
ValuesError

When There is an error in deserializing value for complex field.

Source code in pydantic_settings/sources.py
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
def prepare_field_value(self, field_name: str, field: FieldInfo, value: Any, value_is_complex: bool) -> Any:
    """
    Prepare value for the field.

    * Extract value for nested field.
    * Deserialize value to python object for complex field.

    Args:
        field: The field.
        field_name: The field name.

    Returns:
        A tuple contains prepared value for the field.

    Raises:
        ValuesError: When There is an error in deserializing value for complex field.
    """
    is_complex, allow_parse_failure = self._field_is_complex(field)
    if is_complex or value_is_complex:
        if value is None:
            # field is complex but no value found so far, try explode_env_vars
            env_val_built = self.explode_env_vars(field_name, field, self.env_vars)
            if env_val_built:
                return env_val_built
        else:
            # field is complex and there's a value, decode that as JSON, then add explode_env_vars
            try:
                value = self.decode_complex_value(field_name, field, value)
            except ValueError as e:
                if not allow_parse_failure:
                    raise e

            if isinstance(value, dict):
                return deep_update(value, self.explode_env_vars(field_name, field, self.env_vars))
            else:
                return value
    elif value is not None:
        # simplest case, field is not complex, we only need to add the value if it was found
        return value

next_field staticmethod

next_field(field, key)

Find the field in a sub model by key(env name)

By having the following models:

```py
class SubSubModel(BaseSettings):
    dvals: Dict

class SubModel(BaseSettings):
    vals: list[str]
    sub_sub_model: SubSubModel

class Cfg(BaseSettings):
    sub_model: SubModel
```
Then

next_field(sub_model, 'vals') Returns the vals field of SubModel class next_field(sub_model, 'sub_sub_model') Returns sub_sub_model field of SubModel class

Parameters:

Name Type Description Default
field FieldInfo | Any | None

The field.

required
key str

The key (env name).

required

Returns:

Type Description
FieldInfo | None

Field if it finds the next field otherwise None.

Source code in pydantic_settings/sources.py
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
@staticmethod
def next_field(field: FieldInfo | Any | None, key: str) -> FieldInfo | None:
    """
    Find the field in a sub model by key(env name)

    By having the following models:

        ```py
        class SubSubModel(BaseSettings):
            dvals: Dict

        class SubModel(BaseSettings):
            vals: list[str]
            sub_sub_model: SubSubModel

        class Cfg(BaseSettings):
            sub_model: SubModel
        ```

    Then:
        next_field(sub_model, 'vals') Returns the `vals` field of `SubModel` class
        next_field(sub_model, 'sub_sub_model') Returns `sub_sub_model` field of `SubModel` class

    Args:
        field: The field.
        key: The key (env name).

    Returns:
        Field if it finds the next field otherwise `None`.
    """
    if not field:
        return None

    annotation = field.annotation if isinstance(field, FieldInfo) else field
    if origin_is_union(get_origin(annotation)) or isinstance(annotation, WithArgsTypes):
        for type_ in get_args(annotation):
            type_has_key = EnvSettingsSource.next_field(type_, key)
            if type_has_key:
                return type_has_key
    elif is_model_class(annotation) and annotation.model_fields.get(key):
        return annotation.model_fields[key]

    return None

explode_env_vars

explode_env_vars(field_name, field, env_vars)

Process env_vars and extract the values of keys containing env_nested_delimiter into nested dictionaries.

This is applied to a single field, hence filtering by env_var prefix.

Parameters:

Name Type Description Default
field_name str

The field name.

required
field FieldInfo

The field.

required
env_vars Mapping[str, str | None]

Environment variables.

required

Returns:

Type Description
dict[str, Any]

A dictionary contains extracted values from nested env values.

Source code in pydantic_settings/sources.py
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
def explode_env_vars(self, field_name: str, field: FieldInfo, env_vars: Mapping[str, str | None]) -> dict[str, Any]:
    """
    Process env_vars and extract the values of keys containing env_nested_delimiter into nested dictionaries.

    This is applied to a single field, hence filtering by env_var prefix.

    Args:
        field_name: The field name.
        field: The field.
        env_vars: Environment variables.

    Returns:
        A dictionary contains extracted values from nested env values.
    """
    prefixes = [
        f'{env_name}{self.env_nested_delimiter}' for _, env_name, _ in self._extract_field_info(field, field_name)
    ]
    result: dict[str, Any] = {}
    for env_name, env_val in env_vars.items():
        if not any(env_name.startswith(prefix) for prefix in prefixes):
            continue
        # we remove the prefix before splitting in case the prefix has characters in common with the delimiter
        env_name_without_prefix = env_name[self.env_prefix_len :]
        _, *keys, last_key = env_name_without_prefix.split(self.env_nested_delimiter)
        env_var = result
        target_field: FieldInfo | None = field
        for key in keys:
            target_field = self.next_field(target_field, key)
            env_var = env_var.setdefault(key, {})

        # get proper field with last_key
        target_field = self.next_field(target_field, last_key)

        # check if env_val maps to a complex field and if so, parse the env_val
        if target_field and env_val:
            is_complex, allow_json_failure = self._field_is_complex(target_field)
            if is_complex:
                try:
                    env_val = self.decode_complex_value(last_key, target_field, env_val)
                except ValueError as e:
                    if not allow_json_failure:
                        raise e
        env_var[last_key] = env_val

    return result

InitSettingsSource

InitSettingsSource(settings_cls, init_kwargs)

Bases: PydanticBaseSettingsSource

Source class for loading values provided during settings class initialization.

Source code in pydantic_settings/sources.py
159
160
161
def __init__(self, settings_cls: type[BaseSettings], init_kwargs: dict[str, Any]):
    self.init_kwargs = init_kwargs
    super().__init__(settings_cls)

JsonConfigSettingsSource

JsonConfigSettingsSource(
    settings_cls,
    json_file=DEFAULT_PATH,
    json_file_encoding=None,
)

Bases: InitSettingsSource, ConfigFileSourceMixin

A source class that loads variables from a JSON file

Source code in pydantic_settings/sources.py
738
739
740
741
742
743
744
745
746
747
748
749
750
751
def __init__(
    self,
    settings_cls: type[BaseSettings],
    json_file: PathType | None = DEFAULT_PATH,
    json_file_encoding: str | None = None,
):
    self.json_file_path = json_file if json_file != DEFAULT_PATH else settings_cls.model_config.get('json_file')
    self.json_file_encoding = (
        json_file_encoding
        if json_file_encoding is not None
        else settings_cls.model_config.get('json_file_encoding')
    )
    self.json_data = self._read_files(self.json_file_path)
    super().__init__(settings_cls, self.json_data)

PydanticBaseSettingsSource

PydanticBaseSettingsSource(settings_cls)

Bases: ABC

Abstract base class for settings sources, every settings source classes should inherit from it.

Source code in pydantic_settings/sources.py
86
87
88
def __init__(self, settings_cls: type[BaseSettings]):
    self.settings_cls = settings_cls
    self.config = settings_cls.model_config

get_field_value abstractmethod

get_field_value(field, field_name)

Gets the value, the key for model creation, and a flag to determine whether value is complex.

This is an abstract method that should be overridden in every settings source classes.

Parameters:

Name Type Description Default
field FieldInfo

The field.

required
field_name str

The field name.

required

Returns:

Type Description
tuple[Any, str, bool]

A tuple contains the key, value and a flag to determine whether value is complex.

Source code in pydantic_settings/sources.py
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
@abstractmethod
def get_field_value(self, field: FieldInfo, field_name: str) -> tuple[Any, str, bool]:
    """
    Gets the value, the key for model creation, and a flag to determine whether value is complex.

    This is an abstract method that should be overridden in every settings source classes.

    Args:
        field: The field.
        field_name: The field name.

    Returns:
        A tuple contains the key, value and a flag to determine whether value is complex.
    """
    pass

field_is_complex

field_is_complex(field)

Checks whether a field is complex, in which case it will attempt to be parsed as JSON.

Parameters:

Name Type Description Default
field FieldInfo

The field.

required

Returns:

Type Description
bool

Whether the field is complex.

Source code in pydantic_settings/sources.py
106
107
108
109
110
111
112
113
114
115
116
def field_is_complex(self, field: FieldInfo) -> bool:
    """
    Checks whether a field is complex, in which case it will attempt to be parsed as JSON.

    Args:
        field: The field.

    Returns:
        Whether the field is complex.
    """
    return _annotation_is_complex(field.annotation, field.metadata)

prepare_field_value

prepare_field_value(
    field_name, field, value, value_is_complex
)

Prepares the value of a field.

Parameters:

Name Type Description Default
field_name str

The field name.

required
field FieldInfo

The field.

required
value Any

The value of the field that has to be prepared.

required
value_is_complex bool

A flag to determine whether value is complex.

required

Returns:

Type Description
Any

The prepared value.

Source code in pydantic_settings/sources.py
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
def prepare_field_value(self, field_name: str, field: FieldInfo, value: Any, value_is_complex: bool) -> Any:
    """
    Prepares the value of a field.

    Args:
        field_name: The field name.
        field: The field.
        value: The value of the field that has to be prepared.
        value_is_complex: A flag to determine whether value is complex.

    Returns:
        The prepared value.
    """
    if value is not None and (self.field_is_complex(field) or value_is_complex):
        return self.decode_complex_value(field_name, field, value)
    return value

decode_complex_value

decode_complex_value(field_name, field, value)

Decode the value for a complex field

Parameters:

Name Type Description Default
field_name str

The field name.

required
field FieldInfo

The field.

required
value Any

The value of the field that has to be prepared.

required

Returns:

Type Description
Any

The decoded value for further preparation

Source code in pydantic_settings/sources.py
135
136
137
138
139
140
141
142
143
144
145
146
147
def decode_complex_value(self, field_name: str, field: FieldInfo, value: Any) -> Any:
    """
    Decode the value for a complex field

    Args:
        field_name: The field name.
        field: The field.
        value: The value of the field that has to be prepared.

    Returns:
        The decoded value for further preparation
    """
    return json.loads(value)

SecretsSettingsSource

SecretsSettingsSource(
    settings_cls,
    secrets_dir=None,
    case_sensitive=None,
    env_prefix=None,
    env_ignore_empty=None,
    env_parse_none_str=None,
)

Bases: PydanticBaseEnvSettingsSource

Source class for loading settings values from secret files.

Source code in pydantic_settings/sources.py
352
353
354
355
356
357
358
359
360
361
362
def __init__(
    self,
    settings_cls: type[BaseSettings],
    secrets_dir: str | Path | None = None,
    case_sensitive: bool | None = None,
    env_prefix: str | None = None,
    env_ignore_empty: bool | None = None,
    env_parse_none_str: str | None = None,
) -> None:
    super().__init__(settings_cls, case_sensitive, env_prefix, env_ignore_empty, env_parse_none_str)
    self.secrets_dir = secrets_dir if secrets_dir is not None else self.config.get('secrets_dir')

find_case_path classmethod

find_case_path(dir_path, file_name, case_sensitive)

Find a file within path's directory matching filename, optionally ignoring case.

Parameters:

Name Type Description Default
dir_path Path

Directory path.

required
file_name str

File name.

required
case_sensitive bool

Whether to search for file name case sensitively.

required

Returns:

Type Description
Path | None

Whether file path or None if file does not exist in directory.

Source code in pydantic_settings/sources.py
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
@classmethod
def find_case_path(cls, dir_path: Path, file_name: str, case_sensitive: bool) -> Path | None:
    """
    Find a file within path's directory matching filename, optionally ignoring case.

    Args:
        dir_path: Directory path.
        file_name: File name.
        case_sensitive: Whether to search for file name case sensitively.

    Returns:
        Whether file path or `None` if file does not exist in directory.
    """
    for f in dir_path.iterdir():
        if f.name == file_name:
            return f
        elif not case_sensitive and f.name.lower() == file_name.lower():
            return f
    return None

get_field_value

get_field_value(field, field_name)

Gets the value for field from secret file and a flag to determine whether value is complex.

Parameters:

Name Type Description Default
field FieldInfo

The field.

required
field_name str

The field name.

required

Returns:

Type Description
tuple[Any, str, bool]

A tuple contains the key, value if the file exists otherwise None, and a flag to determine whether value is complex.

Source code in pydantic_settings/sources.py
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
def get_field_value(self, field: FieldInfo, field_name: str) -> tuple[Any, str, bool]:
    """
    Gets the value for field from secret file and a flag to determine whether value is complex.

    Args:
        field: The field.
        field_name: The field name.

    Returns:
        A tuple contains the key, value if the file exists otherwise `None`, and
            a flag to determine whether value is complex.
    """

    for field_key, env_name, value_is_complex in self._extract_field_info(field, field_name):
        path = self.find_case_path(self.secrets_path, env_name, self.case_sensitive)
        if not path:
            # path does not exist, we currently don't return a warning for this
            continue

        if path.is_file():
            return path.read_text().strip(), field_key, value_is_complex
        else:
            warnings.warn(
                f'attempted to load secret file "{path}" but found a {path_type_label(path)} instead.',
                stacklevel=4,
            )

    return None, field_key, value_is_complex

TomlConfigSettingsSource

TomlConfigSettingsSource(
    settings_cls, toml_file=DEFAULT_PATH
)

Bases: InitSettingsSource, ConfigFileSourceMixin

A source class that loads variables from a JSON file

Source code in pydantic_settings/sources.py
763
764
765
766
767
768
769
770
def __init__(
    self,
    settings_cls: type[BaseSettings],
    toml_file: PathType | None = DEFAULT_PATH,
):
    self.toml_file_path = toml_file if toml_file != DEFAULT_PATH else settings_cls.model_config.get('toml_file')
    self.toml_data = self._read_files(self.toml_file_path)
    super().__init__(settings_cls, self.toml_data)

YamlConfigSettingsSource

YamlConfigSettingsSource(
    settings_cls,
    yaml_file=DEFAULT_PATH,
    yaml_file_encoding=None,
)

Bases: InitSettingsSource, ConfigFileSourceMixin

A source class that loads variables from a yaml file

Source code in pydantic_settings/sources.py
785
786
787
788
789
790
791
792
793
794
795
796
797
798
def __init__(
    self,
    settings_cls: type[BaseSettings],
    yaml_file: PathType | None = DEFAULT_PATH,
    yaml_file_encoding: str | None = None,
):
    self.yaml_file_path = yaml_file if yaml_file != DEFAULT_PATH else settings_cls.model_config.get('yaml_file')
    self.yaml_file_encoding = (
        yaml_file_encoding
        if yaml_file_encoding is not None
        else settings_cls.model_config.get('yaml_file_encoding')
    )
    self.yaml_data = self._read_files(self.yaml_file_path)
    super().__init__(settings_cls, self.yaml_data)