Config

This module provides a base class for configs that can be loaded from files, environment variables or command line arguments (via yuio.app).

Derive your config from the Config base class. Inside of its body, define config fields using type annotations, just like dataclasses:

class AppConfig(Config):
    #: trained model to execute
    model: pathlib.Path

    #: input data for the model
    data: pathlib.Path

    #: enable or disable gpu
    use_gpu: bool = True

Then use config’s constructors and the update() method to load it from various sources:

# Load config from a file.
config = config.load_from_json_file('~/.my_app_cfg.json')

# Update config with values from env.
config.update(AppConfig.load_from_env())

Config base class

class yuio.config.Config(*args, **kwargs)[source]

Base class for configs.

Pass keyword args to set fields, or pass another config to copy it:

Config(config1, config2, ..., field1=value1, ...)

Upon creation, all fields that aren’t explicitly initialized and don’t have defaults are considered missing. Accessing them will raise AttributeError.

update(other: _Self | Dict[str, Any], /)[source]

Update fields in this config with fields from another config.

This function is similar to dict.update().

Nested configs are updated recursively.

classmethod load_from_env(prefix: str = '') _Self[source]

Load config from environment variables.

classmethod load_from_json_file(path: str | Path, /, *, ignore_unknown_fields: bool = False, ignore_missing_file: bool = False) _Self[source]

Load config from a .json file.

classmethod load_from_yaml_file(path: str | Path, /, *, ignore_unknown_fields: bool = False, ignore_missing_file: bool = False) _Self[source]

Load config from a .yaml file.

This requires PyYaml package to be installed.

classmethod load_from_toml_file(path: str | Path, /, *, ignore_unknown_fields: bool = False, ignore_missing_file: bool = False) _Self[source]

Load config from a .toml file.

This requires tomllib or toml package to be installed.

classmethod load_from_parsed_file(parsed: Dict[str, object], /, *, ignore_unknown_fields: bool = False) _Self[source]

Load config from parsed config file.

This method takes a dict with arbitrary values that you’d get from parsing type-rich configs such as yaml or json.

For example:

with open('conf.yaml') as file:
    config = Config.load_from_parsed_file(yaml.load(file))

Advanced field configuration

By default, Config infers names for env variables and flags, appropriate parsers, and other things from field’s name, type hint, and comments.

If you need to override them, theres the field() function:

yuio.config.field(default: ~typing.Any = _Placeholders.MISSING, *, parser: ~yuio.parse.Parser[~typing.Any] | None = None, help: str | ~typing.Literal[<disabled>] | None = None, env: str | ~typing.Literal[<disabled>] | None = None, flags: str | ~typing.List[str] | ~typing.Literal[<positional>] | ~typing.Literal[<disabled>] | None = None, completer: ~yuio.complete.Completer | None = None) Any[source]

Field descriptor, used for additional configuration of fields.

Parameters:
  • default – default value for config field, used if field is missing from config.

  • parser – parser that will be used to parse env vars, configs and CLI arguments.

  • help

    Help message that will be used in CLI argument description.

    Pass DISABLED to remove this field from CLI help.

    By default, help message is inferred from comments right above the field definition (comments must start with #:).

    Help messages are formatted using Markdown (see yuio.md).

  • env

    Name of environment variable that will be used for this field.

    Pass DISABLED to disable loading this field form environment variable.

    Pass an empty string to disable prefixing nested config variables.

  • flags

    List of names (or a single name) of CLI flags that will be used for this field.

    This setting is used with yuio.app to configure CLI arguments parsers.

    Pass DISABLED to disable loading this field form CLI arguments.

    Pass POSITIONAL to make this argument positional (only in apps, see yuio.app).

    Pass an empty string to disable prefixing nested config flags.

  • completer

    completer that will be used for autocompletion in CLI.

    This setting is used with yuio.app to configure CLI arguments parsers.

yuio.DISABLED: Literal[<disabled>] = _Placeholders.DISABLED

Indicates that some functionality is disabled.

yuio.MISSING: Literal[<missing>] = _Placeholders.MISSING

Indicates that some value is missing.

yuio.POSITIONAL: Literal[<positional>] = _Placeholders.POSITIONAL

Used with field() to enable positional arguments.

There is also a helper for inlining nested configs:

yuio.config.inline(help: str | ~typing.Literal[<disabled>] | None = None) Any[source]

A shortcut for inlining nested configs.

Equivalent to calling field() with env and flags set to an empty string.

Nesting configs

You can nest configs to achieve modularity:

class ExecutorConfig(Config):
    #: number of threads to use
    threads: int

    #: enable or disable gpu
    use_gpu: bool = True

class AppConfig(Config):
    #: executor parameters
    executor: ExecutorConfig

    #: trained model to execute
    model: pathlib.Path

To initialise a nested config, pass either an instance of if or a dict with its variables to the config’s constructor:

# The following lines are equivalent:
config = AppConfig(executor={'threads': 16})
config = AppConfig(executor=ExecutorConfig(threads=16))

Parsing environment variables

You can load config from environment through load_from_env().

Names of environment variables are just capitalized field names. Use the field() function to override them:

class KillCmdConfig(Config):
    # Will be loaded from `SIGNAL`.
    signal: int

    # Will be loaded from `PROCESS_ID`.
    pid: int = field(env='PROCESS_ID')

In nested configs, environment variable names are prefixed with name of a field that contains the nested config:

class BigConfig(Config):
    # `kill_cmd.signal` will be loaded from `KILL_CMD_SIGNAL`.
    kill_cmd: KillCmdConfig

    # `copy_cmd_2.signal` will be loaded from `KILL_SIGNAL`.
    kill_cmd_2: KillCmdConfig = field(env='KILL')

    # `kill_cmd_3.signal` will be loaded from `SIGNAL`.
    kill_cmd_3: KillCmdConfig = field(env='')

You can also disable loading a field from an environment altogether:

class Config(Config):
    # Will not be loaded from env.
    pid: int = field(env=yuio.DISABLED)

To prefix all variable names with some string, pass the prefix parameter to the load_from_env() function:

# config.kill_cmd.field will be loaded
# from `MY_APP_KILL_CMD_SIGNAL`
config = BigConfig.load_from_env('MY_APP')

Parsing config files

You can load config from structured config files, such as json, yaml or toml:

class ExecutorConfig(Config):
    threads: int
    use_gpu: bool = True

class AppConfig(Config):
    executor: ExecutorConfig
    model: pathlib.Path

config = AppConfig.load_from_json_file('~/.my_app_cfg.json')

In this example, contents of the above config would be:

{
    "executor": {
        "threads": 16,
        "use_gpu": true
    },
    "model": "/path/to/model"
}

Note that, unlike with environment variables, there is no way to inline nested configs.