Warn on deprecated Python-specific index types (#11412)

This commit is contained in:
Adam Turner
2023-05-09 22:57:39 +01:00
committed by GitHub
parent db546189ce
commit 706f5f9cc8
14 changed files with 91 additions and 71 deletions

View File

@@ -14,6 +14,11 @@ Incompatible changes
Deprecated Deprecated
---------- ----------
* #11412: Emit warnings on using a deprecated Python-specific index entry type
(namely, ``module``, ``keyword``, ``operator``, ``object``, ``exception``,
``statement``, and ``builtin``) in the :rst:dir:`index` directive, and
set the removal version to Sphinx 9. Patch by Adam Turner.
Features added Features added
-------------- --------------

View File

@@ -337,6 +337,7 @@ General configuration
* ``epub.unknown_project_files`` * ``epub.unknown_project_files``
* ``epub.duplicated_toc_entry`` * ``epub.duplicated_toc_entry``
* ``i18n.inconsistent_references`` * ``i18n.inconsistent_references``
* ``index``
* ``image.not_readable`` * ``image.not_readable``
* ``ref.term`` * ``ref.term``
* ``ref.ref`` * ``ref.ref``
@@ -388,6 +389,10 @@ General configuration
Added ``i18n.inconsistent_references`` Added ``i18n.inconsistent_references``
.. versionadded:: 7.1
Added ``index`` warning type.
.. confval:: needs_sphinx .. confval:: needs_sphinx
If set to a ``major.minor`` version string like ``'1.1'``, Sphinx will If set to a ``major.minor`` version string like ``'1.1'``, Sphinx will

View File

@@ -896,9 +896,10 @@ mainly contained in information units, such as the language reference.
.. index:: .. index::
single: execution; context single: execution; context
module: __main__ pair: module; __main__
module: sys pair: module; sys
triple: module; search; path triple: module; search; path
seealso: scope
The execution context The execution context
--------------------- ---------------------
@@ -916,25 +917,63 @@ mainly contained in information units, such as the language reference.
The possible entry types are: The possible entry types are:
single single
Creates a single index entry. Can be made a subentry by separating the Creates a single index entry.
subentry text with a semicolon (this notation is also used below to Can be made a sub-entry by separating the sub-entry text with a semicolon
describe what entries are created). (this notation is also used below to describe what entries are created).
Examples:
.. code:: reStructuredText
.. index:: single: execution
single: execution; context
- ``single: execution`` creates an index entry labelled ``execution``.
- ``single: execution; context`` creates an sub-entry of ``execution``
labelled ``context``.
pair pair
``pair: loop; statement`` is a shortcut that creates two index entries, A shortcut to create two index entries.
namely ``loop; statement`` and ``statement; loop``. The pair of values must be separated by a semicolon.
Example:
.. code:: reStructuredText
.. index:: pair: loop; statement
This would create two index entries; ``loop; statement`` and ``statement; loop``.
triple triple
Likewise, ``triple: module; search; path`` is a shortcut that creates A shortcut to create three index entries.
three index entries, which are ``module; search path``, ``search; path, All three values must be separated by a semicolon.
module`` and ``path; module search``. Example:
.. code:: reStructuredText
.. index:: triple: module; search; path
This would create three index entries; ``module; search path``,
``search; path, module``, and ``path; module search``.
see see
``see: entry; other`` creates an index entry that refers from ``entry`` to A shortcut to create an index entry that refers to another entry.
``other``. Example:
.. code:: reStructuredText
.. index:: see: entry; other
This would create an index entry referring from ``entry`` to ``other``
(i.e. 'entry': See 'other').
seealso seealso
Like ``see``, but inserts "see also" instead of "see". Like ``see``, but inserts 'see also' instead of 'see'.
module, keyword, operator, object, exception, statement, builtin module, keyword, operator, object, exception, statement, builtin
These all create two index entries. For example, ``module: hashlib`` These **deprecated** shortcuts all create two index entries.
creates the entries ``module; hashlib`` and ``hashlib; module``. (These For example, ``module: hashlib`` creates the entries ``module; hashlib``
are Python-specific and therefore deprecated.) and ``hashlib; module``.
.. deprecated:: 1.0
These Python-specific entry types are deprecated.
.. versionchanged:: 7.1
Removal version set to Sphinx 9.0.
Using these entry types will now emit warnings with the ``index`` category.
You can mark up "main" index entries by prefixing them with an exclamation You can mark up "main" index entries by prefixing them with an exclamation
mark. The references to "main" entries are emphasized in the generated mark. The references to "main" entries are emphasized in the generated

View File

@@ -16,7 +16,6 @@ from docutils.nodes import Element
from sphinx import addnodes, package_dir from sphinx import addnodes, package_dir
from sphinx.application import Sphinx from sphinx.application import Sphinx
from sphinx.builders import Builder from sphinx.builders import Builder
from sphinx.domains.python import pairindextypes
from sphinx.errors import ThemeError from sphinx.errors import ThemeError
from sphinx.locale import __ from sphinx.locale import __
from sphinx.util import logging, split_index_msg from sphinx.util import logging, split_index_msg
@@ -159,10 +158,6 @@ class I18nBuilder(Builder):
for node, entries in traverse_translatable_index(doctree): for node, entries in traverse_translatable_index(doctree):
for typ, msg, _tid, _main, _key in entries: for typ, msg, _tid, _main, _key in entries:
for m in split_index_msg(typ, msg): for m in split_index_msg(typ, msg):
if typ == 'pair' and m in pairindextypes.values():
# avoid built-in translated message was incorporated
# in 'sphinx.util.nodes.process_index_entry'
continue
catalog.add(m, node) catalog.add(m, node)

View File

@@ -50,13 +50,13 @@ py_sig_re = re.compile(
pairindextypes = { pairindextypes = {
'module': _('module'), 'module': 'module',
'keyword': _('keyword'), 'keyword': 'keyword',
'operator': _('operator'), 'operator': 'operator',
'object': _('object'), 'object': 'object',
'exception': _('exception'), 'exception': 'exception',
'statement': _('statement'), 'statement': 'statement',
'builtin': _('built-in function'), 'builtin': 'built-in function',
} }
@@ -729,7 +729,7 @@ class PyFunction(PyObject):
text = _('%s() (in module %s)') % (name, modname) text = _('%s() (in module %s)') % (name, modname)
self.indexnode['entries'].append(('single', text, node_id, '', None)) self.indexnode['entries'].append(('single', text, node_id, '', None))
else: else:
text = f'{pairindextypes["builtin"]}; {name}()' text = f'built-in function; {name}()'
self.indexnode['entries'].append(('pair', text, node_id, '', None)) self.indexnode['entries'].append(('pair', text, node_id, '', None))
def get_index_text(self, modname: str, name_cls: tuple[str, str]) -> str | None: def get_index_text(self, modname: str, name_cls: tuple[str, str]) -> str | None:
@@ -1058,7 +1058,7 @@ class PyModule(SphinxDirective):
# the platform and synopsis aren't printed; in fact, they are only # the platform and synopsis aren't printed; in fact, they are only
# used in the modindex currently # used in the modindex currently
ret.append(target) ret.append(target)
indextext = f'{pairindextypes["module"]}; {modname}' indextext = f'module; {modname}'
inode = addnodes.index(entries=[('pair', indextext, node_id, '', None)]) inode = addnodes.index(entries=[('pair', indextext, node_id, '', None)])
ret.append(inode) ret.append(inode)
ret.extend(content_node.children) ret.extend(content_node.children)

View File

@@ -223,9 +223,3 @@ admonitionlabels = {
'tip': _('Tip'), 'tip': _('Tip'),
'warning': _('Warning'), 'warning': _('Warning'),
} }
# Moved to sphinx.directives.other (will be overridden later)
versionlabels: dict[str, str] = {}
# Moved to sphinx.domains.python (will be overridden later)
pairindextypes: dict[str, str] = {}

View File

@@ -365,19 +365,23 @@ def process_index_entry(entry: str, targetid: str,
if entry.startswith('!'): if entry.startswith('!'):
main = 'main' main = 'main'
entry = entry[1:].lstrip() entry = entry[1:].lstrip()
for type in pairindextypes: for index_type in pairindextypes:
if entry.startswith(type + ':'): if entry.startswith(f'{index_type}:'):
value = entry[len(type) + 1:].strip() value = entry[len(index_type) + 1:].strip()
value = pairindextypes[type] + '; ' + value value = f'{pairindextypes[index_type]}; {value}'
# xref RemovedInSphinx90Warning
logger.warning(__('%r is deprecated for index entries (from entry %r). '
"Use 'pair: %s' instead."),
index_type, entry, value, type='index')
indexentries.append(('pair', value, targetid, main, None)) indexentries.append(('pair', value, targetid, main, None))
break break
else: else:
for type in indextypes: for index_type in indextypes:
if entry.startswith(type + ':'): if entry.startswith(f'{index_type}:'):
value = entry[len(type) + 1:].strip() value = entry[len(index_type) + 1:].strip()
if type == 'double': if index_type == 'double':
type = 'pair' index_type = 'pair'
indexentries.append((type, value, targetid, main, None)) indexentries.append((index_type, value, targetid, main, None))
break break
# shorthand notation for single entries # shorthand notation for single entries
else: else:

View File

@@ -20,12 +20,5 @@ various index entries
triple: First; Second; Third triple: First; Second; Third
see: Entry; Mailing List see: Entry; Mailing List
seealso: See; Newsletter seealso: See; Newsletter
module: Module
keyword: Keyword
operator: Operator
object: Object
exception: Exception
statement: Statement
builtin: Builtin
That's all. That's all.

View File

@@ -373,7 +373,6 @@ Index markup
pair: entry; pair pair: entry; pair
double: entry; double double: entry; double
triple: index; entry; triple triple: index; entry; triple
keyword: with
see: from; to see: from; to
seealso: fromalso; toalso seealso: fromalso; toalso

View File

@@ -27,7 +27,7 @@ Don't download :download:`this <nonexisting.png>`.
.. index:: .. index::
single: single:
pair: pair:
keyword: seealso:
.. Invalid code-block .. Invalid code-block
.. code-block:: c .. code-block:: c

View File

@@ -117,13 +117,6 @@ def test_gettext_index_entries(app):
"Third", "Third",
"Entry", "Entry",
"See", "See",
"Module",
"Keyword",
"Operator",
"Object",
"Exception",
"Statement",
"Builtin",
] ]
for expect in expected_msgids: for expect in expected_msgids:
assert expect in msgids assert expect in msgids

View File

@@ -1,4 +1,4 @@
"""Test the sphinx.environment.managers.indexentries.""" """Test the sphinx.environment.adapters.indexentries."""
import pytest import pytest

View File

@@ -1,4 +1,4 @@
"""Test the sphinx.environment.managers.toctree.""" """Test the sphinx.environment.adapters.toctree."""
import pytest import pytest
from docutils import nodes from docutils import nodes

View File

@@ -727,13 +727,6 @@ def test_html_index_entries(app):
wrap('a', 'THIRD, FIRST'), wrap('a', 'THIRD, FIRST'),
wrap_nest('li', 'ul', 'ENTRY'), wrap_nest('li', 'ul', 'ENTRY'),
wrap_nest('li', 'ul', 'SEE'), wrap_nest('li', 'ul', 'SEE'),
wrap('a', 'MODULE'),
wrap('a', 'KEYWORD'),
wrap('a', 'OPERATOR'),
wrap('a', 'OBJECT'),
wrap('a', 'EXCEPTION'),
wrap('a', 'STATEMENT'),
wrap('a', 'BUILTIN'),
] ]
for expr in expected_exprs: for expr in expected_exprs:
assert_re_search(expr, result, re.M) assert_re_search(expr, result, re.M)