Skip to content

Commit

Permalink
Use up-to-date Sphinx
Browse files Browse the repository at this point in the history
  • Loading branch information
WyattBlue committed Feb 18, 2025
1 parent 4a7287a commit 05b38be
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 592 deletions.
11 changes: 1 addition & 10 deletions docs/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
SPHINXOPTS =
SPHINXBUILD = sphinx-build
BUILDDIR = _build
FFMPEGDIR = _ffmpeg
PYAV_PIP ?= pip
PIP := $(PYAV_PIP)
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(SPHINXOPTS) .
Expand All @@ -10,14 +9,6 @@ ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(SPHINXOPTS) .

default: html

TAGFILE := _build/doxygen/tagfile.xml

$(TAGFILE):
@if [ ! -d "$(FFMPEGDIR)" ]; then \
git clone --depth=1 git://source.ffmpeg.org/ffmpeg.git $(FFMPEGDIR); \
fi
./generate-tagfile --library $(FFMPEGDIR) -o $(TAGFILE)

TEMPLATES := $(wildcard api/*.py development/*.py)
RENDERED := $(TEMPLATES:%.py=_build/rst/%.rst)

Expand All @@ -30,7 +21,7 @@ clean:
rm -rf $(BUILDDIR) $(FFMPEGDIR)

html: $(RENDERED) $(TAGFILE)
$(PIP) install -U sphinx==5.1.0
$(PIP) install -U sphinx
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html

test:
Expand Down
210 changes: 27 additions & 183 deletions docs/conf.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,10 @@
import logging
import os
import re
import sys
import xml.etree.ElementTree as etree

import sphinx
from docutils import nodes
from sphinx import addnodes
from sphinx.util.docutils import SphinxDirective
import sphinx


logging.basicConfig()

# 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.
sys.path.insert(0, os.path.abspath(".."))

# -- 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.
Expand All @@ -31,37 +18,24 @@
"sphinx.ext.doctest",
]


# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]

# The suffix of source filenames.
source_suffix = ".rst"

# The master toctree document.
master_doc = "index"

# General information about the project.
project = "PyAV"
copyright = "2025, The PyAV Team"

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#

about = {}
with open("../av/about.py") as fp:
exec(fp.read(), about)

# The full version, including alpha/beta/rc tags.
release = about["__version__"]

# The short X.Y version.
version = release.split("-")[0]

exclude_patterns = ["_build"]

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = "sphinx"

# -- Options for HTML output ---------------------------------------------------
Expand All @@ -85,7 +59,6 @@


doctest_global_setup = """
import errno
import os
Expand All @@ -109,29 +82,20 @@ def sandboxed(*args, **kwargs):
os.chdir(here)
video_path = curated('pexels/time-lapse-video-of-night-sky-857195.mp4')
"""

doctest_global_cleanup = """
os.chdir(_cwd)
"""


doctest_global_cleanup = "os.chdir(_cwd)"
doctest_test_doctest_blocks = ""


extlinks = {
"ffstruct": ("http://ffmpeg.org/doxygen/trunk/struct%s.html", "struct "),
"issue": ("https://github.com/PyAV-Org/PyAV/issues/%s", "#"),
"pr": ("https://github.com/PyAV-Org/PyAV/pull/%s", "#"),
"gh-user": ("https://github.com/%s", "@"),
"ffmpeg": ("https://ffmpeg.org/doxygen/trunk/%s.html", "%s"),
"ffstruct": ("https://ffmpeg.org/doxygen/trunk/struct%s.html", "struct %s"),
"issue": ("https://github.com/PyAV-Org/PyAV/issues/%s", "#%s"),
"pr": ("https://github.com/PyAV-Org/PyAV/pull/%s", "#%s"),
"gh-user": ("https://github.com/%s", "@%s"),
}

intersphinx_mapping = {
"https://docs.python.org/3": None,
}
intersphinx_mapping = {"python": ("https://docs.python.org/3", None)}

autodoc_member_order = "bysource"
autodoc_default_options = {
Expand Down Expand Up @@ -238,152 +202,32 @@ def makerow(*texts):
)

seen = set()
if hasattr(enum, "_by_name"): # Our custom enum class
enum_items = enum._by_name.items()
for name, item in enum_items:
if name.lower() in seen:
continue
seen.add(name.lower())

try:
attr = properties[item]
except KeyError:
if cls:
continue
attr = None

value = f"0x{item.value:X}"
doc = item.__doc__ or "-"
tbody += makerow(attr, name, value, doc)

return [table]
else: # Standard IntEnum
enum_items = [
(name, item)
for name, item in vars(enum).items()
if isinstance(item, enum)
]
for name, item in enum_items:
if name.lower() in seen:
continue
seen.add(name.lower())

try:
attr = properties[item]
except KeyError:
if cls:
continue
attr = None

value = f"0x{item.value:X}"
doc = enum.__annotations__.get(name, "---")[1:-1]
tbody += makerow(attr, name, value, doc)

return [table]


doxylink = {}
ffmpeg_tagfile = os.path.abspath(
os.path.join(__file__, "..", "_build", "doxygen", "tagfile.xml")
)
if not os.path.exists(ffmpeg_tagfile):
print("ERROR: Missing FFmpeg tagfile.")
exit(1)
doxylink["ffmpeg"] = (ffmpeg_tagfile, "https://ffmpeg.org/doxygen/trunk/")


def doxylink_create_handler(app, file_name, url_base):
print("Finding all names in Doxygen tagfile", file_name)

doc = etree.parse(file_name)
root = doc.getroot()

parent_map = {} # ElementTree doesn't five us access to parents.
urls = {}

for node in root.findall(".//name/.."):
for child in node:
parent_map[child] = node

kind = node.attrib["kind"]
if kind not in ("function", "struct", "variable"):
continue

name = node.find("name").text

if kind not in ("function",):
parent = parent_map.get(node)
parent_name = parent.find("name") if parent else None
if parent_name is not None:
name = f"{parent_name.text}.{name}"

filenode = node.find("filename")
if filenode is not None:
url = filenode.text
else:
url = "{}#{}".format(
node.find("anchorfile").text,
node.find("anchor").text,
)

urls.setdefault(kind, {})[name] = url

def get_url(name):
# These are all the kinds that seem to exist.
for kind in (
"function",
"struct",
"variable", # These are struct members.
# 'class',
# 'define',
# 'enumeration',
# 'enumvalue',
# 'file',
# 'group',
# 'page',
# 'typedef',
# 'union',
):
enum_items = [
(name, item)
for name, item in vars(enum).items()
if isinstance(item, enum)
]
for name, item in enum_items:
if name.lower() in seen:
continue
seen.add(name.lower())

try:
return urls[kind][name]
attr = properties[item]
except KeyError:
pass

def _doxylink_handler(name, rawtext, text, lineno, inliner, options={}, content=[]):
m = re.match(r"^(.+?)(?:<(.+?)>)?$", text)
title, name = m.groups()
name = name or title

url = get_url(name)
if not url:
if name == "AVFrame.color_primaries":
url = "structAVFrame.html#a59a3f830494f2ed1133103a1bc9481e7"
elif name == "AVFrame.color_trc":
url = "structAVFrame.html#ab09abb126e3922bc1d010cf044087939"
else:
print("ERROR: Could not find", name)
exit(1)

node = addnodes.literal_strong(title, title)
if url:
url = url_base + url
node = nodes.reference("", "", node, refuri=url)
if cls:
continue
attr = None

return [node], []
value = f"0x{item.value:X}"
doc = enum.__annotations__.get(name, "---")[1:-1]
tbody += makerow(attr, name, value, doc)

return _doxylink_handler
return [table]


def setup(app):
app.add_css_file("custom.css")

app.add_directive("flagtable", EnumTable)
app.add_directive("enumtable", EnumTable)
app.add_directive("pyinclude", PyInclude)

skip = os.environ.get("PYAV_SKIP_DOXYLINK")
for role, (filename, url_base) in doxylink.items():
if skip:
app.add_role(role, lambda *args: ([], []))
else:
app.add_role(role, doxylink_create_handler(app, filename, url_base))
Loading

0 comments on commit 05b38be

Please # to comment.