mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Add `sphinx.util.index_entries
` (#11528)
This commit is contained in:
parent
fca33a203d
commit
c9f0e67cca
2
CHANGES
2
CHANGES
@ -16,6 +16,8 @@ Deprecated
|
|||||||
Use ``hashlib`` instead.
|
Use ``hashlib`` instead.
|
||||||
* #11526: Deprecate ``sphinx.testing.path``.
|
* #11526: Deprecate ``sphinx.testing.path``.
|
||||||
Use ``os.path`` or ``pathlib`` instead.
|
Use ``os.path`` or ``pathlib`` instead.
|
||||||
|
* #11528: Deprecate ``sphinx.util.split_index_msg`` and ``sphinx.util.split_into``.
|
||||||
|
Use ``sphinx.util.index_entries.split_index_msg`` instead.
|
||||||
|
|
||||||
Features added
|
Features added
|
||||||
--------------
|
--------------
|
||||||
|
@ -22,6 +22,16 @@ The following is a list of deprecated interfaces.
|
|||||||
- Removed
|
- Removed
|
||||||
- Alternatives
|
- Alternatives
|
||||||
|
|
||||||
|
* - ``sphinx.util.split_into``
|
||||||
|
- 7.2
|
||||||
|
- 9.0
|
||||||
|
- N/A
|
||||||
|
|
||||||
|
* - ``sphinx.util.split_index_msg``
|
||||||
|
- 7.2
|
||||||
|
- 9.0
|
||||||
|
- ``sphinx.util.index_entries.split_index_msg``
|
||||||
|
|
||||||
* - ``sphinx.testing.path``
|
* - ``sphinx.testing.path``
|
||||||
- 7.2
|
- 7.2
|
||||||
- 9.0
|
- 9.0
|
||||||
|
@ -18,10 +18,11 @@ from sphinx.application import Sphinx
|
|||||||
from sphinx.builders import Builder
|
from sphinx.builders import Builder
|
||||||
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
|
||||||
from sphinx.util.console import bold # type: ignore
|
from sphinx.util.console import bold # type: ignore
|
||||||
from sphinx.util.display import status_iterator
|
from sphinx.util.display import status_iterator
|
||||||
from sphinx.util.i18n import CatalogInfo, docname_to_domain
|
from sphinx.util.i18n import CatalogInfo, docname_to_domain
|
||||||
|
from sphinx.util.index_entries import split_index_msg
|
||||||
from sphinx.util.nodes import extract_messages, traverse_translatable_index
|
from sphinx.util.nodes import extract_messages, traverse_translatable_index
|
||||||
from sphinx.util.osutil import canon_path, ensuredir, relpath
|
from sphinx.util.osutil import canon_path, ensuredir, relpath
|
||||||
from sphinx.util.tags import Tags
|
from sphinx.util.tags import Tags
|
||||||
|
@ -11,8 +11,9 @@ from docutils.parsers.rst import directives
|
|||||||
from sphinx import addnodes
|
from sphinx import addnodes
|
||||||
from sphinx.domains import Domain
|
from sphinx.domains import Domain
|
||||||
from sphinx.environment import BuildEnvironment
|
from sphinx.environment import BuildEnvironment
|
||||||
from sphinx.util import logging, split_index_msg
|
from sphinx.util import logging
|
||||||
from sphinx.util.docutils import ReferenceRole, SphinxDirective
|
from sphinx.util.docutils import ReferenceRole, SphinxDirective
|
||||||
|
from sphinx.util.index_entries import split_index_msg
|
||||||
from sphinx.util.nodes import process_index_entry
|
from sphinx.util.nodes import process_index_entry
|
||||||
from sphinx.util.typing import OptionSpec
|
from sphinx.util.typing import OptionSpec
|
||||||
|
|
||||||
|
@ -11,7 +11,8 @@ from sphinx.builders import Builder
|
|||||||
from sphinx.environment import BuildEnvironment
|
from sphinx.environment import BuildEnvironment
|
||||||
from sphinx.errors import NoUri
|
from sphinx.errors import NoUri
|
||||||
from sphinx.locale import _, __
|
from sphinx.locale import _, __
|
||||||
from sphinx.util import logging, split_into
|
from sphinx.util import logging
|
||||||
|
from sphinx.util.index_entries import _split_into
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -41,20 +42,20 @@ class IndexEntries:
|
|||||||
try:
|
try:
|
||||||
if entry_type == 'single':
|
if entry_type == 'single':
|
||||||
try:
|
try:
|
||||||
entry, sub_entry = split_into(2, 'single', value)
|
entry, sub_entry = _split_into(2, 'single', value)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
entry, = split_into(1, 'single', value)
|
entry, = _split_into(1, 'single', value)
|
||||||
sub_entry = ''
|
sub_entry = ''
|
||||||
_add_entry(entry, sub_entry, main,
|
_add_entry(entry, sub_entry, main,
|
||||||
dic=new, link=uri, key=category_key)
|
dic=new, link=uri, key=category_key)
|
||||||
elif entry_type == 'pair':
|
elif entry_type == 'pair':
|
||||||
first, second = split_into(2, 'pair', value)
|
first, second = _split_into(2, 'pair', value)
|
||||||
_add_entry(first, second, main,
|
_add_entry(first, second, main,
|
||||||
dic=new, link=uri, key=category_key)
|
dic=new, link=uri, key=category_key)
|
||||||
_add_entry(second, first, main,
|
_add_entry(second, first, main,
|
||||||
dic=new, link=uri, key=category_key)
|
dic=new, link=uri, key=category_key)
|
||||||
elif entry_type == 'triple':
|
elif entry_type == 'triple':
|
||||||
first, second, third = split_into(3, 'triple', value)
|
first, second, third = _split_into(3, 'triple', value)
|
||||||
_add_entry(first, second + ' ' + third, main,
|
_add_entry(first, second + ' ' + third, main,
|
||||||
dic=new, link=uri, key=category_key)
|
dic=new, link=uri, key=category_key)
|
||||||
_add_entry(second, third + ', ' + first, main,
|
_add_entry(second, third + ', ' + first, main,
|
||||||
@ -62,11 +63,11 @@ class IndexEntries:
|
|||||||
_add_entry(third, first + ' ' + second, main,
|
_add_entry(third, first + ' ' + second, main,
|
||||||
dic=new, link=uri, key=category_key)
|
dic=new, link=uri, key=category_key)
|
||||||
elif entry_type == 'see':
|
elif entry_type == 'see':
|
||||||
first, second = split_into(2, 'see', value)
|
first, second = _split_into(2, 'see', value)
|
||||||
_add_entry(first, _('see %s') % second, None,
|
_add_entry(first, _('see %s') % second, None,
|
||||||
dic=new, link=False, key=category_key)
|
dic=new, link=False, key=category_key)
|
||||||
elif entry_type == 'seealso':
|
elif entry_type == 'seealso':
|
||||||
first, second = split_into(2, 'see', value)
|
first, second = _split_into(2, 'see', value)
|
||||||
_add_entry(first, _('see also %s') % second, None,
|
_add_entry(first, _('see also %s') % second, None,
|
||||||
dic=new, link=False, key=category_key)
|
dic=new, link=False, key=category_key)
|
||||||
else:
|
else:
|
||||||
|
@ -16,7 +16,7 @@ from docutils.nodes import Element, Node
|
|||||||
|
|
||||||
from sphinx import addnodes, package_dir
|
from sphinx import addnodes, package_dir
|
||||||
from sphinx.environment import BuildEnvironment
|
from sphinx.environment import BuildEnvironment
|
||||||
from sphinx.util import split_index_msg
|
from sphinx.util.index_entries import split_index_msg
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from collections.abc import Iterable
|
from collections.abc import Iterable
|
||||||
|
@ -18,8 +18,9 @@ from sphinx.errors import ConfigError
|
|||||||
from sphinx.locale import __
|
from sphinx.locale import __
|
||||||
from sphinx.locale import init as init_locale
|
from sphinx.locale import init as init_locale
|
||||||
from sphinx.transforms import SphinxTransform
|
from sphinx.transforms import SphinxTransform
|
||||||
from sphinx.util import get_filetype, logging, split_index_msg
|
from sphinx.util import get_filetype, logging
|
||||||
from sphinx.util.i18n import docname_to_domain
|
from sphinx.util.i18n import docname_to_domain
|
||||||
|
from sphinx.util.index_entries import split_index_msg
|
||||||
from sphinx.util.nodes import (
|
from sphinx.util.nodes import (
|
||||||
IMAGE_TYPE_NODES,
|
IMAGE_TYPE_NODES,
|
||||||
LITERAL_TYPE_NODES,
|
LITERAL_TYPE_NODES,
|
||||||
|
@ -16,6 +16,7 @@ from sphinx.locale import __
|
|||||||
from sphinx.util import display as _display
|
from sphinx.util import display as _display
|
||||||
from sphinx.util import exceptions as _exceptions
|
from sphinx.util import exceptions as _exceptions
|
||||||
from sphinx.util import http_date as _http_date
|
from sphinx.util import http_date as _http_date
|
||||||
|
from sphinx.util import index_entries as _index_entries
|
||||||
from sphinx.util import logging
|
from sphinx.util import logging
|
||||||
from sphinx.util import osutil as _osutil
|
from sphinx.util import osutil as _osutil
|
||||||
from sphinx.util.console import strip_colors # NoQA: F401
|
from sphinx.util.console import strip_colors # NoQA: F401
|
||||||
@ -220,30 +221,6 @@ def parselinenos(spec: str, total: int) -> list[int]:
|
|||||||
return items
|
return items
|
||||||
|
|
||||||
|
|
||||||
def split_into(n: int, type: str, value: str) -> list[str]:
|
|
||||||
"""Split an index entry into a given number of parts at semicolons."""
|
|
||||||
parts = [x.strip() for x in value.split(';', n - 1)]
|
|
||||||
if len(list(filter(None, parts))) < n:
|
|
||||||
raise ValueError(f'invalid {type} index entry {value!r}')
|
|
||||||
return parts
|
|
||||||
|
|
||||||
|
|
||||||
def split_index_msg(entry_type: str, value: str) -> list[str]:
|
|
||||||
# new entry types must be listed in util/nodes.py!
|
|
||||||
if entry_type == 'single':
|
|
||||||
try:
|
|
||||||
return split_into(2, 'single', value)
|
|
||||||
except ValueError:
|
|
||||||
return split_into(1, 'single', value)
|
|
||||||
if entry_type == 'pair':
|
|
||||||
return split_into(2, 'pair', value)
|
|
||||||
if entry_type == 'triple':
|
|
||||||
return split_into(3, 'triple', value)
|
|
||||||
if entry_type in {'see', 'seealso'}:
|
|
||||||
return split_into(2, 'see', value)
|
|
||||||
raise ValueError(f'invalid {entry_type} index entry {value!r}')
|
|
||||||
|
|
||||||
|
|
||||||
def import_object(objname: str, source: str | None = None) -> Any:
|
def import_object(objname: str, source: str | None = None) -> Any:
|
||||||
"""Import python object by qualname."""
|
"""Import python object by qualname."""
|
||||||
try:
|
try:
|
||||||
@ -300,6 +277,9 @@ _DEPRECATED_OBJECTS = {
|
|||||||
'format_exception_cut_frames': (_exceptions.format_exception_cut_frames,
|
'format_exception_cut_frames': (_exceptions.format_exception_cut_frames,
|
||||||
'sphinx.exceptions.format_exception_cut_frames'),
|
'sphinx.exceptions.format_exception_cut_frames'),
|
||||||
'xmlname_checker': (_xml_name_checker, 'sphinx.builders.epub3._XML_NAME_PATTERN'),
|
'xmlname_checker': (_xml_name_checker, 'sphinx.builders.epub3._XML_NAME_PATTERN'),
|
||||||
|
'split_index_msg': (_index_entries.split_index_msg,
|
||||||
|
'sphinx.util.index_entries.split_index_msg'),
|
||||||
|
'split_into': (_index_entries.split_index_msg, 'sphinx.util.index_entries.split_into'),
|
||||||
'md5': (_md5, ''),
|
'md5': (_md5, ''),
|
||||||
'sha1': (_sha1, ''),
|
'sha1': (_sha1, ''),
|
||||||
}
|
}
|
||||||
|
25
sphinx/util/index_entries.py
Normal file
25
sphinx/util/index_entries.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
|
||||||
|
def split_index_msg(entry_type: str, value: str) -> list[str]:
|
||||||
|
# new entry types must be listed in util/nodes.py!
|
||||||
|
if entry_type == 'single':
|
||||||
|
try:
|
||||||
|
return _split_into(2, 'single', value)
|
||||||
|
except ValueError:
|
||||||
|
return _split_into(1, 'single', value)
|
||||||
|
if entry_type == 'pair':
|
||||||
|
return _split_into(2, 'pair', value)
|
||||||
|
if entry_type == 'triple':
|
||||||
|
return _split_into(3, 'triple', value)
|
||||||
|
if entry_type in {'see', 'seealso'}:
|
||||||
|
return _split_into(2, 'see', value)
|
||||||
|
raise ValueError(f'invalid {entry_type} index entry {value!r}')
|
||||||
|
|
||||||
|
|
||||||
|
def _split_into(n: int, type: str, value: str) -> list[str]:
|
||||||
|
"""Split an index entry into a given number of parts at semicolons."""
|
||||||
|
parts = [x.strip() for x in value.split(';', n - 1)]
|
||||||
|
if len(list(filter(None, parts))) < n:
|
||||||
|
raise ValueError(f'invalid {type} index entry {value!r}')
|
||||||
|
return parts
|
@ -20,8 +20,9 @@ from sphinx.domains import IndexEntry
|
|||||||
from sphinx.domains.std import StandardDomain
|
from sphinx.domains.std import StandardDomain
|
||||||
from sphinx.errors import SphinxError
|
from sphinx.errors import SphinxError
|
||||||
from sphinx.locale import _, __, admonitionlabels
|
from sphinx.locale import _, __, admonitionlabels
|
||||||
from sphinx.util import logging, split_into, texescape
|
from sphinx.util import logging, texescape
|
||||||
from sphinx.util.docutils import SphinxTranslator
|
from sphinx.util.docutils import SphinxTranslator
|
||||||
|
from sphinx.util.index_entries import split_index_msg
|
||||||
from sphinx.util.nodes import clean_astext, get_prev_node
|
from sphinx.util.nodes import clean_astext, get_prev_node
|
||||||
from sphinx.util.template import LaTeXRenderer
|
from sphinx.util.template import LaTeXRenderer
|
||||||
from sphinx.util.texescape import tex_replace_map
|
from sphinx.util.texescape import tex_replace_map
|
||||||
@ -1688,37 +1689,32 @@ class LaTeXTranslator(SphinxTranslator):
|
|||||||
if ismain:
|
if ismain:
|
||||||
m = '|spxpagem'
|
m = '|spxpagem'
|
||||||
try:
|
try:
|
||||||
|
parts = tuple(map(escape, split_index_msg(type, string)))
|
||||||
|
styled = tuple(map(style, parts))
|
||||||
if type == 'single':
|
if type == 'single':
|
||||||
try:
|
try:
|
||||||
p1, p2 = (escape(x) for x in split_into(2, 'single', string))
|
p1, p2 = parts
|
||||||
P1, P2 = style(p1), style(p2)
|
P1, P2 = styled
|
||||||
self.body.append(fr'\index{{{p1}@{P1}!{p2}@{P2}{m}}}')
|
self.body.append(fr'\index{{{p1}@{P1}!{p2}@{P2}{m}}}')
|
||||||
except ValueError:
|
except ValueError:
|
||||||
p = escape(split_into(1, 'single', string)[0])
|
p, = parts
|
||||||
P = style(p)
|
P, = styled
|
||||||
self.body.append(fr'\index{{{p}@{P}{m}}}')
|
self.body.append(fr'\index{{{p}@{P}{m}}}')
|
||||||
elif type == 'pair':
|
elif type == 'pair':
|
||||||
p1, p2 = (escape(x) for x in split_into(2, 'pair', string))
|
p1, p2 = parts
|
||||||
P1, P2 = style(p1), style(p2)
|
P1, P2 = styled
|
||||||
self.body.append(r'\index{%s@%s!%s@%s%s}\index{%s@%s!%s@%s%s}' %
|
self.body.append(fr'\index{{{p1}@{P1}!{p2}@{P2}{m}}}'
|
||||||
(p1, P1, p2, P2, m, p2, P2, p1, P1, m))
|
fr'\index{{{p2}@{P2}!{p1}@{P1}{m}}}')
|
||||||
elif type == 'triple':
|
elif type == 'triple':
|
||||||
p1, p2, p3 = (escape(x) for x in split_into(3, 'triple', string))
|
p1, p2, p3 = parts
|
||||||
P1, P2, P3 = style(p1), style(p2), style(p3)
|
P1, P2, P3 = styled
|
||||||
self.body.append(
|
self.body.append(
|
||||||
r'\index{%s@%s!%s %s@%s %s%s}'
|
fr'\index{{{p1}@{P1}!{p2} {p3}@{P2} {P3}{m}}}'
|
||||||
r'\index{%s@%s!%s, %s@%s, %s%s}'
|
fr'\index{{{p2}@{P2}!{p3}, {p1}@{P3}, {P1}{m}}}'
|
||||||
r'\index{%s@%s!%s %s@%s %s%s}' %
|
fr'\index{{{p3}@{P3}!{p1} {p2}@{P1} {P2}{m}}}')
|
||||||
(p1, P1, p2, p3, P2, P3, m,
|
elif type in {'see', 'seealso'}:
|
||||||
p2, P2, p3, p1, P3, P1, m,
|
p1, p2 = parts
|
||||||
p3, P3, p1, p2, P1, P2, m))
|
P1, _P2 = styled
|
||||||
elif type == 'see':
|
|
||||||
p1, p2 = (escape(x) for x in split_into(2, 'see', string))
|
|
||||||
P1 = style(p1)
|
|
||||||
self.body.append(fr'\index{{{p1}@{P1}|see{{{p2}}}}}')
|
|
||||||
elif type == 'seealso':
|
|
||||||
p1, p2 = (escape(x) for x in split_into(2, 'seealso', string))
|
|
||||||
P1 = style(p1)
|
|
||||||
self.body.append(fr'\index{{{p1}@{P1}|see{{{p2}}}}}')
|
self.body.append(fr'\index{{{p1}@{P1}|see{{{p2}}}}}')
|
||||||
else:
|
else:
|
||||||
logger.warning(__('unknown index entry type %s found'), type)
|
logger.warning(__('unknown index entry type %s found'), type)
|
||||||
|
Loading…
Reference in New Issue
Block a user