From 3e0618ba3a84c7db51813cab43779d11c5fe7802 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 7 Mar 2020 10:29:06 +0900 Subject: [PATCH] Deprecate codes for docutils-0.13 or 0.14 --- CHANGES | 5 +++++ doc/extdev/deprecated.rst | 20 ++++++++++++++++++ doc/usage/configuration.rst | 12 +++++------ sphinx/deprecation.py | 4 ++++ sphinx/directives/patches.py | 20 +++++++++++++++--- sphinx/util/nodes.py | 8 +++++--- sphinx/util/smartypants.py | 6 ++++++ sphinx/writers/html5.py | 33 +++++++++++++++--------------- tests/test_build_epub.py | 4 ---- tests/test_build_html.py | 25 ---------------------- tests/test_build_latex.py | 7 ------- tests/test_domain_cpp.py | 5 ----- tests/test_domain_std.py | 3 --- tests/test_ext_autosectionlabel.py | 8 -------- tests/test_ext_todo.py | 4 ---- tests/test_smartquotes.py | 4 ---- 16 files changed, 79 insertions(+), 89 deletions(-) diff --git a/CHANGES b/CHANGES index 7a26203ba..615bb934d 100644 --- a/CHANGES +++ b/CHANGES @@ -13,6 +13,11 @@ Incompatible changes Deprecated ---------- +* ``sphinx.directives.patches.CSVTable`` +* ``sphinx.directives.patches.ListTable`` +* ``sphinx.directives.patches.RSTTable`` +* ``sphinx.util.smartypants`` + Features added -------------- diff --git a/doc/extdev/deprecated.rst b/doc/extdev/deprecated.rst index e98652ed2..c4cd82b1f 100644 --- a/doc/extdev/deprecated.rst +++ b/doc/extdev/deprecated.rst @@ -26,6 +26,26 @@ The following is a list of deprecated interfaces. - (will be) Removed - Alternatives + * - ``sphinx.directives.patches.CSVTable`` + - 4.0 + - 6.0 + - ``docutils.parsers.rst.diretives.tables.CSVTable`` + + * - ``sphinx.directives.patches.ListTable`` + - 4.0 + - 6.0 + - ``docutils.parsers.rst.diretives.tables.ListSVTable`` + + * - ``sphinx.directives.patches.RSTTable`` + - 4.0 + - 6.0 + - ``docutils.parsers.rst.diretives.tables.RSTTable`` + + * - ``sphinx.util.smartypants`` + - 4.0 + - 6.0 + - ``docutils.utils.smartyquotes`` + * - ``desc_signature['first']`` - - 3.0 diff --git a/doc/usage/configuration.rst b/doc/usage/configuration.rst index e5ab9c7c0..e5e4966ab 100644 --- a/doc/usage/configuration.rst +++ b/doc/usage/configuration.rst @@ -467,11 +467,10 @@ General configuration .. confval:: smartquotes_action - This string, for use with Docutils ``0.14`` or later, customizes the Smart - Quotes transform. See the file :file:`smartquotes.py` at the `Docutils - repository`__ for details. The default ``'qDe'`` educates normal **q**\ - uote characters ``"``, ``'``, em- and en-**D**\ ashes ``---``, ``--``, and - **e**\ llipses ``...``. + This string customizes the Smart Quotes transform. See the file + :file:`smartquotes.py` at the `Docutils repository`__ for details. The + default ``'qDe'`` educates normal **q**\ uote characters ``"``, ``'``, + em- and en-**D**\ ashes ``---``, ``--``, and **e**\ llipses ``...``. .. versionadded:: 1.6.6 @@ -1381,8 +1380,7 @@ that use Sphinx's HTMLWriter class. .. confval:: html_experimental_html5_writer - Output is processed with HTML5 writer. This feature needs docutils 0.13 or - newer. Default is ``False``. + Output is processed with HTML5 writer. Default is ``False``. .. versionadded:: 1.6 diff --git a/sphinx/deprecation.py b/sphinx/deprecation.py index 5e5e673d2..e9510bde4 100644 --- a/sphinx/deprecation.py +++ b/sphinx/deprecation.py @@ -23,6 +23,10 @@ class RemovedInSphinx50Warning(PendingDeprecationWarning): pass +class RemovedInSphinx60Warning(PendingDeprecationWarning): + pass + + RemovedInNextVersionWarning = RemovedInSphinx40Warning diff --git a/sphinx/directives/patches.py b/sphinx/directives/patches.py index 4b73a7955..8a27c0170 100644 --- a/sphinx/directives/patches.py +++ b/sphinx/directives/patches.py @@ -6,6 +6,7 @@ :license: BSD, see LICENSE for details. """ +import warnings from typing import Any, Dict, List, Tuple from typing import cast @@ -15,6 +16,7 @@ from docutils.parsers.rst import directives from docutils.parsers.rst.directives import images, html, tables from sphinx import addnodes +from sphinx.deprecation import RemovedInSphinx60Warning from sphinx.directives import optional_int from sphinx.domains.math import MathDomain from sphinx.util.docutils import SphinxDirective @@ -73,6 +75,11 @@ class RSTTable(tables.RSTTable): Only for docutils-0.13 or older version.""" + def run(self) -> List[Node]: + warnings.warn('RSTTable is deprecated.', + RemovedInSphinx60Warning) + return super().run() + def make_title(self) -> Tuple[nodes.title, List[system_message]]: title, message = super().make_title() if title: @@ -86,6 +93,11 @@ class CSVTable(tables.CSVTable): Only for docutils-0.13 or older version.""" + def run(self) -> List[Node]: + warnings.warn('RSTTable is deprecated.', + RemovedInSphinx60Warning) + return super().run() + def make_title(self) -> Tuple[nodes.title, List[system_message]]: title, message = super().make_title() if title: @@ -99,6 +111,11 @@ class ListTable(tables.ListTable): Only for docutils-0.13 or older version.""" + def run(self) -> List[Node]: + warnings.warn('RSTTable is deprecated.', + RemovedInSphinx60Warning) + return super().run() + def make_title(self) -> Tuple[nodes.title, List[system_message]]: title, message = super().make_title() if title: @@ -209,9 +226,6 @@ class MathDirective(SphinxDirective): def setup(app: "Sphinx") -> Dict[str, Any]: directives.register_directive('figure', Figure) directives.register_directive('meta', Meta) - directives.register_directive('table', RSTTable) - directives.register_directive('csv-table', CSVTable) - directives.register_directive('list-table', ListTable) directives.register_directive('code', Code) directives.register_directive('math', MathDirective) diff --git a/sphinx/util/nodes.py b/sphinx/util/nodes.py index 474a704a1..fa51bec6a 100644 --- a/sphinx/util/nodes.py +++ b/sphinx/util/nodes.py @@ -537,10 +537,12 @@ def process_only_nodes(document: Node, tags: "Tags") -> None: node.replace_self(nodes.comment()) -# monkey-patch Element.copy to copy the rawsource and line -# for docutils-0.14 or older versions. - 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 diff --git a/sphinx/util/smartypants.py b/sphinx/util/smartypants.py index 43f8bc724..2b7503379 100644 --- a/sphinx/util/smartypants.py +++ b/sphinx/util/smartypants.py @@ -26,13 +26,19 @@ """ import re +import warnings from typing import Generator, Iterable, Tuple from docutils.utils import smartquotes +from sphinx.deprecation import RemovedInSphinx60Warning from sphinx.util.docutils import __version_info__ as docutils_version +warnings.warn('sphinx.util.smartypants is deprecated.', + RemovedInSphinx60Warning) + + langquotes = {'af': '“”‘’', 'af-x-altquot': '„”‚’', 'bg': '„“‚‘', # Bulgarian, https://bg.wikipedia.org/wiki/Кавички diff --git a/sphinx/writers/html5.py b/sphinx/writers/html5.py index 0c00a1fa4..5da11840d 100644 --- a/sphinx/writers/html5.py +++ b/sphinx/writers/html5.py @@ -20,7 +20,7 @@ from docutils.writers.html5_polyglot import HTMLTranslator as BaseTranslator from sphinx import addnodes from sphinx.builders import Builder -from sphinx.deprecation import RemovedInSphinx40Warning +from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx60Warning from sphinx.locale import admonitionlabels, _, __ from sphinx.util import logging from sphinx.util.docutils import SphinxTranslator @@ -703,22 +703,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): # overwritten to add even/odd classes - def generate_targets_for_table(self, node: Element) -> None: - """Generate hyperlink targets for tables. - - Original visit_table() generates hyperlink targets inside table tags - () if multiple IDs are assigned to listings. - That is invalid DOM structure. (This is a bug of docutils <= 0.13.1) - - This exports hyperlink targets before tables to make valid DOM structure. - """ - for id in node['ids'][1:]: - self.body.append('' % id) - node['ids'].remove(id) - def visit_table(self, node: Element) -> None: - self.generate_targets_for_table(node) - self._table_row_index = 0 classes = [cls.strip(' \t\n') for cls in self.settings.table_style.split(',')] @@ -772,3 +757,19 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): def unknown_visit(self, node: Node) -> None: raise NotImplementedError('Unknown node: ' + node.__class__.__name__) + + def generate_targets_for_table(self, node: Element) -> None: + """Generate hyperlink targets for tables. + + Original visit_table() generates hyperlink targets inside table tags + (
) if multiple IDs are assigned to listings. + That is invalid DOM structure. (This is a bug of docutils <= 0.13.1) + + This exports hyperlink targets before tables to make valid DOM structure. + """ + warnings.warn('generate_targets_for_table() is deprecated', + RemovedInSphinx60Warning, stacklevel=2) + for id in node['ids'][1:]: + self.body.append('' % id) + node['ids'].remove(id) + diff --git a/tests/test_build_epub.py b/tests/test_build_epub.py index a61c3cbbb..cb60e79ad 100644 --- a/tests/test_build_epub.py +++ b/tests/test_build_epub.py @@ -15,8 +15,6 @@ from xml.etree import ElementTree import pytest -from sphinx.util import docutils - # check given command is runnable def runnable(command): @@ -357,8 +355,6 @@ def test_epub_css_files(app): 'href="https://example.com/custom.css" />' not in content) -@pytest.mark.skipif(docutils.__version_info__ < (0, 13), - reason='docutils-0.13 or above is required') @pytest.mark.sphinx('epub', testroot='roles-download') def test_html_download_role(app, status, warning): app.build() diff --git a/tests/test_build_html.py b/tests/test_build_html.py index 39cb3bf71..b32827392 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -19,7 +19,6 @@ from html5lib import HTMLParser from sphinx.builders.html import validate_html_extra_path, validate_html_static_path from sphinx.errors import ConfigError from sphinx.testing.util import strip_escseq -from sphinx.util import docutils from sphinx.util.inventory import InventoryFile @@ -407,8 +406,6 @@ def test_html4_output(app, status, warning): (".//a[@href='_sources/otherext.foo.txt']", ''), ] })) -@pytest.mark.skipif(docutils.__version_info__ < (0, 13), - reason='docutils-0.13 or above is required') @pytest.mark.sphinx('html', tags=['testtag'], confoverrides={'html_context.hckey_co': 'hcval_co'}) @pytest.mark.test_params(shared_result='test_build_html_output') @@ -418,8 +415,6 @@ def test_html5_output(app, cached_etree_parse, fname, expect): check_xpath(cached_etree_parse(app.outdir / fname), fname, *expect) -@pytest.mark.skipif(docutils.__version_info__ < (0, 13), - reason='docutils-0.13 or above is required') @pytest.mark.sphinx('html') @pytest.mark.test_params(shared_result='test_build_html_output') def test_html_download(app): @@ -444,8 +439,6 @@ def test_html_download(app): assert matched.group(1) == filename -@pytest.mark.skipif(docutils.__version_info__ < (0, 13), - reason='docutils-0.13 or above is required') @pytest.mark.sphinx('html', testroot='roles-download') def test_html_download_role(app, status, warning): app.build() @@ -524,8 +517,6 @@ def test_html_translator(app): (".//h1//span[@class='section-number']", '2.1.1. ', True), ], })) -@pytest.mark.skipif(docutils.__version_info__ < (0, 13), - reason='docutils-0.13 or above is required') @pytest.mark.sphinx('html', testroot='tocdepth') @pytest.mark.test_params(shared_result='test_build_html_tocdepth') def test_tocdepth(app, cached_etree_parse, fname, expect): @@ -571,8 +562,6 @@ def test_tocdepth(app, cached_etree_parse, fname, expect): (".//h4//span[@class='section-number']", '2.1.1. ', True), ], })) -@pytest.mark.skipif(docutils.__version_info__ < (0, 13), - reason='docutils-0.13 or above is required') @pytest.mark.sphinx('singlehtml', testroot='tocdepth') @pytest.mark.test_params(shared_result='test_build_html_tocdepth') def test_tocdepth_singlehtml(app, cached_etree_parse, fname, expect): @@ -630,8 +619,6 @@ def test_numfig_disabled_warn(app, warning): "span[@class='caption-number']", None, True), ], })) -@pytest.mark.skipif(docutils.__version_info__ < (0, 13), - reason='docutils-0.13 or above is required') @pytest.mark.sphinx('html', testroot='numfig') @pytest.mark.test_params(shared_result='test_build_html_numfig') def test_numfig_disabled(app, cached_etree_parse, fname, expect): @@ -738,8 +725,6 @@ def test_numfig_without_numbered_toctree_warn(app, warning): "span[@class='caption-number']", '^Listing 6 $', True), ], })) -@pytest.mark.skipif(docutils.__version_info__ < (0, 13), - reason='docutils-0.13 or above is required') @pytest.mark.sphinx( 'html', testroot='numfig', srcdir='test_numfig_without_numbered_toctree', @@ -846,8 +831,6 @@ def test_numfig_with_numbered_toctree_warn(app, warning): "span[@class='caption-number']", '^Listing 2.2 $', True), ], })) -@pytest.mark.skipif(docutils.__version_info__ < (0, 13), - reason='docutils-0.13 or above is required') @pytest.mark.sphinx('html', testroot='numfig', confoverrides={'numfig': True}) @pytest.mark.test_params(shared_result='test_build_html_numfig_on') def test_numfig_with_numbered_toctree(app, cached_etree_parse, fname, expect): @@ -951,8 +934,6 @@ def test_numfig_with_prefix_warn(app, warning): "span[@class='caption-number']", '^Code-2.2 $', True), ], })) -@pytest.mark.skipif(docutils.__version_info__ < (0, 13), - reason='docutils-0.13 or above is required') @pytest.mark.sphinx('html', testroot='numfig', confoverrides={'numfig': True, 'numfig_format': {'figure': 'Figure:%s', @@ -1057,8 +1038,6 @@ def test_numfig_with_secnum_depth_warn(app, warning): "span[@class='caption-number']", '^Listing 2.1.2 $', True), ], })) -@pytest.mark.skipif(docutils.__version_info__ < (0, 13), - reason='docutils-0.13 or above is required') @pytest.mark.sphinx('html', testroot='numfig', confoverrides={'numfig': True, 'numfig_secnum_depth': 2}) @@ -1142,8 +1121,6 @@ def test_numfig_with_secnum_depth(app, cached_etree_parse, fname, expect): "span[@class='caption-number']", '^Listing 2.2 $', True), ], })) -@pytest.mark.skipif(docutils.__version_info__ < (0, 13), - reason='docutils-0.13 or above is required') @pytest.mark.sphinx('singlehtml', testroot='numfig', confoverrides={'numfig': True}) @pytest.mark.test_params(shared_result='test_build_html_numfig_on') def test_numfig_with_singlehtml(app, cached_etree_parse, fname, expect): @@ -1168,8 +1145,6 @@ def test_numfig_with_singlehtml(app, cached_etree_parse, fname, expect): (".//li/p/a/span", 'No.2', True), ], })) -@pytest.mark.skipif(docutils.__version_info__ < (0, 13), - reason='docutils-0.13 or above is required') @pytest.mark.sphinx('html', testroot='add_enumerable_node', srcdir='test_enumerable_node') def test_enumerable_node(app, cached_etree_parse, fname, expect): diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py index 61020b861..161e522f6 100644 --- a/tests/test_build_latex.py +++ b/tests/test_build_latex.py @@ -22,7 +22,6 @@ from sphinx.builders.latex import default_latex_documents from sphinx.config import Config from sphinx.errors import SphinxError, ThemeError from sphinx.testing.util import strip_escseq -from sphinx.util import docutils from sphinx.util.osutil import cd, ensuredir from sphinx.writers.latex import LaTeXTranslator @@ -1102,8 +1101,6 @@ def test_maxlistdepth_at_ten(app, status, warning): compile_latex_document(app, 'python.tex') -@pytest.mark.skipif(docutils.__version_info__ < (0, 13), - reason='docutils-0.13 or above is required') @pytest.mark.sphinx('latex', testroot='latex-table') @pytest.mark.test_params(shared_result='latex-table') def test_latex_table_tabulars(app, status, warning): @@ -1173,8 +1170,6 @@ def test_latex_table_tabulars(app, status, warning): assert actual == expected -@pytest.mark.skipif(docutils.__version_info__ < (0, 13), - reason='docutils-0.13 or above is required') @pytest.mark.sphinx('latex', testroot='latex-table') @pytest.mark.test_params(shared_result='latex-table') def test_latex_table_longtable(app, status, warning): @@ -1234,8 +1229,6 @@ def test_latex_table_longtable(app, status, warning): assert actual == expected -@pytest.mark.skipif(docutils.__version_info__ < (0, 13), - reason='docutils-0.13 or above is required') @pytest.mark.sphinx('latex', testroot='latex-table') @pytest.mark.test_params(shared_result='latex-table') def test_latex_table_complex_tables(app, status, warning): diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index fba5fdb42..7ed230827 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -16,7 +16,6 @@ import sphinx.domains.cpp as cppDomain from sphinx import addnodes from sphinx.domains.cpp import DefinitionParser, DefinitionError, NoOldIdError from sphinx.domains.cpp import Symbol, _max_id, _id_prefix -from sphinx.util import docutils def parse(name, string): @@ -860,8 +859,6 @@ def test_build_domain_cpp_misuse_of_roles(app, status, warning): assert len(ws) == len(warn) -@pytest.mark.skipif(docutils.__version_info__ < (0, 13), - reason='docutils-0.13 or above is required') @pytest.mark.sphinx(testroot='domain-cpp', confoverrides={'add_function_parentheses': True}) def test_build_domain_cpp_with_add_function_parentheses_is_True(app, status, warning): app.builder.build_all() @@ -903,8 +900,6 @@ def test_build_domain_cpp_with_add_function_parentheses_is_True(app, status, war check(s, t, f) -@pytest.mark.skipif(docutils.__version_info__ < (0, 13), - reason='docutils-0.13 or above is required') @pytest.mark.sphinx(testroot='domain-cpp', confoverrides={'add_function_parentheses': False}) def test_build_domain_cpp_with_add_function_parentheses_is_False(app, status, warning): app.builder.build_all() diff --git a/tests/test_domain_std.py b/tests/test_domain_std.py index 1f0024efc..a887a596f 100644 --- a/tests/test_domain_std.py +++ b/tests/test_domain_std.py @@ -24,7 +24,6 @@ from sphinx.addnodes import ( from sphinx.domains.std import StandardDomain from sphinx.testing import restructuredtext from sphinx.testing.util import assert_node -from sphinx.util import docutils def test_process_doc_handle_figure_caption(): @@ -319,8 +318,6 @@ def test_multiple_cmdoptions(app): assert domain.progoptions[('cmd', '--output')] == ('index', 'cmdoption-cmd-o') -@pytest.mark.skipif(docutils.__version_info__ < (0, 13), - reason='docutils-0.13 or above is required') @pytest.mark.sphinx(testroot='productionlist') def test_productionlist(app, status, warning): app.builder.build_all() diff --git a/tests/test_ext_autosectionlabel.py b/tests/test_ext_autosectionlabel.py index 310435d8e..c8635ce2d 100644 --- a/tests/test_ext_autosectionlabel.py +++ b/tests/test_ext_autosectionlabel.py @@ -12,11 +12,7 @@ import re import pytest -from sphinx.util import docutils - -@pytest.mark.skipif(docutils.__version_info__ < (0, 13), - reason='docutils-0.13 or above is required') @pytest.mark.sphinx('html', testroot='ext-autosectionlabel') def test_autosectionlabel_html(app, status, warning, skipped_labels=False): app.builder.build_all() @@ -55,15 +51,11 @@ def test_autosectionlabel_html(app, status, warning, skipped_labels=False): # Re-use test definition from above, just change the test root directory -@pytest.mark.skipif(docutils.__version_info__ < (0, 13), - reason='docutils-0.13 or above is required') @pytest.mark.sphinx('html', testroot='ext-autosectionlabel-prefix-document') def test_autosectionlabel_prefix_document_html(app, status, warning): test_autosectionlabel_html(app, status, warning) -@pytest.mark.skipif(docutils.__version_info__ < (0, 13), - reason='docutils-0.13 or above is required') @pytest.mark.sphinx('html', testroot='ext-autosectionlabel', confoverrides={'autosectionlabel_maxdepth': 3}) def test_autosectionlabel_maxdepth(app, status, warning): diff --git a/tests/test_ext_todo.py b/tests/test_ext_todo.py index 7b4fdeabe..633b151ac 100644 --- a/tests/test_ext_todo.py +++ b/tests/test_ext_todo.py @@ -12,11 +12,7 @@ import re import pytest -from sphinx.util import docutils - -@pytest.mark.skipif(docutils.__version_info__ < (0, 13), - reason='docutils-0.13 or above is required') @pytest.mark.sphinx('html', testroot='ext-todo', freshenv=True, confoverrides={'todo_include_todos': True, 'todo_emit_warnings': True}) def test_todo(app, status, warning): diff --git a/tests/test_smartquotes.py b/tests/test_smartquotes.py index 6276e6a74..697a7592c 100644 --- a/tests/test_smartquotes.py +++ b/tests/test_smartquotes.py @@ -10,8 +10,6 @@ import pytest -from sphinx.util import docutils - @pytest.mark.sphinx(buildername='html', testroot='smartquotes', freshenv=True) def test_basic(app, status, warning): @@ -63,8 +61,6 @@ def test_smartquotes_disabled(app, status, warning): assert '

-- "Sphinx" is a tool that makes it easy ...

' in content -@pytest.mark.skipif(docutils.__version_info__ < (0, 14), - reason='docutils-0.14 or above is required') @pytest.mark.sphinx(buildername='html', testroot='smartquotes', freshenv=True, confoverrides={'smartquotes_action': 'q'}) def test_smartquotes_action(app, status, warning):