Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 FIX: fixing chapters numbering #829

Merged
merged 2 commits into from Jul 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
54 changes: 28 additions & 26 deletions docs/customize/toc.md
Expand Up @@ -110,37 +110,39 @@ We recommend nesting your sections no more than 3 layers deep (as shown above).
## Number your book's sections

You can automatically add numbers to each section of your book. To add numbers
to any section or subsection of the book, add the `numbered: true` flag to its
entry in your `_toc.yml` file. For example:
to **all sections of your book**, add the `numbered: true` flag to
your introduction page entry (the first entry in `_toc.yml`). For example:

````{list-table}
:header-rows: 1

* - Files
- Chapters
* - ```yaml
- file: myfolder/mypage
numbered: true
sections:
- file: myfolder/mysubpage
```
- ```yaml
- chapter: My chapter
numbered: true
sections:
- file: myfolder/mypage
numbered: true
sections:
- file: myfolder/mysubpage
```
````
```yaml
- file: home
numbered: true
- file: page2
- file: page3
- file: page4
```

This will cause both `myfolder/mypage` as well as `myfolder/asubpage` to be
This will cause all sections of the book to be
numbered. They will follow a hierarchy according to the sub-sections structure
defined in your `_toc.yml` file.

To number *all* of the sections of your book, add the `numbered: true` flag to
the first entry of your `_toc.yml` file.
If you'd like to number **subsets of sections**, group them into chapters and
apply the `numbered: true` flag to the chapters that you wish to be numbered.
For example:

```yaml
- file: home
numbered: true
# This chapter will not be numbered
- chapter: Introduction
sections:
- file: page2
# This chapter will be numbered
- chapter: Chapter 1
numbered: true
sections:
- file: page3
- file: page4
```

### Numbering caveats and notes

Expand Down
7 changes: 2 additions & 5 deletions jupyter_book/toc.py
Expand Up @@ -71,10 +71,7 @@ def add_toctree(app, docname, source):
# Check if subsections are all individual files. If so, embed them in a section
are_files = [("file" in ii) or ("url" in ii) for ii in sections]
if all(are_files):
sections = {"chapter": "", "sections": sections}
if "numbered" in parent_page:
sections["numbered"] = True
sections = [sections]
sections = [{"chapter": "", "sections": sections}]
elif any(are_files) and not all(are_files):
raise ValueError(
f"Mixed chapters and individual files in `_toc.yml` entry {parent_name}"
Expand All @@ -85,7 +82,7 @@ def add_toctree(app, docname, source):
for isection in sections:
# Check for TOC options (that generally only change behavior on top-level page)
toc_options = {}
if "numbered" in isection and isection.get("numbered") is not False:
if isection.get("numbered") or parent_page.get("numbered"):
toc_options["numbered"] = "" # Empty string will == a flag in the toctree
if isection.get("chapter"):
toc_options["caption"] = isection.get("chapter")
Expand Down
18 changes: 18 additions & 0 deletions tests/books/toc/_toc_numbered_chapters.yml
@@ -0,0 +1,18 @@
- file: index
title: Toc
numbered: true
- chapter: Chapter 1
sections:
- file: content1
title: Content1
- file: subfolder/index
title: Subfolder
sections:
- file: subfolder/asubpage
title: Asubpage
- chapter: Chapter 2
sections:
- file: content2
title: Content2
- file: content3
title: Content3
21 changes: 21 additions & 0 deletions tests/books/toc/_toc_numbered_chapters_subset.yml
@@ -0,0 +1,21 @@
- file: index
title: Toc
- chapter: Chapter 1
numbered: true
sections:
- file: content1
title: Content1
- chapter: Chapter 2
sections:
- file: content2
title: Content2
- file: content3
title: Content3
- chapter: Chapter 3
numbered: true
sections:
- file: subfolder/index
title: Subfolder
sections:
- file: subfolder/asubpage
title: Asubpage
33 changes: 32 additions & 1 deletion tests/test_toc.py
Expand Up @@ -2,6 +2,10 @@
from subprocess import run, PIPE
import pytest
import yaml
from bs4 import BeautifulSoup


path_books = Path(__file__).parent.joinpath("books")


def test_toc():
Expand All @@ -21,7 +25,7 @@ def test_toc():


def test_toc_add_titles():
path_book = Path(__file__).parent.joinpath("books", "toc")
path_book = path_books.joinpath("toc")
run(f"jb toc {path_book}".split(), check=True)
toc_yaml = path_book.joinpath("_toc.yml")
res = yaml.safe_load(toc_yaml.read_text(encoding="utf8"))
Expand All @@ -35,3 +39,30 @@ def test_toc_add_titles():
assert "title" in res
for section in res["sections"]:
assert "title" in section


def test_toc_numbered(tmpdir, file_regression):
"""Testing that numbers make it into the sidebar"""
path_output = Path(tmpdir).joinpath("mybook").absolute()
toc_list = [
"_toc_numbered.yml", # Numbered in top-level title
"_toc_numbered_chapters.yml", # Numbered in top-level title w/ chapters
"_toc_numbered_chapters_subset.yml", # Only some sections numbered
]
for itoc in toc_list:
# Numbering with files
p_toc = path_books.joinpath("toc")
path_toc = p_toc.joinpath(itoc)
run(
f"jb build {p_toc} --path-output {path_output} --toc {path_toc} -W".split(),
check=True,
)

path_toc_directive = path_output.joinpath("_build", "html", "index.html")

# get the tableofcontents markup
soup = BeautifulSoup(
path_toc_directive.read_text(encoding="utf8"), "html.parser"
)
toc = soup.select("nav.bd-links")[0]
file_regression.check(str(toc), basename=itoc.split(".")[0], extension=".html")
Expand Up @@ -28,4 +28,4 @@
</a>
</li>
</ul>
</nav>
</nav>
43 changes: 43 additions & 0 deletions tests/test_toc/_toc_numbered_chapters.html
@@ -0,0 +1,43 @@
<nav aria-label="Main navigation" class="bd-links" id="bd-docs-nav">
<ul class="nav sidenav_l1">
<li class="toctree-l1">
<a class="reference internal" href="#">
Main index
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
Chapter 1
</span>
</p>
<ul class="nav sidenav_l1">
<li class="toctree-l1">
<a class="reference internal" href="content1.html">
1. Content1
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="subfolder/index.html">
2. Subfolder
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
Chapter 2
</span>
</p>
<ul class="nav sidenav_l1">
<li class="toctree-l1">
<a class="reference internal" href="content2.html">
1. Content2
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="content3.html">
2. Content3
</a>
</li>
</ul>
</nav>
50 changes: 50 additions & 0 deletions tests/test_toc/_toc_numbered_chapters_subset.html
@@ -0,0 +1,50 @@
<nav aria-label="Main navigation" class="bd-links" id="bd-docs-nav">
<ul class="nav sidenav_l1">
<li class="toctree-l1">
<a class="reference internal" href="#">
Main index
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
Chapter 1
</span>
</p>
<ul class="nav sidenav_l1">
<li class="toctree-l1">
<a class="reference internal" href="content1.html">
1. Content1
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
Chapter 2
</span>
</p>
<ul class="nav sidenav_l1">
<li class="toctree-l1">
<a class="reference internal" href="content2.html">
Content2
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="content3.html">
Content3
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
Chapter 3
</span>
</p>
<ul class="nav sidenav_l1">
<li class="toctree-l1">
<a class="reference internal" href="subfolder/index.html">
1. Subfolder
</a>
</li>
</ul>
</nav>
19 changes: 0 additions & 19 deletions tests/test_tocdirective.py
Expand Up @@ -64,22 +64,3 @@ def test_toc_urllink(tmpdir, file_regression):
soup = BeautifulSoup(path_toc_directive.read_text(encoding="utf8"), "html.parser")
toc = soup.find_all("div", class_="tableofcontents-wrapper")[0]
file_regression.check(str(toc), extension=".html")


def test_toc_numbered(tmpdir, file_regression):
"""Testing that numbers make it into the sidebar"""
path_output = Path(tmpdir).joinpath("mybook").absolute()
# Regular TOC should work
p_toc = path_books.joinpath("toc")
path_toc = p_toc.joinpath("_toc_numbered.yml")
run(
f"jb build {p_toc} --path-output {path_output} --toc {path_toc} -W".split(),
check=True,
)

path_toc_directive = path_output.joinpath("_build", "html", "index.html")

# get the tableofcontents markup
soup = BeautifulSoup(path_toc_directive.read_text(encoding="utf8"), "html.parser")
toc = soup.select("nav.bd-links")[0]
file_regression.check(str(toc), extension=".html")