Simple Configuration manager, plays well with testing.
Install from pypi:
pip install configy
Specify the configuration directives as early in execution as possible:
import configy
try:
# Every option is optional, fill in as makes sense.
configy.load_config(
conf='the_configuration.yaml', # The default config file if not specified as an ENV var
env='CONFIGY_FILE', # The ENV var to look for a config file
defaults='defaults.yaml', # The defaults that is always loaded.
data={'manual': 'defaults'}, # Manually provided defaults loaded
case_sensitive=True # Case Sensitive by default
)
except configy.ConfigyError as e:
# Report config load error to user
Given a sample YAML config file of:
Something:
value: The Value
number: 42
bool1: 1
bool2: FALSE
bool3: y
You then use it so:
>>> from configy import config
>>> config.Something.value
'The Value'
If you try to access any configuration value that isn't defined you will get an exception:
>>> config.Something.other
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'other'
The config object is just a dictionary, so you can use it as a regular dictionary as well:
>>> config['Something']['value']
'The Value'
>>> config.Something.get('other', 'default value')
'default value'
You can request Environment variable substitution by using ${ENVVAR}
in the yaml document:
Something:
full_value: ${ENV_FULL}
part_value: http://${ENV_PART}/something
If the envvar isn't defined, it wills raise ConfigyError
.
Since you can't guarantee the type of a value in the configuration files (YAML treats everything as text), you need to do type conversion manually.
For ints and floats it is easy:
>>> int(config.Something.number)
42
>> float(config.Something.number)
42.0
For booleans it is a bit more tricky, as a boolean can be represented by many different notations. You also don't have complete control over the notation used. For this we provide a to_bool()
helper function.
It treats case-insensitively
True
- 'y', 'yes', '1', 't','true'
False
- 'n', 'no', '0', 'f', 'false'
Anything else will resort to the provided default (which defaults to False)
>>> from configy import config, to_bool
>>> to_bool(config.Something.bool1)
True
>>> to_bool(config.Something.bool2)
False
>>> to_bool(config.Something.bool1)
True
>>> to_bool(config.Something.number)
False
>>> to_bool(config.Something.number, True)
True
>>> to_bool(config.Something.number, None)
None
During testing, one often wants to override some configuration to test something specific. Configy supports this use case.
from configy import config, testconfig
@testconfig.override_config({
'Something': {
'other': 'I now exist',
},
'Extra': 'defined',
})
def test_override():
# Existing values still work as per usual
assert config.Something.value == 'The Value'
# New values
assert config.Something.other == 'I now exist'
assert config.Extra == 'defined'
One can also define configuration to be used:
@testconfig.load_config(
conf='test_config.yaml'
)
def test_load_config():
assert config.testvalue == 'test result'
You can also define the WHOLE configuration that is loaded for that test:
@testconfig.load_config(data={
'testvalue': 'test result',
})
def test_load_config_data():
assert config.testvalue == 'test result'
All the testing decorators will work on method, class and function level.