From a6a5187ed636d86f818b5ab910c280d2fcdf97e1 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Sat, 29 Jan 2022 01:29:10 +0000 Subject: [PATCH 1/5] Fix links in section headings --- pep-0249.txt | 92 ++++++++++++++++++++++++++-------------------------- pep-0512.txt | 4 +-- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/pep-0249.txt b/pep-0249.txt index cce6a35022c..09d19dabc2f 100644 --- a/pep-0249.txt +++ b/pep-0249.txt @@ -12,8 +12,8 @@ Post-History: Replaces: 248 -`Introduction`_ -=============== +Introduction +============ This API has been defined to encourage similarity between the Python modules that are used to access databases. By doing this, we hope to @@ -35,11 +35,11 @@ encouraged to use this version of the specification as basis for new interfaces. -`Module Interface`_ -=================== +Module Interface +================= -`Constructors`_ ---------------- +Constructors +------------ Access to the database is made available through connection objects. The module must provide the following constructor for these: @@ -53,8 +53,8 @@ objects. The module must provide the following constructor for these: which are database dependent. [1]_ -`Globals`_ ----------- +Globals +------- These module globals must be defined: @@ -107,8 +107,8 @@ These module globals must be defined: ============ ============================================================== -`Exceptions`_ -------------- +Exceptions +---------- The module should make all error information available through these exceptions or subclasses thereof: @@ -220,14 +220,14 @@ This is the exception inheritance layout:: .. _Connection: -`Connection Objects`_ -===================== +Connection Objects +================== Connection objects should respond to the following methods. -`Connection methods`_ ---------------------- +Connection methods +------------------ .. .close(): .. _Connection.close: @@ -283,8 +283,8 @@ Connection objects should respond to the following methods. .. _Cursor: -`Cursor Objects`_ -================= +Cursor Objects +============== These objects represent a database cursor, which is used to manage the context of a fetch operation. Cursors created from the same connection @@ -297,8 +297,8 @@ transaction support is implemented (see also the connection's Cursor Objects should respond to the following methods and attributes. -`Cursor attributes`_ --------------------- +Cursor attributes +----------------- .. _.description: @@ -344,8 +344,8 @@ Cursor Objects should respond to the following methods and attributes. latter case to have the object return ``None`` instead of -1. -`Cursor methods`_ ------------------ +Cursor methods +-------------- .. _.callproc: .. _.callproc(): @@ -561,8 +561,8 @@ Cursor Objects should respond to the following methods and attributes. .. _Type Objects: -`Type Objects and Constructors`_ -================================ +Type Objects and Constructors +============================= Many databases need to have the input in a particular format for binding to an operation's input parameters. For example, if an input @@ -682,8 +682,8 @@ on input and output. .. _Implementation Hints: -`Implementation Hints for Module Authors`_ -========================================== +Implementation Hints for Module Authors +======================================= * Date/time objects can be implemented as `Python datetime module `__ objects (available @@ -769,8 +769,8 @@ on input and output. API to create the exception objects. -`Optional DB API Extensions`_ -============================= +Optional DB API Extensions +========================== During the lifetime of DB API 2.0, module authors have often extended their implementations beyond what is required by this DB API @@ -934,8 +934,8 @@ Cursor\ `.lastrowid`_ *Warning Message:* "DB-API extension cursor.lastrowid used" -`Optional Error Handling Extensions`_ -===================================== +Optional Error Handling Extensions +================================== The core DB API specification only introduces a set of exceptions which can be raised to report errors to the user. In some cases, @@ -981,8 +981,8 @@ Cursors should inherit the ``.errorhandler`` setting from their connection objects at cursor creation time. -`Optional Two-Phase Commit Extensions`_ -======================================= +Optional Two-Phase Commit Extensions +==================================== Many databases have support for two-phase commit (TPC) which allows managing transactions across multiple database connections and other @@ -994,8 +994,8 @@ API should be implemented. NotSupportedError_ should be raised, if the database backend support for two-phase commit can only be checked at run-time. -`TPC Transaction IDs`_ ----------------------- +TPC Transaction IDs +------------------- As many databases follow the XA specification, transaction IDs are formed from three components: @@ -1034,8 +1034,8 @@ Transaction IDs are created with the `.xid()`_ Connection method: represent transaction IDs with tuples rather than a custom object. -`TPC Connection Methods`_ -------------------------- +TPC Connection Methods +---------------------- .. _.tpc_*: .. _.tpc_*(): @@ -1117,8 +1117,8 @@ Transaction IDs are created with the `.xid()`_ Connection method: -`Frequently Asked Questions`_ -============================= +Frequently Asked Questions +========================== The database SIG often sees reoccurring questions about the DB API specification. This section covers some of the issues people sometimes @@ -1153,8 +1153,8 @@ between databases and makes writing portable code impossible. -`Major Changes from Version 1.0 to Version 2.0`_ -================================================ +Major Changes from Version 1.0 to Version 2.0 +============================================= The Python Database API 2.0 introduces a few major changes compared to the 1.0 version. Because some of these changes will cause existing DB @@ -1197,8 +1197,8 @@ Post-publishing additions to the DB API 2.0 specification: functionality were specified. -`Open Issues`_ -============== +Open Issues +=========== Although the version 2.0 specification clarifies a lot of questions that were left open in the 1.0 version, there are still some remaining @@ -1213,8 +1213,8 @@ issues which should be addressed in future versions: -`Footnotes`_ -============ +Footnotes +========= .. [1] As a guideline the connection constructor parameters should be implemented as keyword parameters for more intuitive use and @@ -1298,8 +1298,8 @@ issues which should be addressed in future versions: of the ``.rowcount`` attribute. -`Acknowledgements`_ -=================== +Acknowledgements +================ Many thanks go to Andrew Kuchling who converted the Python Database API Specification 2.0 from the original HTML format into the PEP @@ -1312,7 +1312,7 @@ Many thanks to Daniele Varrazzo for converting the specification from text PEP format to ReST PEP format, which allows linking to various parts. -`Copyright`_ -============ +Copyright +========= This document has been placed in the Public Domain. diff --git a/pep-0512.txt b/pep-0512.txt index 5f67af44417..e5c5917f27e 100644 --- a/pep-0512.txt +++ b/pep-0512.txt @@ -465,8 +465,8 @@ Work for this is being tracked at https://github.com/python/core-workflow/issues/7. -Create https://git.python.org -''''''''''''''''''''''''''''' +Create ``https://git.python.org`` +''''''''''''''''''''''''''''''''' Just as hg.python.org [#h.p.o]_ currently points to the Mercurial repository for Python, git.python.org should do the equivalent for From 8af9bf1dadfe5212b79c52a05fa7184831514d36 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Sat, 29 Jan 2022 00:04:56 +0000 Subject: [PATCH 2/5] Remove automatic table of contents --- .../pep_processor/parsing/pep_parser.py | 4 +- .../pep_processor/transforms/pep_contents.py | 79 ------------------- .../transforms/pep_section_linker.py | 30 +++++++ .../pep_processor/transforms/pep_title.py | 3 + 4 files changed, 35 insertions(+), 81 deletions(-) delete mode 100644 pep_sphinx_extensions/pep_processor/transforms/pep_contents.py create mode 100644 pep_sphinx_extensions/pep_processor/transforms/pep_section_linker.py diff --git a/pep_sphinx_extensions/pep_processor/parsing/pep_parser.py b/pep_sphinx_extensions/pep_processor/parsing/pep_parser.py index 2ccbd6cb857..2994848c287 100644 --- a/pep_sphinx_extensions/pep_processor/parsing/pep_parser.py +++ b/pep_sphinx_extensions/pep_processor/parsing/pep_parser.py @@ -4,7 +4,7 @@ from sphinx import parsers -from pep_sphinx_extensions.pep_processor.transforms import pep_contents +from pep_sphinx_extensions.pep_processor.transforms import pep_section_linker from pep_sphinx_extensions.pep_processor.transforms import pep_footer from pep_sphinx_extensions.pep_processor.transforms import pep_headers from pep_sphinx_extensions.pep_processor.transforms import pep_title @@ -27,6 +27,6 @@ def get_transforms(self) -> list[type[transforms.Transform]]: return [ pep_headers.PEPHeaders, pep_title.PEPTitle, - pep_contents.PEPContents, + pep_section_linker.PEPSectionLinker, pep_footer.PEPFooter, ] diff --git a/pep_sphinx_extensions/pep_processor/transforms/pep_contents.py b/pep_sphinx_extensions/pep_processor/transforms/pep_contents.py deleted file mode 100644 index db975549f7f..00000000000 --- a/pep_sphinx_extensions/pep_processor/transforms/pep_contents.py +++ /dev/null @@ -1,79 +0,0 @@ -from __future__ import annotations - -from pathlib import Path - -from docutils import nodes -from docutils import transforms -from docutils.transforms import parts - - -class PEPContents(transforms.Transform): - """Add TOC placeholder and horizontal rule after PEP title and headers.""" - - # Use same priority as docutils.transforms.Contents - default_priority = 380 - - def apply(self) -> None: - if not Path(self.document["source"]).match("pep-*"): - return # not a PEP file, exit early - # Create the contents placeholder section - title = nodes.title("", "", nodes.Text("Contents")) - contents_section = nodes.section("", title) - if not self.document.has_name("contents"): - contents_section["names"].append("contents") - self.document.note_implicit_target(contents_section) - - # Add a table of contents builder - pending = nodes.pending(Contents) - contents_section += pending - self.document.note_pending(pending) - - # Insert the toc after title and PEP headers - self.document.children[0].insert(2, contents_section) - - # Add a horizontal rule before contents - transition = nodes.transition() - self.document[0].insert(2, transition) - - -class Contents(parts.Contents): - """Build Table of Contents from document.""" - def __init__(self, document: nodes.document, startnode: nodes.Node | None = None): - super().__init__(document, startnode) - - # used in parts.Contents.build_contents - self.toc_id = None - self.backlinks = None - - def apply(self) -> None: - contents = self.build_contents(self.document[0][4:]) # skip PEP title, headers,
, and contents - if contents: - self.startnode.replace_self(contents) - else: - # if no contents, remove the empty placeholder - self.startnode.parent.parent.remove(self.startnode.parent) - - def build_contents(self, node: nodes.Node | list[nodes.Node], _level: None = None): - entries = [] - children = getattr(node, "children", node) - - for section in children: - if not isinstance(section, nodes.section): - continue - - title = section[0] - - # remove all pre-existing hyperlinks in the title (e.g. PEP references) - while (link_node := title.next_node(nodes.reference)) is not None: - link_node.replace_self(link_node[0]) - ref_id = section['ids'][0] - title["refid"] = ref_id # Add a link to self - entry_text = self.copy_and_filter(title) - reference = nodes.reference("", "", refid=ref_id, *entry_text) - item = nodes.list_item("", nodes.paragraph("", "", reference)) - - item += self.build_contents(section) # recurse to add sub-sections - entries.append(item) - if entries: - return nodes.bullet_list('', *entries) - return [] diff --git a/pep_sphinx_extensions/pep_processor/transforms/pep_section_linker.py b/pep_sphinx_extensions/pep_processor/transforms/pep_section_linker.py new file mode 100644 index 00000000000..a52f37771ea --- /dev/null +++ b/pep_sphinx_extensions/pep_processor/transforms/pep_section_linker.py @@ -0,0 +1,30 @@ +from pathlib import Path + +from docutils import nodes +from docutils import transforms + + +class PEPSectionLinker(transforms.Transform): + """Link section headings to themselves.""" + + default_priority = 720 + + def apply(self) -> None: + if not Path(self.document["source"]).match("pep-*"): + return # not a PEP file, exit early + _link_section_headings(self.document[0][3:]) # skip PEP title, headers, and
+ + +def _link_section_headings(children: list[nodes.Node]): + for section in children: + if not isinstance(section, nodes.section): + continue + + # remove all pre-existing hyperlinks in the title (e.g. PEP references) + title = section[0] + while (link_node := title.next_node(nodes.reference)) is not None: + link_node.replace_self(link_node[0]) + + title["refid"] = section["ids"][0] # Add a link to self + + _link_section_headings(section.children) # recurse to sub-sections diff --git a/pep_sphinx_extensions/pep_processor/transforms/pep_title.py b/pep_sphinx_extensions/pep_processor/transforms/pep_title.py index 14e1190aabc..29c6e893e78 100644 --- a/pep_sphinx_extensions/pep_processor/transforms/pep_title.py +++ b/pep_sphinx_extensions/pep_processor/transforms/pep_title.py @@ -46,6 +46,9 @@ def apply(self) -> None: pep_title_node.extend(document_children) self.document.note_implicit_target(pep_title_node, pep_title_node) + # Add a horizontal rule after title and PEP headers + self.document[0].insert(2, nodes.transition()) + def _line_to_nodes(text: str) -> list[nodes.Node]: """Parse RST string to nodes.""" From 92f3dc5404e5f2eaa702997713dc781a712e1497 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Sun, 13 Mar 2022 14:15:53 +0000 Subject: [PATCH 3/5] Revert "Remove automatic table of contents" This reverts commit 8af9bf1dadfe5212b79c52a05fa7184831514d36. --- .../pep_processor/parsing/pep_parser.py | 4 +- .../pep_processor/transforms/pep_contents.py | 79 +++++++++++++++++++ .../transforms/pep_section_linker.py | 30 ------- .../pep_processor/transforms/pep_title.py | 3 - 4 files changed, 81 insertions(+), 35 deletions(-) create mode 100644 pep_sphinx_extensions/pep_processor/transforms/pep_contents.py delete mode 100644 pep_sphinx_extensions/pep_processor/transforms/pep_section_linker.py diff --git a/pep_sphinx_extensions/pep_processor/parsing/pep_parser.py b/pep_sphinx_extensions/pep_processor/parsing/pep_parser.py index 2994848c287..2ccbd6cb857 100644 --- a/pep_sphinx_extensions/pep_processor/parsing/pep_parser.py +++ b/pep_sphinx_extensions/pep_processor/parsing/pep_parser.py @@ -4,7 +4,7 @@ from sphinx import parsers -from pep_sphinx_extensions.pep_processor.transforms import pep_section_linker +from pep_sphinx_extensions.pep_processor.transforms import pep_contents from pep_sphinx_extensions.pep_processor.transforms import pep_footer from pep_sphinx_extensions.pep_processor.transforms import pep_headers from pep_sphinx_extensions.pep_processor.transforms import pep_title @@ -27,6 +27,6 @@ def get_transforms(self) -> list[type[transforms.Transform]]: return [ pep_headers.PEPHeaders, pep_title.PEPTitle, - pep_section_linker.PEPSectionLinker, + pep_contents.PEPContents, pep_footer.PEPFooter, ] diff --git a/pep_sphinx_extensions/pep_processor/transforms/pep_contents.py b/pep_sphinx_extensions/pep_processor/transforms/pep_contents.py new file mode 100644 index 00000000000..db975549f7f --- /dev/null +++ b/pep_sphinx_extensions/pep_processor/transforms/pep_contents.py @@ -0,0 +1,79 @@ +from __future__ import annotations + +from pathlib import Path + +from docutils import nodes +from docutils import transforms +from docutils.transforms import parts + + +class PEPContents(transforms.Transform): + """Add TOC placeholder and horizontal rule after PEP title and headers.""" + + # Use same priority as docutils.transforms.Contents + default_priority = 380 + + def apply(self) -> None: + if not Path(self.document["source"]).match("pep-*"): + return # not a PEP file, exit early + # Create the contents placeholder section + title = nodes.title("", "", nodes.Text("Contents")) + contents_section = nodes.section("", title) + if not self.document.has_name("contents"): + contents_section["names"].append("contents") + self.document.note_implicit_target(contents_section) + + # Add a table of contents builder + pending = nodes.pending(Contents) + contents_section += pending + self.document.note_pending(pending) + + # Insert the toc after title and PEP headers + self.document.children[0].insert(2, contents_section) + + # Add a horizontal rule before contents + transition = nodes.transition() + self.document[0].insert(2, transition) + + +class Contents(parts.Contents): + """Build Table of Contents from document.""" + def __init__(self, document: nodes.document, startnode: nodes.Node | None = None): + super().__init__(document, startnode) + + # used in parts.Contents.build_contents + self.toc_id = None + self.backlinks = None + + def apply(self) -> None: + contents = self.build_contents(self.document[0][4:]) # skip PEP title, headers,
, and contents + if contents: + self.startnode.replace_self(contents) + else: + # if no contents, remove the empty placeholder + self.startnode.parent.parent.remove(self.startnode.parent) + + def build_contents(self, node: nodes.Node | list[nodes.Node], _level: None = None): + entries = [] + children = getattr(node, "children", node) + + for section in children: + if not isinstance(section, nodes.section): + continue + + title = section[0] + + # remove all pre-existing hyperlinks in the title (e.g. PEP references) + while (link_node := title.next_node(nodes.reference)) is not None: + link_node.replace_self(link_node[0]) + ref_id = section['ids'][0] + title["refid"] = ref_id # Add a link to self + entry_text = self.copy_and_filter(title) + reference = nodes.reference("", "", refid=ref_id, *entry_text) + item = nodes.list_item("", nodes.paragraph("", "", reference)) + + item += self.build_contents(section) # recurse to add sub-sections + entries.append(item) + if entries: + return nodes.bullet_list('', *entries) + return [] diff --git a/pep_sphinx_extensions/pep_processor/transforms/pep_section_linker.py b/pep_sphinx_extensions/pep_processor/transforms/pep_section_linker.py deleted file mode 100644 index a52f37771ea..00000000000 --- a/pep_sphinx_extensions/pep_processor/transforms/pep_section_linker.py +++ /dev/null @@ -1,30 +0,0 @@ -from pathlib import Path - -from docutils import nodes -from docutils import transforms - - -class PEPSectionLinker(transforms.Transform): - """Link section headings to themselves.""" - - default_priority = 720 - - def apply(self) -> None: - if not Path(self.document["source"]).match("pep-*"): - return # not a PEP file, exit early - _link_section_headings(self.document[0][3:]) # skip PEP title, headers, and
- - -def _link_section_headings(children: list[nodes.Node]): - for section in children: - if not isinstance(section, nodes.section): - continue - - # remove all pre-existing hyperlinks in the title (e.g. PEP references) - title = section[0] - while (link_node := title.next_node(nodes.reference)) is not None: - link_node.replace_self(link_node[0]) - - title["refid"] = section["ids"][0] # Add a link to self - - _link_section_headings(section.children) # recurse to sub-sections diff --git a/pep_sphinx_extensions/pep_processor/transforms/pep_title.py b/pep_sphinx_extensions/pep_processor/transforms/pep_title.py index 29c6e893e78..14e1190aabc 100644 --- a/pep_sphinx_extensions/pep_processor/transforms/pep_title.py +++ b/pep_sphinx_extensions/pep_processor/transforms/pep_title.py @@ -46,9 +46,6 @@ def apply(self) -> None: pep_title_node.extend(document_children) self.document.note_implicit_target(pep_title_node, pep_title_node) - # Add a horizontal rule after title and PEP headers - self.document[0].insert(2, nodes.transition()) - def _line_to_nodes(text: str) -> list[nodes.Node]: """Parse RST string to nodes.""" From 67355b2e3d9e636bf8116322d44e8cdce5da424d Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Sun, 13 Mar 2022 15:25:09 +0000 Subject: [PATCH 4/5] Toggleable ToC --- .../pep_processor/html/pep_html_builder.py | 1 + .../pep_processor/html/pep_html_translator.py | 11 +++++++++++ .../pep_processor/transforms/pep_contents.py | 3 +-- pep_sphinx_extensions/pep_theme/static/style.css | 5 +++++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/pep_sphinx_extensions/pep_processor/html/pep_html_builder.py b/pep_sphinx_extensions/pep_processor/html/pep_html_builder.py index 4ab8b84ae86..6a8447cfe64 100644 --- a/pep_sphinx_extensions/pep_processor/html/pep_html_builder.py +++ b/pep_sphinx_extensions/pep_processor/html/pep_html_builder.py @@ -38,6 +38,7 @@ def get_doc_context(self, docname: str, body: str, _metatags: str) -> dict: toc_tree = self.env.tocs[docname].deepcopy() if len(toc_tree[0]) > 1: toc_tree = toc_tree[0][1] # don't include document title + del toc_tree[0] # remove contents node for node in toc_tree.findall(nodes.reference): node["refuri"] = node["anchorname"] or '#' # fix targets toc = self.render_partial(toc_tree)["fragment"] diff --git a/pep_sphinx_extensions/pep_processor/html/pep_html_translator.py b/pep_sphinx_extensions/pep_processor/html/pep_html_translator.py index d1ad27f2fa9..ae1e1e028a0 100644 --- a/pep_sphinx_extensions/pep_processor/html/pep_html_translator.py +++ b/pep_sphinx_extensions/pep_processor/html/pep_html_translator.py @@ -89,6 +89,17 @@ def depart_label(self, node) -> None: # Close the def tags self.body.append("\n
") + def visit_bullet_list(self, node): + if isinstance(node.parent, nodes.section) and "contents" in node.parent["names"]: + self.body.append("
Contents") + self.context.append("
") + super().visit_bullet_list(node) + + def depart_bullet_list(self, node): + super().depart_bullet_list(node) + if isinstance(node.parent, nodes.section) and "contents" in node.parent["names"]: + self.body.append(self.context.pop()) + def unknown_visit(self, node: nodes.Node) -> None: """No processing for unknown node types.""" pass diff --git a/pep_sphinx_extensions/pep_processor/transforms/pep_contents.py b/pep_sphinx_extensions/pep_processor/transforms/pep_contents.py index db975549f7f..3810429ac78 100644 --- a/pep_sphinx_extensions/pep_processor/transforms/pep_contents.py +++ b/pep_sphinx_extensions/pep_processor/transforms/pep_contents.py @@ -17,8 +17,7 @@ def apply(self) -> None: if not Path(self.document["source"]).match("pep-*"): return # not a PEP file, exit early # Create the contents placeholder section - title = nodes.title("", "", nodes.Text("Contents")) - contents_section = nodes.section("", title) + contents_section = nodes.section("") if not self.document.has_name("contents"): contents_section["names"].append("contents") self.document.note_implicit_target(contents_section) diff --git a/pep_sphinx_extensions/pep_theme/static/style.css b/pep_sphinx_extensions/pep_theme/static/style.css index 4b446d3dded..c3910e26f71 100644 --- a/pep_sphinx_extensions/pep_theme/static/style.css +++ b/pep_sphinx_extensions/pep_theme/static/style.css @@ -118,6 +118,11 @@ pre { padding: .5rem .75rem; } +/* Contents rules */ +details > summary > h2 { + font-weight: bold; +} + /* Definition list rules */ dl dt { font-weight: bold; From 5f5f2a7fb51ec51520f1bde878acff2a24f158e9 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Mon, 14 Mar 2022 01:37:21 +0000 Subject: [PATCH 5/5] Fix rule --- pep_sphinx_extensions/pep_theme/static/style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep_sphinx_extensions/pep_theme/static/style.css b/pep_sphinx_extensions/pep_theme/static/style.css index c3910e26f71..b1d77208ffb 100644 --- a/pep_sphinx_extensions/pep_theme/static/style.css +++ b/pep_sphinx_extensions/pep_theme/static/style.css @@ -119,7 +119,7 @@ pre { } /* Contents rules */ -details > summary > h2 { +details > summary { font-weight: bold; }