Loaders

A “loader” is defined as a class which implements the dataclass_settings.Loader protocol. i.e. a type with a method load(context: Context).

Builtins

The library ships with a few loaders. Additional 1st party loaders will be accepted, particularly if they require no external dependencies to implement. Any candidate loader which requires additional dependencies (for example, AWS Secrets Manager, which would imply boto3) will be added as optional extras.

Env

Env as the name suggests, loads environment variable values.

from __future__ import annotations
from dataclass_settings import load_settings, Env, Secret
from dataclasses import dataclass

@dataclass
class Example:
    env: Annotated[str, Env("ENVIRONMENT")] = "local"
    dsn: Annotated[str, Env("DSN"), Secret('dsn')] = "dsn://"

    sub_config: SubConfig


@dataclass
class SubConfig:
    nested: Annotated[int, Env("NESTED")] = "4"


example: Example = load_settings(Example)

# or, if you want `nested` to be `SUB_CONFIG_NESTED`
example: Example = load_settings(Example, nested_delimiter='_')
class dataclass_settings.loaders.Env(*env_vars)

Abstract base class for generic types.

A generic type is typically declared by inheriting from this class parameterized with one or more type variables. For example, a generic mapping type might be defined as:

class Mapping(Generic[KT, VT]):
    def __getitem__(self, key: KT) -> VT:
        ...
    # Etc.

This class can then be used as follows:

def lookup_name(mapping: Mapping[KT, VT], key: KT, default: VT) -> VT:
    try:
        return mapping[key]
    except KeyError:
        return default
Parameters:

env_vars (str)

env_vars: tuple[str, Ellipsis]
load(context, state)
Parameters:
Return type:

Any

classmethod load_with(*, env=None)
Parameters:

env (EnvLike | None)

Return type:

dataclass_settings.loader.DictState

Secret

Secret point to files which contain the “secret” value in question. This is commonly used in containers/Docker where the location containing the secret is being mounted into the container at runtime.

The default root location is /run/secrets.

from __future__ import annotations
from dataclass_settings import load_settings, Secret
from dataclasses import dataclass

@dataclass
class Example:
    password: Annotated[str, Secret("password")]

example: Example = load_settings(Example)

Note

Note, if the root location of your secrets is not the default one, or it changes based on runtime characteristics (running with Docker Secrets, versus inside k8s) it may be inconvenient to individually annotate each item.

It is possible to centralize such configuration and decouple it from the static definitions of those secrets.

@dataclass
class Example:
    password: Annotated[str, Secret("password")]


dir = "/run/secrets"
if in_k8s:
    dir = dir="/foo/bar"

loader = Secret.load_with(dir=dir)
example: Example = load_settings(Example, extra_loaders=loader)

Note

Secret accepts both multiple secret names, as well as multiple root locations. For example Secret("password", "pass", dir=("/run/secrets", "/foo/bar")). They will be searched in order until the first value which resolves.

class dataclass_settings.loaders.Secret(*names, dir=None)

Abstract base class for generic types.

A generic type is typically declared by inheriting from this class parameterized with one or more type variables. For example, a generic mapping type might be defined as:

class Mapping(Generic[KT, VT]):
    def __getitem__(self, key: KT) -> VT:
        ...
    # Etc.

This class can then be used as follows:

def lookup_name(mapping: Mapping[KT, VT], key: KT, default: VT) -> VT:
    try:
        return mapping[key]
    except KeyError:
        return default
Parameters:
  • names (str)

  • dir (Sequence[dataclass_settings.loader.PathLike] | None)

dir: Sequence[pathlib.PurePath] | None = None
load(context, state)
Parameters:
Return type:

Any

classmethod load_with(*, dir=None)
Parameters:

dir (Sequence[dataclass_settings.loader.PathLike] | None)

Return type:

SecretState

names: tuple[str, Ellipsis] = ()
with_dir(*dir)
Parameters:

dir (str)

Return type:

typing_extensions.Self

with_name(*names)
Parameters:

names (str)

Return type:

typing_extensions.Self

Toml

Toml loads values from a toml file. The key uses toml’s nested naming syntax to target deeply nested keys.

from __future__ import annotations
from dataclass_settings import load_settings, Toml
from dataclasses import dataclass

## pyproject.toml
# [project]
# name = "dataclass-settings"

@dataclass
class Example:
    password: Annotated[str, Toml("project.name", file='pyproject.toml')]

example: Example = load_settings(Example)

Similarly to Secret, the loader can be centrally specified in order to target the same file across a single invocation.

from __future__ import annotations
from dataclass_settings import load_settings, Toml
from dataclasses import dataclass

## pyproject.toml
# [project]
# name = "dataclass-settings"

@dataclass
class Example:
    password: Annotated[str, Toml("project.name")]

loader = Toml.load_with(file="pyproject.toml")
example: Example = load_settings(Example, extra_loaders=loader)

Custom/External Loaders

Defining your own loader is relatively simple:

from typing import Annotated
from pydantic import BaseModel
from dataclass_settings import Loader, load_settings, Context

class FooLoader(Loader):
  prefix: str

  def load(self, context: Context):
    """Adds a prefix str to the end of the field name."""
    return self.prefix + context.field_name


class Config(BaseModel):
  foo: Annotated[str, FooLoader('pref_')]



config: Config = load_settings(Config, extra_loaders=[FooLoader])
assert config == Config(foo='pref_foo')

A loader can accept any input values required to look up the setting value in question.

The Context object contains additional information about the loading context, such as:

  • context.field_name: The name of the field being loaded

  • context.path: The path from the root object to the currently loaded object

  • context.get_name: Automatically conjoins the path and name (using nested_delimiter) if appropriate

  • context.get_state: Returns loader-specific state.

Loader.init

If your loader requires caching state some state between multiple load calls (such as the above “AWS Secrets Manager” example, where you might want to cache the boto3.Session object), you will need to define an init staticmethod/classmethod.

The return value of that function will be recorded into the Context, and context.get_state(self) from inside a Lodder instance will return that state.

from dataclass_settings import Loader, load_settings

class Foo(Loader):
    prefix: str

    @staticmethod
    def init():
        return {'woah': True}

    def load(self, context: Context):
        state = context.get_state(self)
        assert state == {'woah': True}
        ...