1
0
Fork
You've already forked configy
0
Simple Configuration manager, plays well with testing
  • Python 100%
Grigi 0676ed4ac0
All checks were successful
Run tests / Tests (push) Successful in 57s
Publish to Pypi / Publish (push) Successful in 32s
Task to publish release
2025年05月02日 21:25:09 +01:00
.forgejo/workflows Task to publish release 2025年05月02日 21:25:09 +01:00
configy Accept passing pathlib.Path as filenames 2025年04月30日 10:27:53 +01:00
tests Modernising code for Python3.14, dropped support for Python3.7 and below ( #1 ) 2025年04月29日 16:25:01 +00:00
.gitignore Initial commit 2015年09月05日 15:37:36 +02:00
LICENSE license 2015年09月05日 23:36:56 +02:00
pyproject.toml Task to publish release 2025年05月02日 21:25:09 +01:00
README.rst Modernising code for Python3.14, dropped support for Python3.7 and below ( #1 ) 2025年04月29日 16:25:01 +00:00

configy

Simple Configuration manager, plays well with testing.

Basic Usage

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'

Environment variable substitution

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.

Helper functions

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

How to overload settings for testing

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.