Increase minimum Docutils to 0.17

This commit is contained in:
Adam Turner
2022-09-27 18:31:47 +01:00
parent 4660b62de0
commit 080517ce55
16 changed files with 95 additions and 211 deletions
+2 -2
View File
@@ -14,9 +14,9 @@ jobs:
matrix:
include:
- python: "3.8"
docutils: du16
- python: "3.9"
docutils: du17
- python: "3.9"
docutils: du18
- python: "3.10"
docutils: du18
- python: "3.10"
+2 -1
View File
@@ -5,7 +5,8 @@ Dependencies
------------
* #10468: Drop Python 3.6 support
* #10470: Drop Python 3.7 support. Patch by Adam Turner
* #10470: Drop Python 3.7, Docutils 0.14, Docutils 0.15, and Docutils 0.16
support. Patch by Adam Turner
Incompatible changes
--------------------
+1 -1
View File
@@ -63,7 +63,7 @@ dependencies = [
"sphinxcontrib-qthelp",
"Jinja2>=3.0",
"Pygments>=2.12",
"docutils>=0.14,<0.20",
"docutils>=0.17,<0.20",
"snowballstemmer>=2.0",
"babel>=2.9",
"alabaster>=0.7,<0.8",
+3 -14
View File
@@ -12,7 +12,7 @@ if TYPE_CHECKING:
try:
from docutils.nodes import meta as docutils_meta # type: ignore
except ImportError:
# docutils-0.17 or older
# docutils-0.17
from docutils.parsers.rst.directives.html import MetaBody
docutils_meta = MetaBody.meta
@@ -29,18 +29,7 @@ class document(nodes.document):
def set_id(self, node: Element, msgnode: Optional[Element] = None,
suggested_prefix: str = '') -> str:
if docutils.__version_info__ >= (0, 16):
ret = super().set_id(node, msgnode, suggested_prefix) # type: ignore
else:
ret = super().set_id(node, msgnode)
if docutils.__version_info__ < (0, 17):
# register other node IDs forcedly
for node_id in node['ids']:
if node_id not in self.ids:
self.ids[node_id] = node
return ret
return super().set_id(node, msgnode, suggested_prefix) # type: ignore
class translatable(nodes.Node):
@@ -198,7 +187,7 @@ class desc_inline(_desc_classes_injector, nodes.Inline, nodes.TextElement):
classes = ['sig', 'sig-inline']
def __init__(self, domain: str, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
super().__init__(*args, **kwargs, domain=domain)
self['classes'].append(domain)
+20 -21
View File
@@ -19,11 +19,29 @@ from sphinx.util.osutil import SEP, os_path, relpath
from sphinx.util.typing import OptionSpec
try:
from docutils.parsers.rst.directives.misc import Meta as MetaBase # type: ignore
from docutils.parsers.rst.directives.misc import Meta as Meta # type: ignore
except ImportError:
# docutils-0.17 or older
# docutils-0.17
from docutils.parsers.rst.directives.html import Meta as MetaBase
class Meta(MetaBase, SphinxDirective): # type: ignore
def run(self) -> Sequence[Node]: # type: ignore
result = super().run()
for node in result:
# for docutils-0.17. Since docutils-0.18, patching is no longer needed
# because it uses picklable node; ``docutils.nodes.meta``.
if (isinstance(node, nodes.pending) and
isinstance(node.details['nodes'][0], addnodes.docutils_meta)):
meta = node.details['nodes'][0]
meta.source = self.env.doc2path(self.env.docname)
meta.line = self.lineno
meta.rawcontent = meta['content']
# docutils' meta nodes aren't picklable because the class is nested
meta.__class__ = addnodes.meta
return result
if TYPE_CHECKING:
from sphinx.application import Sphinx
@@ -57,25 +75,6 @@ class Figure(images.Figure):
return [figure_node]
class Meta(MetaBase, SphinxDirective):
def run(self) -> Sequence[Node]:
result = super().run()
for node in result:
# for docutils-0.17 or older. Since docutils-0.18, patching is no longer needed
# because it uses picklable node; ``docutils.nodes.meta``.
if (isinstance(node, nodes.pending) and
isinstance(node.details['nodes'][0], addnodes.docutils_meta)):
meta = node.details['nodes'][0]
meta.source = self.env.doc2path(self.env.docname)
meta.line = self.lineno
meta.rawcontent = meta['content']
# docutils' meta nodes aren't picklable because the class is nested
meta.__class__ = addnodes.meta
return result
class CSVTable(tables.CSVTable):
"""The csv-table directive which searches a CSV file from Sphinx project's source
directory when an absolute path is given via :file: option.
+2 -7
View File
@@ -4,7 +4,6 @@ import re
import unicodedata
from typing import TYPE_CHECKING, Any, Dict, Generator, List, Optional, Tuple, cast
import docutils
from docutils import nodes
from docutils.nodes import Element, Node, Text
from docutils.transforms import Transform, Transformer
@@ -342,16 +341,12 @@ class SphinxSmartQuotes(SmartQuotes, SphinxTransform):
# of "Text" nodes (interface to ``smartquotes.educate_tokens()``).
for txtnode in txtnodes:
if is_smartquotable(txtnode):
if docutils.__version_info__ >= (0, 16):
# SmartQuotes uses backslash escapes instead of null-escapes
text = re.sub(r'(?<=\x00)([-\\\'".`])', r'\\\1', str(txtnode))
else:
text = txtnode.astext()
yield ('plain', text)
yield 'plain', text
else:
# skip smart quotes
yield ('literal', txtnode.astext())
yield 'literal', txtnode.astext()
class DoctreeReadEvent(SphinxTransform):
+1 -1
View File
@@ -255,7 +255,7 @@ class Locale(SphinxTransform):
# update meta nodes
if isinstance(node, nodes.pending) and is_pending_meta(node):
# docutils-0.17 or older
# docutils-0.17
node.details['nodes'][0]['content'] = msgstr
continue
elif isinstance(node, addnodes.docutils_meta):
+1 -1
View File
@@ -591,7 +591,7 @@ class SphinxTranslator(nodes.NodeVisitor):
# Node.findall() is a new interface to traverse a doctree since docutils-0.18.
# This applies a patch to docutils up to 0.18 inclusive to provide Node.findall()
# method to use it from our codebase.
if docutils.__version_info__ <= (0, 18):
if docutils.__version_info__[:2] <= (0, 17):
def findall(self, *args, **kwargs):
return iter(self.traverse(*args, **kwargs))
+3 -19
View File
@@ -226,7 +226,7 @@ def is_translatable(node: Node) -> bool:
return True
if is_pending_meta(node) or isinstance(node, addnodes.meta):
# docutils-0.17 or older
# docutils-0.17
return True
elif isinstance(node, addnodes.docutils_meta):
# docutils-0.18+
@@ -268,10 +268,10 @@ def extract_messages(doctree: Element) -> Iterable[Tuple[Element, str]]:
else:
msg = ''
elif isinstance(node, META_TYPE_NODES):
# docutils-0.17 or older
# docutils-0.17
msg = node.rawcontent
elif isinstance(node, nodes.pending) and is_pending_meta(node):
# docutils-0.17 or older
# docutils-0.17
msg = node.details['nodes'][0].rawcontent
elif isinstance(node, addnodes.docutils_meta):
# docutils-0.18+
@@ -625,19 +625,3 @@ def process_only_nodes(document: Node, tags: "Tags") -> None:
# the only node, so we make sure docutils can transfer the id to
# something, even if it's just a comment and will lose the id anyway...
node.replace_self(nodes.comment())
def _new_copy(self: Element) -> Element:
"""monkey-patch Element.copy to copy the rawsource and line
for docutils-0.16 or older versions.
refs: https://sourceforge.net/p/docutils/patches/165/
"""
newnode = self.__class__(self.rawsource, **self.attributes)
if isinstance(self, nodes.Element):
newnode.source = self.source
newnode.line = self.line
return newnode
nodes.Element.copy = _new_copy # type: ignore
-4
View File
@@ -2,7 +2,6 @@
import sys
import docutils
import pytest
@@ -19,9 +18,6 @@ def test_html_translator(app, status, warning):
# no set_translator()
translator_class = app.builder.get_translator_class()
assert translator_class
if docutils.__version_info__ < (0, 13):
assert translator_class.__name__ == 'HTMLTranslator'
else:
assert translator_class.__name__ == 'HTML5Translator'
+2 -10
View File
@@ -15,10 +15,7 @@ from sphinx.testing.util import strip_escseq
from sphinx.util import md5
from sphinx.util.inventory import InventoryFile
if docutils.__version_info__ < (0, 17):
FIGURE_CAPTION = ".//div[@class='figure align-default']/p[@class='caption']"
else:
FIGURE_CAPTION = ".//figure/figcaption/p"
FIGURE_CAPTION = ".//figure/figcaption/p"
ENV_WARNINGS = """\
@@ -442,7 +439,7 @@ def test_docutils17_output(app, cached_etree_parse, fname, expect):
check_xpath(cached_etree_parse(app.outdir / fname), fname, *expect)
@pytest.mark.skipif(docutils.__version_info__ < (0, 18), reason='docutils-0.18+ is required.')
@pytest.mark.skipif(docutils.__version_info__[:2] <= (0, 17), reason='docutils-0.18+ is required.')
@pytest.mark.parametrize("fname,expect", flat_dict({
'index.html': [
(".//div[@class='citation']/span", r'Ref1'),
@@ -1324,11 +1321,6 @@ def test_html_inventory(app):
def test_html_anchor_for_figure(app):
app.builder.build_all()
content = (app.outdir / 'index.html').read_text(encoding='utf8')
if docutils.__version_info__ < (0, 17):
assert ('<p class="caption"><span class="caption-text">The caption of pic</span>'
'<a class="headerlink" href="#id1" title="Permalink to this image">¶</a></p>'
in content)
else:
assert ('<figcaption>\n<p><span class="caption-text">The caption of pic</span>'
'<a class="headerlink" href="#id1" title="Permalink to this image">¶</a></p>\n</figcaption>'
in content)
-30
View File
@@ -2,7 +2,6 @@
import re
import docutils
import pytest
from sphinx.ext.graphviz import ClickableMapDefinition
@@ -14,11 +13,6 @@ def test_graphviz_png_html(app, status, warning):
app.builder.build_all()
content = (app.outdir / 'index.html').read_text(encoding='utf8')
if docutils.__version_info__ < (0, 17):
html = (r'<div class="figure align-default" .*?>\s*'
r'<div class="graphviz"><img .*?/></div>\s*<p class="caption">'
r'<span class="caption-text">caption of graph</span>.*</p>\s*</div>')
else:
html = (r'<figure class="align-default" .*?>\s*'
r'<div class="graphviz"><img .*?/></div>\s*<figcaption>\s*'
r'<p><span class="caption-text">caption of graph</span>.*</p>\s*'
@@ -32,11 +26,6 @@ def test_graphviz_png_html(app, status, warning):
'class="graphviz neato-graph" />')
assert re.search(html, content, re.S)
if docutils.__version_info__ < (0, 17):
html = (r'<div class="figure align-right" .*?>\s*'
r'<div class="graphviz"><img .*?/></div>\s*<p class="caption">'
r'<span class="caption-text">on <em>right</em></span>.*</p>\s*</div>')
else:
html = (r'<figure class="align-right" .*?>\s*'
r'<div class="graphviz"><img .*?/></div>\s*<figcaption>\s*'
r'<p><span class="caption-text">on <em>right</em></span>.*</p>\s*'
@@ -58,15 +47,6 @@ def test_graphviz_svg_html(app, status, warning):
content = (app.outdir / 'index.html').read_text(encoding='utf8')
if docutils.__version_info__ < (0, 17):
html = (r'<div class=\"figure align-default\" .*?>\n'
r'<div class="graphviz"><object data=\".*\.svg\".*>\n'
r'\s*<p class=\"warning\">digraph foo {\n'
r'bar -&gt; baz\n'
r'}</p></object></div>\n'
r'<p class=\"caption\"><span class=\"caption-text\">'
r'caption of graph</span>.*</p>\n</div>')
else:
html = (r'<figure class=\"align-default\" .*?>\n'
r'<div class="graphviz"><object data=\".*\.svg\".*>\n'
r'\s*<p class=\"warning\">digraph foo {\n'
@@ -83,16 +63,6 @@ def test_graphviz_svg_html(app, status, warning):
r' graphviz world')
assert re.search(html, content, re.S)
if docutils.__version_info__ < (0, 17):
html = (r'<div class=\"figure align-right\" .*\>\n'
r'<div class="graphviz"><object data=\".*\.svg\".*>\n'
r'\s*<p class=\"warning\">digraph bar {\n'
r'foo -&gt; bar\n'
r'}</p></object></div>\n'
r'<p class=\"caption\"><span class=\"caption-text\">'
r'on <em>right</em></span>.*</p>\n'
r'</div>')
else:
html = (r'<figure class=\"align-right\" .*\>\n'
r'<div class="graphviz"><object data=\".*\.svg\".*>\n'
r'\s*<p class=\"warning\">digraph bar {\n'
-27
View File
@@ -4,7 +4,6 @@ import os
import re
import sys
import docutils
import pytest
from sphinx.ext.inheritance_diagram import (InheritanceDiagram, InheritanceException,
@@ -140,14 +139,6 @@ def test_inheritance_diagram_png_html(app, status, warning):
content = (app.outdir / 'index.html').read_text(encoding='utf8')
if docutils.__version_info__ < (0, 17):
pattern = ('<div class="figure align-default" id="id1">\n'
'<div class="graphviz">'
'<img src="_images/inheritance-\\w+.png" alt="Inheritance diagram of test.Foo" '
'class="inheritance graphviz" /></div>\n<p class="caption">'
'<span class="caption-text">Test Foo!</span><a class="headerlink" href="#id1" '
'title="Permalink to this image">\xb6</a></p>\n</div>\n')
else:
pattern = ('<figure class="align-default" id="id1">\n'
'<div class="graphviz">'
'<img src="_images/inheritance-\\w+.png" alt="Inheritance diagram of test.Foo" '
@@ -165,16 +156,6 @@ def test_inheritance_diagram_svg_html(app, status, warning):
content = (app.outdir / 'index.html').read_text(encoding='utf8')
if docutils.__version_info__ < (0, 17):
pattern = ('<div class="figure align-default" id="id1">\n'
'<div class="graphviz">'
'<object data="_images/inheritance-\\w+.svg" '
'type="image/svg\\+xml" class="inheritance graphviz">\n'
'<p class=\"warning\">Inheritance diagram of test.Foo</p>'
'</object></div>\n<p class="caption"><span class="caption-text">'
'Test Foo!</span><a class="headerlink" href="#id1" '
'title="Permalink to this image">\xb6</a></p>\n</div>\n')
else:
pattern = ('<figure class="align-default" id="id1">\n'
'<div class="graphviz">'
'<object data="_images/inheritance-\\w+.svg" '
@@ -216,14 +197,6 @@ def test_inheritance_diagram_latex_alias(app, status, warning):
content = (app.outdir / 'index.html').read_text(encoding='utf8')
if docutils.__version_info__ < (0, 17):
pattern = ('<div class="figure align-default" id="id1">\n'
'<div class="graphviz">'
'<img src="_images/inheritance-\\w+.png" alt="Inheritance diagram of test.Foo" '
'class="inheritance graphviz" /></div>\n<p class="caption">'
'<span class="caption-text">Test Foo!</span><a class="headerlink" href="#id1" '
'title="Permalink to this image">\xb6</a></p>\n</div>\n')
else:
pattern = ('<figure class="align-default" id="id1">\n'
'<div class="graphviz">'
'<img src="_images/inheritance-\\w+.png" alt="Inheritance diagram of test.Foo" '
-9
View File
@@ -6,7 +6,6 @@ Runs the text builder in the test root.
import os
import re
import docutils
import pytest
from babel.messages import mofile, pofile
from babel.messages.catalog import Catalog
@@ -1121,10 +1120,6 @@ def test_additional_targets_should_not_be_translated(app):
result = (app.outdir / 'raw.html').read_text(encoding='utf8')
# raw block should not be translated
if docutils.__version_info__ < (0, 17):
expected_expr = """<iframe src="http://sphinx-doc.org"></iframe></div>"""
assert_count(expected_expr, result, 1)
else:
expected_expr = """<iframe src="http://sphinx-doc.org"></iframe></section>"""
assert_count(expected_expr, result, 1)
@@ -1203,10 +1198,6 @@ def test_additional_targets_should_be_translated(app):
result = (app.outdir / 'raw.html').read_text(encoding='utf8')
# raw block should be translated
if docutils.__version_info__ < (0, 17):
expected_expr = """<iframe src="HTTP://SPHINX-DOC.ORG"></iframe></div>"""
assert_count(expected_expr, result, 1)
else:
expected_expr = """<iframe src="HTTP://SPHINX-DOC.ORG"></iframe></section>"""
assert_count(expected_expr, result, 1)
-3
View File
@@ -3,7 +3,6 @@
import re
import warnings
import docutils
import pytest
from docutils import frontend, nodes, utils
from docutils.parsers.rst import Parser as RstParser
@@ -395,8 +394,6 @@ def test_inline(get_verifier, type, rst, html_expected, latex_expected):
None,
),
])
@pytest.mark.skipif(docutils.__version_info__ < (0, 16),
reason='docutils-0.16 or above is required')
def test_inline_docutils16(get_verifier, type, rst, html_expected, latex_expected):
verifier = get_verifier(type)
verifier(rst, html_expected, latex_expected)
+2 -5
View File
@@ -1,6 +1,6 @@
[tox]
minversion = 2.4.0
envlist = docs,flake8,mypy,twine,py{38,39,310,311},du{14,15,16,17,18,19}
envlist = docs,flake8,mypy,twine,py{38,39,310,311},du{17,18,19}
isolated_build = True
[testenv]
@@ -17,11 +17,8 @@ passenv =
TERM
description =
py{38,39,310,311}: Run unit tests against {envname}.
du{14,15,16,17,18,19}: Run unit tests with the given version of docutils.
du{17,18,19}: Run unit tests with the given version of docutils.
deps =
du14: docutils==0.14.*
du15: docutils==0.15.*
du16: docutils==0.16.*
du17: docutils==0.17.*
du18: docutils==0.18.*
du19: docutils==0.19.*