|  | 
|  | 1 | +"""Support for including Misc/NEWS.""" | 
|  | 2 | + | 
|  | 3 | +from __future__ import annotations | 
|  | 4 | + | 
|  | 5 | +import re | 
|  | 6 | +from pathlib import Path | 
|  | 7 | +from typing import TYPE_CHECKING | 
|  | 8 | + | 
|  | 9 | +from docutils import nodes | 
|  | 10 | +from sphinx.locale import _ as sphinx_gettext | 
|  | 11 | +from sphinx.util.docutils import SphinxDirective | 
|  | 12 | + | 
|  | 13 | +if TYPE_CHECKING: | 
|  | 14 | +    from typing import Final | 
|  | 15 | + | 
|  | 16 | +    from docutils.nodes import Node | 
|  | 17 | +    from sphinx.application import Sphinx | 
|  | 18 | +    from sphinx.util.typing import ExtensionMetadata | 
|  | 19 | + | 
|  | 20 | + | 
|  | 21 | +BLURB_HEADER = """\ | 
|  | 22 | ++++++++++++ | 
|  | 23 | +Python News | 
|  | 24 | ++++++++++++ | 
|  | 25 | +""" | 
|  | 26 | + | 
|  | 27 | +bpo_issue_re: Final[re.Pattern[str]] = re.compile( | 
|  | 28 | +    "(?:issue #|bpo-)([0-9]+)", re.ASCII | 
|  | 29 | +) | 
|  | 30 | +gh_issue_re: Final[re.Pattern[str]] = re.compile( | 
|  | 31 | +    "gh-(?:issue-)?([0-9]+)", re.ASCII | re.IGNORECASE | 
|  | 32 | +) | 
|  | 33 | +whatsnew_re: Final[re.Pattern[str]] = re.compile( | 
|  | 34 | +    r"^what's new in (.*?)\??$", re.ASCII | re.IGNORECASE | re.MULTILINE | 
|  | 35 | +) | 
|  | 36 | + | 
|  | 37 | + | 
|  | 38 | +class MiscNews(SphinxDirective): | 
|  | 39 | +    has_content = False | 
|  | 40 | +    required_arguments = 1 | 
|  | 41 | +    optional_arguments = 0 | 
|  | 42 | +    final_argument_whitespace = False | 
|  | 43 | +    option_spec = {} | 
|  | 44 | + | 
|  | 45 | +    def run(self) -> list[Node]: | 
|  | 46 | +        # Get content of NEWS file | 
|  | 47 | +        source, _ = self.get_source_info() | 
|  | 48 | +        news_file = Path(source).resolve().parent / self.arguments[0] | 
|  | 49 | +        self.env.note_dependency(news_file) | 
|  | 50 | +        try: | 
|  | 51 | +            news_text = news_file.read_text(encoding="utf-8") | 
|  | 52 | +        except (OSError, UnicodeError): | 
|  | 53 | +            text = sphinx_gettext("The NEWS file is not available.") | 
|  | 54 | +            return [nodes.strong(text, text)] | 
|  | 55 | + | 
|  | 56 | +        # remove first 3 lines as they are the main heading | 
|  | 57 | +        news_text = news_text.removeprefix(BLURB_HEADER) | 
|  | 58 | + | 
|  | 59 | +        news_text = bpo_issue_re.sub(r":issue:`\1`", news_text) | 
|  | 60 | +        # Fallback handling for GitHub issues | 
|  | 61 | +        news_text = gh_issue_re.sub(r":gh:`\1`", news_text) | 
|  | 62 | +        news_text = whatsnew_re.sub(r"\1", news_text) | 
|  | 63 | + | 
|  | 64 | +        self.state_machine.insert_input(news_text.splitlines(), str(news_file)) | 
|  | 65 | +        return [] | 
|  | 66 | + | 
|  | 67 | + | 
|  | 68 | +def setup(app: Sphinx) -> ExtensionMetadata: | 
|  | 69 | +    app.add_directive("miscnews", MiscNews) | 
|  | 70 | + | 
|  | 71 | +    return { | 
|  | 72 | +        "version": "1.0", | 
|  | 73 | +        "parallel_read_safe": True, | 
|  | 74 | +        "parallel_write_safe": True, | 
|  | 75 | +    } | 
0 commit comments