Skip to content

Commit

Permalink
docs: Make recipe work with MkDocs -f option
Browse files Browse the repository at this point in the history
  • Loading branch information
pawamoy committed Nov 12, 2023
1 parent b3edf89 commit 4a97755
Showing 1 changed file with 81 additions and 62 deletions.
143 changes: 81 additions & 62 deletions docs/recipes.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ Let say you have a project called `project`.
This project has a lot of source files, or modules,
which live in the `src` folder:

```
📁 repo
└─╴📁 src
└─╴📁 project
├─╴📄 lorem
├─╴📄 ipsum
├─╴📄 dolor
├─╴📄 sit
└─╴📄 amet
```tree
repo/
src/
project/
lorem
ipsum
dolor
sit
amet
```

Without an automatic process, you will have to manually
Expand All @@ -49,87 +49,102 @@ and configure it like so:

```yaml title="mkdocs.yml"
plugins:
- search # (1)
- search # (1)!
- gen-files:
scripts:
- docs/gen_ref_pages.py # (2)
- scripts/gen_ref_pages.py # (2)!
- mkdocstrings
```

1. Don't forget to load the `search` plugin when redefining the `plugins` item.
2. The magic happens here, see below how it works.

mkdocs-gen-files is able to run Python scripts at build time.
The Python script that we will execute lives in the docs folder,
The Python script that we will execute lives in a scripts folder,
and is named `gen_ref_pages.py`, like "generate code reference pages".

```python title="docs/gen_ref_pages.py"
```tree
repo/
docs/
index.md
scripts/
gen_ref_pages.py
src/
project/
mkdocs.yml
```

```python title="scripts/gen_ref_pages.py"
"""Generate the code reference pages."""

from pathlib import Path

import mkdocs_gen_files

for path in sorted(Path("src").rglob("*.py")): # (1)
module_path = path.relative_to("src").with_suffix("") # (2)
doc_path = path.relative_to("src").with_suffix(".md") # (3)
full_doc_path = Path("reference", doc_path) # (4)
src = Path(__file__).parent.parent / "src" # (1)!

for path in sorted(src.rglob("*.py")): # (2)!
module_path = path.relative_to(src).with_suffix("") # (3)!
doc_path = path.relative_to(src).with_suffix(".md") # (4)!
full_doc_path = Path("reference", doc_path) # (5)!

parts = list(module_path.parts)

if parts[-1] == "__init__": # (5)
if parts[-1] == "__init__": # (6)!
parts = parts[:-1]
elif parts[-1] == "__main__":
continue

with mkdocs_gen_files.open(full_doc_path, "w") as fd: # (6)
identifier = ".".join(parts) # (7)
print("::: " + identifier, file=fd) # (8)
with mkdocs_gen_files.open(full_doc_path, "w") as fd: # (7)!
identifier = ".".join(parts) # (8)!
print("::: " + identifier, file=fd) # (9)!

mkdocs_gen_files.set_edit_path(full_doc_path, path) # (9)
mkdocs_gen_files.set_edit_path(full_doc_path, path) # (10)!
```

1. Here we recursively list all `.py` files, but you can adapt the code to list
1. It's important to build a path relative to the script itself,
to make it possible to build the docs with MkDocs'
[`-f` option](https://www.mkdocs.org/user-guide/cli/#mkdocs-build).
2. Here we recursively list all `.py` files, but you can adapt the code to list
files with other extensions of course, supporting other languages than Python.
2. The module path will look like `project/lorem`.
3. The module path will look like `project/lorem`.
It will be used to build the *mkdocstrings* autodoc identifier.
3. This is the relative path to the Markdown page.
4. This is the absolute path to the Markdown page. Here we put all reference pages
into a `reference` folder.
5. This part is only relevant for Python modules. We skip `__main__` modules and
4. This is the partial path of the Markdown page for the module.
5. This is the full path of the Markdown page within the docs.
Here we put all reference pages into a `reference` folder.
6. This part is only relevant for Python modules. We skip `__main__` modules and
remove `__init__` from the module parts as it's implicit during imports.
6. Magic! Add the file to MkDocs pages, without actually writing it in the docs folder.
7. Build the autodoc identifier. Here we document Python modules, so the identifier
7. Magic! Add the file to MkDocs pages, without actually writing it in the docs folder.
8. Build the autodoc identifier. Here we document Python modules, so the identifier
is a dot-separated path, like `project.lorem`.
8. Actually write to the magic file.
9. We can even set the `edit_uri` on the pages.
9. Actually write to the magic file.
10. We can even set the `edit_uri` on the pages.

> NOTE:
> It is important to look out for correct edit page behaviour when using generated pages.
> For example, if we have `edit_uri` set to `blob/master/docs/` and the following
> file structure:
>
> ```
> 📁 repo
> ├─ 📄 mkdocs.yml
> │
> ├─ 📁 docs
> │ ├─╴📄 index.md
> │ └─╴📄 gen_ref_pages.py
> │
> └─╴📁 src
> └─╴📁 project
> ├─╴📄 lorem.py
> ├─╴📄 ipsum.py
> ├─╴📄 dolor.py
> ├─╴📄 sit.py
> └─╴📄 amet.py
> ```tree
> repo/
> mkdocs.yml
> docs/
> index.md
> scripts/
> gen_ref_pages.py
> src/
> project/
> lorem.py
> ipsum.py
> dolor.py
> sit.py
> amet.py
> ```
>
> Then we will have to change our `set_edit_path` call to:
>
> ```python
> mkdocs_gen_files.set_edit_path(full_doc_path, Path("../") / path) # (1)
> mkdocs_gen_files.set_edit_path(full_doc_path, Path("../") / path) # (1)!
> ```
>
> 1. Path can be used to traverse the structure in any way you may need, but
Expand Down Expand Up @@ -180,15 +195,15 @@ plugins:
- search
- gen-files:
scripts:
- docs/gen_ref_pages.py
- scripts/gen_ref_pages.py
- literate-nav:
nav_file: SUMMARY.md
- mkdocstrings
```

Then, the previous script is updated like so:

```python title="docs/gen_ref_pages.py" hl_lines="7 21 29 30"
```python title="scripts/gen_ref_pages.py" hl_lines="7 23 31 32"
"""Generate the code reference pages and navigation."""

from pathlib import Path
Expand All @@ -197,9 +212,11 @@ import mkdocs_gen_files

nav = mkdocs_gen_files.Nav()

for path in sorted(Path("src").rglob("*.py")):
module_path = path.relative_to("src").with_suffix("")
doc_path = path.relative_to("src").with_suffix(".md")
src = Path(__file__).parent.parent / "src"

for path in sorted(src.rglob("*.py")):
module_path = path.relative_to(src).with_suffix("")
doc_path = path.relative_to(src).with_suffix(".md")
full_doc_path = Path("reference", doc_path)

parts = tuple(module_path.parts)
Expand All @@ -209,16 +226,16 @@ for path in sorted(Path("src").rglob("*.py")):
elif parts[-1] == "__main__":
continue

nav[parts] = doc_path.as_posix() # (1)
nav[parts] = doc_path.as_posix() # (1)!

with mkdocs_gen_files.open(full_doc_path, "w") as fd:
ident = ".".join(parts)
fd.write(f"::: {ident}")

mkdocs_gen_files.set_edit_path(full_doc_path, path)

with mkdocs_gen_files.open("reference/SUMMARY.md", "w") as nav_file: # (2)
nav_file.writelines(nav.build_literate_nav()) # (3)
with mkdocs_gen_files.open("reference/SUMMARY.md", "w") as nav_file: # (2)!
nav_file.writelines(nav.build_literate_nav()) # (3)!
```

1. Progressively build the navigation object.
Expand All @@ -232,7 +249,7 @@ and replace it with a single line!
nav:
# rest of the navigation...
# defer to gen-files + literate-nav
- Code Reference: reference/ # (1)
- Code Reference: reference/ # (1)!
# rest of the navigation...
```

Expand All @@ -259,7 +276,7 @@ Well, this is possible thanks to a third plugin:

Update the script like this:

```python title="docs/gen_ref_pages.py" hl_lines="18 19"
```python title="scripts/gen_ref_pages.py" hl_lines="20 21"
"""Generate the code reference pages and navigation."""

from pathlib import Path
Expand All @@ -268,9 +285,11 @@ import mkdocs_gen_files

nav = mkdocs_gen_files.Nav()

for path in sorted(Path("src").rglob("*.py")):
module_path = path.relative_to("src").with_suffix("")
doc_path = path.relative_to("src").with_suffix(".md")
src = Path(__file__).parent.parent / "src"

for path in sorted(src.rglob("*.py")):
module_path = path.relative_to(src).with_suffix("")
doc_path = path.relative_to(src).with_suffix(".md")
full_doc_path = Path("reference", doc_path)

parts = tuple(module_path.parts)
Expand Down Expand Up @@ -301,7 +320,7 @@ plugins:
- search
- gen-files:
scripts:
- docs/gen_ref_pages.py
- scripts/gen_ref_pages.py
- literate-nav:
nav_file: SUMMARY.md
- section-index
Expand Down

0 comments on commit 4a97755

Please sign in to comment.