mirror of
				https://github.com/python/cpython.git
				synced 2025-11-02 22:51:25 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			187 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			187 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
"""Support for building "topic help" for pydoc."""
 | 
						|
 | 
						|
from __future__ import annotations
 | 
						|
 | 
						|
from time import asctime
 | 
						|
from typing import TYPE_CHECKING
 | 
						|
 | 
						|
from sphinx.builders.text import TextBuilder
 | 
						|
from sphinx.util import logging
 | 
						|
from sphinx.util.display import status_iterator
 | 
						|
from sphinx.util.docutils import new_document
 | 
						|
from sphinx.writers.text import TextTranslator
 | 
						|
 | 
						|
if TYPE_CHECKING:
 | 
						|
    from collections.abc import Sequence, Set
 | 
						|
 | 
						|
    from sphinx.application import Sphinx
 | 
						|
    from sphinx.util.typing import ExtensionMetadata
 | 
						|
 | 
						|
logger = logging.getLogger(__name__)
 | 
						|
 | 
						|
_PYDOC_TOPIC_LABELS: Sequence[str] = sorted({
 | 
						|
    "assert",
 | 
						|
    "assignment",
 | 
						|
    "assignment-expressions",
 | 
						|
    "async",
 | 
						|
    "atom-identifiers",
 | 
						|
    "atom-literals",
 | 
						|
    "attribute-access",
 | 
						|
    "attribute-references",
 | 
						|
    "augassign",
 | 
						|
    "await",
 | 
						|
    "binary",
 | 
						|
    "bitwise",
 | 
						|
    "bltin-code-objects",
 | 
						|
    "bltin-ellipsis-object",
 | 
						|
    "bltin-null-object",
 | 
						|
    "bltin-type-objects",
 | 
						|
    "booleans",
 | 
						|
    "break",
 | 
						|
    "callable-types",
 | 
						|
    "calls",
 | 
						|
    "class",
 | 
						|
    "comparisons",
 | 
						|
    "compound",
 | 
						|
    "context-managers",
 | 
						|
    "continue",
 | 
						|
    "conversions",
 | 
						|
    "customization",
 | 
						|
    "debugger",
 | 
						|
    "del",
 | 
						|
    "dict",
 | 
						|
    "dynamic-features",
 | 
						|
    "else",
 | 
						|
    "exceptions",
 | 
						|
    "execmodel",
 | 
						|
    "exprlists",
 | 
						|
    "floating",
 | 
						|
    "for",
 | 
						|
    "formatstrings",
 | 
						|
    "function",
 | 
						|
    "global",
 | 
						|
    "id-classes",
 | 
						|
    "identifiers",
 | 
						|
    "if",
 | 
						|
    "imaginary",
 | 
						|
    "import",
 | 
						|
    "in",
 | 
						|
    "integers",
 | 
						|
    "lambda",
 | 
						|
    "lists",
 | 
						|
    "naming",
 | 
						|
    "nonlocal",
 | 
						|
    "numbers",
 | 
						|
    "numeric-types",
 | 
						|
    "objects",
 | 
						|
    "operator-summary",
 | 
						|
    "pass",
 | 
						|
    "power",
 | 
						|
    "raise",
 | 
						|
    "return",
 | 
						|
    "sequence-types",
 | 
						|
    "shifting",
 | 
						|
    "slicings",
 | 
						|
    "specialattrs",
 | 
						|
    "specialnames",
 | 
						|
    "string-methods",
 | 
						|
    "strings",
 | 
						|
    "subscriptions",
 | 
						|
    "truth",
 | 
						|
    "try",
 | 
						|
    "types",
 | 
						|
    "typesfunctions",
 | 
						|
    "typesmapping",
 | 
						|
    "typesmethods",
 | 
						|
    "typesmodules",
 | 
						|
    "typesseq",
 | 
						|
    "typesseq-mutable",
 | 
						|
    "unary",
 | 
						|
    "while",
 | 
						|
    "with",
 | 
						|
    "yield",
 | 
						|
})
 | 
						|
 | 
						|
 | 
						|
class PydocTopicsBuilder(TextBuilder):
 | 
						|
    name = "pydoc-topics"
 | 
						|
 | 
						|
    def init(self) -> None:
 | 
						|
        super().init()
 | 
						|
        self.topics: dict[str, str] = {}
 | 
						|
 | 
						|
    def get_outdated_docs(self) -> str:
 | 
						|
        # Return a string describing what an update build will build.
 | 
						|
        return "all pydoc topics"
 | 
						|
 | 
						|
    def write_documents(self, _docnames: Set[str]) -> None:
 | 
						|
        env = self.env
 | 
						|
 | 
						|
        labels: dict[str, tuple[str, str, str]]
 | 
						|
        labels = env.domains.standard_domain.labels
 | 
						|
 | 
						|
        # docname -> list of (topic_label, label_id) pairs
 | 
						|
        doc_labels: dict[str, list[tuple[str, str]]] = {}
 | 
						|
        for topic_label in _PYDOC_TOPIC_LABELS:
 | 
						|
            try:
 | 
						|
                docname, label_id, _section_name = labels[topic_label]
 | 
						|
            except KeyError:
 | 
						|
                logger.warning("label %r not in documentation", topic_label)
 | 
						|
                continue
 | 
						|
            doc_labels.setdefault(docname, []).append((topic_label, label_id))
 | 
						|
 | 
						|
        for docname, label_ids in status_iterator(
 | 
						|
            doc_labels.items(),
 | 
						|
            "building topics... ",
 | 
						|
            length=len(doc_labels),
 | 
						|
            stringify_func=_display_labels,
 | 
						|
        ):
 | 
						|
            doctree = env.get_and_resolve_doctree(docname, builder=self)
 | 
						|
            doc_ids = doctree.ids
 | 
						|
            for topic_label, label_id in label_ids:
 | 
						|
                document = new_document("<section node>")
 | 
						|
                document.append(doc_ids[label_id])
 | 
						|
                visitor = TextTranslator(document, builder=self)
 | 
						|
                document.walkabout(visitor)
 | 
						|
                self.topics[topic_label] = visitor.body
 | 
						|
 | 
						|
    def finish(self) -> None:
 | 
						|
        topics_repr = "\n".join(
 | 
						|
            f"    '{topic}': {_repr(self.topics[topic])},"
 | 
						|
            for topic in sorted(self.topics)
 | 
						|
        )
 | 
						|
        topics = f"""\
 | 
						|
# Autogenerated by Sphinx on {asctime()}
 | 
						|
# as part of the release process.
 | 
						|
 | 
						|
topics = {{
 | 
						|
{topics_repr}
 | 
						|
}}
 | 
						|
"""
 | 
						|
        self.outdir.joinpath("topics.py").write_text(topics, encoding="utf-8")
 | 
						|
 | 
						|
 | 
						|
def _display_labels(item: tuple[str, Sequence[tuple[str, str]]]) -> str:
 | 
						|
    _docname, label_ids = item
 | 
						|
    labels = [name for name, _id in label_ids]
 | 
						|
    if len(labels) > 4:
 | 
						|
        return f"{labels[0]}, {labels[1]}, ..., {labels[-2]}, {labels[-1]}"
 | 
						|
    return ", ".join(labels)
 | 
						|
 | 
						|
 | 
						|
def _repr(text: str, /) -> str:
 | 
						|
    """Return a triple-single-quoted representation of text."""
 | 
						|
    if "'''" not in text:
 | 
						|
        return f"r'''{text}'''"
 | 
						|
    text = text.replace("\\", "\\\\").replace("'''", r"\'\'\'")
 | 
						|
    return f"'''{text}'''"
 | 
						|
 | 
						|
 | 
						|
def setup(app: Sphinx) -> ExtensionMetadata:
 | 
						|
    app.add_builder(PydocTopicsBuilder)
 | 
						|
 | 
						|
    return {
 | 
						|
        "version": "1.0",
 | 
						|
        "parallel_read_safe": True,
 | 
						|
        "parallel_write_safe": True,
 | 
						|
    }
 |