# Runtime Settings Processing

Author:

  David Goodger, Günter Milde

Contact:
  docutils-develop@lists.sourceforge.net
Date:
  2024-08-15
Revision:
  9906
Copyright:
  This document has been placed in the public domain.

Abstract

A detailled description of Docutil's settings processing framework.

The docutils/__init__.py, docutils/core.py, and docutils.frontend.py modules are described. Following along with the actual code is recommended.

See Docutils Runtime Settings for a high-level description of the core API and Docutils Configuration for a description of the individual settings.

Note

This document is informal. It describes the state in Docutils 0.18.1. Implementation details will change with the move to replace the deprecated optparse module with argparse.

## Settings priority

Docutils overlays default and explicitly specified values from various sources such that settings behave the way we want and expect them to behave.

The souces are overlaid in the following order (later sources overwrite earlier ones):

1. Defaults specified in settings_spec and settings_defaults attributes for each component. (details)

2. Defaults specified in settings_default_overrides attribute for each component. (details)

3. Settings specified in the "settings_overrides" argument of the Publisher convenience functions rsp. the settings_overrides attribute of a core.Publisher instance. (details)

4. If enabled, settings specified in active sections of the configuration files in the order described in Configuration File Sections & Entries. (details)

   See also Configuration File Sections & Entries.

5. If enabled, command line arguments (details).

Settings assigned to the "settings" argument of the convenience functions or the Publisher.settings attribute are used instead of the above sources (see below for details for command-line tools and other applications).

## Runtime settings processing for command-line tools

The command-line front-end tools usually import and call the Publisher convenience function publish_cmdline().

1. docutils.core.publish_cmdline() creates a Publisher instance:

       publisher = core.Publisher(…, settings)

   eventually sets the components from the respective names, and calls

       publisher.publish(argv, …, settings_spec,
                         settings_overrides, config_section, …)

2. If publisher.settings is None, publisher.publish() calls:

       publisher.process_command_line(…,
           settings_spec, config_section, **defaults)

   with defaults taken from publisher.settings_overrides.

   If publisher.settings is defined, steps 3 to 5 are skipped.

3. publisher.process_command_line() calls:

       optpar = publisher.setup_option_parser(…,
                    settings_spec, config_section, **defaults)

4. publisher.setup_option_parser()

   - merges the value of the "config_section" argument into settings_spec and

   - creates an OptionParser instance

         optpar = docutils.frontend.OptionParser(components, defaults)

     with components the tuple of the SettingsSpec instances (publisher.parser, publisher.reader, publisher.writer, settings_spec)

5. The OptionParser instance prepends itself to the components tuple and calls self.populate_from_components(components), which updates the attribute self.defaults in two steps:

   1. For each component passed, component.settings_spec is processed and component.settings_defaults is applied.

   2. In a second loop, for each component component.settings_default_overrides is applied. This way, component.settings_default_overrides can override the default settings of any other component.

6. Back in OptionParser.__init__(), self.defaults is updated with the defaults argument passed to OptionParser(…) in step 5.

   This means that the settings_overrides argument of the convenience functions has priority over all SettingsSpec.settings_spec defaults.

7. If configuration files are enabled, self.get_standard_config_settings() is called.

   This reads the Docutils configuration files, and returns a dictionary of settings in active sections which is used to update optpar.defaults. So configuration file settings have priority over all software-defined defaults.

8. publisher.process_command_line() calls optpar.parse_args(). The OptionParser parses all command line options and returns a docutils.frontend.Values object. This is assigned to publisher.settings. So command-line options have priority over configuration file settings.

9. The <source> and <destination> command-line arguments are also parsed, and assigned to publisher.settings._source and publisher.settings._destination respectively.

10. publisher.publish() calls publisher.set_io() with no arguments. If either publisher.source or publisher.destination are not set, the corresponding publisher.set_source() and publisher.set_destination() are called:

    publisher.set_source()

      checks for a source_path argument, and if there is none (which is the case for command-line use), it is taken from publisher.settings._source. publisher.source is set by instantiating a publisher.source_class object. For command-line front-end tools, the default publisher.source_class (i.e. docutils.io.FileInput) is used.

    publisher.set_destination()

      does the same job for the destination. (the default publisher.destination_class is docutils.io.FileOutput).

11. publisher.publish() passes publisher.settings to the reader component's read() method.

12. The reader component creates a new document root node. nodes.document.__init__() adds the settings to the internal attributes.

    All components acting on the Document Tree are handed the document root node and can access the runtime settings as document.settings.

## Runtime settings processing for other applications

The convenience functions , core.publish_file(), core.publish_string(), or core.publish_parts() do not parse the command line for settings.

1. The convenience functions call the generic programmatic interface function core.publish_programmatically() that creates a core.Publisher instance

       pub = core.Publisher(…, settings)

   eventually sets the components from the respective names, and calls

       publisher.process_programmatic_settings(
           settings_spec, settings_overrides, config_section)

2. If publisher.settings is None, publisher.process_programmatic_settings() calls:

       publisher.get_settings(settings_spec, config_section, **defaults)

   with defaults taken from publisher.settings_overrides.

   If publisher.settings is defined, the following steps are skipped.

3. publisher.get_settings() calls:

       optpar = publisher.setup_option_parser(…,
                    settings_spec, config_section, **defaults)

4. The OptionParser instance determines setting defaults as described in steps 4 to 7 in the previous section.

5. Back in publisher.get_settings(), the frontend.Values instance returned by optpar.get_default_values() is stored in publisher.settings.

6. publish_programmatically() continues with setting publisher.source and publisher.destination.

7. Finally, publisher.publish() is called. As publisher.settings is not None, no further command line processing takes place.

8. All components acting on the Document Tree are handed the document root node and can access the runtime settings as document.settings (cf. steps 11 and 12 in the previous section).