From 4e875d6baf92b429189a5bbacad94666589b2ace Mon Sep 17 00:00:00 2001 From: Angus Hollands Date: Fri, 9 Feb 2024 10:56:11 +0000 Subject: [PATCH 01/10] fix: use config-inited --- src/sphinx_book_theme/__init__.py | 47 ++++++++++--------------------- src/sphinx_book_theme/nodes.py | 20 +++++++++++++ 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/src/sphinx_book_theme/__init__.py b/src/sphinx_book_theme/__init__.py index da9e7498..224887aa 100644 --- a/src/sphinx_book_theme/__init__.py +++ b/src/sphinx_book_theme/__init__.py @@ -4,14 +4,13 @@ from pathlib import Path from functools import lru_cache -from docutils.parsers.rst.directives.body import Sidebar from docutils import nodes as docutil_nodes from sphinx.application import Sphinx from sphinx.locale import get_translation from sphinx.util import logging from pydata_sphinx_theme.utils import get_theme_options_dict -from .nodes import SideNoteNode +from .nodes import Margin, SideNoteNode from .header_buttons import ( prep_header_buttons, add_header_buttons, @@ -179,33 +178,12 @@ def check_deprecation_keys(app): ) -class Margin(Sidebar): - """Goes in the margin to the right of the page.""" - - optional_arguments = 1 - required_arguments = 0 - - def run(self): - """Run the directive.""" - if not self.arguments: - self.arguments = [""] - nodes = super().run() - nodes[0].attributes["classes"].append("margin") - - # Remove the "title" node if it is empty - if not self.arguments: - nodes[0].children.pop(0) - return nodes - - def update_general_config(app): theme_dir = get_html_theme_path() - # Update templates for sidebar. Needed for jupyter-book builds as jb - # uses an instance of Sphinx class from sphinx.application to build the app. - # The __init__ function of which calls self.config.init_values() just - # before emitting `config-inited` event. The init_values function overwrites - # templates_path variable. - app.config.templates_path.append(os.path.join(theme_dir, "components")) + + app.config.templates_path.append( + os.path.join(theme_dir, "components") + ) def update_templates(app, pagename, templatename, context, doctree): @@ -245,11 +223,20 @@ def setup(app: Sphinx): app.connect("builder-inited", check_deprecation_keys) app.connect("builder-inited", update_sourcename) app.connect("builder-inited", update_context_with_repository_info) - app.connect("builder-inited", update_general_config) app.connect("html-page-context", add_metadata_to_page) app.connect("html-page-context", hash_html_assets) app.connect("html-page-context", update_templates) + # This extension has both theme-like and extension-like features. + # Themes are initialised immediately before use, thus we cannot + # rely on an event to set the config - the theme config must be + # set in setup(app): + update_general_config_config(app) + # Meanwhile, extensions are initialised _first_, and any config + # values set during setup() will be overwritten. We must therefore + # register the `config-inited` event to set these config options + app.connect("config-inited", update_general_config) + # Nodes SideNoteNode.add_node(app) @@ -266,10 +253,6 @@ def setup(app: Sphinx): # Post-transforms app.add_post_transform(HandleFootnoteTransform) - # Update templates for sidebar, for builds where config-inited is not called - # (does not work in case of jupyter-book) - app.config.templates_path.append(os.path.join(theme_dir, "components")) - return { "parallel_read_safe": True, "parallel_write_safe": True, diff --git a/src/sphinx_book_theme/nodes.py b/src/sphinx_book_theme/nodes.py index 7735652c..4e5a1223 100644 --- a/src/sphinx_book_theme/nodes.py +++ b/src/sphinx_book_theme/nodes.py @@ -1,6 +1,7 @@ from docutils import nodes from sphinx.application import Sphinx from typing import Any, cast +from docutils.parsers.rst.directives.body import Sidebar class SideNoteNode(nodes.Element): @@ -35,3 +36,22 @@ def depart_SideNoteNode(self, node): self.body.append( f"" ) + + +class Margin(Sidebar): + """Goes in the margin to the right of the page.""" + + optional_arguments = 1 + required_arguments = 0 + + def run(self): + """Run the directive.""" + if not self.arguments: + self.arguments = [""] + nodes = super().run() + nodes[0].attributes["classes"].append("margin") + + # Remove the "title" node if it is empty + if not self.arguments: + nodes[0].children.pop(0) + return nodes From fce9b33656f628a0d250b7ce92bf23c183d8f418 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 9 Feb 2024 11:03:38 +0000 Subject: [PATCH 02/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/sphinx_book_theme/__init__.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/sphinx_book_theme/__init__.py b/src/sphinx_book_theme/__init__.py index 224887aa..686e3392 100644 --- a/src/sphinx_book_theme/__init__.py +++ b/src/sphinx_book_theme/__init__.py @@ -181,9 +181,7 @@ def check_deprecation_keys(app): def update_general_config(app): theme_dir = get_html_theme_path() - app.config.templates_path.append( - os.path.join(theme_dir, "components") - ) + app.config.templates_path.append(os.path.join(theme_dir, "components")) def update_templates(app, pagename, templatename, context, doctree): @@ -229,9 +227,9 @@ def setup(app: Sphinx): # This extension has both theme-like and extension-like features. # Themes are initialised immediately before use, thus we cannot - # rely on an event to set the config - the theme config must be + # rely on an event to set the config - the theme config must be # set in setup(app): - update_general_config_config(app) + update_general_config_config(app) # Meanwhile, extensions are initialised _first_, and any config # values set during setup() will be overwritten. We must therefore # register the `config-inited` event to set these config options From b6c6d4c86565498a20d27d4f93bd7958362cfec0 Mon Sep 17 00:00:00 2001 From: Angus Hollands Date: Fri, 9 Feb 2024 11:04:20 +0000 Subject: [PATCH 03/10] refactor: create directives modulie --- src/sphinx_book_theme/__init__.py | 3 ++- src/sphinx_book_theme/directives.py | 20 ++++++++++++++++++++ src/sphinx_book_theme/nodes.py | 19 ------------------- 3 files changed, 22 insertions(+), 20 deletions(-) create mode 100644 src/sphinx_book_theme/directives.py diff --git a/src/sphinx_book_theme/__init__.py b/src/sphinx_book_theme/__init__.py index 224887aa..2ebafc6a 100644 --- a/src/sphinx_book_theme/__init__.py +++ b/src/sphinx_book_theme/__init__.py @@ -10,7 +10,8 @@ from sphinx.util import logging from pydata_sphinx_theme.utils import get_theme_options_dict -from .nodes import Margin, SideNoteNode +from .directives import Margin +from .nodes import SideNoteNode from .header_buttons import ( prep_header_buttons, add_header_buttons, diff --git a/src/sphinx_book_theme/directives.py b/src/sphinx_book_theme/directives.py new file mode 100644 index 00000000..adaa004f --- /dev/null +++ b/src/sphinx_book_theme/directives.py @@ -0,0 +1,20 @@ +from docutils.parsers.rst.directives.body import Sidebar + + +class Margin(Sidebar): + """Goes in the margin to the right of the page.""" + + optional_arguments = 1 + required_arguments = 0 + + def run(self): + """Run the directive.""" + if not self.arguments: + self.arguments = [""] + nodes = super().run() + nodes[0].attributes["classes"].append("margin") + + # Remove the "title" node if it is empty + if not self.arguments: + nodes[0].children.pop(0) + return nodes diff --git a/src/sphinx_book_theme/nodes.py b/src/sphinx_book_theme/nodes.py index 4e5a1223..42fbb730 100644 --- a/src/sphinx_book_theme/nodes.py +++ b/src/sphinx_book_theme/nodes.py @@ -1,7 +1,6 @@ from docutils import nodes from sphinx.application import Sphinx from typing import Any, cast -from docutils.parsers.rst.directives.body import Sidebar class SideNoteNode(nodes.Element): @@ -37,21 +36,3 @@ def depart_SideNoteNode(self, node): f"" ) - -class Margin(Sidebar): - """Goes in the margin to the right of the page.""" - - optional_arguments = 1 - required_arguments = 0 - - def run(self): - """Run the directive.""" - if not self.arguments: - self.arguments = [""] - nodes = super().run() - nodes[0].attributes["classes"].append("margin") - - # Remove the "title" node if it is empty - if not self.arguments: - nodes[0].children.pop(0) - return nodes From 5339a48a4cca841d64f9411f5c469955da5aa474 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 9 Feb 2024 11:12:30 +0000 Subject: [PATCH 04/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/sphinx_book_theme/nodes.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sphinx_book_theme/nodes.py b/src/sphinx_book_theme/nodes.py index 42fbb730..7735652c 100644 --- a/src/sphinx_book_theme/nodes.py +++ b/src/sphinx_book_theme/nodes.py @@ -35,4 +35,3 @@ def depart_SideNoteNode(self, node): self.body.append( f"" ) - From d1c49f056fc9e6cf7539bd4eaaf104060f35b159 Mon Sep 17 00:00:00 2001 From: Angus Hollands Date: Fri, 9 Feb 2024 11:20:18 +0000 Subject: [PATCH 05/10] fix: typo --- src/sphinx_book_theme/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sphinx_book_theme/__init__.py b/src/sphinx_book_theme/__init__.py index 7158ab34..756ab753 100644 --- a/src/sphinx_book_theme/__init__.py +++ b/src/sphinx_book_theme/__init__.py @@ -230,7 +230,7 @@ def setup(app: Sphinx): # Themes are initialised immediately before use, thus we cannot # rely on an event to set the config - the theme config must be # set in setup(app): - update_general_config_config(app) + update_general_config(app) # Meanwhile, extensions are initialised _first_, and any config # values set during setup() will be overwritten. We must therefore # register the `config-inited` event to set these config options From 3099805248cc612cadae51e1048098014ea43f66 Mon Sep 17 00:00:00 2001 From: Angus Hollands Date: Fri, 9 Feb 2024 11:56:30 +0000 Subject: [PATCH 06/10] test: check warnings --- pyproject.toml | 9 +++++++++ tests/test_build.py | 17 +++++++---------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 1fd0f2b6..dfcea540 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,6 +13,13 @@ additional-compiled-static-assets = [ testpaths = [ "tests" ] +filterwarnings = [ + "error", + 'ignore:Jupyter is migrating its paths to use standard platformdirs:DeprecationWarning', + 'ignore:The frontend\.OptionParser class will be replaced:DeprecationWarning', + 'ignore:The frontend\.Option class will be removed:DeprecationWarning', + 'ignore:nodes\.Node\.traverse\(\) is obsoleted by Node\.findall\(\):PendingDeprecationWarning', +] [project] name = "sphinx-book-theme" @@ -82,3 +89,5 @@ test = [ [project.urls] Repository = "https://github.com/executablebooks/sphinx-book-theme" Documentation = "https://sphinx-book-theme.readthedocs.io/" + + diff --git a/tests/test_build.py b/tests/test_build.py index 70339c6e..48c62e0e 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -28,9 +28,10 @@ def __init__(self, app: SphinxTestApp, src: Path): f".sphinx{sphinx.version_info[0]}" # software version tracking for fixtures ) - def build(self, assert_pass=True): + def build(self, assert_pass=True, assert_no_warnings=True): self.app.build() - assert self.warnings == "", self.status + if assert_no_warnings: + assert self.warnings == "", self.status return self @property @@ -62,14 +63,10 @@ def _func(src_folder, **kwargs): yield _func -def test_parallel_build(): - # We cannot use the sphinx_build_factory because SpinxTestApp does - # not have a way to pass parallel=2 to the Sphinx constructor - # https://github.com/sphinx-doc/sphinx/blob/d8c006f1c0e612d0dc595ae463b8e4c3ebee5ca4/sphinx/testing/util.py#L101 - check_call( - f"sphinx-build -j 2 -W -b html {path_tests}/sites/parallel-build build", - shell=True, - ) +def test_parallel_build(sphinx_build_factory): + sphinx_build = sphinx_build_factory("parallel-build", parallel=2) # type: SphinxBuild + sphinx_build.build(assert_pass=True, assert_no_warnings=False) # TODO: filter these warnings + assert (sphinx_build.outdir / "index.html").exists(), sphinx_build.outdir.glob("*") def test_build_book(sphinx_build_factory, file_regression): From f0482f7d9a0e7e2dfbe2e172b2d15782f4f1795d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 9 Feb 2024 11:57:43 +0000 Subject: [PATCH 07/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pyproject.toml | 2 -- tests/test_build.py | 5 +++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index dfcea540..cd2c7e58 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -89,5 +89,3 @@ test = [ [project.urls] Repository = "https://github.com/executablebooks/sphinx-book-theme" Documentation = "https://sphinx-book-theme.readthedocs.io/" - - diff --git a/tests/test_build.py b/tests/test_build.py index 48c62e0e..77621e5f 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -1,7 +1,6 @@ import os from pathlib import Path from shutil import copytree, rmtree -from subprocess import check_call from importlib.metadata import version from packaging.version import parse @@ -65,7 +64,9 @@ def _func(src_folder, **kwargs): def test_parallel_build(sphinx_build_factory): sphinx_build = sphinx_build_factory("parallel-build", parallel=2) # type: SphinxBuild - sphinx_build.build(assert_pass=True, assert_no_warnings=False) # TODO: filter these warnings + sphinx_build.build( + assert_pass=True, assert_no_warnings=False + ) # TODO: filter these warnings assert (sphinx_build.outdir / "index.html").exists(), sphinx_build.outdir.glob("*") From 18b10413a5ff6f76d075ba18d6979347fbbabed8 Mon Sep 17 00:00:00 2001 From: Angus Hollands Date: Fri, 9 Feb 2024 11:57:47 +0000 Subject: [PATCH 08/10] test: restore deleted regression test --- tests/test_build/build__pagetoc--page-onetitlenoheadings.html | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tests/test_build/build__pagetoc--page-onetitlenoheadings.html diff --git a/tests/test_build/build__pagetoc--page-onetitlenoheadings.html b/tests/test_build/build__pagetoc--page-onetitlenoheadings.html new file mode 100644 index 00000000..dde1aee4 --- /dev/null +++ b/tests/test_build/build__pagetoc--page-onetitlenoheadings.html @@ -0,0 +1,2 @@ +
+
From 6af8015e50f309fc2068f19fb00d49fe904ea2e4 Mon Sep 17 00:00:00 2001 From: Angus Hollands Date: Fri, 9 Feb 2024 12:13:38 +0000 Subject: [PATCH 09/10] test: catch warnings on MacOS --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index cd2c7e58..f852e6ea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,6 +19,9 @@ filterwarnings = [ 'ignore:The frontend\.OptionParser class will be replaced:DeprecationWarning', 'ignore:The frontend\.Option class will be removed:DeprecationWarning', 'ignore:nodes\.Node\.traverse\(\) is obsoleted by Node\.findall\(\):PendingDeprecationWarning', + # jupyter-client throws this + 'ignore:datetime\.datetime\.utcfromtimestamp\(\) is deprecated:DeprecationWarning', + 'ignore:datetime\.datetime\.utcnow\(\) is deprecated:DeprecationWarning', ] [project] From 41aebcfa207dbb7c7323e403669af65570265508 Mon Sep 17 00:00:00 2001 From: Angus Hollands Date: Fri, 9 Feb 2024 12:14:57 +0000 Subject: [PATCH 10/10] test: fix warning on 3.11 5.0 --- pyproject.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index f852e6ea..2ade6497 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,6 +22,8 @@ filterwarnings = [ # jupyter-client throws this 'ignore:datetime\.datetime\.utcfromtimestamp\(\) is deprecated:DeprecationWarning', 'ignore:datetime\.datetime\.utcnow\(\) is deprecated:DeprecationWarning', + # Sphinx triggers this + '''ignore:'imghdr' is deprecated and slated for removal in Python 3\.13:DeprecationWarning''', ] [project]