How to build these docs#

The documentation is a Sphinx project written in reStructuredText and rendered with the Book theme. Sources are in docs/; the generated site goes to docs/_build/html/ and is not committed.

Install#

The docs extra installs Sphinx and the Book theme into the active virtual environment:

.\.venv\Scripts\Activate.ps1
python -m pip install -e ".[docs]"

Build and view#

python -m sphinx -b html -W -E docs docs/_build/html
start docs/_build/html/index.html

Option

Effect

-b html

Build the HTML site.

-W

Treat warnings as errors, so a broken link, a missing toctree entry or a bad heading reference fails the build instead of shipping.

-E

Ignore the cached environment and re-read every file. Use it to pick up the version and the “last updated” time, which are computed when conf.py runs.

For a quicker edit loop, drop -E and -W and rebuild; Sphinx then rebuilds only changed pages. Run the full strict command before committing.

Where the pieces live#

File

Purpose

docs/conf.py

Sphinx settings: the sphinx_book_theme theme, the browser title, the date format, and the version, which is read from pyproject.toml so it is bumped in one place.

docs/index.rst

The landing page, with the version and build time, and the top-level toctree.

docs/<folder>/index.rst

The page that lists a folder’s documents in its own toctree (database/, appendix/).

docs/_build/

Generated output; listed in .gitignore and excluded in conf.py.

The sources sit directly in docs/ rather than in a docs/source/ folder, because the build output is already kept apart in docs/_build/.

Version and last updated#

  • The version shown in the browser title and on the landing page comes from the version line in pyproject.toml.

  • Last updated appears in every page footer and on the landing page. It is the time of the build, not of the last edit to each page, because the project is not required to be a Git repository. Per-page edit dates would need a Git-aware extension such as sphinx-last-updated-by-git.

Publishing the docs to GitHub Pages#

The built site is published from a separate repository, samkhalilian/samkhalilian.github.io, which GitHub Pages serves from the root of its main branch at https://samkhalilian.dev/ (the custom domain comes from the CNAME file). That repository contains only the contents of docs/_build/html, plus two Pages files that are not part of the Sphinx output:

  • CNAME: the custom domain. Deleting it breaks samkhalilian.dev.

  • .nojekyll: lets GitHub Pages serve the _static and _sources folders.

Publishing mirrors docs/_build/html into a clone of that repository, keeping those two files and .git:

Remove-Item -Recurse -Force docs\_build
python -m sphinx -b html -W -E docs docs/_build/html

git clone https://github.com/samkhalilian/samkhalilian.github.io.git $env:TEMP\pages
robocopy docs\_build\html $env:TEMP\pages /MIR /XD .git .doctrees /XF CNAME .nojekyll
git -C $env:TEMP\pages add -A
git -C $env:TEMP\pages status
git -C $env:TEMP\pages commit -m "Publish trade-engine docs"
git -C $env:TEMP\pages push

Notes:

  • Start from a clean build. Sphinx does not delete pages that no longer exist, so removing docs/_build first stops renamed or deleted pages from being published.

  • ``robocopy /MIR`` deletes anything in the target that is not in the source, apart from what is excluded (.git, CNAME, .nojekyll). Run it only against the temporary clone, and read git status before committing.

  • Robocopy exit codes 0 to 7 mean success (for example 1 means files were copied); 8 or higher is a failure.

  • Copy ``html``, not all of ``_build``. .doctrees is Sphinx’s build cache and is excluded.

  • The previous site is kept on a branch. Before this repository was changed to hold only these docs, its earlier contents (a separate blog) were saved on the backup-before-docs-replace branch, and they also remain in the Git history of main. To restore them, check out that branch or revert the publishing commit.

  • Anything else published to this repository replaces these docs. If the blog is built and copied into samkhalilian.github.io again, run the commands above afterwards.

  • The published site is public, even though both repositories are private. This includes the _sources folder with the reStructuredText sources. Review the docs before publishing.

Naming conventions#

  • reStructuredText file names use snake_case, for example multi_asset.rst and build_docs.rst, not multi-asset.rst. The name in a toctree or a :doc: reference is the same name without the extension. Folder names are single lowercase words where possible (database, appendix).

  • Repository names use kebab-case, for example trade-engine, not trade_engine (see How this repo was built).

Writing pages#

  • Put a page in the folder that matches its subject: storage and schemas in docs/database/, calculations and process pages in docs/, project and tooling notes in docs/appendix/.

  • Add every new page to a toctree. A page that is in no toctree triggers a warning, which fails the strict build.

  • Link pages with :doc:`/folder/page` and sections with :ref: rather than file paths, so Sphinx checks the links.

  • Write formulas with the math directive or the :math: role; they are rendered by MathJax. Use code:: text blocks for architecture sketches.

  • Use Implemented and Required as defined in Trade Engine — v1 Spec, and label planned designs as planned.

  • When code changes behaviour, update the page that describes it in the same commit.

Converting Markdown drafts#

The first drafts were Markdown. They were converted once with pandoc through the pypandoc_binary package, which bundles pandoc so nothing else needs installing. It is not in the docs extra because it was only needed for that one-off conversion:

import pypandoc
rst = pypandoc.convert_file(
    "page.md", "rst", format="gfm+tex_math_dollars", extra_args=["--list-tables"]
)

--list-tables produces list-table directives instead of grid tables that break when text changes, and tex_math_dollars turns $...$ into :math: roles. Links between documents must then be rewritten from page.md to :doc: references by hand or with a small script.

Troubleshooting#

Symptom

Cause and fix

Could not import extension or sphinx_book_theme not found

The docs extra is not installed in the active environment; run the install command above.

document isn't included in any toctree

Add the page to a toctree.

toctree contains reference to nonexisting document

A name in a toctree does not match a file; check the path and that it has no .rst extension.

Unknown target name

A section reference such as Some heading followed by _ does not match the heading text exactly, or the heading is in another file. Use :doc: or :ref: for another page.

The version or the build time looks stale

Rebuild with -E.

Title underline too short

The line of =, - or ~ under a heading must be at least as long as the heading.