getconf
=======

.. image:: https://secure.travis-ci.org/Polyconseil/getconf.png?branch=master
    :target: http://travis-ci.org/Polyconseil/getconf/

.. image:: https://img.shields.io/pypi/v/getconf.svg
    :target: https://getconf.readthedocs.io/en/latest/changelog.html
    :alt: Latest Version

.. image:: https://img.shields.io/pypi/pyversions/getconf.svg
    :target: https://pypi.python.org/pypi/getconf/
    :alt: Supported Python versions

.. image:: https://img.shields.io/pypi/wheel/getconf.svg
    :target: https://pypi.python.org/pypi/getconf/
    :alt: Wheel status

.. image:: https://img.shields.io/pypi/l/getconf.svg
    :target: https://pypi.python.org/pypi/getconf/
    :alt: License

The ``getconf`` project provides simple configuration helpers for Python programs.

It provides a simple API to read from various configuration files and environment variables:

.. code-block:: python

    import getconf
    config = getconf.ConfigGetter('myproj', ['/etc/myproj.conf'])
    db_host = config.getstr('db.host', 'localhost')
    db_port = config.getint('db.port', 5432)


Beyond this API, getconf aims at unifying configuration setup across development and production systems,
respecting the standard procedures in each system:

* Allow userspace configuration on development systems
* Allow multiple different configurations for continuous integration systems
* Use standard configuration space in ``/etc`` on traditional production servers
* Handle environment-based configuration for cloud-based platforms

``getconf`` is distributed under the two-clause BSD license, a copy of
which is in the source.

``getconf`` v1.11 onwards supports Python 3.5, 3.6, 3.7, 3.8, 3.9 and 3.10.
v1.11.x are the last versions to support Python 3.5 & 3.6.
v1.9.x are the last versions to support Python 2.7 and 3.4.
v1.8.x are the last versions to support Python 3.3.
v1.5.x are the last versions to support Python 2.6.


Links
-----

- Package on `PyPI`_: http://pypi.python.org/pypi/getconf/
- Doc on `ReadTheDocs <http://readthedocs.org/>`_: http://readthedocs.org/docs/getconf/
- Source on `GitHub <http://github.com/>`_: http://github.com/Polyconseil/getconf/


Installation
------------

Install the package from `PyPI`_, using pip:

.. code-block:: sh

    pip install getconf

Or from GitHub:

.. code-block:: sh

    git clone git://github.com/Polyconseil/getconf


``getconf`` has no external dependency beyond Python.


Introduction
------------

.. note:: Please refer to the full doc for :doc:`reference <reference>` and
          :doc:`advanced usage <advanced>`.

All configuration values are accessed through the ``getconf.ConfigGetter`` object:

.. code-block:: python

    import getconf
    config = getconf.ConfigGetter('myproj', ['/etc/myproj/settings.ini', './local_settings.ini'])

The above line declares:

* Use the ``myproj`` namespace (explained later; this is mostly used for environment-based configuration, as a prefix for environment variables)
* Look, in turn, at ``/etc/myproj/settings.ini`` (for production) and ``./local_settings.ini`` (for development); the latter overriding the former.


Once the ``getconf.ConfigGetter`` has been configured, it can be used to retrieve settings:

.. code-block:: python

    debug = config.getbool('debug', False)
    db_host = config.getstr('db.host', 'localhost')
    db_port = config.getint('db.port', 5432)
    allowed_hosts = config.getlist('django.allowed_hosts', ['*'])

All settings have a type (default is text), and accept a default value.
They use namespaces (think 'sections') for easier reading.

With the above setup, ``getconf`` will try to provide ``db.host`` by inspecting
the following options in order (it stops at the first defined value):

- From the environment variable ``MYPROJ_DB_HOST``, if defined
- From the ``host`` key in the ``[db]`` section of ``./local_settings.ini``
- From the ``host`` key in the ``[db]`` section of ``/etc/myproj/settings.ini``
- From the default provided value, ``'localhost'``


Features
--------

**Env-based configuration files**
    An extra configuration file/directory/glob can be provided through ``MYPROJ_CONFIG``;
    it takes precedence over other files

**Default options**
    An extra dictionary can be provided as ``ConfigGetter(defaults=some_dict)``;
    it is used after configuration files and environment variables.

    It should be a dict mapping a section name to a dict of ``key => value``:

    .. code-block:: pycon

        >>> config = ConfigGetter('myproj', defaults={'db': {'host': 'localhost'}})
        >>> config.getstr('db.host')
        'localhost'

**Typed getters**
    ``getconf`` can convert options into a few standard types:

    .. code-block:: python

        config.getbool('db.enabled', False)
        config.getint('db.port', 5432)
        config.getlist('db.tables')  # Expects a comma-separated list
        config.getfloat('db.auto_vacuum_scale_factor', 0.2)
        config.gettimedelta('account_activation.validity', '2d')
        config.getpath('django.static_root', pathlib.Path(BASE_DIR / 'static'))

    ``getconf`` can also convert options to user-defined standard-type-based types:

    .. code-block:: python

        class Environment(str, enum.Enum):
            DEV = 'dev'
            PROD = 'prod'
        config.getenum('environment', Environment.PROD)

Concepts
--------

``getconf`` relies on a few key concepts:

**namespace**
    Each ``ConfigGetter`` works within a specific namespace (its first argument).

    Its goal is to avoid mistakes while reading the environment:
    with ``ConfigGetter(namespace='myproj')``, only environment variables
    beginning with ``MYPROJ_`` will be read.

    It is, however, possible to disable namespacing by using
    ``ConfigGetter(namespace=getconf.NO_NAMESPACE)``.

**Sections**
    The configuration options for a project often grow quite a lot;
    to restrict complexity, ``getconf`` splits values into sections,
    similar to Python's ``configparser`` module.

    Section are handled differently depending on the actual configuration
    source:

    * ``section.key`` is mapped to ``MYPROJ_SECTION_KEY`` for environment variables
    * ``section.key`` is mapped to ``[section] key =`` in configuration files
    * ``section.key`` is mapped to ``defaults['section']['key']`` in the defaults dict.

**Default section**
    Some settings are actually "globals" for a projet.
    This is handled by unset section names:

    * ``key`` is mapped to ``MYPROJ_KEY`` for environment variables
    * ``key`` is mapped to ``[DEFAULT] key =`` in configuration files
    * ``key`` is mapped to ``defaults['DEFAULT']['key']`` in the defaults dict.


.. _PyPI: http://pypi.python.org/
