Typed registry approach

Added in version 2.0.0.

How to use

Define settings using a subclass of TypedSettingRegistry and helper functions default_setting(), required_setting(), optional_setting(), flag_setting().

Nest registries using nested_settings() .

from typing import final

from omniconf import TypedSettingRegistry, default_setting, nested_settings, required_setting

# Define settings
@final
class ListenConfig(TypedSettingRegistry):
    address = required_setting("listen.address", type=str, help="Listen on this address")
    port = default_setting("listen.port", type=int, default=8081, help="Listen on this port")


@final
class DatabaseConfig(TypedSettingRegistry):
    dsn = required_setting("database.dsn", type=str, help="Database connection dsn")


@final
class ApplicationConfig(TypedSettingRegistry):
    listen = nested_settings(ListenConfig)
    database = nested_settings(DatabaseConfig)


# Load from available backends
conf = ApplicationConfig()
conf.load()

# Use values
db = connect_db(dsn=conf.database.dsn)
start_app(address=conf.listen.address, port=conf.listen.port, db=db)

(Nested) registries are a prime target to be passed around as parameters:

def connect_db(conf: DatabaseConfig) -> DbConnection:
    return do_actual_db_connection(dsn=conf.dsn)

def start_app(conf: ListenConfig, db: DbConnection) -> None:
    do_actual_start_app(address=conf.address, port=conf.port, db=db)

conf = ApplicationConfig()
conf.load()

db = connect_db(conf.database)
start_app(conf.listen, db)

Defining a registry

class omniconf.TypedSettingRegistry[source]

A specialized version of SettingRegistry that allows registering Setting s by defining them in a class hierarchy with proper Python typing support.

clear() → None[source]

Clears all registered Setting s .

Warning: this method is not as useful as it seems, because next load this registry will be empty and load nothing.

See TypedSettingRegistry.unload() instead.

load(backends: Sequence[ConfigBackend] | None = None, autoconfigure_prefix: str | None = None) → None[source]

Loads the registered Setting s using the provided backends.

See ConfigRegistry.load() for details on behaviour.

show_usage(name: str | None = None, top_message: str | None = None, bottom_message: str | None = None, out: TextIO | None = None, exit: int = 0) → None[source]

Convenience method to show pretty argparse usage information on the CLI.

See show_usage() for information on behaviour.

unload() → None[source]

Unloads all values from all registered Setting s .

See ConfigRegistry.clear() for details on behaviour.

Defining settings

omniconf.default_setting(key: str, type: type[_T_co] | Callable[[...], _T_co], default: _T_co, help: str | None = None, sensitive: bool = False) → DefaultSetting[_T_co][source]

Typed Setting that does not require a value and will return a default value when not loaded.

omniconf.required_setting(key: str, type: type[_T_co] | Callable[[...], _T_co], help: str | None = None, sensitive: bool = False) → RequiredSetting[_T_co][source]

Typed Setting that requires a value.

omniconf.optional_setting(key: str, type: type[_T_co] | Callable[[...], _T_co], help: str | None = None, sensitive: bool = False) → OptionalSetting[_T_co][source]

Typed Setting that does not require a value and can return None when not loaded.

omniconf.flag_setting(key: str, default: bool, help: str | None = None, sensitive: bool = False) → DefaultSetting[bool][source]

Typed Setting that gets set to True if the default is set to False and a Trueish value is loaded. Also works the other way around, loading `False` if the default is set to `True`.

omniconf.nested_settings(registry: type[_T_registry]) → _T_registry[source]

A nested TypedSettingRegistry that gets loaded along with its parent.

Debugging

If you’re running into weird behaviour, try setting OMNICONF_DEBUG=1 as environment value. This will cause TypedSettingRegistry to output logs to logging.Logger named omniconf.typed_registry at the debug level.