Config Options, a Sphinx extension

Documentation Status

This is the README.rst file of the repo. I recommend to compare the raw text on github with the built documentation.

Motivation

During coding, I often define a (nested) dictionary config which collects all the necessary parameters for setting up a simulation (or equivalently: creating a complicated object), i.e., I have something like a setup(config) function, which sets up the whole thing, and the config dictionary contains all the parameters required to run the simulation/create the complicated object. The config then gets passed on to other functions/classes, which can read out config values and take appropriate actions. The motivation for this extension is that I want to document the entries of the config dictionary close to the code using them, not in the documentation of the setup function. However, inside the setup function, we need to collect all the possible values of the config to give the user an idea of what he options he can choose. That’s what this extension does.

What this is

This (more precisely, the file ext/sphinx_cfg_options.py) is an extension for Sphinx. It adds the domain cfg with directives .. cfg:config:: config_name to document a config (= a bunch of options) and .. cfg:option:: option_name (= an entry of a config). The roles :cfg:config: and :cfg:option: allow references to these definitions from anywhere in the documentation. Moreover, the options of a given config are collected and summarized at the beginning of the config description. Further, there are two indices provided, which list all the options and configs at a single place and enhance search results:

Example usage

Consider a factory producing vehicles. It can define the following config with a .. cfg:config:: Vehicle directive.

config Vehicle
option default summary

fuel

"gasoline"

Type of the used fuel, ``"gasoline"`` or ``"diesel"``.

fuel_consumption

How many liters of fuel are used for going 100km.

max_speed

220.

Maximum speed of the vehicle in km/h. [...]

tank

The capacity of the tank in liters.

option max_speed: float = 220.

Maximum speed of the vehicle in km/h. This description might go over multiple lines and gets fully parsed.

Note

The table above only shows the first line of the description.

In the built documentation, this directive includes a summary table in the beginning with all the options defined for the config of that name “Vehicle”.

In the function that sets up the engine, we notice that we need another parameter: the type of the fuel. If we want to define only a single option value, we can use the .. cfg:option:: directive:

option Vehicle.fuel: str = "gasoline"

Type of the used fuel, "gasoline" or "diesel".

If you want to document multiple options at once, Alternatively, it can be more conventient to use the .. cfg:configoptions:: directive, which gets parsed in the same way as the .. cfg:config::.

option Vehicle.tank: float

The capacity of the tank in liters.

option Vehicle.fuel_consumption: float

How many liters of fuel are used for going 100km.


Now let’s say we want to setup a factory for cars. The car factory can use the vehicle factory, so the config of the car factory should include the config of the vehicle factory. This is indicated by the option :include: Vehicle in the body of the config:

config Car
option default summary

fuel (from Vehicle)

"gasoline"

Type of the used fuel, ``"gasoline"`` or ``"diesel"``.

fuel_consumption (from Vehicle)

How many liters of fuel are used for going 100km.

max_speed (from Vehicle)

220.

Maximum speed of the vehicle in km/h. [...]

tank (from Vehicle)

The capacity of the tank in liters.

You can also link to the configs with Vehicle and Car, and to individual parameters like Vehicle.fuel or Car.fuel; the latter two point to the same definition in this case.

Of course, a new config can also define it’s own parameters in addition to using the include. Also, note that the include is recursive, as shown in the following example. In case of duplicated parameter keys, all definitions are listed.

config ElectricCar
option default summary

fuel

Additional choice ``"battery"`` on top of what :cfg:option:`Vehicle.fuel` d [...]

fuel_consumption (from Vehicle)

How many liters of fuel are used for going 100km.

hybrid

False

Whether the car has both an internal combustion engine and an electric moto [...]

max_speed (from Vehicle)

220.

Maximum speed of the vehicle in km/h. [...]

tank (from Vehicle)

The capacity of the tank in liters.

option fuel

Additional choice "battery" on top of what Vehicle.fuel defines.

option hybrid: bool = False

Whether the car has both an internal combustion engine and an electric motor, or not.

As you might have expected, the references Vehicle.fuel and ElectricCar.fuel now point to the two different definitions.

Tip

You can include a config of the same name at multiple positions in the documentation, and you don’t need to repeat all the options again. If you want to specify what the :cfg:config: role points to, you can use the :master: option in one of the .. cfg:config directives, as demonstrated in the following.

config ElectricCar
option default summary

fuel

Additional choice ``"battery"`` on top of what :cfg:option:`Vehicle.fuel` d [...]

fuel_consumption (from Vehicle)

How many liters of fuel are used for going 100km.

hybrid

False

Whether the car has both an internal combustion engine and an electric moto [...]

max_speed (from Vehicle)

220.

Maximum speed of the vehicle in km/h. [...]

tank (from Vehicle)

The capacity of the tank in liters.

Installation

You need Sphinx version >=3.0. Put the ext/sphinx_cfg_options.py somewhere where it can be imported as python module during the sphinx build. (This can be acchieved by updating sys.path inside the conf.py, take a look at the example provided in this repo).

config conf.py
option default summary

cfg_options_always_include

[]

List of config names which each config should include. [...]

cfg_options_default_in_summary_table

True

Whether to include the column "default" in the summary tables.

cfg_options_parse_comma_sep_names

False

When parsing the content of ``.. cfg:config::``, [...]

cfg_options_parse_numpydoc_style_options

True

Allows to disable the parsing of the ``.. cfg:config::`` content. [...]

cfg_options_recursive_includes

True

If config A includes B and B includes C, this option sets whether A automat [...]

cfg_options_summary

"table"

Choose how to format the summary at the g

cfg_options_table_add_header

True

Include the header "option default summary" in the option tables in the beg [...]

cfg_options_unique

True

If True, the options within a config should be unique, and only one is shown.

option cfg_options_recursive_includes = True

If config A includes B and B includes C, this option sets whether A automatically includes C.

option cfg_options_parse_numpydoc_style_options = True

Allows to disable the parsing of the .. cfg:config:: content. If disabled, you need to use the .. cfg:option:: for all context.

option cfg_options_parse_comma_sep_names = False

When parsing the content of .. cfg:config::, allow multiple ‘,’-separated option names in a single line.

option cfg_options_summary: "table", "list", or None = "table"

Choose how to format the summary at the g

option cfg_options_table_add_header = True

Include the header “option default summary” in the option tables in the beginnning of a config.

option cfg_options_default_in_summary_table = True

Whether to include the column “default” in the summary tables.

option cfg_options_unique = True

If True, the options within a config should be unique, and only one is shown.

option cfg_options_always_include: list = []

List of config names which each config should include. This is usefull if you have default values which are read out in any config.

Limitations

  • Right now, the “summary” of an option to be included into the summary table of a config does not get parsed.

  • Parsing of the optionname : type = value line is probably not very stable.

License

MIT license, feel free to reuse the extension in your own projects.