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."))