Getting started¶
ClassyConf aims to be the configuration management solution for perfectionists with deadlines.
It solves many problems, so let’s get started with an incremental introduction to what it can do for you.
1. Declaring settings¶
The simplest ways to get started with classyconf is to use the
Configuration
class, to
declare all the settings of your app.
This pythonic class allows you to encapsulate all configuration
in one object by declaring your settings using the
Value
descriptor.
In this case, we will use a single debug setting, but there could be as many as you need.
from classyconf import Configuration, Value, as_boolean
class AppConfig(Configuration):
DEBUG = Value(default=False, cast=as_boolean, help="Toggle debugging on/off.")
We are using the as_boolean
cast for the DEBUG
setting. The
as_boolean
cast converts values like On|Off
, 1|0
, yes|no
,
true|false
, t|f
into Python boolean True
or False
.
See also
Visit the Casts section to find out more about other casts or how to write your own.
Since we provided a boolean default, there is no need to explicitely set
a cast in this case, classyconf will choose the as_boolean
to save
you some typing. Visit the Implicit casts section to see how to
customize this.
2. Discovering settings¶
Now that we defined the settings we needed, we will define where to obtain them.
Loaders will help you customize how configuration discovery works. This is a list of objects that will be used to discover settings from different sources.
Loaders can be declared in the Meta
class:
from classyconf import Configuration, Value, Environment
class AppConfig(Configuration):
DEBUG = Value(default=False, help="Toggle debugging on/off.")
class Meta:
loaders=[Environment()]
In this case we are telling classyconf to only search for settings in the
os.enviroment
variables. I know, this is not very useful, and seems like
an overkill. Let’s override this default loaders list and introduce another
loader to gather setting from a .ini file.
>>> from classyconf import Environment, IniFile
>>> config = AppConfig(loaders=[
... Environment(),
... IniFile("/etc/myapp/conf.ini", section="settings")
... ])
Now you might be asking, is this reading a file? do I have to create it? How do I access my settings?
Configuration discovery only happens when a Value
setting is first accessed,
so nothing gets evaluated until then.
The config instance can accessed as dict or object. Let’s trigger a look up:
>>> config.DEBUG # config["DEBUG"] also works!
False
Each loader is checked in the given order. In this case, we will first lookup
each setting in the os.enviroment
variables and, when not found, the
declared .ini file (inside the settings
section), but if this file
doesn’t exist or is broken, this loader is ignored.
If a setting is not found by any loader, the default value is returned, if
set, or a
UnknownConfiguration
exception is thrown.
Now we all know that the industry practices have set different naming
conventions for diffent configuration formats. Is it camelCase
for
.json files? Is it UPPER_CASE
for the enviroment variables and
lower_case
for .ini files? Don’t worry, classyconf has your back.
Most loaders include a keyfmt
callable argument. This allows you
to alter the name of the setting for each individual loader.
Let’s customize this:
>>> from classyconf import EnvPrefix
>>> config = AppConfig(loaders=[
... Environment(keyfmt=EnvPrefix("MY_APP_")),
... IniFile("/etc/myapp/conf.ini", section="settings", keyfmt=str.lower)
... ])
Now if you access config.DEBUG
, classyconf will first check for
MY_APP_DEBUG=xxx
in the os.enviroment
but for debug=xxx
in the
.ini
file.
See also
The rationale for keyfmt
is to follow the best practices for
naming variables, and respecting namespaces for each source of config.
Read more at Naming conventions and namespaces for settings.
3. Extending settings¶
As you know, the same code might run in several different enviroments, like dev, staging, prod, etc.
Although Configuration
classes can be extended to define new
Value
attributes or override
them, the recomended way is to simply override the settings sources per
enviroment.
from classyconf import EnvFile
class StagingConfig(AppConfig):
class Meta:
loaders = [EnvFile("staging.env")]
As we saw earlier, loaders can also be overridden at instantiation time.
from classyconf import Dict, EnvFile
test_config = AppConfig(loaders=[Dict({"DEBUG": True}), EnvFile("test.env")]
In the snippet above we used the Dict
loader, which comes handy to ensure certain hardcoded settings always get
picked up.
4. Inspecting settings¶
Later this object can be used to print configuration, this will evaluate every setting.
>>> config = AppConfig()
>>> print(config)
DEBUG=False - Toggle debugging on/off.
Or with __repl__()
you get a preview of how it was instantiated.
>>> config = AppConfig()
>>> config
AppConf(loaders=[Environment()])
It can also be iterated. This gives you the field key and the Value
instance for you to keep inspecting (this doesn’t evaluate the setting).
>>> for setting in config:
... print(setting)
...
('DEBUG', Value(key="DEBUG", help="Toggle debugging on/off."))