Contributing to the documentation

Here we describe the guidelines and conventions for contributing to the Finesse documentation.

How to build the documentation

A pdf and an html version of the documentation need to be built as part of the GitLab pipeline. They need to be manually triggered after the build jobs are completed. The generated pages can be accessed in the artefacts of the documentation building jobs. However, this is often not a convenient way to iterate when writing the documentation, and a local build of the documentation can be more efficient.

The documentation system uses Sphinx to build the document(s). If Finesse was installed for code development in the conda environment file (./environment.yml), everything needed should already be installed. If not, consult Installing Finesse for how to install Finesse.

The documentation can be built locally using the make commands executed in the docs/ subdirectory. Run make with no arguments to print a list of available output formats. For example:

make html

This will generate the website version in the docs/build/html directory (with docs/build/html/index.html as the landing page).

The build process can be quite long. To speed it up, you can skip building the API documentation pages, which takes a long time:

make html_no_api

or skip also the executing of the jupyter code using

make html_no_api_no_jupyter

To remove temporary files created during the build process, use:

make clean

Note

To build the PDF docs (using make latexpdf), you must ensure that a comprehensive LaTeX package (such as texlive) is available on the system path.

Supported formats

Finesse documentation supports two formats for creating pages:

  • reStructured Text (reST)

    The primary format supported by Sphinx is reStructured Text. Each .rst file corresponds to a page in the documentation. The extension jupyter_sphinx allows executing Python code and displaying the results directly in the documentation, including in the API pages generated from the Python docstrings.

  • MyST-NB

    It is possible to write jupyter notebooks (.ipynb) that can be included directly in the documentation, while still being fully compatible with jupyter. It is an easy way to create pages or code examples. MyST-NB adds some notations to the standard markdown used in the jupyter notebook to allow a seamless integration with Sphinx and reStructured Text.

    The JupyterLab plugin jupyterlab-myst can be installed using pip or the JupyterLab plugin manager and will allow the rendering of some MyST-NB specific formatting.

There is no preferred method to create a documentation page; the choice is left to the author. Newcomers may find it easier to write Jupyter notebooks as they are probably already familiar with the format, and it allows a live rendering of the page that closely resembles the final product (especially with the JupyterLab plugin).

See the Authoring documentation section for more information about the two formats.

Directory organization

docs

Root directory for the documentation. Notably, it contains the Makefile file defining the build target.

docs/source

Contains the source files for the documentation and the Sphinx config file conf.py. Each subdirectory inside docs/source corresponds to a section and contains the files needed to generate it.

Each directory, including docs/source, contains a file named index.rst. Any new page needs to be added to that index file to be shown in the table of contents of the documentation.

docs/build

This is where the documents created using make will be generated, each in their subdirectory.

docs/resources

Contains some resource files (like images). Resource files are also present in the source subdirectories.

Updating the Changelog

In principle, every change made to Finesse that is relevant to Finesse users should be documented in the Changelog. Internal changes relevant only to the developers can be left out. We follow the format from keepachangelog. Special care should be taken to document changes that are not backwards compatible (i.e. will break existing code) and changes that will quietly change the scientific output of existing code.

The changelog should always have a section on top titled ‘Next Release’, which should be replaced with the actual version when Releasing finesse. It is encouraged to write a small summary of the changes, highlighting the most important ones so users don’t have to scroll through all items to see if something is relevant. If possible, the changelog should refer to actual documentation pages, but it can include small code snippets or comparison plots highlighting the different output between the new and old versions.

Comments and todo items

The .. todo:: directive will add a highlighted todo item in the manual. These should be used only as placeholders for larger sections, such as .. todo:: This section is missing for a missing section. For internal todo items such as ‘fix this later’, a simple comment can be used, for example: .. Todo: fix this later.

Writing Sphinx compatible docstrings

To produce well-formatted API documentation for Finesse, all module, class and function docstrings will be written in the numpydoc style (follow the link for the style guide).

Note

In contrast to PEP-257, numpydoc asks for class __init__ methods to be documented in the class docstring, not under the __init__ method itself.

Note

There is currently no directly supported method for documenting properties in numpydoc, instead you should use reST syntax in the docstrings for a class property. This involves using docstrings only for the “getter” and passing the tags :`getter`: and :`setter`: to document both. An example is shown below for the nr property of the class BeamParam:

@property
def nr(self):
    """The refractive index associated with the `BeamParam`.

    :`getter`: Returns the index of refraction.
    :`setter`: Sets the index of refraction.
    """
    return self.__nr

@nr.setter
def nr(self, value):
    self.__nr = value

The above docstrings result in the finesse.gaussian.BeamParam.nr documentation page.

Documenting Cython extensions

See Documenting Cython extensions.

Style guide

Finesse is developed by many people and maintaining consistency across the documentation is essential. The following subsections describe some style aspects to be conformed to when writing documentation.

Where style guidance is undefined, conform first to the rules enforced by doc8 then the Python documentation style guide.

Line length

Try to stick to a maximum of 88 characters. This is consistent with the rules for Python code, set by Black. This limit isn’t just for aesthetics in your IDE: code blocks in documentation pages with longer lines will overflow the visible page and create irritating horizontal scroll bars.

You may wish to create a ruler in your IDE to give a visual cue for this limit.

Hint

In some editors you can highlight a block of text and press Alt + Q to automatically wrap the text at the configured line length. In Visual Studio Code you might wish to install the Rewrap extension to enable this shortcut, and set a ruler in .vscode/settings.json using e.g. "editor.rulers": [88],.

Style

Try not to write documentation with many nested subsections; documentation should be mostly prose. Only the first four section levels are displayed in the sidebar of the HTML documentation, and each level beyond the top level is hidden until its parent is navigated to. If a section makes sense to appear in the sidebar then it should be within the top four levels; use common sense.

Titles

Section titles should use sentence case, e.g. Showing output from inline scripts, not Showing Output from Inline Scripts.

Do not use backtick-style (``thing``) or replacement (e.g. |Finesse|) formatting in titles as these do not render nicely in the sidebar. Instead you could consider using single quotes, e.g. “Logging via the Python ‘logging’ module”.

Code examples

Code examples should follow the same style <code_style> as Finesse itself.

Grammar

Tone

Use an affirmative, succinct tone. Concise is better than verbose. Users typically don’t read whole pages of documentation but rather arrive at particular sections via links or search results.

English

Use of US English is preferred, for consistency with the Python documentation; however, refactoring existing text just for the sake of changing English forms is discouraged - focus your efforts on something more fruitful. As with the Python documentation, consistency within a page or section is more important than global consistency.

References to Finesse

Finesse 3 should be referred to in the documentation simply as Finesse. Explicit inclusion of version numbers should only be made when referring to or comparing differences in behaviour.

Core documentation should focus on explaining how Finesse 3 works, not how it’s different to other tools or previous versions. Discussions of differences between Finesse 2 and 3 should be kept in relevant sections. It’s fine however to include brief “see also” directives in Finesse 3 documentation pointing to such discussions.

Capitalisation

Various Finesse-related terms have particular capitalisation conventions. Some are also defined as macros which format the text appropriately:

  • |Finesse|, not e.g. FINESSE

  • Pykat, not e.g. PyKat

  • KatScript, not e.g. kat script, katscript, or kat-script

Linting tools

The doc8 package provides a command line tool to check documentation. Running doc8 from the project root directory will have it automatically pick up the line length setting defined in pyproject.toml. For instance, you can lint the whole documentation source with:

$ cd /path/to/finesse/git/project/  # The directory that contains pyproject.toml.
$ doc8 docs/source

This will print a list of files and their corresponding issues, if any.

Authoring documentation

Extensive documentation about reStructuredText and MyST can be found online. Here are some resources to get started:

In the following, important points and guidelines for Finesse will be presented.

reStructuredText (reST)

Sphinx’s default file format is reStructuredText. It is a versatile and extensive language offering many possibilities for creating rich documents with internal and external linking, images, figures, tables and more. To be able to fully utilize the format, some basic concepts need to be understood, notably the concepts of role and directive. They are key mechanisms for adding semantic meaning and extended functionality to documents.

role

A role is an inline markup element used to annotate small pieces of text with specific meaning or behavior. Roles are written using a colon syntax, such as :role:`text` (e.g., :math:`E=mc^2`), and are typically used to insert things like hyperlinks, inline code, or mathematical expressions. Roles help enrich the document by adding metadata or context.

directive

Directives are block-level constructs that extend reST’s capabilities beyond basic text formatting. They begin with a double-dot prefix and include a name and optional arguments or content (e.g., .. note:: or .. code-block:: python). Directives can be used to insert figures, generate tables of contents, or highlight source code.

Markedly Structured Text (MyST)

MyST extends standard Markdown (CommonMark) with features like directives and roles, similar to reStructuredText, making it compatible with Sphinx. MyST-NB allows the MyST language to be used inside Jupyter Notebook markdown cells. This allows authors to easily write Jupyter notebooks to be seamlessly integrated with the rest of the documentation while keeping them executable. See the Comparison between reST and MyST for a short comparison of the notations of reST and MyST.

Table 1 Comparison between reST and MyST

reStructuredText

MyST

Role

:role-name:`role content`
{role-name}`role content`

Directives

.. directivename:: arguments
   :key1: val1
   :key2: val2

   This is
   directive content
```{directivename} arguments
:key1: val1
:key2: val2

This is
directive content
```

Label

.. _my-label:
(my-label)=

Special formatting of the word Finesse

As shown here, Finesse uses a special formatting when displayed. To display it, you need to write |Finesse| when using reStructuredText and as {{Finesse}} when using MyST-NB.

Note

Do not use the special formatting in titles as it can break formatting when linked to or used in a table of contents.

What to add at the top of a page

At the top of a new page, include a label for internal linking and a title. In addition, when writing reStructuredText, you should include the /defs.hrst file so the special formatting of the word Finesse is activated. This formatting is available automatically when using MyST-NB.

Here are simple examples of what a header of a page should look like:

reStructuredText

.. include:: /defs.hrst
.. _my-section:

==================
My awesome section
==================

This amazing section contains ...

MyST-NB

(my-section)=

# My awesome section

This amazing section contains ...

Linking to internal and external objects

Sphinx enables you to cross-reference modules, classes, functions, and attributes both internal to the project and external to it. To cross-reference an internal object (or attribute, method etc.) simply use the following directives:

  • :mod:`.internal_module_name` to create a link to an internal module,

  • :class:`.internal_class_name` to create a link to an internal class,

  • :func:`.internal_function_name` to create a link to an internal function or :meth:`.internal_class_name.internal_function_name` to create a link to an internal class method,

  • :attr:`.internal_class_name.internal_attribute_name` to create a link to an internal class attribute.

The Finesse documentation tooling provides additional cross-reference support for various situations:

  • :kat:command:`command_name` to create a link to a kat-script command,

  • :kat:element:`element_name` to create a link to a kat-script element,

  • :kat:analysis:`analysis_name` to create a link to a kat-script analysis,

  • :issue:`123` to create a link to an issue on the tracker,

  • :source:`path/to/script.py` to create a link to a source code file relative to the Finesse package root (i.e. /src/finesse/).

Linking to objects in external modules is just as simple. What external modules are available are defined by the intersphinx_mapping inside finesse/docs/source/conf.py. Details on how to specify new targets in this variable see the intersphinx documentation. The available module for interlinking are:

Showing output from inline scripts

With MyST-NB, code execution and output can be used as usual. What you see is what you get.

For reST, the jupyter-sphinx extension is available which provides the ability to execute code embedded in the documentation in a Jupyter kernel, then show the code (with syntax highlighting) alongside the outputs of that code in the documentation. It also supports plot outputs (and others, such as LaTeX and JavaScript widgets).

Code is executed in the environment used to build the documentation, so the finesse package is available to import and run.

Simple code blocks can be executed with .. jupyter-execute:: directives. More advanced usage is possible, such as running scripts within different kernels (using the :id: directive option), showing line numbers, importing and showing the contents of scripts on the file system, etc. See the jupyter-sphinx documentation for more information.

Sections

With MyST-NB, the standard Markdown notation (#, ##, …) need to be used to structure the document.

With reST, there are particular characters assigned to heading levels; the structure is determined from the succession of headings as defined in each .rst file. Finesse documentation should nevertheless ideally follow this convention:

  • = with overline, for page titles

  • =, for sections

  • -, for subsections

  • ^, for subsubsections

  • ", for paragraphs

Code examples

Write code examples using the same formatting rules as Finesse source code.

Prefer the use of .. code-block:: (provided by Sphinx) rather than .. code:: (provided by docutils).