FAQ

Why not use environment variables directly?

There is a common pattern to read configurations in environment variable that look similar to the code below:

if os.environ.get("DEBUG", False):
    print(True)
else:
    print(False)

But this code have some issues:

  1. If envvar DEBUG=False this code will print True because os.environ.get("DEBUG", False) will return an string ‘False’ instead of a boolean False. And a non-empty string has a True boolean value.
  2. We can’t (dis|en)able debug with envvars DEBUG=yes|no, DEBUG=1|0, DEBUG=True|False.
  3. If we want to use this configuration during development we need to define this envvar all the time. We can’t define this setting in a configuration file that will be used if DEBUG envvar is not defined.

When should I use configuration files?

Environment variables shouldn’t hold sensitive data, there are potential security issues:

  1. Accidental leaks via logging or error reporting services.
  2. Child process inheritance.

Command line arguments are great for exploring the possibilities of an app, but passing lot’s of arguments either in the short -s or long --more-verbose formats can be cumbersome.

Sometimes files are more convinient and documenting than command line arguments or env vars. Some file formats allow for comments and are great as templates to build upon.

If your app is a long running process, like a webserver, you can issue a SIGHUP signal so that it reloads it’s config from files. Env vars and command line arguments cannot be easily changed from the outside after startup.

Why are executable config files a bad idea?

Executable files can be used as config sources like .vimrc, Vagrantfile, etc. This approach has some drawbacks.

First, your users now need to learn a new programming language, just to configure your application. Some apps (like the suckless bundle) go as far as requiring you to patch and compile your app to change it’s configuration.

And second, your configuration is no longer hierarchical, your application cannot extract configuration from different sources by executing different files, because you cannot know in advance what is being executed. So you typically end up with one single executable file as config that takes care of everything.

On the other hand, classyconf encourages traditional formats for configuration, like enviroment variables or ini files. The best way to think of configuration is as a set of key/value dicts that need to be merged into a single config dict. No need to get fancy.

Is classyconf tied to Django or Flask?

No, classyconf was designed to be framework agnostic, can be used for web, CLI or GUI applications.

Why create a library similar to prettyconf or goodconf instead of using it?

Although prettyconf is great and very flexible, I don’t like that the config(“debug”) call isn’t lazy, so putting it into a class isn’t enough:

from prettyconf import config

class MyConfig():
    debug = config("debug")   # this is evaluated when this module is loaded

I also didn’t like the default RecursiveSearch that it provides and I also needed to implement many changes and move fast to see what would work.

I’ve made several contributions to prettyconf and even have a talk about it, but I needed to change its behaviour, break things and move fast. This is backward incompatible, so, it could break software that relies on the old behaviour.

You can use any of them. Both are good libraries and provides a similar set of features.

Other libraries had other issues:

  • Were tied to a specific web app framework.
  • Didn’t allow you to specify configuration sources and their hierarchy.
  • Had a global configuration object, or made it really hard to override specific configuration when writing tests.
  • Settings were eagerly evaluated.
  • Had no facilities for auto-generating configuration documentation or inspecting it.

Classyconf is classy, it’s pretty, it’s good.

How does classyconf compare to python-dotenv?

python-dotenv reads the key, value pair from .env file and adds them to environment variable. It is good for some tools that simply proxy the env to some other process, like docker-compose or pipenv.

On the other hand, classyconf does not populate the os.environ dictionary, because it is designed to discover configuration from diferent sources, the environment being just one of them.

Other similar projects are direnv and envdir to load environment variables from directories and files.

In case you are running your app as an systemd unit, there is a section to directly list the env vars or to suply a env file.

What are some useful third-parties casts for Django?

Django is a popular python web framework that imposes some structure on the way its settings are configured. Here are a few 3rd party casts that help you adapt strings into that inner structures:

  • dj-database-url - Parses URLs like mysql://user:pass@server/db into Django DATABASES configuration format.
  • django-cache-url - Parses URLs like memcached://server:port/prefix into Django CACHES configuration format.
  • dj-email-url - Parses URLs like smtp://user@domain.com:pass@smtp.example.com:465/?ssl=True with parameters used in Django EMAIL_* configurations.
  • dj-admins-setting - Parses emails lists for the ADMINS configuration.