Documenting configuration
It’s hard to keep configuration documentation up-to-date as projects change over time.
Everett comes with a Sphinx
extension for documenting configuration. It has autocomponentconfig
and
automoduleconfig
directives for automatically generating documentation. It
also has everett:component
and everett:option
directives for manually
documenting configuration. It also comes with :everett:option:
and
:everett:component:
roles letting you create links to specific
configuration things in your documentation.
Configuration options are added to the index and have unique links making it easier to find and point people to specific configuration documentation.
Changed in version 3.0.0: Complete rewrite of Sphinx directives.
Directives
- .. automoduleconfig::
Requires Python 3.8 or higher.
Automatically documents the configuration options set in a Python module using the specified
everett.manager.ConfigManager
.The argument is the Python dotted path to the
everett.manager.ConfigManager
instance.Note
The automoduleconfig directive works by parsing the Python module as an AST and then traverses the AST.
It does not execute the module, so it doesn’t evaluate any values.
Note
automoduleconfig
requires Python 3.8 or higher.If you’re using ReadTheDocs, it defaults to Python 3.7. You’ll need to configure the version of Python to use by adding a configuration file.
See ReadTheDocs configuration file documentation for more details.
Options
- :show-table: (no value)
If set, will create a table summarizing the options in this module with links to the option details.
- :hide-name: (no value)
If set, this will hide the name derived from the Python dotted path and use “Configuration” instead.
This affects how the options are indexed. If you’re documenting multiple modules this way, options that exist in multiple modules will create a conflict.
- :show-docstring: (str, empty str, or omitted)
If omitted, this does nothing.
If set, but with no value, this will include the module docstring in the documentation.
If set with a value of the name of an attribute in the module, this will include the value of that attribute in the documentation.
Example to include the module
__doc__
:.. automoduleconfig:: myproject.settings._config :show-docstring:
Example to include the value of the value of the
HELP
attribute:.. automoduleconfig:: myproject.settings._config :show-docstring: HELP
- :namespace: (str)
If set, this prefixes all the option keys with the specified namespace.
For example, if you set namespace to
source_db
, then keyhost
would result insource_db_host
being documented. (Case is dependent on the “case” directive option.)
- :case: ("upper", "lower", or omitted)
Specifies whether to convert the full namespaced key to all uppercase, all lowercase, or leave it as is.
- .. autocomponentconfig::
Automatically documents the configuration options for the specified class and its superclasses.
The argument is the Python dotted path to the class.
Warning
autocomponentconfig
imports the code to be documented. If any of the imported modules have side-effects at import, they will be executed when building the documentation.Options
- :show-table: (no value)
If set, will create a table summarizing the options in this component with links to the option details.
- :hide-name: (no value)
If set, this will hide the name of the class and use “Configuration” instead.
This affects how the options are indexed. If you’re documenting multiple classes this way, options that exist in multiple classes will create a conflict.
- :show-docstring: (str, empty str, or omitted)
If omitted, this does nothing.
If set, but with no value, this will include the class docstring in the documentation.
If set with a value of the name of an attribute of the class, this will include the value of that attribute in the documentation.
Example to include the class docstring:
.. automoduleconfig:: myproject.MyClass :show-docstring:
Example to include the value of the value of the
HELP
attribute:.. automoduleconfig:: myproject.MyClass :show-docstring: HELP
- :namespace: (str)
If set, this prefixes all the option keys with the specified namespace.
For example, if you set namespace to
source_db
, then keyhost
would result insource_db_host
being documented. (Case is dependent on the “case” directive option.)
- :case: ("upper", "lower", or omitted)
Specifies whether to convert the full namespaced key to all uppercase, all lowercase, or leave it as is.
- .. everett:component::
Defines an Everett component which is any Python class that has an inner class named
Config
which defines configuration options.The argument is the Python dotted path to the class.
Add
everett:option
as part of the description.
- .. everett:option::
Defines an Everett configuration option.
The argument is the option key.
Options
- :parser: (str)
The name of the parser for this option.
- :default: (str)
If not set, the default is
NO_VALUE
which means that this option has no default value.If set, this is the default value. Enclose the value in double-quotes because all default values must be strings.
- :required: (no value)
If set, this option is required.
If not set and the option has a default, then this option is not required.
If not set and the option has no default, then this option is required.
This option is not required:
.. everett:option:: HOST :default: localhost
These two options are required:
.. everett:option:: USERNAME .. everett:option:: PASSWORD :required:
Examples
Documenting component configuration
Here’s an example Everett component:
# recipes_appconfig.py
import logging
from everett.manager import ConfigManager, Option
TEXT_TO_LOGGING_LEVEL = {
"CRITICAL": 50,
"ERROR": 40,
"WARNING": 30,
"INFO": 20,
"DEBUG": 10,
}
def parse_loglevel(value):
try:
return TEXT_TO_LOGGING_LEVEL[value.upper()]
except KeyError as exc:
raise ValueError(
f'"{value}" is not a valid logging level. Try CRITICAL, ERROR, '
"WARNING, INFO, DEBUG"
) from exc
class AppConfig:
class Config:
debug = Option(
parser=bool,
default="false",
doc="Turns on debug mode for the application",
)
loglevel = Option(
parser=parse_loglevel,
default="INFO",
doc=(
"Log level for the application; CRITICAL, ERROR, WARNING, INFO, "
"DEBUG"
),
)
def init_app():
manager = ConfigManager.from_dict({})
config = manager.with_options(AppConfig())
logging.basicConfig(level=config("loglevel"))
if config("debug"):
logging.info("debug mode!")
if __name__ == "__main__":
init_app()
You can use the autocomponentconfig
directive to extract the configuration
information from the AppConfig
class and document it:
.. autocomponentconfig:: recipes_appconfig.AppConfig
:case: upper
:show-table:
That gives you something that looks like this:
- component recipes_appconfig.AppConfig
Configuration summary:
Setting
Parser
Required?
bool
recipes_appconfig.parse_loglevel
Configuration options:
- DEBUG
- Parser:
bool
- Default:
“false”
- Required:
No
Turns on debug mode for the application
- LOGLEVEL
- Parser:
recipes_appconfig.parse_loglevel
- Default:
“INFO”
- Required:
No
Log level for the application; CRITICAL, ERROR, WARNING, INFO, DEBUG
You can link to components with the :everett:component:
role and options
using the :everett:option:
role.
Example component link:
Component link: :everett:component:`recipes_appconfig.AppConfig`
Component link: recipes_appconfig.AppConfig
Example option link:
Option link: :everett:option:`recipes_appconfig.AppConfig.DEBUG`
Option link: recipes_appconfig.AppConfig.DEBUG
Documenting module configuration
You can use automoduleconfig
to document configuration that’s set at module
import. This is helpful for Django settings modules.
Example configuration code that sets up a
everett.manager.ConfigManager
and calls it _config
:
# recipes_djangosettings.py
from everett.manager import ConfigManager
_config = ConfigManager.basic_config()
DEBUG = _config(
"debug", parser=bool, default="False", doc="Whether or not DEBUG mode is enabled."
)
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.memcached.PyMemcacheCache",
"LOCATION": _config(
"cache_location", default="127.0.0.1:11211", doc="Memcache cache location."
),
"TIMEOUT": _config(
"cache_timeout",
default="500",
parser=int,
doc="Timeout to use when accessing cache.",
),
"KEY_PREFIX": _config(
"cache_key_prefix",
default="socorro",
doc="Key prefix to use for all cache keys.",
),
}
}
Example documentation directive:
.. automoduleconfig:: recipes_djangosettings._config
:hide-name:
:case: upper
:show-table:
That gives you this:
- Configuration
Configuration summary:
Setting
Parser
Required?
bool
str
int
str
Configuration options:
- DEBUG
- Parser:
bool
- Default:
“False”
- Required:
No
Whether or not DEBUG mode is enabled.
- CACHE_LOCATION
- Parser:
str
- Default:
“127.0.0.1:11211”
- Required:
No
Memcache cache location.
- CACHE_TIMEOUT
- Parser:
int
- Default:
“500”
- Required:
No
Timeout to use when accessing cache.
- CACHE_KEY_PREFIX
- Parser:
str
- Default:
“socorro”
- Required:
No
Key prefix to use for all cache keys.