Modelsettings is a straight-forward, easy to use python application settings manager that includes ini file, environment variable, and command-line parameter support.
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:
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.
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
--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
The .ini file is read first, then the environment variables, then the command-line parameters.
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.
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 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.
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
.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"]
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 \
<container-name>
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.