Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve documentation #87

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
4 changes: 4 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.todo',
'sphinx.ext.viewcode',
]

Expand All @@ -57,6 +58,9 @@
autodoc_preserve_defaults = True


todo_include_todos = False


default_role = 'py:obj'


Expand Down
105 changes: 105 additions & 0 deletions docs/examples.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
.. _examples:

Examples
========

Although confidence is internally divided in a number of modules, all of the functions and types intended for use are available to import from the confidence module.

.. code-block:: python

# manually creating a Configuration object from a dict of values is about as
# simple as it sounds:
config = confidence.Configuration({
'service.host': 'example.com',
'service.port': 443,
})

# suppose there's a function connect that takes two arguments
# we can connect to the configured host and port as such:
connection = connect(config.service.host, config.service.port)
# should the argument names align with the configuration (host and port),
# we could treat the configured namespace "service" as a dict and pass it as such:
connection = connect(**config.service)

Reading configuration from a file
---------------------------------

Wrapping a `dict` with a `Configuration` is nice, but configuration is more often found in files.
Confidence loads configuration from file in the YAML format:

.. code-block:: yaml

# suppose we'd save this as path/to/file.yaml
service:
host: example.com
port: 443
# note that we could also have expressed the two properties as
# service.host: ...
# service.port: ...
# dotted names are equivalent to nested ones

.. code-block:: python

# loadf simply takes a path or path-like to load configuration from
config = confidence.loadf('path/to/file.yaml')
# the result is the same as the example above, we can use config.service like we would a dict
connection = connect(**config.service)

Reading from multiple files
---------------------------

If you split your configuration over multiple files as they contain configuration for different things, like a service to connect to and some local paths to store data, confidence can load them both as if they were one:

.. code-block:: yaml

# some system-wide configuration in /etc/paths.yaml
paths:
data: /storage/data
backup: /mnt/backup/data

.. code-block:: yaml

# service configuration as before, stored in path/to/service.yaml
service.host: example.com
service.port: 443

.. code-block:: python

# loadf can take multiple files, the contents of which are combined into a
# single Configuration object
config = confidence.loadf('/etc/paths.yaml', 'path/to/service.yaml')

# there's still something to connect to the service
connection = connect(**config.service)
# and some extra things that configure the place to backup to
connection.backup_to(config.paths.backup)

Overriding defaults from one file to the next
---------------------------------------------

If values from multiple files overlap (like if ``/etc/paths.yaml`` would contain ``service.port: 80``), things become slightly more complicated.
Confidence uses a predictable :term:`precedence` of content here: the value that gets loaded last has the highest precedence (or 'wins').
`loadf` will load content in the order of the arguments that get passed, so ``service.port`` would be 443, as defined in ``path/to/service.yaml``.
You can use this behaviour to define defaults somewhere, that get overridden later:

.. code-block:: yaml

# some system-wide configuration in /etc/paths.yaml
service.port: 80

paths:
data: /storage/data
backup: /mnt/backup/data

.. code-block:: yaml

service:
host: example.com
port: 443

.. todo::

- Configuration from a name
- Configuration from multiple names
- Configuration from reordered loaders
- Configuration from mixed / custom loaders
23 changes: 23 additions & 0 deletions docs/glossary.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Glossary
========

.. glossary::
:sorted:

load order

loader

locality

namespace

precedence

reference
22 changes: 17 additions & 5 deletions docs/index.rst
Original file line number Diff line number Diff line change
@@ -1,20 +1,32 @@
Configure with confidence
=========================

``confidence`` helps loading configuration options from file into a user-friendly object at runtime.
Confidence does two things: it helps loading configuration options from file(s) and presents those options as a user-friendly object at runtime.
Inspired by the way Python's own ``pip`` reads its configuration (try ``pip config debug`` if you're not familiar with ``pip``'s configuration),
confidence uses a similarly flexible, but deterministic approach to combining information from multiple configuration files.
If that sounds awfully complicated, there's no requirement that you need to use anything that feels complicated.
See the :ref:`examples <examples>`, ranging from very simple to more complex uses of confidence' capabilities.

As a quick overview, confidence contains the following features:

- dict-like `Configuration` object supporting attribute access to configured values;
- customizable loading of multiple sources (files, environment variables, …) into a single object with deterministic precedence of those sources;
- the ability to make and resolve references to values or entire namespaces.

Contents
--------

.. toctree::
:maxdepth: 2

examples
use
recipes
api
glossary

.. todo::

Indices and tables
------------------
Integrate ``CHANGES.md`` here without having to duplicate it.

* :ref:`genindex`
* :ref:`search`
.. todolist::
14 changes: 8 additions & 6 deletions docs/recipes.rst
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
Recipes
=======

- option subtrees
- default
- singular vs plural
- combining with command line arguments
- command line defaults from files
- command line is highest precedence
.. todo::

- option subtrees
- default
- singular vs plural
- combining with command line arguments
- command line defaults from files
- command line is highest precedence
10 changes: 7 additions & 3 deletions docs/use.rst
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
How to use confidence
=====================

- loading files
- loading by name
- creating `.Configuration` objects manually
.. todo::

- loading files
- loading by name
- creating `.Configuration` objects manually
- pass values as ``**kwargs``
- fail-fast: missing

Logging
-------
Expand Down
9 changes: 9 additions & 0 deletions noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ def update(session):
session.run('pip-compile', '--upgrade', '--no-header', '--no-emit-index-url', '--pip-args', f'--python-version {oldest_python}', '--output-file', 'test-requirements.txt', 'test-requirements.in')


@nox.session(python=newest_python)
def docs(session):
session.install('-r', 'requirements.txt')
session.install('sphinx', 'sphinx-rtd-theme')

# override setting to include todos here
session.run('sphinx-build', '-b', 'html', '-D', 'todo_include_todos=True', 'docs/', 'dist/docs/')


@nox.session(python=oldest_python)
def dist(session):
session.install('wheel')
Expand Down