Skip to main content

Globally scoped configuration with argparse integration

Project description

Effortless Config

PyPI version CircleCI

Globally scoped configuration with argparse integration.

Installation

pip install effortless-config

Rationale

  1. When building machine learning models, I often find myself with a file named config.py that has a bunch of global variables that I reference throughout the codebase.
  2. As the work progresses, I end up with groups of specific configuration settings that correspond to specific experiments.
  3. I want to be able to select configuration group on the command line when I start an experiment.
  4. And I want to be able to override certain settings within that experiment, from the command line.

Basic usage

First, define a class that extends effortless_config.Config and specify your default configuration values inside it:

from effortless_config import Config

class config(Config):  # lowercase "c" optional

    SOME_INTEGER_SETTING = 10
    FLOAT_SETTING = 0.5
    A_BOOLEAN = False
    MY_STRING_SETTING = 'foo'

Then you can refer to these settings elsewhere in your code base:

def main():
    print(f'SOME_INTEGER_SETTING is {config.SOME_INTEGER_SETTING}')
    print(f'FLOAT_SETTING is {config.FLOAT_SETTING}')
    print(f'A_BOOLEAN is {config.A_BOOLEAN}')
    print(f'MY_STRING_SETTING is {config.MY_STRING_SETTING}')

The function config.parse_args() creates an argparse parser from your configuration. If we put the two previous code snippets in a file called basic_example.py and finish it off with

if __name__ == '__main__':
    config.parse_args()
    main()

...we can see the available settings with -h/--help:

$ python basic_example.py --help
usage: basic_example.py [-h] [--some-integer-setting SOME_INTEGER_SETTING]
                        [--float-setting FLOAT_SETTING] [--a-boolean {true,false}]
                        [--my-string-setting MY_STRING_SETTING]

optional arguments:
  -h, --help            show this help message and exit
  --some-integer-setting SOME_INTEGER_SETTING
  --float-setting FLOAT_SETTING
  --a-boolean {true,false}
  --my-string-setting MY_STRING_SETTING

We can then override configuration settings from the command line:

$ python basic_example.py
SOME_INTEGER_SETTING is 10
FLOAT_SETTING is 0.5
A_BOOLEAN is False
MY_STRING_SETTING is foo

$ python basic_example.py --some-integer-setting 1000
SOME_INTEGER_SETTING is 1000
FLOAT_SETTING is 0.5
A_BOOLEAN is False
MY_STRING_SETTING is foo

Using groups

Configuration groups are families of settings that you want to tie together. For example, you might have some machine learning problem for which you have a large model and a small model, and you want to easily switch between the two models without having to specify all parameters on the command line every time.

To specify groups, use the settings(...) function:

from effortless_config import Config, setting

class config(Config):
    groups = ['large', 'small']

    NUM_LAYERS = setting(default=5, large=10, small=3)
    NUM_UNITS = setting(default=128, large=512, small=32)
    USE_SKIP_CONNECTIONS = setting(default=True, small=False)
    LEARNING_RATE = 0.1
    OPTIMIZER = 'adam'

setting(...) has the signature:

def setting(default: T, **kwargs: T) -> T

...where T is Union[int, float, str, bool, NoneType] and kwargs is a map from group names to values. Specifying parameters by value is shorthand for a setting with no groups, i.e. SOME_KEY = 'value' is equivalent to SOME_KEY = setting(default='value').

When using groups you must first define the group names using the config.groups list.

Then in your code you can use these settings like in the basic example

def main():
    print(f'NUM_LAYERS is {config.NUM_LAYERS}')
    print(f'NUM_UNITS is {config.NUM_UNITS}')
    print(f'USE_SKIP_CONNECTIONS is {config.USE_SKIP_CONNECTIONS}')
    print(f'LEARNING_RATE is {config.LEARNING_RATE}')
    print(f'OPTIMIZER is {config.OPTIMIZER}')


if __name__ == '__main__':
    config.parse_args()
    main()

Now we see an additional --configuration option when we ask for --help:

$ python group_example.py --help
usage: group_example.py [-h] [--configuration {default,large,small}]
                        [--num-layers NUM_LAYERS] [--num-units NUM_UNITS]
                        [--use-skip-connections {true,false}]
                        [--learning-rate LEARNING_RATE] [--optimizer OPTIMIZER]

optional arguments:
  -h, --help            show this help message and exit
  --configuration {default,large,small}, -c {default,large,small}
  --num-layers NUM_LAYERS
  --num-units NUM_UNITS
  --use-skip-connections {true,false}
  --learning-rate LEARNING_RATE
  --optimizer OPTIMIZER

The --configuration option specifies the configuration group, and defaults to default if omitted.

For example:

$ python group_example.py
NUM_LAYERS is 5
NUM_UNITS is 128
USE_SKIP_CONNECTIONS is True
LEARNING_RATE is 0.1
OPTIMIZER is adam

$ python group_example.py --configuration large
NUM_LAYERS is 10
NUM_UNITS is 512
USE_SKIP_CONNECTIONS is True
LEARNING_RATE is 0.1
OPTIMIZER is adam

$ python group_example.py --configuration small
NUM_LAYERS is 3
NUM_UNITS is 32
USE_SKIP_CONNECTIONS is False
LEARNING_RATE is 0.1
OPTIMIZER is adam

We can also override individual settings in conjunction with groups. Individual settings take precedence over the group setting:

$ python group_example.py --configuration large --num-units 768
NUM_LAYERS is 10
NUM_UNITS is 768
USE_SKIP_CONNECTIONS is True
LEARNING_RATE is 0.1
OPTIMIZER is adam

Testing

When writing tests, you can use the config.override context manager to override individual settings:

import pytest
from .config import config

def test_with_context_manager():
    with config.override(FLOAT_SETTING=0.8, A_BOOLEAN=True):
        assert config.FLOAT_SETTING * config.SOME_INTEGER_SETTING == 8
        assert config.A_BOOLEAN is True

The config.override method can also be used without context management in conjunction with config.reset_to_defaults:

def test_with_manual_reset():
    config.override(FLOAT_SETTING=0.8, A_BOOLEAN=True)
    assert config.FLOAT_SETTING * config.SOME_INTEGER_SETTING == 8
    assert config.A_BOOLEAN is True
    config.reset_to_defaults()

Btw, this has nothing to do with Chef's Effortless Config project, I forgot to google the name before I put it on pypi and now I guess I'm stuck with it.

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

effortless-config-0.4.0.tar.gz (6.9 kB view details)

Uploaded Source

Built Distribution

effortless_config-0.4.0-py3-none-any.whl (7.8 kB view details)

Uploaded Python 3

File details

Details for the file effortless-config-0.4.0.tar.gz.

File metadata

  • Download URL: effortless-config-0.4.0.tar.gz
  • Upload date:
  • Size: 6.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.0.1 requests-toolbelt/0.8.0 tqdm/4.32.2 CPython/3.7.3

File hashes

Hashes for effortless-config-0.4.0.tar.gz
Algorithm Hash digest
SHA256 6ab7c59536de94e399201ad4f8a6eb2396e8ffa0767c39f7d1af888b064b1b30
MD5 9900253beeef057e2eee53dcf1b85669
BLAKE2b-256 d49eff44b15483e9374f9530670359c9dfc991b8e8b371ed154708435a161b60

See more details on using hashes here.

File details

Details for the file effortless_config-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: effortless_config-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 7.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.0.1 requests-toolbelt/0.8.0 tqdm/4.32.2 CPython/3.7.3

File hashes

Hashes for effortless_config-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2b5610b1832a09ff960d2577c92f1b70c37f0e897e14d37c15d4144bfa12c9c2
MD5 fca939d7d8bceac03f2cb51373678d57
BLAKE2b-256 f661718b402cf707650d525c0fa9c2e250fee3851a634dab5ef184700e36d1fd

See more details on using hashes here.

Supported by

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