blob: 63f8f0114b589cdf8760a9c8c489fce4b90b8d93 [file]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- 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 = 'Apache DataFusion Comet'
copyright = '2023-2024, Apache Software Foundation'
author = 'Apache Software Foundation'
# -- General configuration ---------------------------------------------------
# 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.ext.autodoc',
'sphinx.ext.autosummary',
'sphinx.ext.doctest',
'sphinx.ext.ifconfig',
'sphinx.ext.mathjax',
'sphinx.ext.viewcode',
'sphinx.ext.napoleon',
'myst_parser',
'sphinx_reredirects',
]
source_suffix = {
'.rst': 'restructuredtext',
'.md': 'markdown',
}
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# 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 = [
# Per-Spark-version compatibility pages are generated by docs/build.sh from these
# templates; the templates themselves are not part of the rendered docs.
'user-guide/latest/compatibility/expressions/_category_template',
]
# Show members for classes in .. autosummary
autodoc_default_options = {
"members": None,
"undoc-members": None,
"show-inheritance": None,
"inherited-members": None,
}
autosummary_generate = True
# -- 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 = 'pydata_sphinx_theme'
html_logo = "_static/images/DataFusionComet-Logo-Light.png"
html_theme_options = {
"logo": {
"image_light": "_static/images/DataFusionComet-Logo-Light.png",
"image_dark": "_static/images/DataFusionComet-Logo-Dark.png",
},
"use_edit_page_button": False,
"secondary_sidebar_items": ["page-toc"],
"collapse_navigation": True,
"navbar_start": ["navbar-logo"],
"navbar_center": ["navbar-nav"],
"navbar_end": ["navbar-icon-links", "theme-switcher"],
"icon_links": [
{
"name": "GitHub",
"url": "https://github.com/apache/datafusion-comet",
"icon": "fa-brands fa-github",
},
],
}
html_context = {
"default_mode": "light",
"github_user": "apache",
"github_repo": "datafusion-comet",
"github_version": "main",
"doc_path": "docs/source",
}
# 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_static_path = ['_static']
html_css_files = [
"theme_overrides.css"
]
html_js_files = [
("https://buttons.github.io/buttons.js", {'async': 'true', 'defer': 'true'}),
"comet-ux.js",
]
html_sidebars = {
"**": ["search-field.html", "docs-sidebar.html"],
# Landing page is a full-width marketing page — no left rail.
"index": [],
}
# tell myst_parser to auto-generate anchor links for headers h1, h2, h3, h4
myst_heading_anchors = 4
# enable nice rendering of checkboxes for the task lists
myst_enable_extensions = ["colon_fence", "deflist", "tasklist"]
redirects = {
"overview.html": "index.html",
"gluten_comparison.html": "about/gluten_comparison.html",
"user-guide/overview.html": "../index.html",
"user-guide/gluten_comparison.html": "../about/gluten_comparison.html",
"user-guide/compatibility.html": "latest/compatibility.html",
"user-guide/configs.html": "latest/configs.html",
"user-guide/datasource.html": "latest/datasource.html",
"user-guide/datatypes.html": "latest/datatypes.html",
"user-guide/expressions.html": "latest/expressions.html",
"user-guide/iceberg.html": "latest/iceberg.html",
"user-guide/installation.html": "latest/installation.html",
"user-guide/kubernetes.html": "latest/kubernetes.html",
"user-guide/metrics.html": "latest/metrics.html",
"user-guide/operators.html": "latest/operators.html",
"user-guide/source.html": "latest/source.html",
"user-guide/tuning.html": "latest/tuning.html",
}
# -- $COMET_VERSION substitution -------------------------------------------
# build.sh runs `replace_in_files` after copying source/ → temp/ to swap the
# $COMET_VERSION placeholder with the real version from pom.xml. When Sphinx
# is invoked directly against source/ (local dev, IDE preview, etc.), that
# substitution never runs and the literal "$COMET_VERSION" leaks into page
# titles, breadcrumbs, and the toctree caption. The hook below mirrors the
# build.sh substitution at Sphinx read-time so local builds match prod.
def _read_comet_version():
import os
import xml.etree.ElementTree as ET
pom_path = os.path.normpath(os.path.join(os.path.dirname(__file__), "..", "..", "pom.xml"))
try:
tree = ET.parse(pom_path)
root = tree.getroot()
ns = {"m": "http://maven.apache.org/POM/4.0.0"}
ver = root.find("m:version", ns)
if ver is not None and ver.text:
return ver.text.strip()
except Exception:
pass
return "latest"
_comet_version = _read_comet_version()
def _substitute_version(app, docname, source):
if "$COMET_VERSION" in source[0]:
source[0] = source[0].replace("$COMET_VERSION", _comet_version)
# -- User Guide sidebar: nest per-version pages under captions --------------
# Every User Guide page groups its pages under captions (Getting Started,
# What Comet Supports, ...) via nested `.. toctree::` blocks in that version's
# own index page — except the tree rendered from user-guide/index itself
# (the version accordion: current version, Development Snapshot, Older
# Versions), where expanding a version used to show a flat list instead of
# the same captioned groups. That's because Sphinx's toctree resolution only
# keeps `:caption:` labels for the page acting as the root of the resolved
# fragment; once a version's toctree is merged as a *child* of the index page
# (two hops away), its captions are dropped. To nest them back in, we resolve
# each version's own toctree separately (as if it were the root, via
# pydata-sphinx-theme's internal toctree helpers) and splice the captioned
# fragment into that version's accordion in the outer, uncaptioned tree.
# Older Versions is left as-is; it isn't touched here.
#
# We render this same nested tree, always anchored at user-guide/index, for
# EVERY page under user-guide/ (not just the index page). Sub-pages used to
# fall back to a different, shallower anchor (the version's own index),
# which dropped the version accordion entirely and replaced the sidebar with
# a completely different tree on every navigation — jarring, and the reason
# an earlier commit on this branch flattened everything back to one
# consistent depth. Keeping one fixed anchor everywhere gets the same
# stability without giving up captions: only the "current" highlighting and
# which accordion is auto-expanded change between pages.
#
# This relies on two undocumented, module-level helpers from
# pydata_sphinx_theme.toctree (get_nonroot_toctree, add_collapse_checkboxes).
# They're pinned via requirements.txt (pydata-sphinx-theme<0.17.0), so a
# theme upgrade won't silently change this behavior.
def _build_user_guide_sidebar_html(app, pagename, context):
from bs4 import BeautifulSoup
from pydata_sphinx_theme.toctree import (
_get_ancestor_pagename,
add_collapse_checkboxes,
get_nonroot_toctree,
)
from sphinx.environment.adapters.toctree import TocTree
outer = context["generate_toctree_html"](
"sidebar", startdepth=1, maxdepth=4, collapse=False,
includehidden=True, titles_only=True,
)
# generate_toctree_html is memoized by the theme and returns a shared,
# mutable BeautifulSoup object; re-parse into an independent tree so the
# splicing below can't compound across repeated calls for this page.
soup = BeautifulSoup(str(outer), "html.parser")
# Resolve the same depth-1 ancestor generate_toctree_html used above
# (user-guide/index, regardless of which user-guide/* page is actually
# being rendered) so we read its toctree's own doc list rather than
# pagename's — pagename is the page being viewed, not the page that
# owns the version-accordion toctree.
toctree = TocTree(app.env)
ancestorname, _ = _get_ancestor_pagename(app, pagename, startdepth=1)
# That toctree lists, in order: the current stable version, the
# development snapshot, then Older Versions. Nest captions into the
# first two; Older Versions keeps its existing flat list.
version_docnames = app.env.toctree_includes.get(ancestorname, [])
top_level_items = soup.select("ul.bd-sidenav > li.toctree-l1")
for li, docname in zip(top_level_items, version_docnames[:2]):
details = li.find("details")
inner_ul = details.find("ul") if details else None
if inner_ul is None:
continue
captioned = get_nonroot_toctree(
app, pagename, docname, toctree,
collapse=False, maxdepth=4, includehidden=True, titles_only=True,
)
if captioned is None:
continue
frag_soup = BeautifulSoup(
app.builder.render_partial(captioned)["fragment"], "html.parser"
)
# The fragment was resolved as its own root, so its items are labeled
# toctree-l1/-l2/...; shift by one to match the depth they actually
# sit at once nested inside this version's own l1 entry.
for tag in frag_soup.find_all(class_=True):
tag["class"] = [
f"toctree-l{int(cl[len('toctree-l'):]) + 1}"
if cl.startswith("toctree-l") and cl[len("toctree-l"):].isdigit()
else cl
for cl in tag["class"]
]
add_collapse_checkboxes(frag_soup)
for child in list(frag_soup.children):
inner_ul.insert_before(child)
inner_ul.decompose()
return str(soup)
def _add_user_guide_sidebar_context(app, pagename, templatename, context, doctree):
if pagename.startswith("user-guide/"):
context["user_guide_sidebar_html"] = (
lambda: _build_user_guide_sidebar_html(app, pagename, context)
)
def setup(app):
app.connect("source-read", _substitute_version)
app.connect("html-page-context", _add_user_guide_sidebar_context)
return {"version": _comet_version, "parallel_read_safe": True, "parallel_write_safe": True}