Skip to content
Browse files

Use sphinx to create NVDA developer documentation (PR #9968)

Fixes #9840


When we switched to Python 3, we had to abandon Epydoc for developer documentation.
From the alternatives, sphinx seemed to be the most useful to us:
- It is the only supported api doc generator on Read the Docs
- It is used by numerous other projects, including python, wxPython, pyserial and configobj
- It is heavily extensible.
- In the end, it might allow us to integrate the user docs in the build process, thereby adding the ability to abandon txt2tags. Even if we don't, sphinx has markdown support with a simple extension.


Reimplements the functionality of `scons devDocs`, they are now build using sphinx.
Move `devDocs` build script from `sconstruct` to the devDocs folder

- The layout of the dev docs is likely to be broken, as we are still using epidoc style doc strings that have to be converted to the Python (restructured text) style doc strings
- Read the Docs builds docs on Linux. If we want to support this, it will require some source code changes. We can work around a lot of cases using mock imports. We may be able to build the docs ourselves on CI and push them afterwards. 
- No built in support for type hints, though there is an extension for that.

Incompatible doc string syntax:
Currently, we use epytext/epydoc style annotations for our doc strings. such as:
	@param test: a parameter
	@type test: int
Sphinx uses directives like `:param` and `:type`. It also allows nesting them, e.g. `:param test int: a parameter`
Another important prerequisite is that sphinx doc strings require an empty line between the doc string body and the parameter info.

	"""This is a doc string.
	:param test: this fails and isn't parsed correctly (i.e. printer literally)

	:param test: this succeeds and is marked up correctly.

sphinx-epytext has been considered but that doesn't handle the empty line case.
  • Loading branch information
leonardder authored and feerrenrut committed Jan 20, 2020
1 parent f25f33d commit e1e4a5515912721e839c862241a8356598050ba5
@@ -74,13 +74,12 @@ install:

- ps: |
$sconsOutTargets = "launcher"
$sconsOutTargets = "launcher developerGuide changes userGuide client"
$sconsOutTargets += " appx"
$sconsArgs = "version=$env:version"
if ($env:release) {
$sconsOutTargets += " changes userGuide developerGuide client"
$sconsArgs += " release=1"
if ($env:versionType) {
@@ -0,0 +1,2 @@
@@ -0,0 +1,105 @@
# A part of NonVisual Desktop Access (NVDA)
# Copyright (C) 2019 NV Access Limited, Leonard de Ruijter
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.

# Configuration file for the Sphinx documentation builder.

# -- Path setup --------------------------------------------------------------

import os
import sys
sys.path.insert(0, os.path.abspath('../source'))
import sourceEnv # noqa: F401, E402

# Initialize languageHandler so that sphinx is able to deal with translatable strings.
import languageHandler # noqa: E402

# Initialize globalvars.appArgs to something sensible.
import globalVars # noqa: E402

class AppArgs:
# Set an empty comnfig path
# This is never used as we don't initialize config, but some modules expect this to be set.
configPath = ""
secure = False
disableAddons = True
launcher = False

globalVars.appArgs = AppArgs()

# Import NVDA's versionInfo module.
import versionInfo # noqa: E402
# Set a suitable updateVersionType for the updateCheck module to be imported
versionInfo.updateVersionType = "stable"

# -- Project information -----------------------------------------------------

project =
copyright = versionInfo.copyright
author = versionInfo.publisher

# The major project version
version = versionInfo.formatVersionForGUI(

# The full version, including alpha/beta/rc tags
release = versionInfo.version

# -- General configuration ---------------------------------------------------

default_role = 'py:obj'

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = [

# -- Options for HTML output -------------------------------------------------

# The theme to use for HTML and HTML Help pages.

html_theme = "sphinx_rtd_theme"

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

# -- Extension configuration -------------------------------------------------

# sphinx.ext.autodoc configuration

# Both the class’ and the __init__ method’s docstring are concatenated and inserted.
autoclass_content = "both"
autodoc_member_order = 'bysource'
autodoc_mock_imports = [
"louis", # Not our project

# Perform some manual mocking of specific objects.
# autodoc can only mock modules, not objects.
from sphinx.ext.autodoc.mock import _make_subclass # noqa: E402

import config # noqa: E402
# Mock an instance of the configuration manager.
config.conf = _make_subclass("conf", "config")()
@@ -0,0 +1 @@
@@ -0,0 +1,2 @@
@@ -0,0 +1,35 @@
# This file is a part of the NVDA project.
# URL:
# Copyright 2019 NV Access Limited.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2.0, as published by
# the Free Software Foundation.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# This license can be found at:

import sys


doInstall = env.Command(
"_executed_requirements.txt", # $TARGET
"requirements.txt", # $SOURCE
# Install deps from requirements file.
sys.executable, "-m", "pip",
"install", "--no-warn-script-location", "-r", "$SOURCE",
# Copy the requirements file, this is used to stop scons from
# triggering pip from attempting re-installing when nothing has
# changed. Pip takes a long time to determine that deps are met.
Copy('$TARGET', '$SOURCE')


0 comments on commit e1e4a55

Please sign in to comment.
You can’t perform that action at this time.