From 105c583f0605d336c9fc981e49e7a4ed4ef25f30 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 8 Feb 2022 15:59:09 +0000 Subject: [PATCH 01/14] Revert "Close #9993: std domain: Allow to refer an inline target via ref role" This reverts commit e3ee8b378a37958f48d97d74a5c264f1f02e153e. This is a breaking change that should not have been introduced in a minor release (or arguably at all, given the impact). Signed-off-by: Stephen Finucane Closes: #10177 --- sphinx/domains/std.py | 8 +++----- tests/test_domain_std.py | 9 --------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py index e9f75325a33..0a3e6a3425e 100644 --- a/sphinx/domains/std.py +++ b/sphinx/domains/std.py @@ -762,11 +762,10 @@ def process_doc(self, env: "BuildEnvironment", docname: str, document: nodes.doc sectname = clean_astext(title) elif node.tagname == 'rubric': sectname = clean_astext(node) - elif node.tagname == 'target' and len(node) > 0: - # inline target (ex: blah _`blah` blah) - sectname = clean_astext(node) elif self.is_enumerable_node(node): sectname = self.get_numfig_title(node) + if not sectname: + continue else: toctree = next(node.findall(addnodes.toctree), None) if toctree and toctree.get('caption'): @@ -774,8 +773,7 @@ def process_doc(self, env: "BuildEnvironment", docname: str, document: nodes.doc else: # anonymous-only labels continue - if sectname: - self.labels[name] = docname, labelid, sectname + self.labels[name] = docname, labelid, sectname def add_program_option(self, program: str, name: str, docname: str, labelid: str) -> None: self.progoptions[program, name] = (docname, labelid) diff --git a/tests/test_domain_std.py b/tests/test_domain_std.py index 00e7361a394..d001a939dde 100644 --- a/tests/test_domain_std.py +++ b/tests/test_domain_std.py @@ -453,12 +453,3 @@ def test_labeled_rubric(app): domain = app.env.get_domain("std") assert 'label' in domain.labels assert domain.labels['label'] == ('index', 'label', 'blah blah blah') - - -def test_inline_target(app): - text = "blah _`inline target` blah\n" - restructuredtext.parse(app, text) - - domain = app.env.get_domain("std") - assert 'inline target' in domain.labels - assert domain.labels['inline target'] == ('index', 'inline-target', 'inline target') From dfcb5d2f4c20f46a6d440b2c92b16ac692c3c53d Mon Sep 17 00:00:00 2001 From: Jean Abou Samra Date: Sun, 16 Jan 2022 00:37:13 +0100 Subject: [PATCH 02/14] Categorize warnings for inconsistent references in i18n This allows suppressing them using the suppress_warnings configuration variable. --- doc/usage/configuration.rst | 14 ++++++++++---- sphinx/transforms/i18n.py | 10 +++++----- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/doc/usage/configuration.rst b/doc/usage/configuration.rst index 737e2282330..aaa3c8231fa 100644 --- a/doc/usage/configuration.rst +++ b/doc/usage/configuration.rst @@ -316,7 +316,11 @@ General configuration * ``app.add_role`` * ``app.add_generic_role`` * ``app.add_source_parser`` + * ``autosectionlabel.*`` * ``download.not_readable`` + * ``epub.unknown_project_files`` + * ``epub.duplicated_toc_entry`` + * ``i18n.inconsistent_references`` * ``image.not_readable`` * ``ref.term`` * ``ref.ref`` @@ -332,11 +336,9 @@ General configuration * ``toc.excluded`` * ``toc.not_readable`` * ``toc.secnum`` - * ``epub.unknown_project_files`` - * ``epub.duplicated_toc_entry`` - * ``autosectionlabel.*`` - You can choose from these types. + You can choose from these types. You can also give only the first + component to exclude all warnings attached to it. Now, this option should be considered *experimental*. @@ -366,6 +368,10 @@ General configuration Added ``toc.excluded`` and ``toc.not_readable`` + .. versionadded:: 4.4 + + Added ``i18n.inconsistent_references`` + .. confval:: needs_sphinx If set to a ``major.minor`` version string like ``'1.1'``, Sphinx will diff --git a/sphinx/transforms/i18n.py b/sphinx/transforms/i18n.py index fb2824fe05e..198a6342746 100644 --- a/sphinx/transforms/i18n.py +++ b/sphinx/transforms/i18n.py @@ -309,7 +309,7 @@ def list_replace_or_append(lst: List[N], old: N, new: N) -> None: logger.warning(__('inconsistent footnote references in translated message.' + ' original: {0}, translated: {1}') .format(old_foot_ref_rawsources, new_foot_ref_rawsources), - location=node) + location=node, type='i18n', subtype='inconsistent_references') old_foot_namerefs: Dict[str, List[nodes.footnote_reference]] = {} for r in old_foot_refs: old_foot_namerefs.setdefault(r.get('refname'), []).append(r) @@ -352,7 +352,7 @@ def list_replace_or_append(lst: List[N], old: N, new: N) -> None: logger.warning(__('inconsistent references in translated message.' + ' original: {0}, translated: {1}') .format(old_ref_rawsources, new_ref_rawsources), - location=node) + location=node, type='i18n', subtype='inconsistent_references') old_ref_names = [r['refname'] for r in old_refs] new_ref_names = [r['refname'] for r in new_refs] orphans = list(set(old_ref_names) - set(new_ref_names)) @@ -380,7 +380,7 @@ def list_replace_or_append(lst: List[N], old: N, new: N) -> None: logger.warning(__('inconsistent footnote references in translated message.' + ' original: {0}, translated: {1}') .format(old_foot_ref_rawsources, new_foot_ref_rawsources), - location=node) + location=node, type='i18n', subtype='inconsistent_references') for oldf in old_foot_refs: refname_ids_map.setdefault(oldf["refname"], []).append(oldf["ids"]) for newf in new_foot_refs: @@ -399,7 +399,7 @@ def list_replace_or_append(lst: List[N], old: N, new: N) -> None: logger.warning(__('inconsistent citation references in translated message.' + ' original: {0}, translated: {1}') .format(old_cite_ref_rawsources, new_cite_ref_rawsources), - location=node) + location=node, type='i18n', subtype='inconsistent_references') for oldc in old_cite_refs: refname_ids_map.setdefault(oldc["refname"], []).append(oldc["ids"]) for newc in new_cite_refs: @@ -419,7 +419,7 @@ def list_replace_or_append(lst: List[N], old: N, new: N) -> None: logger.warning(__('inconsistent term references in translated message.' + ' original: {0}, translated: {1}') .format(old_xref_rawsources, new_xref_rawsources), - location=node) + location=node, type='i18n', subtype='inconsistent_references') def get_ref_key(node: addnodes.pending_xref) -> Optional[Tuple[str, str, str]]: case = node["refdomain"], node["reftype"] From 94d78d8747b454a00a06623facdaedfbb2d88b17 Mon Sep 17 00:00:00 2001 From: Jean Abou Samra Date: Sun, 16 Jan 2022 03:15:46 +0100 Subject: [PATCH 03/14] Close #3985: Implement #noqa for i18n When cross-references in the original paragraph and the translated paragraph do not match, a warning is emitted. It is useful, because it allows to catch mistakes, but it can also be an annoyance since sometimes it is expected that the cross-references will not match. For example, a reference that is repeated in the original text may need to be factored out for good style in the target language. Another example: if the translator needs to translate a universally understood term in the source language into a term that not everyone knows is the translation of this original term, adding a reference to the glossary can be warranted. This allows the translated message to start with '#noqa' in order to disable the warning. --- doc/usage/advanced/intl.rst | 18 ++++++++ sphinx/transforms/i18n.py | 34 +++++++++++--- tests/roots/test-intl/literalblock.txt | 8 ++++ tests/roots/test-intl/noqa.txt | 16 +++++++ .../test-intl/xx/LC_MESSAGES/literalblock.po | 6 +++ tests/roots/test-intl/xx/LC_MESSAGES/noqa.po | 46 +++++++++++++++++++ tests/test_intl.py | 29 ++++++++++++ 7 files changed, 151 insertions(+), 6 deletions(-) create mode 100644 tests/roots/test-intl/noqa.txt create mode 100644 tests/roots/test-intl/xx/LC_MESSAGES/noqa.po diff --git a/doc/usage/advanced/intl.rst b/doc/usage/advanced/intl.rst index 3bf353e8d72..1284064102d 100644 --- a/doc/usage/advanced/intl.rst +++ b/doc/usage/advanced/intl.rst @@ -68,6 +68,24 @@ be translated you need to follow these instructions: * Run your desired build. +In order to protect against mistakes, a warning is emitted if +cross-references in the translated paragraph do not match those from the +original. This can be turned off globally using the +:confval:`suppress_warnings` configuration variable. Alternatively, to +turn it off for one message only, end the message with ``#noqa`` like +this:: + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse + risus tortor, luctus id ultrices at. #noqa + +(Write ``\#noqa`` in case you want to have "#noqa" literally in the +text. This does not apply to code blocks, where ``#noqa`` is ignored +because code blocks do not contain references anyway.) + +.. versionadded:: 4.4 + The ``#noqa`` mechanism. + + Translating with sphinx-intl ---------------------------- diff --git a/sphinx/transforms/i18n.py b/sphinx/transforms/i18n.py index 198a6342746..d38403ab561 100644 --- a/sphinx/transforms/i18n.py +++ b/sphinx/transforms/i18n.py @@ -9,6 +9,7 @@ """ from os import path +from re import DOTALL, match from textwrap import indent from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Type, TypeVar @@ -82,6 +83,14 @@ def publish_msgstr(app: "Sphinx", source: str, source_path: str, source_line: in config.rst_prolog = rst_prolog # type: ignore +def parse_noqa(source: str) -> Tuple[str, bool]: + m = match(r"(.*)(? None: # phase1: replace reference ids with translated names for node, msg in extract_messages(self.document): msgstr = catalog.gettext(msg) + + # There is no point in having #noqa on literal blocks because + # they cannot contain references. Recognizing it would just + # completely prevent escaping the #noqa. Outside of literal + # blocks, one can always write \#noqa. + if not isinstance(node, LITERAL_TYPE_NODES): + msgstr, _ = parse_noqa(msgstr) + # XXX add marker to untranslated parts if not msgstr or msgstr == msg or not msgstr.strip(): # as-of-yet untranslated @@ -139,6 +156,7 @@ def apply(self, **kwargs: Any) -> None: patch = publish_msgstr(self.app, msgstr, source, node.line, self.config, settings) + # FIXME: no warnings about inconsistent references in this part # XXX doctest and other block markup if not isinstance(patch, nodes.paragraph): continue # skip for now @@ -228,6 +246,11 @@ def apply(self, **kwargs: Any) -> None: continue # skip if the node is already translated by phase1 msgstr = catalog.gettext(msg) + + # See above. + if not isinstance(node, LITERAL_TYPE_NODES): + msgstr, noqa = parse_noqa(msgstr) + # XXX add marker to untranslated parts if not msgstr or msgstr == msg: # as-of-yet untranslated continue @@ -273,7 +296,6 @@ def apply(self, **kwargs: Any) -> None: patch = publish_msgstr(self.app, msgstr, source, node.line, self.config, settings) - # Structural Subelements phase2 if isinstance(node, nodes.title): # get node that placed as a first child @@ -303,7 +325,7 @@ def list_replace_or_append(lst: List[N], old: N, new: N) -> None: is_autofootnote_ref = NodeMatcher(nodes.footnote_reference, auto=Any) old_foot_refs: List[nodes.footnote_reference] = list(node.findall(is_autofootnote_ref)) # NOQA new_foot_refs: List[nodes.footnote_reference] = list(patch.findall(is_autofootnote_ref)) # NOQA - if len(old_foot_refs) != len(new_foot_refs): + if not noqa and len(old_foot_refs) != len(new_foot_refs): old_foot_ref_rawsources = [ref.rawsource for ref in old_foot_refs] new_foot_ref_rawsources = [ref.rawsource for ref in new_foot_refs] logger.warning(__('inconsistent footnote references in translated message.' + @@ -346,7 +368,7 @@ def list_replace_or_append(lst: List[N], old: N, new: N) -> None: is_refnamed_ref = NodeMatcher(nodes.reference, refname=Any) old_refs: List[nodes.reference] = list(node.findall(is_refnamed_ref)) new_refs: List[nodes.reference] = list(patch.findall(is_refnamed_ref)) - if len(old_refs) != len(new_refs): + if not noqa and len(old_refs) != len(new_refs): old_ref_rawsources = [ref.rawsource for ref in old_refs] new_ref_rawsources = [ref.rawsource for ref in new_refs] logger.warning(__('inconsistent references in translated message.' + @@ -374,7 +396,7 @@ def list_replace_or_append(lst: List[N], old: N, new: N) -> None: old_foot_refs = list(node.findall(is_refnamed_footnote_ref)) new_foot_refs = list(patch.findall(is_refnamed_footnote_ref)) refname_ids_map: Dict[str, List[str]] = {} - if len(old_foot_refs) != len(new_foot_refs): + if not noqa and len(old_foot_refs) != len(new_foot_refs): old_foot_ref_rawsources = [ref.rawsource for ref in old_foot_refs] new_foot_ref_rawsources = [ref.rawsource for ref in new_foot_refs] logger.warning(__('inconsistent footnote references in translated message.' + @@ -393,7 +415,7 @@ def list_replace_or_append(lst: List[N], old: N, new: N) -> None: old_cite_refs: List[nodes.citation_reference] = list(node.findall(is_citation_ref)) new_cite_refs: List[nodes.citation_reference] = list(patch.findall(is_citation_ref)) # NOQA refname_ids_map = {} - if len(old_cite_refs) != len(new_cite_refs): + if not noqa and len(old_cite_refs) != len(new_cite_refs): old_cite_ref_rawsources = [ref.rawsource for ref in old_cite_refs] new_cite_ref_rawsources = [ref.rawsource for ref in new_cite_refs] logger.warning(__('inconsistent citation references in translated message.' + @@ -413,7 +435,7 @@ def list_replace_or_append(lst: List[N], old: N, new: N) -> None: old_xrefs = list(node.findall(addnodes.pending_xref)) new_xrefs = list(patch.findall(addnodes.pending_xref)) xref_reftarget_map = {} - if len(old_xrefs) != len(new_xrefs): + if not noqa and len(old_xrefs) != len(new_xrefs): old_xref_rawsources = [xref.rawsource for xref in old_xrefs] new_xref_rawsources = [xref.rawsource for xref in new_xrefs] logger.warning(__('inconsistent term references in translated message.' + diff --git a/tests/roots/test-intl/literalblock.txt b/tests/roots/test-intl/literalblock.txt index 2b9eb8eb192..583b5b61072 100644 --- a/tests/roots/test-intl/literalblock.txt +++ b/tests/roots/test-intl/literalblock.txt @@ -49,6 +49,14 @@ code blocks literal-block in list +.. highlight:: none + +:: + + test_code_for_noqa() + continued() + + doctest blocks ============== diff --git a/tests/roots/test-intl/noqa.txt b/tests/roots/test-intl/noqa.txt new file mode 100644 index 00000000000..004b301461e --- /dev/null +++ b/tests/roots/test-intl/noqa.txt @@ -0,0 +1,16 @@ +First section +============= + +Some text with a reference, :ref:`next-section`. + +Another reference: :ref:`next-section`. + +This should allow to test escaping ``#noqa``. + +.. _next-section: + +Next section +============ + +Some text, again referring to the section: :ref:`next-section`. + diff --git a/tests/roots/test-intl/xx/LC_MESSAGES/literalblock.po b/tests/roots/test-intl/xx/LC_MESSAGES/literalblock.po index 04029535950..8d3e5d8bec1 100644 --- a/tests/roots/test-intl/xx/LC_MESSAGES/literalblock.po +++ b/tests/roots/test-intl/xx/LC_MESSAGES/literalblock.po @@ -77,6 +77,12 @@ msgid "literal-block\n" msgstr "LITERAL-BLOCK\n" "IN LIST" +msgid "test_code_for_noqa()\n" +"continued()" +msgstr "" +"# TRAILING noqa SHOULD NOT GET STRIPPED\n" +"# FROM THIS BLOCK. #noqa" + msgid "doctest blocks" msgstr "DOCTEST-BLOCKS" diff --git a/tests/roots/test-intl/xx/LC_MESSAGES/noqa.po b/tests/roots/test-intl/xx/LC_MESSAGES/noqa.po new file mode 100644 index 00000000000..1af66b47df0 --- /dev/null +++ b/tests/roots/test-intl/xx/LC_MESSAGES/noqa.po @@ -0,0 +1,46 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) +# This file is distributed under the same license as the Sphinx intl <Tests> package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-01-16 15:23+0100\n" +"PO-Revision-Date: 2022-01-16 15:23+0100\n" +"Last-Translator: Jean Abou Samra <jean@abou-samra.fr>\n" +"Language-Team: \n" +"Language: xx\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 3.0\n" + +#: ../tests/roots/test-intl/noqa.txt:2 +msgid "First section" +msgstr "FIRST SECTION" + +#: ../tests/roots/test-intl/noqa.txt:4 +msgid "Some text with a reference, :ref:`next-section`." +msgstr "TRANSLATED TEXT WITHOUT REFERENCE. #noqa" + +#: ../tests/roots/test-intl/noqa.txt:6 +msgid "Another reference: :ref:`next-section`." +msgstr "" +"TEST noqa WHITESPACE INSENSITIVITY.\n" +"# \n" +" noqa" + +#: ../tests/roots/test-intl/noqa.txt:8 +msgid "This should allow to test escaping ``#noqa``." +msgstr "``#noqa`` IS ESCAPED AT THE END OF THIS STRING. \\#noqa" + +#: ../tests/roots/test-intl/noqa.txt:13 +msgid "Next section" +msgstr "NEXT SECTION WITH PARAGRAPH TO TEST BARE noqa" + +# This edge case should not fail. +#: ../tests/roots/test-intl/noqa.txt:15 +msgid "Some text, again referring to the section: :ref:`next-section`." +msgstr "#noqa" diff --git a/tests/test_intl.py b/tests/test_intl.py index 62dbb13528c..c1c6a4d6e38 100644 --- a/tests/test_intl.py +++ b/tests/test_intl.py @@ -192,6 +192,32 @@ def test_text_inconsistency_warnings(app, warning): assert_re_search(expected_citation_warning_expr, warnings) +@sphinx_intl +@pytest.mark.sphinx('text') +@pytest.mark.test_params(shared_result='test_intl_basic') +def test_noqa(app, warning): + app.build() + result = (app.outdir / 'noqa.txt').read_text() + expect = r"""FIRST SECTION +************* + +TRANSLATED TEXT WITHOUT REFERENCE. + +TEST noqa WHITESPACE INSENSITIVITY. + +"#noqa" IS ESCAPED AT THE END OF THIS STRING. #noqa + + +NEXT SECTION WITH PARAGRAPH TO TEST BARE noqa +********************************************* + +Some text, again referring to the section: NEXT SECTION WITH PARAGRAPH +TO TEST BARE noqa. +""" + assert result == expect + assert "next-section" not in getwarning(warning) + + @sphinx_intl @pytest.mark.sphinx('text') @pytest.mark.test_params(shared_result='test_intl_basic') @@ -1186,6 +1212,9 @@ def test_additional_targets_should_be_translated(app): """<span class="c1"># SYS IMPORTING</span>""") assert_count(expected_expr, result, 1) + # '#noqa' should remain in literal blocks. + assert_count("#noqa", result, 1) + # [raw.txt] result = (app.outdir / 'raw.html').read_text() From fa63db8dc6845d49daf05d7fe48a7999e0765aa2 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA <i.tkomiya@gmail.com> Date: Sun, 6 Mar 2022 18:47:11 +0900 Subject: [PATCH 04/14] Update versionadded to 4.5 --- doc/usage/advanced/intl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/usage/advanced/intl.rst b/doc/usage/advanced/intl.rst index 1284064102d..ccdb6e98275 100644 --- a/doc/usage/advanced/intl.rst +++ b/doc/usage/advanced/intl.rst @@ -82,7 +82,7 @@ this:: text. This does not apply to code blocks, where ``#noqa`` is ignored because code blocks do not contain references anyway.) -.. versionadded:: 4.4 +.. versionadded:: 4.5 The ``#noqa`` mechanism. From 7b55447b7e7a554e5ac4aae061f72b832d132f04 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA <i.tkomiya@gmail.com> Date: Sun, 6 Mar 2022 18:47:17 +0900 Subject: [PATCH 05/14] Update versionadded to 4.5 --- doc/usage/configuration.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/usage/configuration.rst b/doc/usage/configuration.rst index aaa3c8231fa..6441ee567e2 100644 --- a/doc/usage/configuration.rst +++ b/doc/usage/configuration.rst @@ -368,7 +368,7 @@ General configuration Added ``toc.excluded`` and ``toc.not_readable`` - .. versionadded:: 4.4 + .. versionadded:: 4.5 Added ``i18n.inconsistent_references`` From 554f589fde62473552a16194b4f77f74c3decf11 Mon Sep 17 00:00:00 2001 From: Nico Albers <nico.albers@aboutyou.com> Date: Sun, 13 Mar 2022 11:21:30 +0100 Subject: [PATCH 06/14] escape base_uri in extlinks to avoid regex issues with URIs containing special characters --- sphinx/ext/extlinks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/ext/extlinks.py b/sphinx/ext/extlinks.py index 8caba884298..6601f067773 100644 --- a/sphinx/ext/extlinks.py +++ b/sphinx/ext/extlinks.py @@ -70,7 +70,7 @@ def check_uri(self, refnode: nodes.reference) -> None: title = refnode.astext() for alias, (base_uri, _caption) in self.app.config.extlinks.items(): - uri_pattern = re.compile(base_uri.replace('%s', '(?P<value>.+)')) + uri_pattern = re.compile(re.escape(base_uri).replace('%s', '(?P<value>.+)')) match = uri_pattern.match(uri) if match and match.groupdict().get('value'): # build a replacement suggestion From a001bf47d66ae804a9a6e5d754de9b5eda4d0eb9 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA <i.tkomiya@gmail.com> Date: Sun, 27 Mar 2022 23:06:02 +0900 Subject: [PATCH 07/14] Update CHANGES for PR #10107 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 17606bd7307..d382941ea9a 100644 --- a/CHANGES +++ b/CHANGES @@ -27,6 +27,8 @@ Features added * #9337: HTML theme, add option ``enable_search_shortcuts`` that enables :kbd:'/' as a Quick search shortcut and :kbd:`Esc` shortcut that removes search highlighting. +* #10107: i18n: Allow to suppress translation warnings by adding ``#noqa`` + comment to the tail of each translation message * #10252: C++, support attributes on classes, unions, and enums. * #10253: :rst:dir:`pep` role now generates URLs based on peps.python.org From c93b95d685aea6c8e4392d624e4668587b9e5726 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA <i.tkomiya@gmail.com> Date: Sun, 27 Mar 2022 23:06:42 +0900 Subject: [PATCH 08/14] Merge CHANGES entry for 4.4.1 to 4.5.0 --- CHANGES | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/CHANGES b/CHANGES index d382941ea9a..7dd7d56c71d 100644 --- a/CHANGES +++ b/CHANGES @@ -35,6 +35,8 @@ Features added Bugs fixed ---------- +* #9876: autodoc: Failed to document an imported class that is built from native + binary module * #10133: autodoc: Crashed when mocked module is used for type annotation * #10146: autodoc: :confval:`autodoc_default_options` does not support ``no-value`` option @@ -60,30 +62,6 @@ Bugs fixed Testing -------- -Release 4.4.1 (in development) -============================== - -Dependencies ------------- - -Incompatible changes --------------------- - -Deprecated ----------- - -Features added --------------- - -Bugs fixed ----------- - -* #9876: autodoc: Failed to document an imported class that is built from native - binary module - -Testing --------- - Release 4.4.0 (released Jan 17, 2022) ===================================== From 8a1830ca36ddea80f8bcbc20c1090280a0a5197a Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA <i.tkomiya@gmail.com> Date: Sun, 27 Mar 2022 23:12:18 +0900 Subject: [PATCH 09/14] Update CHANGES for PR #10178 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 7dd7d56c71d..610c5ecf855 100644 --- a/CHANGES +++ b/CHANGES @@ -8,6 +8,8 @@ Incompatible changes -------------------- * #10112: extlinks: Disable hardcoded links detector by default +* #9993, #10177: std domain: Disallow to refer an inline target via + :rst:role:`ref` role Deprecated ---------- From aee4e42b81d56c57e1311176ce175ba3374baa0a Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA <i.tkomiya@gmail.com> Date: Sun, 27 Mar 2022 23:55:10 +0900 Subject: [PATCH 10/14] extlink: Strip a leading backslash on compiling pattern --- sphinx/ext/extlinks.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sphinx/ext/extlinks.py b/sphinx/ext/extlinks.py index 6601f067773..a574d665af1 100644 --- a/sphinx/ext/extlinks.py +++ b/sphinx/ext/extlinks.py @@ -26,6 +26,7 @@ """ import re +import sys import warnings from typing import Any, Dict, List, Tuple @@ -70,7 +71,12 @@ def check_uri(self, refnode: nodes.reference) -> None: title = refnode.astext() for alias, (base_uri, _caption) in self.app.config.extlinks.items(): - uri_pattern = re.compile(re.escape(base_uri).replace('%s', '(?P<value>.+)')) + if sys.version_info < (3, 7): + # Replace a leading backslash because re.escape() inserts a backslash before % on python 3.6 + uri_pattern = re.compile(re.escape(base_uri).replace('\\%s', '(?P<value>.+)')) + else: + uri_pattern = re.compile(re.escape(base_uri).replace('%s', '(?P<value>.+)')) + match = uri_pattern.match(uri) if match and match.groupdict().get('value'): # build a replacement suggestion From 81830cc77047ce39eab056a70b44a2d97848550c Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA <i.tkomiya@gmail.com> Date: Sun, 27 Mar 2022 23:58:39 +0900 Subject: [PATCH 11/14] Fix a flake8 warning --- sphinx/ext/extlinks.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sphinx/ext/extlinks.py b/sphinx/ext/extlinks.py index a574d665af1..659a92b799c 100644 --- a/sphinx/ext/extlinks.py +++ b/sphinx/ext/extlinks.py @@ -72,7 +72,8 @@ def check_uri(self, refnode: nodes.reference) -> None: for alias, (base_uri, _caption) in self.app.config.extlinks.items(): if sys.version_info < (3, 7): - # Replace a leading backslash because re.escape() inserts a backslash before % on python 3.6 + # Replace a leading backslash because re.escape() inserts a backslash before % + # on python 3.6 uri_pattern = re.compile(re.escape(base_uri).replace('\\%s', '(?P<value>.+)')) else: uri_pattern = re.compile(re.escape(base_uri).replace('%s', '(?P<value>.+)')) From c34444149d7703ae2bf415adbec97324a5842632 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA <i.tkomiya@gmail.com> Date: Mon, 28 Mar 2022 00:08:28 +0900 Subject: [PATCH 12/14] Update CHANGES for PR #10263 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index 610c5ecf855..2fa96036424 100644 --- a/CHANGES +++ b/CHANGES @@ -44,6 +44,7 @@ Bugs fixed ``no-value`` option * #9971: autodoc: TypeError is raised when the target object is annotated by unhashable object +* #10205: extlinks: Failed to compile regexp on checking hardcoded links * #10277: html search: Could not search short words (ex. "use") * #9529: LaTeX: named auto numbered footnote (ex. ``[#named]``) that is referred multiple times was rendered to a question mark From 2329fdef8c20c6c75194f5d842b8f62ebad5c79d Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA <i.tkomiya@gmail.com> Date: Mon, 28 Mar 2022 00:56:22 +0900 Subject: [PATCH 13/14] Bump to 4.5.0 final --- CHANGES | 10 ++-------- sphinx/__init__.py | 4 ++-- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/CHANGES b/CHANGES index 2fa96036424..373585b81ab 100644 --- a/CHANGES +++ b/CHANGES @@ -1,8 +1,5 @@ -Release 4.5.0 (in development) -============================== - -Dependencies ------------- +Release 4.5.0 (released Mar 28, 2022) +===================================== Incompatible changes -------------------- @@ -62,9 +59,6 @@ Bugs fixed * #10122: sphinx-build: make.bat does not check the installation of sphinx-build command before showing help -Testing --------- - Release 4.4.0 (released Jan 17, 2022) ===================================== diff --git a/sphinx/__init__.py b/sphinx/__init__.py index 6a2bcb25b07..218f8fe3028 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -19,7 +19,7 @@ warnings.filterwarnings('ignore', "'U' mode is deprecated", DeprecationWarning, module='docutils.io') -__version__ = '4.5.0+' +__version__ = '4.5.0' __released__ = '4.5.0' # used when Sphinx builds its own docs #: Version info for better programmatic use. @@ -30,7 +30,7 @@ #: #: .. versionadded:: 1.2 #: Before version 1.2, check the string ``sphinx.__version__``. -version_info = (4, 5, 0, 'beta', 0) +version_info = (4, 5, 0, 'final', 0) package_dir = path.abspath(path.dirname(__file__)) From 4221d1a5163d023d80a34bd4a12e9c2a2c648ae3 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA <i.tkomiya@gmail.com> Date: Mon, 28 Mar 2022 00:58:54 +0900 Subject: [PATCH 14/14] Bump version --- CHANGES | 21 +++++++++++++++++++++ sphinx/__init__.py | 6 +++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 373585b81ab..1874d1b1acd 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,24 @@ +Release 4.5.1 (in development) +============================== + +Dependencies +------------ + +Incompatible changes +-------------------- + +Deprecated +---------- + +Features added +-------------- + +Bugs fixed +---------- + +Testing +-------- + Release 4.5.0 (released Mar 28, 2022) ===================================== diff --git a/sphinx/__init__.py b/sphinx/__init__.py index 218f8fe3028..7672b33a2e1 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -19,8 +19,8 @@ warnings.filterwarnings('ignore', "'U' mode is deprecated", DeprecationWarning, module='docutils.io') -__version__ = '4.5.0' -__released__ = '4.5.0' # used when Sphinx builds its own docs +__version__ = '4.5.1+' +__released__ = '4.5.1' # used when Sphinx builds its own docs #: Version info for better programmatic use. #: @@ -30,7 +30,7 @@ #: #: .. versionadded:: 1.2 #: Before version 1.2, check the string ``sphinx.__version__``. -version_info = (4, 5, 0, 'final', 0) +version_info = (4, 5, 1, 'beta', 0) package_dir = path.abspath(path.dirname(__file__))