Skip to content

Fix #9240: Unknown node error for pending_xref_condition is raised #9246

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Incompatible changes
* #9222: Update Underscore.js to 1.13.1
* #9217: manpage: Stop creating a section directory on build manpage by default
(see :confval:`man_make_section_directory`)
* #9240: Unknown node error for pending_xref_condition is raised if an extension
Copy link
Contributor

@ruro ruro May 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tk0miya I just noticed, that you put this in the Incompatible changes section instead of Bugs fixed. Also, this should probably read "Unknown node error for pending_xref_condition is no longer raised if ...".

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, it's my wrong...

that does not support the node installs a missing-reference handler

Deprecated
----------
Expand Down
28 changes: 19 additions & 9 deletions sphinx/transforms/post_transforms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
:license: BSD, see LICENSE for details.
"""

from typing import Any, Dict, List, Optional, Tuple, Type, cast
from typing import Any, Dict, List, Optional, Sequence, Tuple, Type, cast

from docutils import nodes
from docutils.nodes import Element
from docutils.nodes import Element, Node

from sphinx import addnodes
from sphinx.addnodes import pending_xref
Expand All @@ -26,10 +26,6 @@

logger = logging.getLogger(__name__)

if False:
# For type annotation
from docutils.nodes import Node


class SphinxPostTransform(SphinxTransform):
"""A base class of post-transforms.
Expand Down Expand Up @@ -71,7 +67,12 @@ class ReferencesResolver(SphinxPostTransform):

def run(self, **kwargs: Any) -> None:
for node in self.document.traverse(addnodes.pending_xref):
contnode = cast(nodes.TextElement, node[0].deepcopy())
content = self.find_pending_xref_condition(node, ("resolved", "*"))
if content:
contnode = cast(Element, content[0].deepcopy())
else:
contnode = cast(Element, node[0].deepcopy())

newnode = None

typ = node['reftype']
Expand Down Expand Up @@ -108,9 +109,9 @@ def run(self, **kwargs: Any) -> None:
else:
newnodes = [contnode]
if newnode is None and isinstance(node[0], addnodes.pending_xref_condition):
matched = find_pending_xref_condition(node, "*")
matched = self.find_pending_xref_condition(node, ("*",))
if matched:
newnodes = matched.children
newnodes = matched
else:
logger.warning(__('Could not determine the fallback text for the '
'cross-reference. Might be a bug.'), location=node)
Expand Down Expand Up @@ -193,6 +194,15 @@ def warn_missing_reference(self, refdoc: str, typ: str, target: str,
msg = __('%r reference target not found: %s') % (typ, target)
logger.warning(msg, location=node, type='ref', subtype=typ)

def find_pending_xref_condition(self, node: pending_xref, conditions: Sequence[str]
) -> Optional[List[Node]]:
for condition in conditions:
matched = find_pending_xref_condition(node, condition)
if matched:
return matched.children
else:
return None


class OnlyNodeTransform(SphinxPostTransform):
default_priority = 50
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nitpicky = True
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
transforms-post_transforms-missing-reference
============================================

:class:`io.StringIO`

58 changes: 58 additions & 0 deletions tests/test_transforms_post_transforms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"""
test_transforms_post_transforms
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Tests the post_transforms

:copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

import pytest
from docutils import nodes


@pytest.mark.sphinx('html', testroot='transforms-post_transforms-missing-reference')
def test_nitpicky_warning(app, status, warning):
app.build()
assert ('index.rst:4: WARNING: py:class reference target '
'not found: io.StringIO' in warning.getvalue())

content = (app.outdir / 'index.html').read_text()
assert ('<p><code class="xref py py-class docutils literal notranslate"><span class="pre">'
'io.StringIO</span></code></p>' in content)


@pytest.mark.sphinx('html', testroot='transforms-post_transforms-missing-reference',
freshenv=True)
def test_missing_reference(app, status, warning):
def missing_reference(app, env, node, contnode):
assert app is app
assert env is app.env
assert node['reftarget'] == 'io.StringIO'
assert contnode.astext() == 'io.StringIO'

return nodes.inline('', 'missing-reference.StringIO')

warning.truncate(0)
app.connect('missing-reference', missing_reference)
app.build()
assert warning.getvalue() == ''

content = (app.outdir / 'index.html').read_text()
assert '<p><span>missing-reference.StringIO</span></p>' in content


@pytest.mark.sphinx('html', testroot='domain-py-python_use_unqualified_type_names',
freshenv=True)
def test_missing_reference_conditional_pending_xref(app, status, warning):
def missing_reference(app, env, node, contnode):
return contnode

warning.truncate(0)
app.connect('missing-reference', missing_reference)
app.build()
assert warning.getvalue() == ''

content = (app.outdir / 'index.html').read_text()
assert '<span class="n"><span class="pre">Age</span></span>' in content