Python environment configuration simplified.
Config2 (for Python) - which is highly inspired by node-config - organizes hierarchical configurations for your app deployments.
It lets you define a set of default parameters, and extend them for different deployment environments (development, qa, staging, production, etc.).
Configurations are stored in configuration files within your application, and can be overridden and extended by environment variables, command line parameters, or external sources.
This gives your application a consistent configuration interface shared among a growing list of npm modules also using node-config.
NOTE: This project is more or less in pair with node-config implementation, with exception for some fluff that could be considered too much magic such as deployment specific multi-instance deployments which I so far haven't found any good motivation for, and some other questionable advanced features mentioned in the wiki pages.
...based on node-config project guidelines:
- Simple - Get started fast
Powerful - For multi-node enterprise deployment- excluded because with power comes responsability- Flexible - Supporting multiple config file formats
- Lightweight - Small file and memory footprint
- Predictable - Well tested foundation for module and app developers
Install using pip:
$ pip install config21. Assuming we have a python application project...
some_project
└── app.py
app.py - some app making serious $$$
# business logicprint('$$$')2. Let's add some environment specific config files...
some_project
└── config
├── default.yml
├── development.yml
├── foo.yml
└── production.yml
└── app.py
default.yml - with some bogus nested settings shared for all environments (defaults)
a1: DEFAULT 1a2:
b1: [1, 2, 3]b2:
- foo
- barb3:
c1: 1c2: "DEFAULT 2"development.yml - with some bogus nested settings overriden for development environment (overriden)
a2:
b2:
- DEV 1b3:
c2: "DEV 2"some_key_only_for_dev: truefoo.yml - with some bogus nested settings overriden for foo environment (overriden)
a2:
b2:
- FOO 1b3:
c2: "FOO 2"some_key_only_for_foo: trueproduction.yml - with some bogus nested settings overriden for production environment (overriden)
a2:
b2:
- PROD 1b3:
c2: "PROD 2"some_key_only_for_prod: true3. Let's now run the app using various environments...
$ python app.py
fromconfig2.configimportconfigconfig.get_env() # => Noneconfig.get() # => {'a1': 'DEFAULT 1', 'a2': {'b1': [1, 2, 3], 'b2': ['foo', 'bar'], 'b3': {'c1': 1, 'c2': 'DEFAULT 2'}}}config.a1# => 'DEFAULT 1'config.a2# => {'b1': [1, 2, 3], 'b2': ['foo', 'bar'], 'b3': {'c1': 1, 'c2': 'DEFAULT 2'}}config.a2.b3.c2# => 'DEFAULT 2'print('$$$')$ ENV=development python app.py
fromconfig2.configimportconfigconfig.get_env() # => 'development'config.get() # => {'a1': 'DEFAULT 1', 'a2': {'b1': [1, 2, 3], 'b2': ['DEV 1'], 'b3': {'c1': 1, 'c2': 'DEV 2'}}, 'some_key_only_for_dev': True}config.a1# => 'DEFAULT 1'config.a2# => {'b1': [1, 2, 3], 'b2': ['DEV 1'], 'b3': {'c1': 1, 'c2': 'DEV 2'}}config.a2.b3.c2# => 'DEV was here 2'config.some_key_only_for_dev# => Trueconfig.some_key_only_for_foo# => AttributeErrorconfig.some_key_only_for_prod# => AttributeErrorprint('$$$')$ ENV=foo python app.py
fromconfig2.configimportconfigconfig.get_env() # => 'foo'config.get() # => {'a1': 'DEFAULT 1', 'a2': {'b1': [1, 2, 3], 'b2': ['FOO 1'], 'b3': {'c1': 1, 'c2': 'FOO 2'}}, 'some_key_only_for_foo': True}config.a1# => 'DEFAULT 1'config.a2# => {'b1': [1, 2, 3], 'b2': ['FOO 1'], 'b3': {'c1': 1, 'c2': 'FOO 2'}}config.a2.b3.c2# => 'FOO was here 2'config.key_only_for_foo# => Trueconfig.some_key_only_for_dev# => AttributeErrorconfig.some_key_only_for_prod# => AttributeErrorprint('$$$')$ ENV=production python app.py
fromconfig2.configimportconfigconfig.get_env() # => 'production'config.get() # => {'a1': 'DEFAULT 1', 'a2': {'b1': [1, 2, 3], 'b2': ['PROD 1'], 'b3': {'c1': 1, 'c2': 'PROD 2'}}, 'some_key_only_for_foo': True}config.a1# => 'DEFAULT 1'config.a2# => {'b1': [1, 2, 3], 'b2': ['PROD 1'], 'b3': {'c1': 1, 'c2': 'PROD 2'}}config.a2.b3.c2# => 'PROD was here 2'config.some_key_only_for_prod# => Trueconfig.some_key_only_for_dev# => AttributeErrorconfig.some_key_only_for_foo# => AttributeErrorprint('$$$')etc.
4. Optionally, let's now introduce custom config environment variables...
some_project
└── config
├── custom-environment-variables.yml
├── default.yml
├── development.yml
├── foo.yml
└── production.yml
└── app.py
custom-environment-variables.yml - with mappings of config keys to environment variables
a1: A1a2:
b3:
c2: C25. Let's now run the app using custom environment variables to override config...
$ A1=x C2=y python app.py
fromconfig2.configimportconfigconfig.get_env() # => Noneconfig.get() # => {'a1': 'x', 'a2': {'b1': [1, 2, 3], 'b2': ['foo', 'bar'], 'b3': {'c1': 1, 'c2': 'y'}}}config.a1# => 'x'config.a2# => {'b1': [1, 2, 3], 'b2': ['foo', 'bar'], 'b3': {'c1': 1, 'c2': 'y'}}config.a2.b3.c2# => 'y'print('$$$')Clone down source code:
$ make installRun colorful tests, with only native environment (dependency sandboxing up to you):
$ make testRun less colorful tests, with multi-environment (using tox):
$ make test-toxThis project was mainly initiated - in lack of existing alternatives - to be used at our work at Markable.ai to have common code conventions between various programming environments where Python (research, CV, AI) and Node.js (I/O, APIs, UIs, scripts) currently are most used.
Released under the MIT license.