fixup! sphinx.ext.extlinks: Allow `%s` in link caption string

The old syntax will be deprecated in 4.x and 5.x and removed in Sphinx
6.0.
This commit is contained in:
Merry Bass 2021-04-09 12:24:15 +02:00 committed by Takeshi KOMIYA
parent 75605d437f
commit 93cf1a57d9

View File

@ -19,10 +19,13 @@
You can also give an explicit caption, e.g. :exmpl:`Foo <foo>`. You can also give an explicit caption, e.g. :exmpl:`Foo <foo>`.
Both, the url string and the caption string must escape ``%`` as ``%%``.
:copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
import warnings
from typing import Any, Dict, List, Tuple from typing import Any, Dict, List, Tuple
from docutils import nodes, utils from docutils import nodes, utils
@ -31,36 +34,44 @@ from docutils.parsers.rst.states import Inliner
import sphinx import sphinx
from sphinx.application import Sphinx from sphinx.application import Sphinx
from sphinx.deprecation import RemovedInSphinx60Warning
from sphinx.util.nodes import split_explicit_title from sphinx.util.nodes import split_explicit_title
from sphinx.util.typing import RoleFunction from sphinx.util.typing import RoleFunction
def make_link_role(base_url: str, caption: str) -> RoleFunction: def make_link_role(name: str, base_url: str, caption: str) -> RoleFunction:
# Check whether we have base_url and caption strings have an '%s' for
# expansion. If not, fall back the the old behaviour and use the string as
# a prefix.
# Remark: It is an implementation detail that we use Pythons %-formatting.
# So far we only expose ``%s`` and require quoting of ``%`` using ``%%``.
try:
base_url % 'dummy'
except (TypeError, ValueError):
warnings.warn('extlinks: Sphinx-6.0 will require base URL to '
'contain exactly one \'%s\' and all other \'%\' need '
'to be escaped as \'%%\'.', RemovedInSphinx60Warning)
base_url = base_url.replace('%', '%%') + '%s'
if caption is not None:
try:
caption % 'dummy'
except (TypeError, ValueError):
warnings.warn('extlinks: Sphinx-6.0 will require a caption string to '
'contain exactly one \'%s\' and all other \'%\' need '
'to be escaped as \'%%\'.', RemovedInSphinx60Warning)
caption = caption.replace('%', '%%') + '%s'
def role(typ: str, rawtext: str, text: str, lineno: int, def role(typ: str, rawtext: str, text: str, lineno: int,
inliner: Inliner, options: Dict = {}, content: List[str] = [] inliner: Inliner, options: Dict = {}, content: List[str] = []
) -> Tuple[List[Node], List[system_message]]: ) -> Tuple[List[Node], List[system_message]]:
text = utils.unescape(text) text = utils.unescape(text)
has_explicit_title, title, part = split_explicit_title(text) has_explicit_title, title, part = split_explicit_title(text)
try: full_url = base_url % part
full_url = base_url % part
except (TypeError, ValueError):
inliner.reporter.warning(
'unable to expand %s extlink with base URL %r, please make '
'sure the base contains \'%%s\' exactly once'
% (typ, base_url), line=lineno)
full_url = base_url + part
if not has_explicit_title: if not has_explicit_title:
if caption is None: if caption is None:
title = full_url title = full_url
else: else:
try: title = caption % part
title = caption % part
except (TypeError, ValueError):
inliner.reporter.warning(
'unable to expand %s extlink with caption %r, please make '
'sure the caption contains \'%%s\' exactly once'
% (typ, caption), line=lineno)
title = caption + part
pnode = nodes.reference(title, title, internal=False, refuri=full_url) pnode = nodes.reference(title, title, internal=False, refuri=full_url)
return [pnode], [] return [pnode], []
return role return role
@ -68,7 +79,7 @@ def make_link_role(base_url: str, caption: str) -> RoleFunction:
def setup_link_roles(app: Sphinx) -> None: def setup_link_roles(app: Sphinx) -> None:
for name, (base_url, caption) in app.config.extlinks.items(): for name, (base_url, caption) in app.config.extlinks.items():
app.add_role(name, make_link_role(base_url, caption)) app.add_role(name, make_link_role(name, base_url, caption))
def setup(app: Sphinx) -> Dict[str, Any]: def setup(app: Sphinx) -> Dict[str, Any]: