Skip to article frontmatterSkip to article content

How to update Sphinx options during the build

As part of the pydata-sphinx-theme we have a few settings that auto-enable extensions and configure them on behalf of the user. It has always been mysterious to me how to do this properly during the Sphinx build. It’s easy to configure things with conf.py ahead of time, but what if you want to manually set a value during the build?

I finally figured it out, so documenting the process here.

Use the builder-inited event

Define a Sphinx event for builder-inited. This will trigger after the builder has been selected, but before the environent is finalized for the build. This should be a function that takes a single (app) parameter.

Use app._raw_config to find the user-provided config

Use the app._raw_config object to detect user-given config. This is first written when Sphinx is initialized and should be a good indication of what the user provided.

This is useful if you only want to over-ride something if the user didn’t set it themselves. However, the app.config object will have all of the config options, including defaults.

Update configuration options with the app.config object

Update app.config.keyname. You can set and update configuration values directly with app.config.keyname = "foo". The way Sphinx does this is by directly setting app.config.__dict__["keyname"] = "foo", but this doesn’t seem to be necessary and I’m not sure why they do it that way.

Update HTML theme options with app.builder.theme_options

Update app.builder.theme_options. Many people (including myself) incorrectly try to update app.config.html_theme_options during a build event. But this doesn’t do anything because the’ve already been copied over to app.builder.theme_options early in the build process. Annoyingly, the copied dictionary in app.builder.theme_options does not point to the same points in memory as app.config.html_theme_options.

This copy action is done here.

An example

Here’s an example of the whole process in action:

# This function will update a single configuration value
def update_config(app):
   # Check if a value was provided by the user
   if "foo" in app.config._raw_values:
      # Update a config value
      app.config.__dict__["foo"] = "bar"

   # Update an HTML theme value
   app.builder.theme_options["foo2"] = "bar2"

# Register the above function to be called during the builder-inited phase
def setup(app):
  app.connect("builder-inited", update_config)