From 129ecb2821fac6a291905be63f6477192695dc32 Mon Sep 17 00:00:00 2001 From: "C.A.M. Gerlach" Date: Fri, 19 Nov 2021 00:12:39 -0600 Subject: [PATCH 1/2] Don't auto-add inline links to ref section & rm if empty, per #2130 --- pep2html.py | 45 ++++++++++++++- .../pep_processor/transforms/pep_footer.py | 56 +++++-------------- 2 files changed, 58 insertions(+), 43 deletions(-) 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: From 5788d8aed3935428eeab9c7edf4354a3efdfaba5 Mon Sep 17 00:00:00 2001 From: "C.A.M. Gerlach" <CAM.Gerlach@Gerlach.CAM> Date: Tue, 23 Nov 2021 20:40:43 -0600 Subject: [PATCH 2/2] Further simplify footer references section cleanup code Co-Authored-By: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- pep2html.py | 34 ++++++------------- .../pep_processor/transforms/pep_footer.py | 28 ++++----------- 2 files changed, 16 insertions(+), 46 deletions(-) diff --git a/pep2html.py b/pep2html.py index aabb0e1465a..24b7c16fe2f 100755 --- a/pep2html.py +++ b/pep2html.py @@ -53,7 +53,7 @@ from docutils import core, nodes, utils from docutils.readers import standalone -from docutils.transforms import frontmatter, misc, peps, Transform +from docutils.transforms import frontmatter, peps, Transform from docutils.parsers import rst class DataError(Exception): @@ -442,37 +442,23 @@ class PEPFooter(Transform): default_priority = 520 def apply(self): - pep_source_path = Path(self.document["source"]) - if not pep_source_path.match("pep-*"): + 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)): + for section in reversed(self.document): if not isinstance(section, nodes.section): continue title_words = section[0].astext().lower().split() - if "references" in title_words: - reference_section = section + if 'references' in title_words: + # Remove references section if there are no displayed + # footnotes (it only has title & link target nodes) + if all(isinstance(ref_node, (nodes.title, nodes.target)) + for ref_node in section): + section.parent.remove(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): diff --git a/pep_sphinx_extensions/pep_processor/transforms/pep_footer.py b/pep_sphinx_extensions/pep_processor/transforms/pep_footer.py index 5b8cc47dd5a..39dad0404b2 100644 --- a/pep_sphinx_extensions/pep_processor/transforms/pep_footer.py +++ b/pep_sphinx_extensions/pep_processor/transforms/pep_footer.py @@ -4,7 +4,6 @@ from docutils import nodes from docutils import transforms -from docutils.transforms import misc from pep_sphinx_extensions import config @@ -29,40 +28,25 @@ def apply(self) -> None: if not pep_source_path.match("pep-*"): return # not a PEP file, exit early - doc = self.document[0] - reference_section = None - # Iterate through sections from the end of the document - for i, section in enumerate(reversed(doc)): + for section in reversed(self.document[0]): if not isinstance(section, nodes.section): continue title_words = section[0].astext().lower().split() if "references" in title_words: - reference_section = section + # Remove references section if there are no displayed + # footnotes (it only has title & link target nodes) + if all(isinstance(ref_node, (nodes.title, nodes.target)) + for ref_node in section): + section.parent.remove(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) - # Add link to source text and last modified date if pep_source_path.stem != "pep-0000": self.document += _add_source_link(pep_source_path) self.document += _add_commit_history_info(pep_source_path) -def _cleanup_callback(pending: nodes.pending) -> None: - """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: """Add link to source text on VCS (GitHub)""" source_link = config.pep_vcs_url + pep_source_path.name