Implementation of key-value pair based configuration for Python applications.
⚠️ Please use essentials-configuration instead of this library. This library won't be extended with more features.
Features:
- support for most common sources of application settings
- support for overriding settings in sequence
- support for nested structures and lists, using attribute notation
- strategy to use environment specific settings
This library is freely inspired by .NET Core Microsoft.Extensions.Configuration
namespace and its pleasant design (ref. MSDN documentation, Microsoft Extensions Configuration Deep Dive).
The main class is influenced by Luciano Ramalho`s example of JSON structure explorer using attribute notation, in his book Fluent Python.
- yaml files
- json files
- ini files
- environmental variables
- dictionaries
- keys and values
pip install roconfiguration
In this example, configuration will be comprised of anything inside a file
settings.yaml
and environmental variables. Settings are applied in order, so
environmental variables with matching name override values from the yaml
file.
from roconfiguration import Configuration
config = Configuration()
config.add_yaml_file("settings.yaml")
config.add_environmental_variables()
In this example, if an environmental variable with name APP_ENVIRONMENT
and
value dev
exists, and a configuration file with name settings.dev.yaml
is
present, it is read to override values configured in settings.yaml
file.
import os
from roconfiguration import Configuration
environment_name = os.environ["APP_ENVIRONMENT"]
config = Configuration()
config.add_yaml_file("settings.yaml")
config.add_yaml_file(f"settings.{environment_name}.yaml", optional=True)
config.add_environmental_variables()
import os
from roconfiguration import Configuration
config = Configuration()
# will read only environmental variables
# starting with "APP_", case insensitively
config.add_environmental_variables("APP_")
Ini files are parsed using the built-in configparser
module, therefore
support [DEFAULT]
section; all values are kept as strings.
from roconfiguration import Configuration
config = Configuration()
config.add_ini_file("settings.ini")
JSON files are parsed using the built-in json
module.
from roconfiguration import Configuration
config = Configuration()
config.add_json_file("settings.json")
from roconfiguration import Configuration
config = Configuration({"host": "localhost", "port": 8080})
config.add_map({"hello": "world", "example": [{"id": 1}, {"id": 2}]})
assert config.host == "localhost"
assert config.port == 8080
assert config.hello == "world"
assert config.example[0].id == 1
assert config.example[1].id == 2
from roconfiguration import Configuration
config = Configuration({"host": "localhost", "port": 8080})
config.add_value("port", 44555)
assert config.host == "localhost"
assert config.port == 44555
config = Configuration(
{
"a": {
"b": 1,
"c": 2,
"d": {
"e": 3,
"f": 4,
},
}
}
)
assert config.a.b == 1
assert config.a.d.e == 3
assert config.a.d.f == 4
config.add_value("a:d:e", 5)
assert config.a.d.e == 5
assert config.a.d.f == 4
config = Configuration(
{
"a": {
"b": 1,
"c": 2,
"d": {
"e": 3,
"f": 4,
},
}
}
)
assert config.a.b == 1
assert config.a.d.e == 3
assert config.a.d.f == 4
# NB: if an env variable such as:
# a:d:e=5
# or...
# a__d__e=5
#
# is defined, it overrides the value from the dictionary
config.add_environmental_variables()
assert config.a.d.e == 5
config = Configuration(
{
"b2c": [
{"tenant": "1"},
{"tenant": "2"},
{"tenant": "3"},
]
}
)
config.add_value("b2c:1:tenant", "4")
assert config.b2c[0].tenant == "1"
assert config.b2c[1].tenant == "4"
assert config.b2c[2].tenant == "3"
pip install -r requirements.txt
# run tests using automatic discovery:
pytest