An open API service indexing awesome lists of open source software.

https://github.com/cidrblock/modelsettings

Modelsettings is a straight-forward, easy to use python application settings manager that includes ini file, environment variable, and command-line parameter support.
https://github.com/cidrblock/modelsettings

argparse docker environment-variables ini-parser python twelve-factor

Last synced: 10 months ago
JSON representation

Modelsettings is a straight-forward, easy to use python application settings manager that includes ini file, environment variable, and command-line parameter support.

Awesome Lists containing this project

README

          

[![Build Status](https://travis-ci.org/cidrblock/modelsettings.svg?branch=master)](https://travis-ci.org/cidrblock/modelsettings)

# Model Settings

## Overview

Modelsettings is a straight-forward, easy to use python application settings manager that includes ini file, environment variable, and command-line parameter support.

The necessary settings variables are declared in a yaml model, which is then used to parse an .ini file, environment variables, and finally command-line arguments.

In addition to reading settings from the three sources, modelsettings also includes sample configuration generator support for:
- command-line
- environment variables (e.g., export statements)
- ini file
- docker run
- docker compose
- kubernetes
- drone plugins

## Quick start

### Build the model

Modelsettings looks for a `model_settings.yml` in the current working directory. A simple `model_settings.yml` file might look like this:

```
env_prefix: CF
model:
cream:
choices:
- True
- False
default: False
example: True
help: Would you like cream in your coffee?
required: True
sugar:
choices:
- True
- False
default: True
example: True
help: Would you like sugar in your coffee?
required: True
size:
choices:
- 10
- 12
- 16
default: 12
example: 16
help: What size cup would you like in ounces?
required: True
```
`env_prefix` is used as a prefix for the environment variables, this helps avoid name collision when running multiple python applications in the same shell.

`model` is a dictionary of required settings values.

### Import and use the module

In your application, simply import modelsettings.

```
$ python3 -m venv venv
$ source venv/bin/activate
$ pip install modelsettings
```
app.py
```
from modelsettings import settings

def main():
output = f"You ordered a {settings.SIZE} oz. cup of coffee"
modifiers = []
if settings.CREAM: modifiers.append("cream")
if settings.SUGAR: modifiers.append("sugar")
if modifiers:
output += " with " + " and ".join(modifiers)
output += "."
print(output)

if __name__ == "__main__":
main()

```
All settings are converted to uppercase and available as `settings.XXXXX`

## Additional command-line parameters

### `--help`

Argparse help is generated from the model:

```
$ python app.py --help
usage: app.py [-h]
[--generate {command,docker-run,docker-compose,ini,env,kubernetes,readme,drone-plugin}]
[--settings SETTINGS] [--cream {True,False}]
[--sugar {True,False}] [--size {10,12,16}]

optional arguments:
-h, --help show this help message and exit
--generate {command,docker-run,docker-compose,ini,env,kubernetes,readme,drone-plugin}
Generate a template
--settings SETTINGS Specify a settings file. (ie settings.dev)
--cream {True,False} Would you like cream in your coffee? e.g., True
--sugar {True,False} Would you like sugar in your coffee? e.g., True
--size {10,12,16} What size cup would you like in ounces? e.g., 16
```

### `--generate`

A command-line parameter of generate is added to the application which, when used, will generate sample settings in a number of formats.

```
$ python app.py --generate env
export CF_CREAM=True
export CF_SIZE=16
export CF_SUGAR=True
```

### `--generate readme`

Markdown can be generated which includes all the available generate formats.

```
$ python app.py --generate readme >> README.md
```
## Order of operations

The .ini file is read first, then the environment variables, then the command-line parameters.

### .ini file support

The application will now support loading settings from a `settings.ini` file.

```
$ cat settings.ini
[settings]
cream=True
size=16
sugar=True
$ python app.py
You ordered a 16 oz. cup of coffee with cream and sugar.
```
An alternate settings file can be specified with the command line, this is useful during development of the application.

```
$ cat settings.dev
[settings]
cream=True
size=10
sugar=False
$ python app.py --settings settings.dev
You ordered a 10 oz. cup of coffee with cream.
$ python app.py --settings settings.dev --size 16
You ordered a 16 oz. cup of coffee with cream.
```

### Environment variable support

All settings can be stored as environment variables. The environment variables should be prefaced with the `env_prefix` from the `model_settings.yml` file and capitalized.

```
$ export CF_CREAM=False
$ export CF_SIZE=12
$ export CF_SUGAR=True
$ python app.py
You ordered a 12 oz. cup of coffee with sugar.
$ export CF_CREAM=True
$ python app.py
You ordered a 12 oz. cup of coffee with cream and sugar.
```

### Command-line parameter support

Command line parameters take precedence over `.ini` files and environment variables.

```
$ python app.py --size 10 --sugar False --cream False
You ordered a 10 oz. cup of coffee.
$ python app.py --size 12 --sugar True --cream False
You ordered a 12 oz. cup of coffee with sugar.
$ python app.py --size 16 --sugar True --cream True
You ordered a 16 oz. cup of coffee with cream and sugar.
```

## model_settings.yml

1) The model support 5 basic python types:
- `bool`
- `int`
- `float`
- `string`
- `list`
- `dict`

The type is derived from the example given, and the settings variable is cast to that type.

In the example below, each supported type is shown with a corresponding yaml native example.

`example` is therefore a required property for every entry in the model.

```
bool:
choices:
- True
- False
default: False
help: This is an integer setting
required: False
example: True
integer:
choices:
- 10
- 20
default: 60
help: This is an integer setting
required: False
example: 30
float:
default: 60.5
help: This is an integer setting
required: False
example: 30.5
string:
default: string
help: This is a string setting
required: False
example: string
dictionary:
default:
key: value
help: This is a dict setting
required: False
example:
key: value
list:
default:
- item1
- item2
help: This is a list setting
required: False
example:
- item1
- item2
```

## Dictionaries and lists objects in `.ini` and environment variables.

Dictionary and lists should be represented as json in `.ini` files and environment variables:

```
$ more complex.yml
env_prefix: RM
model:
dictionary:
default:
key: value
help: This is a dict setting
required: False
example:
key: value
list:
default:
- item1
- item2
help: This is a list setting
required: False
example:
- item1
- item2
$ export MODEL_SETTINGS=complex.yml

$ python app.py --generate env
export RM_DICTIONARY='{"key": "value"}'
export RM_LIST='["item1", "item2"]'

$ python app.py --generate ini
[settings]
dictionary={"key": "value"}
list=["item1", "item2"]
```

## Docker

Because all settings are supported as environment variables, transitioning a python application to a docker container is simple.

Dockerfile
```
FROM python:3.6.4-alpine

RUN apk add -U \
ca-certificates \
&& rm -rf /var/cache/apk/* \
&& pip install --no-cache-dir --upgrade pip

WORKDIR /usr/src/app/
ADD model_settings.yml .
ADD app.py .
ADD requirements.txt .
RUN pip install -r requirements.txt

ENTRYPOINT ["python", "app.py"]
```

Build
```
$ docker build -t coffee .
<...>
Successfully built 74938ac5902a
Successfully tagged coffee:latest
```
Generate
```
$ python app.py --generate docker-run
docker run -it \
-e CF_CREAM=True \
-e CF_SIZE=16 \
-e CF_SUGAR=True \

```
Run
```
$ docker run -it \
-e CF_CREAM=True \
-e CF_SIZE=16 \
-e CF_SUGAR=True \
coffee
You ordered a 16 oz. cup of coffee with cream and sugar.

$ docker run -it \
-e CF_CREAM=False \
-e CF_SIZE=12 \
-e CF_SUGAR=True \
coffee
You ordered a 12 oz. cup of coffee with sugar.
```