Skip to main content

Hierarchical config loader

Project description

CarlyleConfig

Small Hierarchical Configuration loader

PyPI version

Examples

Simple example

import argparse

from carlyleconfig import deriveconfig, derive
from carlyleconfig.plugins import ArgParsePlugin


# Load the ArgParsePlugin and attach it to the default derive object.
# this gives us access to the derive.field().with_argparse(...) method.
# The with_constant and with_env_var methods are plugins that are loaded
# by default since they are so simple.
PARSER_PLUGIN = ArgParsePlugin()
derive.plugins = [PARSER_PLUGIN]


@deriveconfig
class Config:
    # Derive the debug field from the following sources in order:
    # 1) an argparse argument named --debug.
    #    Defaults to None if not provided so we can fall through to the next case
    #    if not provided. Uses argparse's store_true action if it is provided so we get a bool
    #    value.
    # 2) the EXAMPLE_DEBUG environment variable. The string env var is cast to a bool.
    #    If not present None will be returned, falling through to the next case.
    # 3) a constant value of False, this will always provide a value and should be treated
    #    as the last fallback case.
    debug: bool = (
        derive.field()
        .from_argparse("--debug", action="store_true", default=None)
        .from_env_var("EXAMPLE_DEBUG", cast=bool)
        .from_constant(False)
    )


def main():
    parser = argparse.ArgumentParser()
    # Binding the parser to the ArgParsePlugin allows it to fill out extra
    # arguments, and intercept the parse_args() call.
    PARSER_PLUGIN.bind_parser(parser)

    # Since we don't have any other arguments we don't need to save the args.
    # the ArgParsePlugin intercepts the call and gets a copy of the parsed args
    # to use when populating the Config object.
    parser.parse_args()

    # Instantiating a Config object resolves the derive chains into concrete values.
    # Explicit overrides can be provided as well, such as Config(debug=True).
    config = Config()
    print(f'DEBUG: {config.debug}')


if __name__ == "__main__":
    main()
$ python samples/example.py
DEBUG: False
$ EXAMPLE_DEBUG=1 python samples/example.py
DEBUG: True
$ python samples/example.py --debug
DEBUG: True

Loading from files

This example adds a file as an additional source of configuration. And the added indirection of allowing config to change where the config file is loaded from.

import argparse

from carlyleconfig import deriveconfig, derive
from carlyleconfig.plugins import ArgParsePlugin


# Load the ArgParsePlugin and attach it to the default derive object.
# this gives us access to the derive.field().with_argparse(...) method.
# The with_constant, with_file, and with_env_var methods are plugins that are
# loaded by default since they require no extra steps.
PARSER_PLUGIN = ArgParsePlugin()
derive.plugins = [PARSER_PLUGIN]


@deriveconfig
class Config:
    # Derive the filepath field from the first non-None source below:
    # 1) The command line argument --config-path. If not provided it will be
    #    None falling through to the next case.
    # 2) The environment variable EXAMPLE_CONFIG_PATH if present.
    # 3) Constant value of ~/.default-config.json
    filepath: str = (
        derive.field()
        .from_argparse("--config-path", default=None)
        .from_env_var('EXAMPLE_CONFIG_PATH')
        .from_constant("~/.default-config.json")
    )

    # Derive the debug field from the following sources in order:
    # 1) an argparse argument named --debug.
    #    Defaults to None if not provided so we can fall through to the next case
    #    if not provided. Uses argparse's store_true action if it is provided so we get a bool
    #    value.
    # 2) the EXAMPLE_DEBUG environment variable. The string env var is cast to a bool.
    #    If not present None will be returned, falling through to the next case.
    # 3) A file named filepath. filepath is a reference to the prior config key in this class.
    #    Since it is loaded first we can ues a reference to it here as if it were a concrete
    #    value.
    #    Once the file is read it will be parsed as json by the from_json_file method. Finally
	#    the object will be searched using the "DEBUG" jmespath expression, and the result of
	#    that is returned.
    # 4) a constant value of False, this will always provide a value and should be treated
    #    as the last fallback case.
    debug: bool = (
        derive.field()
        .from_argparse("--debug", action="store_true", default=None)
        .from_env_var("EXAMPLE_DEBUG", cast=bool)
        .from_json_file(filepath, jmespath='DEBUG')
        .from_constant(False)
    )

    # Grab the full contents of the config file without any parsing by using
    # the from_file method without any parser/selector.
    # Provide a default of empty string in case the file doesn't exist.
    raw_config_file: str = derive.field().from_file(filepath).from_constant("")


def main():
    parser = argparse.ArgumentParser()
    # Binding the parser to the ArgParsePlugin allows it to fill out extra
    # arguments, and intercept the parse_args() call.
    PARSER_PLUGIN.bind_parser(parser)

    # Since we don't have any other arguments we don't need to save the args.
    # the ArgParsePlugin intercepts the call and gets a copy of the parsed args
    # to use when populating the Config object.
    parser.parse_args()

    # Instantiating a Config object resolves the derive chains into concrete values.
    # Explicit overrides can be provided as well, such as Config(debug=True).
    config = Config()
    print(f"DEBUG: {config.debug}")
    print(f'config file contents: "{config.raw_config_file}"')


if __name__ == "__main__":
    main()
$ python samples/config-file.py
DEBUG: False
config file contents: ""

$ python samples/config-file.py --config-path samples/configs/debug.json
DEBUG: True
config file contents: "{
    "DEBUG": true
}
"
$ python samples/config-file.py --config-path samples/configs/no-debug.json
DEBUG: False
config file contents: "
{
    "DEBUG": false
}
"

$ python samples/config-file.py --config-path samples/configs/missing-config.json
DEBUG: False
config file contents: "{}
"
 python samples/config-file.py --config-path samples/configs/missing-config.json --debug
DEBUG: True
config file contents: "{}
"

$ EXAMPLE_CONFIG_PATH=samples/configs/debug.json python samples/config-file.py
DEBUG: True
config file contents: "{
    "DEBUG": true
}
"

$ EXAMPLE_CONFIG_PATH=samples/configs/debug.json python samples/config-file.py --config-path samples/configs/no-debug.json
DEBUG: False
config file contents: "
{
    "DEBUG": false
}
"

$ EXAMPLE_CONFIG_PATH=samples/configs/debug.json python samples/config-file.py --config-path samples/configs/no-debug.json --debug
DEBUG: True
config file contents: "
{
    "DEBUG": false
}
""

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

carlyleconfig-2025.43.1.tar.gz (22.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

carlyleconfig-2025.43.1-py3-none-any.whl (19.7 kB view details)

Uploaded Python 3

File details

Details for the file carlyleconfig-2025.43.1.tar.gz.

File metadata

  • Download URL: carlyleconfig-2025.43.1.tar.gz
  • Upload date:
  • Size: 22.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for carlyleconfig-2025.43.1.tar.gz
Algorithm Hash digest
SHA256 0e522ecd43932978451decf721d6fdf0be3f9be209a028eb0f689a287f29b871
MD5 c0f4c2d090545f2d480998dc8b42b2c8
BLAKE2b-256 4001002e89631dbb3aae8bfcd9f478b9ed0ffdf3930be1487ee346f4ba6d6233

See more details on using hashes here.

File details

Details for the file carlyleconfig-2025.43.1-py3-none-any.whl.

File metadata

File hashes

Hashes for carlyleconfig-2025.43.1-py3-none-any.whl
Algorithm Hash digest
SHA256 2366c43e92147a31511f0c144dcbc3762cd8936b677813e6e7616b03fbfee273
MD5 4ebeee6950c40bedba34d6062abaa08a
BLAKE2b-256 97178b028adf038b039c1f17b696ffd53dd5c4047400d44d7a412ec8c442b3ba

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page