Package: bison
bisonPython application configurationWhat is Bison?Bison is a configuration solution for Python applications that aims to be simple
and intuitive. It supports:reading from YAML config filesreading from environment variablessetting explicit valuessetting defaultsconfiguration validationconfiguration access/manipulation with dot notationInstead of implementing custom configuration reading and parsing, you can use
Bison to handle it for you.Bison was inspired byViperand the lack of good
application configuration solutions for Python (at least, in my opinion). Documentation
for Bison can be found onReadtheDocsBison uses the following precedence order. Each item in the list takes precedence
over the item below it.override (e.g. callingBison.set())environmentconfig filedefaultsInstallationBison can be installed withpippip install bisonor withpipenvpipenv install bisonUsing BisonCreating a configuration SchemeA configuration scheme is not required by Bison, but having one allows you to set default
values for configuration fields as well as do configuration validation. It is pretty easy
to create a new Scheme:scheme=bison.Scheme()A Scheme is really just a container for configuration options, so without any options, a
Scheme is somewhat useless.Configuration OptionsThere are currently three types of configuration options:bison.Optionbison.DictOptionbison.ListOptionTheir intended functionality should be mostly obvious from their names. AnOptionrepresents
a singular value in a configuration. ADictOptionrepresents a dictionary or mapping of values
in a configuration. AListOptionrepresents a list of values in a configuration.See thedocumentationfor more on how options can be configured.Any number of options can be added to a Scheme, but as a simple example we can define a Scheme
which expects a key "log", and a key "count".scheme=bison.Scheme(bison.Option('log'),bison.Option('count'),)Configuration ValidationValidation operates based on the constraints set on the options. Above, there are no
constraints (other than the need for those keys to exist), so any value for "log" and
"count" will pass validation.An option can be constrained in different ways by using its keyword arguments. For example,
to ensure the value for "count" is an integer,bison.Option('count',field_type=int)Or, to restrict the values to a set of choicesbison.Option('log',choices=['debug','info','warn','error'])Thedocumentationgoes into more detail about other validation settings.Setting DefaultsIf a default value is not set on an option, it is considered required. In these cases,
if the key specified by that value is not present in the parse configuration, it will
cause a validation failure.If a default value is set, then the absence of that field in the configuration will not
cause a validation failure.bison.Option('log',default='info')Configuring BisonOnce you have a Scheme to use (if you'd like to), it will need to be passed to a Bison
object to manage the config building.scheme=bison.Scheme()config=bison.Bison(scheme)There are a few options that can be set on the Bison object to change how it
searches for and builds the unified configuration.For reading configuration filesconfig.config_name='config'# name of the config file (no extension)config.add_config_paths(# paths to look in for the config file'.','/tmp/app')config.config_format=bison.YAML# the config format to useFor reading environment variablesconfig.env_prefix="MY_APP"# the prefix to use for environment variablesconfig.auto_env=True#  automatically bind all options to env variables based on their keyBuilding the unified configOnce the scheme has been set (if using) and Bison has been configured, the only thing
left to do is to read in all the config sources and parse them into a unified config.
This is done simply withconfig.parse()ExampleBelow is a complete example for parsing a hypothetical application configuration which
is described by the following YAML config.log:debugport:5000settings:requests:timeout:3backends:-host:10.1.2.3port:5001-host:10.1.2.4port:5013-host:10.1.2.5port:5044importbison# the scheme for the configuration. this allows us to set defaults# and validate configuration dataconfig_scheme=bison.Scheme(bison.Option('log',default='info',choices=['debug','info','warn','error']),bison.Option('port',field_type=int),bison.DictOption('settings',scheme=bison.Scheme(bison.DictOption('requests',scheme=bison.Scheme(bison.Option('timeout',field_type=int))))),bison.ListOption('backends',member_scheme=bison.Scheme(bison.Option('host',field_type=str),bison.Option('port',field_type=int))))# create a new Bison instance to store and manage configuration dataconfig=bison.Bison(scheme=config_scheme)# set the config file name to 'app' (default is 'config') and set the# search paths to '.' and '/tmp/app/config'config.config_name='app'config.add_config_paths('.','/tmp/app/config')# set the environment variable prefix and enable auto-envconfig.env_prefix='MY_APP'config.auto_env=True# finally, parse the config sources to build the unified configurationconfig.parse()See theexampledirectory for this example along with demonstrations
of how to access configuration data.Future WorkThere is more that can be done to improve Bison and expand its functionality. If
you wish to contribute, open a pull request. If you have questions or feature requests,
open an issue. Below are some high level ideas for future improvements:Support additional configuration formats (JSON, TOML, ...)Versioned configurations