Skip to content

Commit

Permalink
Refactor auto-generate API docs (#331)
Browse files Browse the repository at this point in the history
* Add `clean` action to Windows `make` file

* Use `fail-on-warning` mode in Windows `make` file

* Drop unused `--keep-going` flag in Makefile

* Refactor auto-generate api docs

* Update contributing docs

* Remove Sphinx version constraint

* Document make-mode only

* Allow target chaining in Windows make
  • Loading branch information
lochhh authored Oct 25, 2024
1 parent 1b6b44d commit 7813e7c
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 65 deletions.
51 changes: 14 additions & 37 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -291,55 +291,24 @@ All subsequent commands should be run from this directory.

To build the documentation, run:

::::{tab-set}
:::{tab-item} Unix platforms with `make`
```sh
make html
```
The local build can be viewed by opening `docs/build/html/index.html` in a browser.
:::

:::{tab-item} All platforms
```sh
python make_api_index.py && sphinx-build source build -W --keep-going
```
The local build can be viewed by opening `docs/build/index.html` in a browser.
:::
::::

To re-build the documentation after making changes, run the command below. It will remove all generated files in `docs/`,
including the auto-generated API index `source/api_index.rst`, and those in `build/`, `source/api/`, and `source/examples/`, and then re-build the documentation.
To re-build the documentation after making changes, we recommend removing existing build files first.
The following command will remove all generated files in `docs/`,
including the auto-generated API index `source/api_index.rst`, and those in `build/`, `source/api/`, and `source/examples/`. It will then re-build the documentation:

::::{tab-set}
:::{tab-item} Unix platforms with `make`
```sh
make clean html
```
:::

:::{tab-item} All platforms
```sh
rm -f source/api_index.rst && rm -rf build && rm -rf source/api && rm -rf source/examples
python make_api_index.py && sphinx-build source build -W --keep-going
```
:::
::::

To check that external links are correctly resolved, run:

::::{tab-set}
:::{tab-item} Unix platforms with `make`
```sh
make linkcheck
```
:::

:::{tab-item} All platforms
```sh
sphinx-build source build -b linkcheck -W --keep-going
```
:::
::::

If the linkcheck step incorrectly marks links with valid anchors as broken, you can skip checking the anchors in specific links by adding the URLs to `linkcheck_anchors_ignore_for_url` in `docs/source/conf.py`, e.g.:

Expand All @@ -352,6 +321,14 @@ linkcheck_anchors_ignore_for_url = [
]
```

:::{tip}
The `make` commands can be combined to run multiple tasks sequentially.
For example, to re-build the documentation and check the links, run:
```sh
make clean html linkcheck
```
:::

## Sample data

We maintain some sample datasets to be used for testing, examples and tutorials on an
Expand Down Expand Up @@ -399,9 +376,9 @@ To add a new file, you will need to:
6. Determine the sha256 checksum hash of each new file. You can do this in a terminal by running:
::::{tab-set}
:::{tab-item} Ubuntu
```bash
sha256sum <filename>
```
```bash
sha256sum <filename>
```
:::

:::{tab-item} MacOS
Expand Down
3 changes: 1 addition & 2 deletions docs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
# You can set these variables from the command line, and also
# from the environment for the first two.
# -W: if there are warnings, treat them as errors and exit with status 1.
# --keep-going: run sphinx-build to completion and exit with status 1 if errors.
SPHINXOPTS ?= -W --keep-going
SPHINXOPTS ?= -W
SPHINXBUILD ?= sphinx-build
SOURCEDIR = source
BUILDDIR = build
Expand Down
19 changes: 16 additions & 3 deletions docs/make.bat
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ if "%SPHINXBUILD%" == "" (
)
set SOURCEDIR=source
set BUILDDIR=build
set SPHINXOPTS=-W

%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
Expand All @@ -25,10 +26,22 @@ if errorlevel 9009 (

if "%1" == "" goto help

echo "Generating API index..."
python make_api_index.py
:process_targets
if "%1" == "clean" (
@echo Removing auto-generated files under 'docs' and 'src'...
rmdir /S /Q %BUILDDIR%
del /Q %SOURCEDIR%\api_index.rst
rmdir /S /Q %SOURCEDIR%\api\
rmdir /S /Q %SOURCEDIR%\examples\
) else (
@echo Generating API index...
python make_api_index.py
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
)

shift
if not "%1" == "" goto process_targets

%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end

:help
Expand Down
37 changes: 15 additions & 22 deletions docs/make_api_index.py
Original file line number Diff line number Diff line change
@@ -1,43 +1,36 @@
"""Generate the API index page for all ``movement`` modules."""

import os
from pathlib import Path

# Modules to exclude from the API index
exclude_modules = ["cli_entrypoint"]

# Set the current working directory to the directory of this script
script_dir = os.path.dirname(os.path.abspath(__file__))
script_dir = Path(__file__).resolve().parent
os.chdir(script_dir)


def make_api_index():
"""Create a doctree of all ``movement`` modules."""
doctree = "\n"

for root, _, files in os.walk("../movement"):
# Remove leading "../"
root = root[3:]
for file in sorted(files):
if file.endswith(".py") and not file.startswith("_"):
# Convert file path to module name
module_name = os.path.join(root, file)
module_name = module_name[:-3].replace(os.sep, ".")
# Check if the module should be excluded
if not any(
file.startswith(exclude_module)
for exclude_module in exclude_modules
):
doctree += f" {module_name}\n"

api_path = Path("../movement")
for path in sorted(api_path.rglob("*.py")):
if path.name.startswith("_"):
continue
# Convert file path to module name
rel_path = path.relative_to(api_path.parent)
module_name = str(rel_path.with_suffix("")).replace(os.sep, ".")
if rel_path.stem not in exclude_modules:
doctree += f" {module_name}\n"
# Get the header
with open("./source/_templates/api_index_head.rst") as f:
api_head = f.read()
api_head_path = Path("source") / "_templates" / "api_index_head.rst"
api_head = api_head_path.read_text()
# Write api_index.rst with header + doctree
with open("./source/api_index.rst", "w") as f:
f.write("..\n This file is auto-generated.\n\n")
output_path = Path("source") / "api_index.rst"
with output_path.open("w") as f:
f.write(api_head)
f.write(doctree)
print(os.path.abspath("./source/api_index.rst"))


if __name__ == "__main__":
Expand Down
2 changes: 1 addition & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ myst-parser
nbsphinx
pydata-sphinx-theme
setuptools-scm
sphinx>=7.0
sphinx
sphinx-autodoc-typehints
sphinx-design
sphinx-gallery
Expand Down
3 changes: 3 additions & 0 deletions docs/source/_templates/api_index_head.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
..
This file is auto-generated.
.. _target-api:

API Reference
Expand Down

0 comments on commit 7813e7c

Please sign in to comment.