Skip to content

Commit ff4d83d

Browse files
committed
👌 IMPROVE: toc.yml validation
1 parent 030e06f commit ff4d83d

File tree

3 files changed

+24
-3
lines changed

3 files changed

+24
-3
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ external_toc_path = "_toc.yml" # optional, default: _toc.yml
2323
external_toc_exclude_missing = False # optional, default: False
2424
```
2525

26+
Note the `external_toc_path` is always read as a Unix path.
27+
2628
### Basic Structure
2729

2830
A minimal ToC defines the top level `root` key, for a single root document file:
@@ -326,6 +328,9 @@ Questions / TODOs:
326328
- test against orphan file
327329
- https://github.com/executablebooks/sphinx-book-theme/pull/304
328330
- CLI command to generate toc from existing documentation `toctrees` (and then remove toctree directives)
331+
- test rebuild on toc changes (and document how rebuilds are controlled when toc changes)
332+
- some jupyter-book issues point to potential changes in numbering, based on where the `toctree` is in the document.
333+
So could look into placing it e.g. under the first heading/title
329334

330335
[github-ci]: https://github.com/executablebooks/sphinx-external-toc/workflows/continuous-integration/badge.svg?branch=main
331336
[github-link]: https://github.com/executablebooks/sphinx-external-toc

sphinx_external_toc/api.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ def parse_toc_yaml(path: Union[str, Path], encoding: str = "utf8") -> SiteMap:
161161
def parse_toc_data(data: Dict[str, Any]) -> SiteMap:
162162
"""Parse a dictionary of the ToC."""
163163
if not isinstance(data, Mapping):
164-
MalformedError(f"toc is not a mapping: {type(data)}")
164+
raise MalformedError(f"toc is not a mapping: {type(data)}")
165165

166166
defaults: Dict[str, Any] = data.get("defaults", {})
167167

@@ -210,11 +210,22 @@ def _parse_doc_item(
210210
"toctree section contains incompatible keys "
211211
f"{link_keys!r}: {path}{part_idx}/{sect_idx}"
212212
)
213+
213214
if link_keys == {FILE_KEY}:
214215
sections.append(FileItem(section[FILE_KEY]))
215216
elif link_keys == {GLOB_KEY}:
217+
if "sections" in section or "parts" in section:
218+
raise MalformedError(
219+
"toctree section contains incompatible keys "
220+
f"{GLOB_KEY} and parts/sections: {path}{part_idx}/{sect_idx}"
221+
)
216222
sections.append(GlobItem(section[GLOB_KEY]))
217223
elif link_keys == {URL_KEY}:
224+
if "sections" in section or "parts" in section:
225+
raise MalformedError(
226+
"toctree section contains incompatible keys "
227+
f"{URL_KEY} and parts/sections: {path}{part_idx}/{sect_idx}"
228+
)
218229
sections.append(UrlItem(section[URL_KEY], section.get("title")))
219230

220231
# generate toc key-word arguments

sphinx_external_toc/events.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Sphinx event functions and directives."""
22
import glob
3-
from pathlib import Path
3+
from pathlib import Path, PurePosixPath
44
from typing import Any, List, Optional, Set
55

66
from docutils import nodes
@@ -50,8 +50,13 @@ def parse_toc_to_env(app: Sphinx, config: Config) -> None:
5050
5151
Also, change the ``master_doc`` and add to ``exclude_patterns`` if necessary.
5252
"""
53+
path = Path(app.srcdir) / PurePosixPath(app.config["external_toc_path"])
54+
if not (path.exists() and path.is_file()):
55+
raise ExtensionError(
56+
f"[etoc] `external_toc_path` is not an existing file: {path}"
57+
)
5358
try:
54-
site_map = parse_toc_yaml(Path(app.srcdir) / app.config["external_toc_path"])
59+
site_map = parse_toc_yaml(path)
5560
except Exception as exc:
5661
raise ExtensionError(f"[etoc] {exc}") from exc
5762
config.external_site_map = site_map

0 commit comments

Comments
 (0)