From e023d1082d574d422ce50a8a99c8c012d6a21f92 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 1 Jan 2022 20:03:17 +0900 Subject: [PATCH 1/9] A happy new year! (again) --- sphinx/locale/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/locale/__init__.py b/sphinx/locale/__init__.py index 8fc6c15197e..5378da0a351 100644 --- a/sphinx/locale/__init__.py +++ b/sphinx/locale/__init__.py @@ -4,7 +4,7 @@ Locale utilities. - :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ From a0e44a7300b12c6946ba13cdf6ffc917298cbf60 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 3 Jan 2022 01:05:46 +0900 Subject: [PATCH 2/9] test: Migrate to Node.findall() from Node.traverse() --- tests/test_domain_py.py | 6 +++--- tests/test_domain_std.py | 4 ++-- tests/test_markup.py | 2 +- tests/test_util_nodes.py | 14 +++++++------- tests/test_versioning.py | 18 +++++++++--------- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/tests/test_domain_py.py b/tests/test_domain_py.py index ec4a0b8a799..de544d25dc8 100644 --- a/tests/test_domain_py.py +++ b/tests/test_domain_py.py @@ -79,7 +79,7 @@ def assert_refnode(node, module_name, class_name, target, reftype=None, assert_node(node, **attributes) doctree = app.env.get_doctree('roles') - refnodes = list(doctree.traverse(pending_xref)) + refnodes = list(doctree.findall(pending_xref)) assert_refnode(refnodes[0], None, None, 'TopLevel', 'class') assert_refnode(refnodes[1], None, None, 'top_level', 'meth') assert_refnode(refnodes[2], None, 'NestedParentA', 'child_1', 'meth') @@ -97,7 +97,7 @@ def assert_refnode(node, module_name, class_name, target, reftype=None, assert len(refnodes) == 13 doctree = app.env.get_doctree('module') - refnodes = list(doctree.traverse(pending_xref)) + refnodes = list(doctree.findall(pending_xref)) assert_refnode(refnodes[0], 'module_a.submodule', None, 'ModTopLevel', 'class') assert_refnode(refnodes[1], 'module_a.submodule', 'ModTopLevel', @@ -126,7 +126,7 @@ def assert_refnode(node, module_name, class_name, target, reftype=None, assert len(refnodes) == 16 doctree = app.env.get_doctree('module_option') - refnodes = list(doctree.traverse(pending_xref)) + refnodes = list(doctree.findall(pending_xref)) print(refnodes) print(refnodes[0]) print(refnodes[1]) diff --git a/tests/test_domain_std.py b/tests/test_domain_std.py index 14c2bd3e288..1428bce3177 100644 --- a/tests/test_domain_std.py +++ b/tests/test_domain_std.py @@ -36,7 +36,7 @@ def test_process_doc_handle_figure_caption(): ids={'testid': figure_node}, citation_refs={}, ) - document.traverse.return_value = [] + document.findall.return_value = [] domain = StandardDomain(env) if 'testname' in domain.data['labels']: @@ -60,7 +60,7 @@ def test_process_doc_handle_table_title(): ids={'testid': table_node}, citation_refs={}, ) - document.traverse.return_value = [] + document.findall.return_value = [] domain = StandardDomain(env) if 'testname' in domain.data['labels']: diff --git a/tests/test_markup.py b/tests/test_markup.py index fbd4e20cc72..e1e01491a3a 100644 --- a/tests/test_markup.py +++ b/tests/test_markup.py @@ -67,7 +67,7 @@ def parse_(rst): parser = RstParser() parser.parse(rst, document) SphinxSmartQuotes(document, startnode=None).apply() - for msg in document.traverse(nodes.system_message): + for msg in list(document.findall(nodes.system_message)): if msg['level'] == 1: msg.replace_self([]) return document diff --git a/tests/test_util_nodes.py b/tests/test_util_nodes.py index 1e08244cc05..fe0a278e695 100644 --- a/tests/test_util_nodes.py +++ b/tests/test_util_nodes.py @@ -60,31 +60,31 @@ def test_NodeMatcher(): # search by node class matcher = NodeMatcher(nodes.paragraph) - assert len(list(doctree.traverse(matcher))) == 3 + assert len(list(doctree.findall(matcher))) == 3 # search by multiple node classes matcher = NodeMatcher(nodes.paragraph, nodes.literal_block) - assert len(list(doctree.traverse(matcher))) == 4 + assert len(list(doctree.findall(matcher))) == 4 # search by node attribute matcher = NodeMatcher(block=1) - assert len(list(doctree.traverse(matcher))) == 1 + assert len(list(doctree.findall(matcher))) == 1 # search by node attribute (Any) matcher = NodeMatcher(block=Any) - assert len(list(doctree.traverse(matcher))) == 3 + assert len(list(doctree.findall(matcher))) == 3 # search by both class and attribute matcher = NodeMatcher(nodes.paragraph, block=Any) - assert len(list(doctree.traverse(matcher))) == 2 + assert len(list(doctree.findall(matcher))) == 2 # mismatched matcher = NodeMatcher(nodes.title) - assert len(list(doctree.traverse(matcher))) == 0 + assert len(list(doctree.findall(matcher))) == 0 # search with Any does not match to Text node matcher = NodeMatcher(blah=Any) - assert len(list(doctree.traverse(matcher))) == 0 + assert len(list(doctree.findall(matcher))) == 0 @pytest.mark.parametrize( diff --git a/tests/test_versioning.py b/tests/test_versioning.py index 9961fe46406..4de8331aae7 100644 --- a/tests/test_versioning.py +++ b/tests/test_versioning.py @@ -70,16 +70,16 @@ def test_picklablility(): copy.settings.warning_stream = None copy.settings.env = None copy.settings.record_dependencies = None - for metanode in copy.traverse(meta): + for metanode in copy.findall(meta): metanode.__class__ = addnodes.meta loaded = pickle.loads(pickle.dumps(copy, pickle.HIGHEST_PROTOCOL)) - assert all(getattr(n, 'uid', False) for n in loaded.traverse(is_paragraph)) + assert all(getattr(n, 'uid', False) for n in loaded.findall(is_paragraph)) def test_modified(): modified = doctrees['modified'] new_nodes = list(merge_doctrees(original, modified, is_paragraph)) - uids = [n.uid for n in modified.traverse(is_paragraph)] + uids = [n.uid for n in modified.findall(is_paragraph)] assert not new_nodes assert original_uids == uids @@ -87,7 +87,7 @@ def test_modified(): def test_added(): added = doctrees['added'] new_nodes = list(merge_doctrees(original, added, is_paragraph)) - uids = [n.uid for n in added.traverse(is_paragraph)] + uids = [n.uid for n in added.findall(is_paragraph)] assert len(new_nodes) == 1 assert original_uids == uids[:-1] @@ -95,7 +95,7 @@ def test_added(): def test_deleted(): deleted = doctrees['deleted'] new_nodes = list(merge_doctrees(original, deleted, is_paragraph)) - uids = [n.uid for n in deleted.traverse(is_paragraph)] + uids = [n.uid for n in deleted.findall(is_paragraph)] assert not new_nodes assert original_uids[::2] == uids @@ -103,7 +103,7 @@ def test_deleted(): def test_deleted_end(): deleted_end = doctrees['deleted_end'] new_nodes = list(merge_doctrees(original, deleted_end, is_paragraph)) - uids = [n.uid for n in deleted_end.traverse(is_paragraph)] + uids = [n.uid for n in deleted_end.findall(is_paragraph)] assert not new_nodes assert original_uids[:-1] == uids @@ -111,7 +111,7 @@ def test_deleted_end(): def test_insert(): insert = doctrees['insert'] new_nodes = list(merge_doctrees(original, insert, is_paragraph)) - uids = [n.uid for n in insert.traverse(is_paragraph)] + uids = [n.uid for n in insert.findall(is_paragraph)] assert len(new_nodes) == 1 assert original_uids[0] == uids[0] assert original_uids[1:] == uids[2:] @@ -120,7 +120,7 @@ def test_insert(): def test_insert_beginning(): insert_beginning = doctrees['insert_beginning'] new_nodes = list(merge_doctrees(original, insert_beginning, is_paragraph)) - uids = [n.uid for n in insert_beginning.traverse(is_paragraph)] + uids = [n.uid for n in insert_beginning.findall(is_paragraph)] assert len(new_nodes) == 1 assert len(uids) == 4 assert original_uids == uids[1:] @@ -130,7 +130,7 @@ def test_insert_beginning(): def test_insert_similar(): insert_similar = doctrees['insert_similar'] new_nodes = list(merge_doctrees(original, insert_similar, is_paragraph)) - uids = [n.uid for n in insert_similar.traverse(is_paragraph)] + uids = [n.uid for n in insert_similar.findall(is_paragraph)] assert len(new_nodes) == 1 assert new_nodes[0].rawsource == 'Anyway I need more' assert original_uids[0] == uids[0] From d1a070efd85d590e9aad7a43be1284385dc53901 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 3 Jan 2022 02:01:44 +0900 Subject: [PATCH 3/9] test: manpage: double quotes are escaped since docutils-0.18 Double quotes are escaped to `\(dq` on manpage output since docutils-0.18. --- tests/test_smartquotes.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/test_smartquotes.py b/tests/test_smartquotes.py index a46e667ca4a..bd821616782 100644 --- a/tests/test_smartquotes.py +++ b/tests/test_smartquotes.py @@ -11,6 +11,8 @@ import pytest from html5lib import HTMLParser +from sphinx.util import docutils + @pytest.mark.sphinx(buildername='html', testroot='smartquotes', freshenv=True) def test_basic(app, status, warning): @@ -51,7 +53,10 @@ def test_man_builder(app, status, warning): app.build() content = (app.outdir / 'python.1').read_text() - assert '\\-\\- "Sphinx" is a tool that makes it easy ...' in content + if docutils.__version_info__ > (0, 18): + assert r'\-\- \(dqSphinx\(dq is a tool that makes it easy ...' in content + else: + assert r'\-\- "Sphinx" is a tool that makes it easy ...' in content @pytest.mark.sphinx(buildername='latex', testroot='smartquotes', freshenv=True) From ab5b8dc9ee3137f087c98be381f9e7b69dc6f858 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 8 Jan 2022 22:57:31 +0900 Subject: [PATCH 4/9] CI: refactor tox.ini; Install HEAD of docutils directly --- tox.ini | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tox.ini b/tox.ini index 824ab3f387b..f0afd779b6a 100644 --- a/tox.ini +++ b/tox.ini @@ -32,9 +32,7 @@ commands= [testenv:du-latest] commands = - git clone https://repo.or.cz/docutils.git {temp_dir}/docutils - python -m pip install {temp_dir}/docutils/docutils - rm -rf {temp_dir}/docutils + python -m pip install "git+https://repo.or.cz/docutils.git#subdirectory=docutils" {[testenv]commands} [testenv:flake8] From eab7efc33331d3ca5ced5f3d0caee7a99a01381e Mon Sep 17 00:00:00 2001 From: Martin Fischer Date: Sat, 8 Jan 2022 07:12:33 +0100 Subject: [PATCH 5/9] doc: Linkify issue numbers in changelog to GitHub --- doc/conf.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/doc/conf.py b/doc/conf.py index 3b39aa6d54b..ccc2788f0d4 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -1,5 +1,6 @@ # Sphinx documentation build configuration file +import os import re import sphinx @@ -139,10 +140,33 @@ def parse_event(env, sig, signode): return name +def linkify_issues_in_changelog(app, docname, source): + """ Linkify issue references like #123 in changelog to GitHub. """ + + if docname == 'changes': + changelog_path = os.path.join(os.path.dirname(__file__), "../CHANGES") + # this path trickery is needed because this script can + # be invoked with different working directories: + # * running make in docs/ + # * running python setup.py build_sphinx in the repo root dir + + with open(changelog_path) as f: + changelog = f.read() + + def linkify(match): + url = 'https://github.com/sphinx-doc/sphinx/issues/' + match[1] + return '`{} <{}>`_'.format(match[0], url) + + linkified_changelog = re.sub(r'(?:PR)?#([0-9]+)\b', linkify, changelog) + + source[0] = source[0].replace('.. include:: ../CHANGES', linkified_changelog) + + def setup(app): from sphinx.ext.autodoc import cut_lines from sphinx.util.docfields import GroupedField app.connect('autodoc-process-docstring', cut_lines(4, what=['module'])) + app.connect('source-read', linkify_issues_in_changelog) app.add_object_type('confval', 'confval', objname='configuration value', indextemplate='pair: %s; configuration value') From a98b605100a7d8bff146b7776cfefef9f452904f Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 9 Jan 2022 00:54:35 +0900 Subject: [PATCH 6/9] Fix mypy violations (with mypy-0.931) --- setup.py | 2 +- sphinx/directives/patches.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 44da14d094d..a8279a14fa4 100644 --- a/setup.py +++ b/setup.py @@ -44,7 +44,7 @@ 'lint': [ 'flake8>=3.5.0', 'isort', - 'mypy>=0.930', + 'mypy>=0.931', 'docutils-stubs', "types-typed-ast", "types-pkg_resources", diff --git a/sphinx/directives/patches.py b/sphinx/directives/patches.py index f01423a88d4..056baa49634 100644 --- a/sphinx/directives/patches.py +++ b/sphinx/directives/patches.py @@ -9,7 +9,7 @@ import os import warnings from os import path -from typing import TYPE_CHECKING, Any, Dict, List, Tuple, cast +from typing import TYPE_CHECKING, Any, Dict, List, Sequence, Tuple, cast from docutils import nodes from docutils.nodes import Node, make_id, system_message @@ -71,7 +71,7 @@ def run(self) -> List[Node]: class Meta(MetaBase, SphinxDirective): - def run(self) -> List[Node]: + def run(self) -> Sequence[Node]: result = super().run() for node in result: if (isinstance(node, nodes.pending) and From a80023f381e8458a77e730385357fe1fd309790d Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 9 Jan 2022 00:59:32 +0900 Subject: [PATCH 7/9] Fix mypy violations (with types-requests-2.27.3) --- sphinx/util/requests.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sphinx/util/requests.py b/sphinx/util/requests.py index bd9a94338e9..581efbfd586 100644 --- a/sphinx/util/requests.py +++ b/sphinx/util/requests.py @@ -25,17 +25,17 @@ except ImportError: # python-requests package in Debian jessie does not provide ``requests.packages.urllib3``. # So try to import the exceptions from urllib3 package. - from urllib3.exceptions import SSLError # type: ignore + from urllib3.exceptions import SSLError try: from requests.packages.urllib3.exceptions import InsecureRequestWarning except ImportError: try: # for Debian-jessie - from urllib3.exceptions import InsecureRequestWarning # type: ignore + from urllib3.exceptions import InsecureRequestWarning except ImportError: # for requests < 2.4.0 - InsecureRequestWarning = None # type: ignore + InsecureRequestWarning = None useragent_header = [('User-Agent', From 9db86f6aaba426b15d9da837bb94360011e36093 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 9 Jan 2022 01:11:22 +0900 Subject: [PATCH 8/9] Fix mypy violations (with mypy-0.931) --- sphinx/directives/patches.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/directives/patches.py b/sphinx/directives/patches.py index 3c532b812bc..d76bb74c702 100644 --- a/sphinx/directives/patches.py +++ b/sphinx/directives/patches.py @@ -83,7 +83,7 @@ def run(self) -> Sequence[Node]: # docutils' meta nodes aren't picklable because the class is nested meta.__class__ = addnodes.meta - return result # type: ignore + return result class RSTTable(tables.RSTTable): From 81998842f5780cddbccbc9e8e2999968c951b328 Mon Sep 17 00:00:00 2001 From: Philipp A Date: Mon, 10 Jan 2022 17:02:40 +0100 Subject: [PATCH 9/9] Fix typing in docfields.py --- sphinx/util/docfields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/util/docfields.py b/sphinx/util/docfields.py index e2179a25ec8..fd84cc85bb2 100644 --- a/sphinx/util/docfields.py +++ b/sphinx/util/docfields.py @@ -21,7 +21,7 @@ from sphinx.util.typing import TextlikeNode if TYPE_CHECKING: - from sphinx.directive import ObjectDescription + from sphinx.directives import ObjectDescription logger = logging.getLogger(__name__)