|
| 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