From fc2ca413ece79c083d52a86df982b33e61847327 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 12 Sep 2021 18:54:36 +0900 Subject: [PATCH 01/14] refactor: Use logger.warning() instead of reporter.warning() --- sphinx/directives/other.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/sphinx/directives/other.py b/sphinx/directives/other.py index e131fe820..78890b14c 100644 --- a/sphinx/directives/other.py +++ b/sphinx/directives/other.py @@ -19,7 +19,7 @@ from docutils.parsers.rst.directives.misc import Include as BaseInclude from sphinx import addnodes from sphinx.domains.changeset import VersionChange # NOQA # for compatibility from sphinx.locale import _ -from sphinx.util import docname_join, url_re +from sphinx.util import docname_join, logging, url_re from sphinx.util.docutils import SphinxDirective from sphinx.util.matching import Matcher, patfilter from sphinx.util.nodes import explicit_title_re @@ -30,6 +30,7 @@ if TYPE_CHECKING: glob_re = re.compile(r'.*[*?\[].*') +logger = logging.getLogger(__name__) def int_or_nothing(argument: str) -> int: @@ -106,9 +107,8 @@ class TocTree(SphinxDirective): toctree['entries'].append((None, docname)) toctree['includefiles'].append(docname) if not docnames: - ret.append(self.state.document.reporter.warning( - 'toctree glob pattern %r didn\'t match any documents' - % entry, line=self.lineno)) + logger.warning('toctree glob pattern %r didn\'t match any documents', + entry, location=toctree) else: if explicit: ref = explicit.group(2) @@ -132,16 +132,14 @@ class TocTree(SphinxDirective): else: message = 'toctree contains reference to nonexisting document %r' - ret.append(self.state.document.reporter.warning(message % docname, - line=self.lineno)) + logger.warning(message, docname, location=toctree) self.env.note_reread() else: if docname in all_docnames: all_docnames.remove(docname) else: - message = 'duplicated entry found in toctree: %s' - ret.append(self.state.document.reporter.warning(message % docname, - line=self.lineno)) + logger.warning('duplicated entry found in toctree: %s', docname, + location=toctree) toctree['entries'].append((title, docname)) toctree['includefiles'].append(docname) @@ -250,8 +248,9 @@ class Acks(SphinxDirective): self.state.nested_parse(self.content, self.content_offset, node) if len(node.children) != 1 or not isinstance(node.children[0], nodes.bullet_list): - reporter = self.state.document.reporter - return [reporter.warning('.. acks content is not a list', line=self.lineno)] + logger.warning('.. acks content is not a list', + location=(self.env.docname, self.lineno)) + return [] return [node] @@ -274,8 +273,9 @@ class HList(SphinxDirective): self.state.nested_parse(self.content, self.content_offset, node) if len(node.children) != 1 or not isinstance(node.children[0], nodes.bullet_list): - reporter = self.state.document.reporter - return [reporter.warning('.. hlist content is not a list', line=self.lineno)] + logger.warning('.. hlist content is not a list', + location=(self.env.docname, self.lineno)) + return [] fulllist = node.children[0] # create a hlist node where the items are distributed npercol, nmore = divmod(len(fulllist), ncolumns) From 5c4f741fffa0d698e82d31b3dd76c34982d313b5 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 12 Sep 2021 18:58:16 +0900 Subject: [PATCH 02/14] Fix i18n: messages in sphinx.directives.other are not translated --- sphinx/directives/other.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sphinx/directives/other.py b/sphinx/directives/other.py index 78890b14c..f04526f93 100644 --- a/sphinx/directives/other.py +++ b/sphinx/directives/other.py @@ -18,7 +18,7 @@ from docutils.parsers.rst.directives.misc import Include as BaseInclude from sphinx import addnodes from sphinx.domains.changeset import VersionChange # NOQA # for compatibility -from sphinx.locale import _ +from sphinx.locale import _, __ from sphinx.util import docname_join, logging, url_re from sphinx.util.docutils import SphinxDirective from sphinx.util.matching import Matcher, patfilter @@ -107,7 +107,7 @@ class TocTree(SphinxDirective): toctree['entries'].append((None, docname)) toctree['includefiles'].append(docname) if not docnames: - logger.warning('toctree glob pattern %r didn\'t match any documents', + logger.warning(__('toctree glob pattern %r didn\'t match any documents'), entry, location=toctree) else: if explicit: @@ -128,9 +128,9 @@ class TocTree(SphinxDirective): toctree['entries'].append((title, ref)) elif docname not in self.env.found_docs: if excluded(self.env.doc2path(docname, None)): - message = 'toctree contains reference to excluded document %r' + message = __('toctree contains reference to excluded document %r') else: - message = 'toctree contains reference to nonexisting document %r' + message = __('toctree contains reference to nonexisting document %r') logger.warning(message, docname, location=toctree) self.env.note_reread() @@ -138,7 +138,7 @@ class TocTree(SphinxDirective): if docname in all_docnames: all_docnames.remove(docname) else: - logger.warning('duplicated entry found in toctree: %s', docname, + logger.warning(__('duplicated entry found in toctree: %s'), docname, location=toctree) toctree['entries'].append((title, docname)) @@ -248,7 +248,7 @@ class Acks(SphinxDirective): self.state.nested_parse(self.content, self.content_offset, node) if len(node.children) != 1 or not isinstance(node.children[0], nodes.bullet_list): - logger.warning('.. acks content is not a list', + logger.warning(__('.. acks content is not a list'), location=(self.env.docname, self.lineno)) return [] return [node] @@ -273,7 +273,7 @@ class HList(SphinxDirective): self.state.nested_parse(self.content, self.content_offset, node) if len(node.children) != 1 or not isinstance(node.children[0], nodes.bullet_list): - logger.warning('.. hlist content is not a list', + logger.warning(__('.. hlist content is not a list'), location=(self.env.docname, self.lineno)) return [] fulllist = node.children[0] From ca146ac18be3fdb9108b8d9dcb0b165ee62e56df Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 12 Sep 2021 19:18:21 +0900 Subject: [PATCH 03/14] Close #9623: Allow to suppress warnings on excluded document found in toctree --- CHANGES | 3 +++ doc/usage/configuration.rst | 1 + sphinx/directives/other.py | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 9e8bc1151..331f14d81 100644 --- a/CHANGES +++ b/CHANGES @@ -13,6 +13,9 @@ Deprecated Features added -------------- +* #9623: Allow to suppress "toctree contains reference to excluded document" + warnings using :confval:`suppress_warnings` + Bugs fixed ---------- diff --git a/doc/usage/configuration.rst b/doc/usage/configuration.rst index a6607e57e..dba3cc831 100644 --- a/doc/usage/configuration.rst +++ b/doc/usage/configuration.rst @@ -329,6 +329,7 @@ General configuration * ``ref.python`` * ``misc.highlighting_failure`` * ``toc.circular`` + * ``toc.not_readable`` * ``toc.secnum`` * ``epub.unknown_project_files`` * ``epub.duplicated_toc_entry`` diff --git a/sphinx/directives/other.py b/sphinx/directives/other.py index f04526f93..7e5b341f0 100644 --- a/sphinx/directives/other.py +++ b/sphinx/directives/other.py @@ -132,7 +132,8 @@ class TocTree(SphinxDirective): else: message = __('toctree contains reference to nonexisting document %r') - logger.warning(message, docname, location=toctree) + logger.warning(message, docname, type='toc', subtype='not_readable', + location=toctree) self.env.note_reread() else: if docname in all_docnames: From ee1cae8c1c2c0e3df9cd2343c32c83ad6142aaca Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 7 Nov 2021 20:04:16 +0900 Subject: [PATCH 04/14] Replace distutils.versions.LooseVersion by packaging.version.Version Distutils module are now deprecated and will be removed in Python 3.12. This replaces it by packaging module and reduces the dependency to it. refs: #9820 --- sphinx/highlighting.py | 4 ++-- sphinx/util/docutils.py | 4 ++-- tests/test_build_html.py | 11 ++++++----- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/sphinx/highlighting.py b/sphinx/highlighting.py index 329561df0..addd0d45c 100644 --- a/sphinx/highlighting.py +++ b/sphinx/highlighting.py @@ -8,11 +8,11 @@ :license: BSD, see LICENSE for details. """ -from distutils.version import LooseVersion from functools import partial from importlib import import_module from typing import Any, Dict +from packaging import version from pygments import __version__ as pygmentsversion from pygments import highlight from pygments.filters import ErrorToken @@ -64,7 +64,7 @@ _LATEX_ADD_STYLES_FIXPYG = r''' {\let\fcolorbox\spx@fixpyg@fcolorbox\PYG@do{#2}}} \makeatother ''' -if tuple(LooseVersion(pygmentsversion).version) <= (2, 7, 4): +if version.parse(pygmentsversion).release <= (2, 7, 4): _LATEX_ADD_STYLES += _LATEX_ADD_STYLES_FIXPYG diff --git a/sphinx/util/docutils.py b/sphinx/util/docutils.py index 047a0faa6..c3d385306 100644 --- a/sphinx/util/docutils.py +++ b/sphinx/util/docutils.py @@ -12,7 +12,6 @@ import os import re from contextlib import contextmanager from copy import copy -from distutils.version import LooseVersion from os import path from types import ModuleType from typing import (IO, TYPE_CHECKING, Any, Callable, Dict, Generator, List, Optional, Set, @@ -26,6 +25,7 @@ from docutils.parsers.rst import Directive, directives, roles from docutils.parsers.rst.states import Inliner from docutils.statemachine import State, StateMachine, StringList from docutils.utils import Reporter, unescape +from packaging import version from sphinx.errors import SphinxError from sphinx.locale import _ @@ -41,7 +41,7 @@ if TYPE_CHECKING: from sphinx.environment import BuildEnvironment -__version_info__ = tuple(LooseVersion(docutils.__version__).version) +__version_info__ = version.parse(docutils.__version__).release additional_nodes: Set[Type[Element]] = set() diff --git a/tests/test_build_html.py b/tests/test_build_html.py index 2e9a43f51..106ad0470 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -10,13 +10,13 @@ import os import re -from distutils.version import LooseVersion from itertools import chain, cycle from unittest.mock import ANY, call, patch import pygments import pytest from html5lib import HTMLParser +from packaging import version from sphinx.builders.html import validate_html_extra_path, validate_html_static_path from sphinx.errors import ConfigError @@ -30,6 +30,9 @@ else: FIGURE_CAPTION = ".//figure/figcaption/p" +PYGMENTS_VERSION = version.parse(pygments.__version__).release + + ENV_WARNINGS = """\ %(root)s/autodoc_fodder.py:docstring of autodoc_fodder.MarkupError:\\d+: \ WARNING: Explicit markup ends without a blank line; unexpected unindent. @@ -1576,8 +1579,7 @@ def test_html_codeblock_linenos_style_table(app): app.build() content = (app.outdir / 'index.html').read_text() - pygments_version = tuple(LooseVersion(pygments.__version__).version) - if pygments_version >= (2, 8): + if PYGMENTS_VERSION >= (2, 8): assert ('
1\n'
                 '2\n'
                 '3\n'
@@ -1592,8 +1594,7 @@ def test_html_codeblock_linenos_style_inline(app):
     app.build()
     content = (app.outdir / 'index.html').read_text()
 
-    pygments_version = tuple(LooseVersion(pygments.__version__).version)
-    if pygments_version > (2, 7):
+    if PYGMENTS_VERSION > (2, 7):
         assert '1' in content
     else:
         assert '1 ' in content

From 4cd19b8274de7513203738c7a5b6d9d32775cd67 Mon Sep 17 00:00:00 2001
From: Takeshi KOMIYA 
Date: Tue, 9 Nov 2021 01:54:56 +0900
Subject: [PATCH 05/14] Close #9450: mathjax: Load MathJax via "defer" strategy

To allow configure MathJax via static JS file, it should be loaded via
"defer" strategy.
---
 CHANGES                | 1 +
 sphinx/ext/mathjax.py  | 2 +-
 tests/test_ext_math.py | 2 +-
 3 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/CHANGES b/CHANGES
index 33d20a45b..0c07f4806 100644
--- a/CHANGES
+++ b/CHANGES
@@ -23,6 +23,7 @@ Incompatible changes
 * #9695: The rendering of Javascript domain declarations is implemented
   with more docutils nodes to allow better CSS styling.
   It may break existing styling.
+* #9450: mathjax: Load MathJax via "defer" strategy
 
 
 Deprecated
diff --git a/sphinx/ext/mathjax.py b/sphinx/ext/mathjax.py
index 46ca3b332..eb06908d3 100644
--- a/sphinx/ext/mathjax.py
+++ b/sphinx/ext/mathjax.py
@@ -81,7 +81,7 @@ def install_mathjax(app: Sphinx, pagename: str, templatename: str, context: Dict
     domain = cast(MathDomain, app.env.get_domain('math'))
     if app.registry.html_assets_policy == 'always' or domain.has_equations(pagename):
         # Enable mathjax only if equations exists
-        options = {'async': 'async'}
+        options = {'defer': 'defer'}
         if app.config.mathjax_options:
             options.update(app.config.mathjax_options)
         app.add_js_file(app.config.mathjax_path, **options)  # type: ignore
diff --git a/tests/test_ext_math.py b/tests/test_ext_math.py
index 973fc3699..7c78954b7 100644
--- a/tests/test_ext_math.py
+++ b/tests/test_ext_math.py
@@ -71,7 +71,7 @@ def test_mathjax_options(app, status, warning):
     app.builder.build_all()
 
     content = (app.outdir / 'index.html').read_text()
-    assert ('' in content)
 

From 3599f7d844322a52bc36903ed1fa5f9c4424e8b1 Mon Sep 17 00:00:00 2001
From: Jakob Lykke Andersen 
Date: Tue, 9 Nov 2021 09:18:50 +0100
Subject: [PATCH 06/14] Make fallback for changed get_signature_prefix()

Fixes sphinx-doc/sphinx#9832
---
 sphinx/domains/python.py | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py
index fd6a78892..051da4480 100644
--- a/sphinx/domains/python.py
+++ b/sphinx/domains/python.py
@@ -495,7 +495,13 @@ class PyObject(ObjectDescription[Tuple[str, str]]):
 
         sig_prefix = self.get_signature_prefix(sig)
         if sig_prefix:
-            signode += addnodes.desc_annotation(str(sig_prefix), '', *sig_prefix)
+            if type(sig_prefix) is str:
+                logger.warning("Python directive get_signature_prefix() returns a str ('{}')"
+                               " instead of a list of nodes (changed in 4.3).".format(sig_prefix),
+                               location=signode)
+                signode += addnodes.desc_annotation(sig_prefix, '', nodes.Text(sig_prefix, sig_prefix))
+            else:
+                signode += addnodes.desc_annotation(str(sig_prefix), '', *sig_prefix)
 
         if prefix:
             signode += addnodes.desc_addname(prefix, prefix)

From d20cb96773bd89e58da21f4996c20679dfb129e9 Mon Sep 17 00:00:00 2001
From: Jakob Lykke Andersen 
Date: Tue, 9 Nov 2021 09:31:56 +0100
Subject: [PATCH 07/14] Fix lint errors

---
 sphinx/domains/python.py | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py
index 051da4480..402bdfc9f 100644
--- a/sphinx/domains/python.py
+++ b/sphinx/domains/python.py
@@ -496,10 +496,12 @@ class PyObject(ObjectDescription[Tuple[str, str]]):
         sig_prefix = self.get_signature_prefix(sig)
         if sig_prefix:
             if type(sig_prefix) is str:
-                logger.warning("Python directive get_signature_prefix() returns a str ('{}')"
-                               " instead of a list of nodes (changed in 4.3).".format(sig_prefix),
-                               location=signode)
-                signode += addnodes.desc_annotation(sig_prefix, '', nodes.Text(sig_prefix, sig_prefix))
+                logger.warning(
+                    "Python directive get_signature_prefix() returns a str ('{}')"
+                    " instead of a list of nodes (changed in 4.3).".format(sig_prefix),
+                    location=signode)
+                signode += addnodes.desc_annotation(sig_prefix, '',  # type: ignore
+                                                    nodes.Text(sig_prefix))  # type: ignore
             else:
                 signode += addnodes.desc_annotation(str(sig_prefix), '', *sig_prefix)
 

From 203094b4c3d0db34527281bd29601ab418325d5c Mon Sep 17 00:00:00 2001
From: Takeshi KOMIYA 
Date: Tue, 9 Nov 2021 01:29:52 +0900
Subject: [PATCH 08/14] Close #9618: i18n: Add gettext_allow_fuzzy_translations

---
 CHANGES                     |  2 ++
 doc/usage/configuration.rst |  7 +++++++
 sphinx/application.py       |  3 ++-
 sphinx/builders/__init__.py |  3 ++-
 sphinx/config.py            |  1 +
 sphinx/util/i18n.py         |  4 ++--
 tests/test_intl.py          | 38 +++++++++++++++++++++++++++++++++++++
 7 files changed, 54 insertions(+), 4 deletions(-)

diff --git a/CHANGES b/CHANGES
index 33d20a45b..2278f2486 100644
--- a/CHANGES
+++ b/CHANGES
@@ -43,6 +43,8 @@ Features added
 * #9691: C, added new info-field ``retval``
   for :rst:dir:`c:function` and :rst:dir:`c:macro`.
 * C++, added new info-field ``retval`` for :rst:dir:`cpp:function`.
+* #9618: i18n: Add :confval:`gettext_allow_fuzzy_translations` to allow "fuzzy"
+  messages for translation
 * #9672: More CSS classes on Python domain descriptions
 * #9695: More CSS classes on Javascript domain descriptions
 * #9683: Revert the removal of ``add_stylesheet()`` API.  It will be kept until
diff --git a/doc/usage/configuration.rst b/doc/usage/configuration.rst
index 46c82e56d..6725bd3e0 100644
--- a/doc/usage/configuration.rst
+++ b/doc/usage/configuration.rst
@@ -802,6 +802,13 @@ documentation on :ref:`intl` for details.
    .. versionchanged:: 1.5
       Use ``locales`` directory as a default value
 
+.. confval:: gettext_allow_fuzzy_translations
+
+   If true, "fuzzy" messages in the message catalogs are used for translation.
+   The default is ``False``.
+
+   .. versionadded:: 4.3
+
 .. confval:: gettext_compact
 
    .. versionadded:: 1.1
diff --git a/sphinx/application.py b/sphinx/application.py
index 4a75a83fe..ec0234a4e 100644
--- a/sphinx/application.py
+++ b/sphinx/application.py
@@ -284,7 +284,8 @@ class Sphinx:
                                      self.config.language, self.config.source_encoding)
             for catalog in repo.catalogs:
                 if catalog.domain == 'sphinx' and catalog.is_outdated():
-                    catalog.write_mo(self.config.language)
+                    catalog.write_mo(self.config.language,
+                                     self.config.gettext_allow_fuzzy_translations)
 
             locale_dirs: List[Optional[str]] = list(repo.locale_dirs)
             locale_dirs += [None]
diff --git a/sphinx/builders/__init__.py b/sphinx/builders/__init__.py
index 5ad989539..64c621a1c 100644
--- a/sphinx/builders/__init__.py
+++ b/sphinx/builders/__init__.py
@@ -217,7 +217,8 @@ class Builder:
         for catalog in status_iterator(catalogs, __('writing output... '), "darkgreen",
                                        len(catalogs), self.app.verbosity,
                                        stringify_func=cat2relpath):
-            catalog.write_mo(self.config.language)
+            catalog.write_mo(self.config.language,
+                             self.config.gettext_allow_fuzzy_translations)
 
     def compile_all_catalogs(self) -> None:
         repo = CatalogRepository(self.srcdir, self.config.locale_dirs,
diff --git a/sphinx/config.py b/sphinx/config.py
index 2ca20cb48..05bcdeccc 100644
--- a/sphinx/config.py
+++ b/sphinx/config.py
@@ -103,6 +103,7 @@ class Config:
         'language': (None, 'env', [str]),
         'locale_dirs': (['locales'], 'env', []),
         'figure_language_filename': ('{root}.{language}{ext}', 'env', [str]),
+        'gettext_allow_fuzzy_translations': (False, 'gettext', []),
 
         'master_doc': ('index', 'env', []),
         'root_doc': (lambda config: config.master_doc, 'env', []),
diff --git a/sphinx/util/i18n.py b/sphinx/util/i18n.py
index e82e33f57..02b42cf0b 100644
--- a/sphinx/util/i18n.py
+++ b/sphinx/util/i18n.py
@@ -59,7 +59,7 @@ class CatalogInfo(LocaleFileInfoBase):
             not path.exists(self.mo_path) or
             path.getmtime(self.mo_path) < path.getmtime(self.po_path))
 
-    def write_mo(self, locale: str) -> None:
+    def write_mo(self, locale: str, use_fuzzy: bool = False) -> None:
         with open(self.po_path, encoding=self.charset) as file_po:
             try:
                 po = read_po(file_po, locale)
@@ -69,7 +69,7 @@ class CatalogInfo(LocaleFileInfoBase):
 
         with open(self.mo_path, 'wb') as file_mo:
             try:
-                write_mo(file_mo, po)
+                write_mo(file_mo, po, use_fuzzy)
             except Exception as exc:
                 logger.warning(__('writing error: %s, %s'), self.mo_path, exc)
 
diff --git a/tests/test_intl.py b/tests/test_intl.py
index 30beb1135..3b54063ef 100644
--- a/tests/test_intl.py
+++ b/tests/test_intl.py
@@ -1301,6 +1301,44 @@ def getwarning(warnings):
     return strip_escseq(warnings.getvalue().replace(os.sep, '/'))
 
 
+@pytest.mark.sphinx('html', testroot='basic',
+                    srcdir='gettext_allow_fuzzy_translations',
+                    confoverrides={
+                        'language': 'de',
+                        'gettext_allow_fuzzy_translations': True
+                    })
+def test_gettext_allow_fuzzy_translations(app):
+    locale_dir = app.srcdir / 'locales' / 'de' / 'LC_MESSAGES'
+    locale_dir.makedirs()
+    with (locale_dir / 'index.po').open('wb') as f:
+        catalog = Catalog()
+        catalog.add('features', 'FEATURES', flags=('fuzzy',))
+        pofile.write_po(f, catalog)
+
+    app.build()
+    content = (app.outdir / 'index.html').read_text()
+    assert 'FEATURES' in content
+
+
+@pytest.mark.sphinx('html', testroot='basic',
+                    srcdir='gettext_disallow_fuzzy_translations',
+                    confoverrides={
+                        'language': 'de',
+                        'gettext_allow_fuzzy_translations': False
+                    })
+def test_gettext_disallow_fuzzy_translations(app):
+    locale_dir = app.srcdir / 'locales' / 'de' / 'LC_MESSAGES'
+    locale_dir.makedirs()
+    with (locale_dir / 'index.po').open('wb') as f:
+        catalog = Catalog()
+        catalog.add('features', 'FEATURES', flags=('fuzzy',))
+        pofile.write_po(f, catalog)
+
+    app.build()
+    content = (app.outdir / 'index.html').read_text()
+    assert 'FEATURES' not in content
+
+
 @pytest.mark.sphinx('html', testroot='basic', confoverrides={'language': 'de'})
 def test_customize_system_message(make_app, app_params, sphinx_test_tempdir):
     try:

From 22bec4ffe43babda23a8f0a8db0c7f5b87a24a18 Mon Sep 17 00:00:00 2001
From: Takeshi KOMIYA 
Date: Wed, 10 Nov 2021 01:43:59 +0900
Subject: [PATCH 09/14] Fix #9623: Separate warning type 'toc.not_readable' to
 'toc.excluded'

---
 doc/usage/configuration.rst | 5 +++++
 sphinx/directives/other.py  | 4 +++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/doc/usage/configuration.rst b/doc/usage/configuration.rst
index dba3cc831..395708b57 100644
--- a/doc/usage/configuration.rst
+++ b/doc/usage/configuration.rst
@@ -329,6 +329,7 @@ General configuration
    * ``ref.python``
    * ``misc.highlighting_failure``
    * ``toc.circular``
+   * ``toc.excluded``
    * ``toc.not_readable``
    * ``toc.secnum``
    * ``epub.unknown_project_files``
@@ -361,6 +362,10 @@ General configuration
 
       Added ``epub.duplicated_toc_entry``
 
+   .. versionchanged:: 4.3
+
+      Added ``toc.excluded`` and ``toc.not_readable``
+
 .. confval:: needs_sphinx
 
    If set to a ``major.minor`` version string like ``'1.1'``, Sphinx will
diff --git a/sphinx/directives/other.py b/sphinx/directives/other.py
index 7e5b341f0..03eb6d3d2 100644
--- a/sphinx/directives/other.py
+++ b/sphinx/directives/other.py
@@ -129,10 +129,12 @@ class TocTree(SphinxDirective):
                 elif docname not in self.env.found_docs:
                     if excluded(self.env.doc2path(docname, None)):
                         message = __('toctree contains reference to excluded document %r')
+                        subtype = 'excluded'
                     else:
                         message = __('toctree contains reference to nonexisting document %r')
+                        subtype = 'not_readable'
 
-                    logger.warning(message, docname, type='toc', subtype='not_readable',
+                    logger.warning(message, docname, type='toc', subtype=subtype,
                                    location=toctree)
                     self.env.note_reread()
                 else:

From 63bd4b8062eaa65f107ce0b5066f8c7229f1c63c Mon Sep 17 00:00:00 2001
From: Jakob Lykke Andersen 
Date: Tue, 9 Nov 2021 20:37:34 +0100
Subject: [PATCH 10/14] Use warnings.warn and deprecation warning

---
 sphinx/domains/python.py | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py
index 402bdfc9f..46a67b4ea 100644
--- a/sphinx/domains/python.py
+++ b/sphinx/domains/python.py
@@ -496,10 +496,12 @@ class PyObject(ObjectDescription[Tuple[str, str]]):
         sig_prefix = self.get_signature_prefix(sig)
         if sig_prefix:
             if type(sig_prefix) is str:
-                logger.warning(
-                    "Python directive get_signature_prefix() returns a str ('{}')"
-                    " instead of a list of nodes (changed in 4.3).".format(sig_prefix),
-                    location=signode)
+                warnings.warn(
+                    "Python directive method get_signature_prefix()"
+                    " returning a string is deprecated."
+                    " It must now return a list of nodes."
+                    " Return value was '{}'.".format(sig_prefix),
+                    RemovedInSphinx50Warning)
                 signode += addnodes.desc_annotation(sig_prefix, '',  # type: ignore
                                                     nodes.Text(sig_prefix))  # type: ignore
             else:

From 53396360848812dd38d98c3fdd2605139ef2c306 Mon Sep 17 00:00:00 2001
From: Takeshi KOMIYA 
Date: Thu, 11 Nov 2021 02:07:48 +0900
Subject: [PATCH 11/14] Fix the type of deprecation warning for
 get_signature_prefix (refs: #9833)

---
 sphinx/domains/python.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py
index 46a67b4ea..b932a9ea5 100644
--- a/sphinx/domains/python.py
+++ b/sphinx/domains/python.py
@@ -26,7 +26,7 @@ from sphinx import addnodes
 from sphinx.addnodes import desc_signature, pending_xref, pending_xref_condition
 from sphinx.application import Sphinx
 from sphinx.builders import Builder
-from sphinx.deprecation import RemovedInSphinx50Warning
+from sphinx.deprecation import RemovedInSphinx50Warning, RemovedInSphinx60Warning
 from sphinx.directives import ObjectDescription
 from sphinx.domains import Domain, Index, IndexEntry, ObjType
 from sphinx.environment import BuildEnvironment
@@ -501,7 +501,7 @@ class PyObject(ObjectDescription[Tuple[str, str]]):
                     " returning a string is deprecated."
                     " It must now return a list of nodes."
                     " Return value was '{}'.".format(sig_prefix),
-                    RemovedInSphinx50Warning)
+                    RemovedInSphinx60Warning)
                 signode += addnodes.desc_annotation(sig_prefix, '',  # type: ignore
                                                     nodes.Text(sig_prefix))  # type: ignore
             else:

From 3001cc9f8d35a3520bb017c345c29faec66d4848 Mon Sep 17 00:00:00 2001
From: Takeshi KOMIYA 
Date: Thu, 11 Nov 2021 02:22:40 +0900
Subject: [PATCH 12/14] Bump to 4.3.0 final

---
 CHANGES            | 29 ++---------------------------
 sphinx/__init__.py |  4 ++--
 2 files changed, 4 insertions(+), 29 deletions(-)

diff --git a/CHANGES b/CHANGES
index 421c9ecec..89486060a 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,5 @@
-Release 4.3.0 (in development)
-==============================
+Release 4.3.0 (released Nov 11, 2021)
+=====================================
 
 Dependencies
 ------------
@@ -25,7 +25,6 @@ Incompatible changes
   It may break existing styling.
 * #9450: mathjax: Load MathJax via "defer" strategy
 
-
 Deprecated
 ----------
 
@@ -100,30 +99,6 @@ Bugs fixed
 * Intersphinx, for unresolved references with an explicit inventory,
   e.g., ``proj:myFunc``, leave the inventory prefix in the unresolved text.
 
-Testing
---------
-
-Release 4.2.1 (in development)
-==============================
-
-Dependencies
-------------
-
-Incompatible changes
---------------------
-
-Deprecated
-----------
-
-Features added
---------------
-
-Bugs fixed
-----------
-
-Testing
---------
-
 Release 4.2.0 (released Sep 12, 2021)
 =====================================
 
diff --git a/sphinx/__init__.py b/sphinx/__init__.py
index c4c10e92f..9e0f7a286 100644
--- a/sphinx/__init__.py
+++ b/sphinx/__init__.py
@@ -27,7 +27,7 @@ if 'PYTHONWARNINGS' not in os.environ:
 warnings.filterwarnings('ignore', "'U' mode is deprecated",
                         DeprecationWarning, module='docutils.io')
 
-__version__ = '4.3.0+'
+__version__ = '4.3.0'
 __released__ = '4.3.0'  # used when Sphinx builds its own docs
 
 #: Version info for better programmatic use.
@@ -38,7 +38,7 @@ __released__ = '4.3.0'  # used when Sphinx builds its own docs
 #:
 #: .. versionadded:: 1.2
 #:    Before version 1.2, check the string ``sphinx.__version__``.
-version_info = (4, 3, 0, 'beta', 0)
+version_info = (4, 3, 0, 'final', 0)
 
 package_dir = path.abspath(path.dirname(__file__))
 

From 8e0c7a75f8d818171144e7fd5b6e1f9202272ac3 Mon Sep 17 00:00:00 2001
From: Takeshi KOMIYA 
Date: Thu, 11 Nov 2021 02:24:22 +0900
Subject: [PATCH 13/14] Bump version

---
 CHANGES            | 21 +++++++++++++++++++++
 sphinx/__init__.py |  6 +++---
 2 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/CHANGES b/CHANGES
index 89486060a..81e2ebf64 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,24 @@
+Release 4.3.1 (in development)
+==============================
+
+Dependencies
+------------
+
+Incompatible changes
+--------------------
+
+Deprecated
+----------
+
+Features added
+--------------
+
+Bugs fixed
+----------
+
+Testing
+--------
+
 Release 4.3.0 (released Nov 11, 2021)
 =====================================
 
diff --git a/sphinx/__init__.py b/sphinx/__init__.py
index 9e0f7a286..62b3645e7 100644
--- a/sphinx/__init__.py
+++ b/sphinx/__init__.py
@@ -27,8 +27,8 @@ if 'PYTHONWARNINGS' not in os.environ:
 warnings.filterwarnings('ignore', "'U' mode is deprecated",
                         DeprecationWarning, module='docutils.io')
 
-__version__ = '4.3.0'
-__released__ = '4.3.0'  # used when Sphinx builds its own docs
+__version__ = '4.3.1+'
+__released__ = '4.3.1'  # used when Sphinx builds its own docs
 
 #: Version info for better programmatic use.
 #:
@@ -38,7 +38,7 @@ __released__ = '4.3.0'  # used when Sphinx builds its own docs
 #:
 #: .. versionadded:: 1.2
 #:    Before version 1.2, check the string ``sphinx.__version__``.
-version_info = (4, 3, 0, 'final', 0)
+version_info = (4, 3, 1, 'beta', 0)
 
 package_dir = path.abspath(path.dirname(__file__))
 

From 121d9394fc5d33f13c66599620a9b9966c894b6a Mon Sep 17 00:00:00 2001
From: Takeshi KOMIYA 
Date: Thu, 11 Nov 2021 02:25:06 +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 81e2ebf64..5450e9550 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,24 @@
+Release 4.4.0 (in development)
+==============================
+
+Dependencies
+------------
+
+Incompatible changes
+--------------------
+
+Deprecated
+----------
+
+Features added
+--------------
+
+Bugs fixed
+----------
+
+Testing
+--------
+
 Release 4.3.1 (in development)
 ==============================
 
diff --git a/sphinx/__init__.py b/sphinx/__init__.py
index 62b3645e7..307426eb7 100644
--- a/sphinx/__init__.py
+++ b/sphinx/__init__.py
@@ -27,8 +27,8 @@ if 'PYTHONWARNINGS' not in os.environ:
 warnings.filterwarnings('ignore', "'U' mode is deprecated",
                         DeprecationWarning, module='docutils.io')
 
-__version__ = '4.3.1+'
-__released__ = '4.3.1'  # used when Sphinx builds its own docs
+__version__ = '4.4.0+'
+__released__ = '4.4.0'  # used when Sphinx builds its own docs
 
 #: Version info for better programmatic use.
 #:
@@ -38,7 +38,7 @@ __released__ = '4.3.1'  # used when Sphinx builds its own docs
 #:
 #: .. versionadded:: 1.2
 #:    Before version 1.2, check the string ``sphinx.__version__``.
-version_info = (4, 3, 1, 'beta', 0)
+version_info = (4, 4, 0, 'beta', 0)
 
 package_dir = path.abspath(path.dirname(__file__))