diff --git a/pep2html.py b/pep2html.py index 9a2b666f0d7..aabb0e1465a 100755 --- a/pep2html.py +++ b/pep2html.py @@ -45,6 +45,7 @@ import random import time from io import open +from pathlib import Path try: from html import escape except ImportError: @@ -52,7 +53,7 @@ from docutils import core, nodes, utils from docutils.readers import standalone -from docutils.transforms import peps, frontmatter, Transform +from docutils.transforms import frontmatter, misc, peps, Transform from docutils.parsers import rst class DataError(Exception): @@ -433,6 +434,46 @@ def apply(self): elif name == 'version' and len(body): utils.clean_rcs_keywords(para, self.rcs_keyword_substitutions) + +class PEPFooter(Transform): + """Remove the References section if it is empty when rendered.""" + + # Uses same priority as docutils.transforms.TargetNotes + default_priority = 520 + + def apply(self): + pep_source_path = Path(self.document["source"]) + if not pep_source_path.match("pep-*"): + return # not a PEP file, exit early + + doc = self.document + reference_section = None + + # Iterate through sections from the end of the document + for i, section in enumerate(reversed(doc)): + if not isinstance(section, nodes.section): + continue + title_words = section[0].astext().lower().split() + if "references" in title_words: + reference_section = section + break + + # Remove references section if there are no displayed footnotes + if reference_section: + pending = nodes.pending( + misc.CallBack, details={"callback": _cleanup_callback}) + reference_section.append(pending) + self.document.note_pending(pending, priority=1) + + +def _cleanup_callback(pending): + """Remove an empty "References" section.""" + for footer_node in pending.parent: + if isinstance(footer_node, (nodes.title, nodes.target, nodes.pending)): + return + pending.parent.parent.remove(pending.parent) + + class PEPReader(standalone.Reader): supported = ('pep',) @@ -453,7 +494,7 @@ def get_transforms(self): transforms.remove(frontmatter.DocTitle) transforms.remove(frontmatter.SectionSubTitle) transforms.remove(frontmatter.DocInfo) - transforms.extend([PEPHeaders, peps.Contents, peps.TargetNotes]) + transforms.extend([PEPHeaders, peps.Contents, PEPFooter]) return transforms settings_default_overrides = {'pep_references': 1, 'rfc_references': 1} diff --git a/pep_sphinx_extensions/pep_processor/transforms/pep_footer.py b/pep_sphinx_extensions/pep_processor/transforms/pep_footer.py index 5fa1b3844d4..5b8cc47dd5a 100644 --- a/pep_sphinx_extensions/pep_processor/transforms/pep_footer.py +++ b/pep_sphinx_extensions/pep_processor/transforms/pep_footer.py @@ -5,7 +5,6 @@ from docutils import nodes from docutils import transforms from docutils.transforms import misc -from docutils.transforms import references from pep_sphinx_extensions import config @@ -13,14 +12,9 @@ class PEPFooter(transforms.Transform): """Footer transforms for PEPs. - - Appends external links to footnotes. + - Removes the References section if it is empty when rendered. - Creates a link to the (GitHub) source text. - TargetNotes: - Locate the `References` section, insert a placeholder at the end - for an external target footnote insertion transform, and schedule - the transform to run immediately. - Source Link: Create the link to the source file from the document source path, and append the text to the end of the document. @@ -36,10 +30,9 @@ def apply(self) -> None: return # not a PEP file, exit early doc = self.document[0] - reference_section = copyright_section = None + reference_section = None # Iterate through sections from the end of the document - num_sections = len(doc) for i, section in enumerate(reversed(doc)): if not isinstance(section, nodes.section): continue @@ -47,31 +40,12 @@ def apply(self) -> None: if "references" in title_words: reference_section = section break - elif "copyright" in title_words: - copyright_section = num_sections - i - 1 - - # Add a references section if we didn't find one - if not reference_section: - reference_section = nodes.section() - reference_section += nodes.title("", "References") - self.document.set_id(reference_section) - if copyright_section: - # Put the new "References" section before "Copyright": - doc.insert(copyright_section, reference_section) - else: - # Put the new "References" section at end of doc: - doc.append(reference_section) - - # Add and schedule execution of the TargetNotes transform - pending = nodes.pending(references.TargetNotes) - reference_section.append(pending) - self.document.note_pending(pending, priority=0) - - # If there are no references after TargetNotes has finished, remove the - # references section - pending = nodes.pending(misc.CallBack, details={"callback": _cleanup_callback}) - reference_section.append(pending) - self.document.note_pending(pending, priority=1) + + # Remove references section if there are no displayed footnotes + if reference_section: + pending = nodes.pending(misc.CallBack, details={"callback": _cleanup_callback}) + reference_section.append(pending) + self.document.note_pending(pending, priority=1) # Add link to source text and last modified date if pep_source_path.stem != "pep-0000": @@ -80,13 +54,13 @@ def apply(self) -> None: def _cleanup_callback(pending: nodes.pending) -> None: - """Remove an empty "References" section. - - Called after the `references.TargetNotes` transform is complete. - - """ - if len(pending.parent) == 2: # and <pending> - pending.parent.parent.remove(pending.parent) + """Remove an empty "References" section.""" + for ref_node in pending.parent: + # Don't remove section if has more than title, link targets and pending + if not isinstance( + ref_node, (nodes.title, nodes.target, nodes.pending)): + return + pending.parent.parent.remove(pending.parent) def _add_source_link(pep_source_path: Path) -> nodes.paragraph: