pax_global_header00006660000000000000000000000064145772607440014532gustar00rootroot0000000000000052 comment=af57bfea058991559ecb23b149b2ba5e060a014f sphinx-remove-toctrees-1.0.0/000077500000000000000000000000001457726074400161625ustar00rootroot00000000000000sphinx-remove-toctrees-1.0.0/.github/000077500000000000000000000000001457726074400175225ustar00rootroot00000000000000sphinx-remove-toctrees-1.0.0/.github/workflows/000077500000000000000000000000001457726074400215575ustar00rootroot00000000000000sphinx-remove-toctrees-1.0.0/.github/workflows/tests.yml000066400000000000000000000023301457726074400234420ustar00rootroot00000000000000name: tests on: push: branches: [main] tags: - "v[0-9]+.[0-9]+.[0-9]+*" pull_request: jobs: tests: runs-on: ubuntu-latest strategy: matrix: python-version: ["3.9", "3.10", "3.11", "3.12"] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | python -m pip install --upgrade pip pip install -e .[tests] - name: Run tests run: | pytest publish: name: Publish to PyPi needs: [tests] if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') runs-on: ubuntu-latest steps: - name: Checkout source uses: actions/checkout@v4 - name: Set up Python 3.11 uses: actions/setup-python@v4 with: python-version: 3.11 - name: Build package run: | pip install wheel python setup.py sdist bdist_wheel - name: Publish uses: pypa/gh-action-pypi-publish@v1.8.14 with: user: __token__ password: ${{ secrets.PYPI_API_TOKEN }} sphinx-remove-toctrees-1.0.0/.gitignore000066400000000000000000000023761457726074400201620ustar00rootroot00000000000000# Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover .hypothesis/ .pytest_cache/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder target/ # Jupyter Notebook .ipynb_checkpoints # pyenv .python-version # celery beat schedule file celerybeat-schedule # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ # Docs _build/ # VS code config .vscode node_modules/ .DS_Store .idea sphinx-remove-toctrees-1.0.0/LICENSE000077500000000000000000000020571457726074400171760ustar00rootroot00000000000000MIT License Copyright (c) 2018 Chris Holdgraf Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. sphinx-remove-toctrees-1.0.0/README.md000066400000000000000000000061701457726074400174450ustar00rootroot00000000000000# Remove toctrees from Sphinx pages ![pypi](https://img.shields.io/pypi/v/sphinx-remove-toctrees) Improve your Sphinx build time by selectively removing TocTree objects from pages. This is useful if your documentation uses auto-generated API documentation, which generates **a lot** of stub pages. This extension can be used to remove the sidebar links for just the pages you specify, speed up the build considerably. ## Who is this for? This package is for maintainers that use Sphinx and have really large API documentation (or for some other reason, have a ton of nested pages). If you use a Sphinx theme that contains the entire Table of Contents on every page (e.g., any theme that has "collapsable" sidebar sections), this will slow things down considerably. Use this theme to speed up your builds. ## Install Install the extension via `pip`: ```console $ pip install sphinx-remove-toctrees ``` activate it by adding it to your Sphinx extensions in `conf.py`: ```python extensions.append("sphinx_remove_toctrees") ``` ## Use In `conf.py`, there is a top-level configuration key called `remove_from_toctrees` that allows you to specify the pages to remove from your sidebar. Provide a list of `glob`-like paths **relative to your documentation root**. Each entry should match to pages that should be removed from the sidebar. For example, the following configuration will remove all pages from the folder `api/generated`, and the specific page `subfolder/page_two.rst`: ```python remove_from_toctrees = ["api/generated/*", "subfolder/page_two.rst"] ``` This is particularly useful in combination with the `autosummary` directive, which tends to generate a ton of stub-pages that slows things down. If you have the following autosummary directive in a page at `myfolder/page1.rst`: ```rst .. autosummary: datetime.datetime :toctree: api_gen ``` This will generate stub-pages in a `myfolder/api_gen/` folder. To remove each of these pages from your sidebar, you would configure this extension like so: ```python remove_from_toctrees = ["myfolder/api_gen/*"] ``` ## Try it with this documentation This extension doesn't have a hosted documentation page, but there is one in the `docs/` folder of this repository. You can use that folder to preview this extension in action. ## How this works Sphinx keeps track of `toctree` objects to represent the structure of your documentation. These exist in the Sphinx environment object, at `env.tocs`. There are two places in the build where this is relevant here: - Early in the build, Sphinx uses these `tocs` to ensure that files in your documentation are linked _somewhere_, and will raise warnings if it finds a file that is not in one of the `tocs`. - Later in the build, Sphinx uses these `tocs` to build the HTML `toctree` with links to pages in your documentation. If there are many elements in `tocs`, it will take a long time to resolve all of these links! This extension runs *after* the first step, but *before* the second step. It removes all the `toctree` objects that you specify, so that no warnings are raised about missing files, but they are removed from the sidebar and don't slow down your build. sphinx-remove-toctrees-1.0.0/docs/000077500000000000000000000000001457726074400171125ustar00rootroot00000000000000sphinx-remove-toctrees-1.0.0/docs/Makefile000066400000000000000000000011461457726074400205540ustar00rootroot00000000000000# Minimal makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build SPHINXPROJ = SphinxCopybutton SOURCEDIR = . BUILDDIR = _build # Put it first so that "make" without argument is like "make help". help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) .PHONY: help Makefile # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) sphinx-remove-toctrees-1.0.0/docs/conf.py000066400000000000000000000115451457726074400204170ustar00rootroot00000000000000# # Configuration file for the Sphinx documentation builder. # # This file does only contain a selection of the most common options. For a # full list see the documentation: # http://www.sphinx-doc.org/en/master/config # -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # # import os # import sys # sys.path.insert(0, os.path.abspath('.')) # -- Project information ----------------------------------------------------- project = "Sphinx Remove Toctrees" copyright = "2018, Executable Books Project" author = "Executable Books Project" # The short X.Y version version = "" # The full version, including alpha/beta/rc tags release = "" # -- General configuration --------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. # # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = ["sphinx_remove_toctrees", "myst_parser", "sphinx.ext.autosummary"] # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] # The master toctree document. master_doc = "index" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path . exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # The name of the Pygments (syntax highlighting) style to use. pygments_style = "sphinx" # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = "sphinx_book_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # # html_theme_options = {} # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_title = "Sphinx Remove Toctrees" # Custom sidebar templates, must be a dictionary that maps document names # to template names. # # The default sidebars (for documents that don't match any pattern) are # defined by theme itself. Builtin themes are using these templates by # default: ``['localtoc.html', 'relations.html', 'sourcelink.html', # 'searchbox.html']``. # # html_sidebars = {} # CopyButton configuration remove_from_toctrees = ["second/nested_hidden/*"] # -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. htmlhelp_basename = "SphinxCopybuttondoc" # -- Options for LaTeX output ------------------------------------------------ latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # # 'preamble': '', # Latex figure (float) alignment # # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ ( master_doc, "SphinxCopybutton.tex", "Sphinx Copybutton Documentation", "Executable Books Project", "manual", ) ] # -- Options for manual page output ------------------------------------------ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, "sphinxcopybutton", "Sphinx Copybutton Documentation", [author], 1) ] # -- Options for Texinfo output ---------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ( master_doc, "SphinxCopybutton", "Sphinx Copybutton Documentation", author, "SphinxCopybutton", "One line description of project.", "Miscellaneous", ) ] def setup(app): app.add_css_file("custom.css") sphinx-remove-toctrees-1.0.0/docs/index.md000066400000000000000000000001131457726074400205360ustar00rootroot00000000000000```{include} ../README.md ``` ```{toctree} :hidden: second/second_page ```sphinx-remove-toctrees-1.0.0/docs/requirements.txt000066400000000000000000000000701457726074400223730ustar00rootroot00000000000000sphinx ipython sphinx-book-theme # Install ourselves . sphinx-remove-toctrees-1.0.0/docs/second/000077500000000000000000000000001457726074400203655ustar00rootroot00000000000000sphinx-remove-toctrees-1.0.0/docs/second/nested/000077500000000000000000000000001457726074400216475ustar00rootroot00000000000000sphinx-remove-toctrees-1.0.0/docs/second/nested/nested_page_shown.md000066400000000000000000000001161457726074400256630ustar00rootroot00000000000000# A nested page that should be shown. This page will show up in the sidebar. sphinx-remove-toctrees-1.0.0/docs/second/nested_hidden/000077500000000000000000000000001457726074400231625ustar00rootroot00000000000000sphinx-remove-toctrees-1.0.0/docs/second/nested_hidden/nested_page_hidden.md000066400000000000000000000001011457726074400272650ustar00rootroot00000000000000# Third nested page This page shouldn't show up in the sidebar. sphinx-remove-toctrees-1.0.0/docs/second/second_page.md000066400000000000000000000002431457726074400231550ustar00rootroot00000000000000# Second nested page This page will show up in the sidebar, but the children will not. ```{toctree} nested/nested_page_shown nested_hidden/nested_page_hidden ```sphinx-remove-toctrees-1.0.0/noxfile.py000066400000000000000000000013101457726074400201730ustar00rootroot00000000000000import nox from pathlib import Path nox.options.reuse_existing_virtualenvs = True @nox.session() def docs(session): _install_environment(session) session.run("sphinx-build", "-b", "html", "docs", "docs/_build/html") @nox.session(name="tests") def tests(session): _install_environment(session) session.run("pytest", *session.posargs) def _install_environment(session): """Install the JS and Python environment needed to develop the theme.""" # Assume that if sphinx is already installed, we don't need to re-install bin = Path(session.bin) if list(bin.rglob("sphinx-build")) and "reinstall" not in session.posargs: return session.install("-e", ".[docs,tests]") sphinx-remove-toctrees-1.0.0/pyproject.toml000066400000000000000000000022771457726074400211060ustar00rootroot00000000000000[build-system] requires = ["hatchling"] build-backend = "hatchling.build" [project] name = "sphinx-remove-toctrees" dynamic = ["version"] description = "Reduce your documentation build size by selectively removing toctrees from pages." readme = "README.md" license = { file = "LICENSE" } requires-python = ">=3.9" authors = [ { name = "Executable Book Project" }, ] classifiers = [ "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", ] dependencies = [ "sphinx>=5", ] [project.optional-dependencies] code_style = [ "pre-commit>=2.12", ] docs = [ "ipython", "myst-parser", "sphinx-book-theme", ] tests = [ "ipython", "myst-parser", "pytest", "sphinx-book-theme", ] [project.urls] Homepage = "https://github.com/executablebooks/sphinx-remove-toctrees" [tool.hatch.version] path = "sphinx_remove_toctrees/__init__.py" [tool.hatch.build.targets.wheel] exclude = [ "/sphinx_remove_toctrees/tests/*" ] sphinx-remove-toctrees-1.0.0/sphinx_remove_toctrees/000077500000000000000000000000001457726074400227605ustar00rootroot00000000000000sphinx-remove-toctrees-1.0.0/sphinx_remove_toctrees/__init__.py000066400000000000000000000042511457726074400250730ustar00rootroot00000000000000"""A small sphinx extension to remove toctrees.""" from pathlib import Path from sphinx.util import logging from sphinx import addnodes __version__ = "1.0.0" logger = logging.getLogger(__name__) def findall(node): # findall replaces traverse in docutils v0.18 # note a difference is that findall is an iterator return getattr(node, "findall", node.traverse) def remove_toctrees(app, env): """Remove toctrees from pages a user provides. This happens at the end of the build process, so even though the toctrees are removed, it won't raise sphinx warnings about un-referenced pages. """ if len(app.config.remove_toctrees_from) > 0: app.config.remove_from_toctrees = app.config.remove_toctrees_from logger.warning( "`remove_toctrees_from` is deprecated, use `remove_from_toctrees`" ) patterns = app.config.remove_from_toctrees if isinstance(patterns, str): patterns = [patterns] # Figure out the list of patterns to remove from all toctrees to_remove = [] for pattern in patterns: # Inputs should either be a glob pattern or a direct path so just use glob srcdir = Path(env.srcdir) for matched in srcdir.glob(pattern): to_remove.append( str(matched.relative_to(srcdir).with_suffix("").as_posix()) ) # Loop through all tocs and remove the ones that match our pattern for _, tocs in env.tocs.items(): for toctree in findall(tocs)(addnodes.toctree): new_entries = [] for entry in toctree.attributes.get("entries", []): if entry[1] not in to_remove: new_entries.append(entry) # If there are no more entries just remove the toctree if len(new_entries) == 0: toctree.parent.remove(toctree) else: toctree.attributes["entries"] = new_entries def setup(app): # noqa: D103 app.add_config_value("remove_toctrees_from", [], "html") app.add_config_value("remove_from_toctrees", [], "html") app.connect("env-updated", remove_toctrees) return {"parallel_read_safe": True, "parallel_write_safe": True} sphinx-remove-toctrees-1.0.0/sphinx_remove_toctrees/tests/000077500000000000000000000000001457726074400241225ustar00rootroot00000000000000sphinx-remove-toctrees-1.0.0/sphinx_remove_toctrees/tests/site/000077500000000000000000000000001457726074400250665ustar00rootroot00000000000000sphinx-remove-toctrees-1.0.0/sphinx_remove_toctrees/tests/site/conf.py000066400000000000000000000003401457726074400263620ustar00rootroot00000000000000project = "Sphinx Remove Toctrees test" extensions = ["sphinx_remove_toctrees", "myst_parser"] master_doc = "index" html_theme = "sphinx_book_theme" remove_from_toctrees = ["nested/nested_page_hidden.md", "nested_hidden/*"] sphinx-remove-toctrees-1.0.0/sphinx_remove_toctrees/tests/site/index.md000066400000000000000000000000611457726074400265140ustar00rootroot00000000000000# Sphinx Remove Toctrees ```{toctree} second ```sphinx-remove-toctrees-1.0.0/sphinx_remove_toctrees/tests/site/nested/000077500000000000000000000000001457726074400263505ustar00rootroot00000000000000sphinx-remove-toctrees-1.0.0/sphinx_remove_toctrees/tests/site/nested/nested_page_hidden.md000066400000000000000000000001011457726074400324530ustar00rootroot00000000000000# Third nested page This page shouldn't show up in the sidebar. sphinx-remove-toctrees-1.0.0/sphinx_remove_toctrees/tests/site/nested/nested_page_shown.md000066400000000000000000000001161457726074400323640ustar00rootroot00000000000000# A nested page that should be shown. This page will show up in the sidebar. sphinx-remove-toctrees-1.0.0/sphinx_remove_toctrees/tests/site/nested_hidden/000077500000000000000000000000001457726074400276635ustar00rootroot00000000000000sphinx-remove-toctrees-1.0.0/sphinx_remove_toctrees/tests/site/nested_hidden/nested_page_hidden.md000066400000000000000000000000561457726074400337770ustar00rootroot00000000000000# Third nested page This page will be hidden.sphinx-remove-toctrees-1.0.0/sphinx_remove_toctrees/tests/site/second.md000066400000000000000000000002751457726074400266670ustar00rootroot00000000000000# Second nested page This page will show up in the sidebar, but the children will not. ```{toctree} nested/nested_page_shown nested/nested_page_hidden nested_hidden/nested_page_hidden ```sphinx-remove-toctrees-1.0.0/sphinx_remove_toctrees/tests/test_build.py000066400000000000000000000023041457726074400266310ustar00rootroot00000000000000import os from pathlib import Path from shutil import copytree from bs4 import BeautifulSoup from sphinx import version_info as sphinx_version_info pytest_plugins = "sphinx.testing.fixtures" path_test_doc = Path(__file__).parent / "site" def test_build_html(make_app, tmp_path): """Test building the base html template and config.""" src_dir = tmp_path / "test_doc" copytree(path_test_doc, src_dir) # For compatibility with multiple versions of sphinx, convert pathlib.Path to # sphinx.testing.path.path here. if sphinx_version_info >= (7, 2): app_src_dir = src_dir else: from sphinx.testing.path import path app_src_dir = path(os.fspath(src_dir)) app = make_app(srcdir=app_src_dir) app.build() index = tmp_path / "test_doc" / "_build" / "html" / "index.html" assert index.exists() index = BeautifulSoup(index.read_text()) sidenav = index.select("ul.bd-sidenav")[0] # Grab all references to second-level links, we should *only* find the shown page second_level_links = sidenav.select(".toctree-l2 a") assert len(second_level_links) == 1 assert second_level_links[0].attrs["href"] == "nested/nested_page_shown.html"