diff --git a/docs/customize/toc.md b/docs/customize/toc.md index b8f6aba62..2eec5d2da 100644 --- a/docs/customize/toc.md +++ b/docs/customize/toc.md @@ -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 diff --git a/jupyter_book/toc.py b/jupyter_book/toc.py index 77a4e8831..d0ffa2171 100644 --- a/jupyter_book/toc.py +++ b/jupyter_book/toc.py @@ -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}" @@ -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") diff --git a/tests/books/toc/_toc_numbered_chapters.yml b/tests/books/toc/_toc_numbered_chapters.yml new file mode 100644 index 000000000..b90d2ce86 --- /dev/null +++ b/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 diff --git a/tests/books/toc/_toc_numbered_chapters_subset.yml b/tests/books/toc/_toc_numbered_chapters_subset.yml new file mode 100644 index 000000000..76aba839c --- /dev/null +++ b/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 diff --git a/tests/test_toc.py b/tests/test_toc.py index 360382499..1b658415f 100644 --- a/tests/test_toc.py +++ b/tests/test_toc.py @@ -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(): @@ -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")) @@ -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") diff --git a/tests/test_tocdirective/test_toc_numbered.html b/tests/test_toc/_toc_numbered.html similarity index 98% rename from tests/test_tocdirective/test_toc_numbered.html rename to tests/test_toc/_toc_numbered.html index de8eb6188..ba7864a07 100644 --- a/tests/test_tocdirective/test_toc_numbered.html +++ b/tests/test_toc/_toc_numbered.html @@ -28,4 +28,4 @@ - \ No newline at end of file + diff --git a/tests/test_toc/_toc_numbered_chapters.html b/tests/test_toc/_toc_numbered_chapters.html new file mode 100644 index 000000000..353d9b284 --- /dev/null +++ b/tests/test_toc/_toc_numbered_chapters.html @@ -0,0 +1,43 @@ + diff --git a/tests/test_toc/_toc_numbered_chapters_subset.html b/tests/test_toc/_toc_numbered_chapters_subset.html new file mode 100644 index 000000000..df3986239 --- /dev/null +++ b/tests/test_toc/_toc_numbered_chapters_subset.html @@ -0,0 +1,50 @@ + diff --git a/tests/test_tocdirective.py b/tests/test_tocdirective.py index c30c10a43..9fbe1bbcf 100644 --- a/tests/test_tocdirective.py +++ b/tests/test_tocdirective.py @@ -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")