mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge pull request #8707 from tk0miya/8704_viewcode_not_working
Fix #8704: viewcode: anchors are generated in incremental build
This commit is contained in:
commit
d5bc970dd9
2
CHANGES
2
CHANGES
@ -10,6 +10,7 @@ Incompatible changes
|
|||||||
Deprecated
|
Deprecated
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
* pending_xref node for viewcode extension
|
||||||
* ``sphinx.builders.linkcheck.CheckExternalLinksBuilder.broken``
|
* ``sphinx.builders.linkcheck.CheckExternalLinksBuilder.broken``
|
||||||
* ``sphinx.builders.linkcheck.CheckExternalLinksBuilder.good``
|
* ``sphinx.builders.linkcheck.CheckExternalLinksBuilder.good``
|
||||||
* ``sphinx.builders.linkcheck.CheckExternalLinksBuilder.redirected``
|
* ``sphinx.builders.linkcheck.CheckExternalLinksBuilder.redirected``
|
||||||
@ -69,6 +70,7 @@ Bugs fixed
|
|||||||
* #8094: texinfo: image files on the different directory with document are not
|
* #8094: texinfo: image files on the different directory with document are not
|
||||||
copied
|
copied
|
||||||
* #8720: viewcode: module pages are generated for epub on incremental build
|
* #8720: viewcode: module pages are generated for epub on incremental build
|
||||||
|
* #8704: viewcode: anchors are generated in incremental build after singlehtml
|
||||||
* #8671: :confval:`highlight_options` is not working
|
* #8671: :confval:`highlight_options` is not working
|
||||||
* #8341: C, fix intersphinx lookup types for names in declarations.
|
* #8341: C, fix intersphinx lookup types for names in declarations.
|
||||||
* C, C++: in general fix intersphinx and role lookup types.
|
* C, C++: in general fix intersphinx and role lookup types.
|
||||||
|
@ -26,6 +26,11 @@ The following is a list of deprecated interfaces.
|
|||||||
- (will be) Removed
|
- (will be) Removed
|
||||||
- Alternatives
|
- Alternatives
|
||||||
|
|
||||||
|
* - pending_xref node for viewcode extension
|
||||||
|
- 3.5
|
||||||
|
- 5.0
|
||||||
|
- ``sphinx.ext.viewcode.viewcode_anchor``
|
||||||
|
|
||||||
* - ``sphinx.builders.linkcheck.CheckExternalLinksBuilder.broken``
|
* - ``sphinx.builders.linkcheck.CheckExternalLinksBuilder.broken``
|
||||||
- 3.5
|
- 3.5
|
||||||
- 5.0
|
- 5.0
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
import posixpath
|
import posixpath
|
||||||
import traceback
|
import traceback
|
||||||
|
import warnings
|
||||||
from os import path
|
from os import path
|
||||||
from typing import Any, Dict, Generator, Iterable, Optional, Set, Tuple, cast
|
from typing import Any, Dict, Generator, Iterable, Optional, Set, Tuple, cast
|
||||||
|
|
||||||
@ -19,10 +20,13 @@ from docutils.nodes import Element, Node
|
|||||||
import sphinx
|
import sphinx
|
||||||
from sphinx import addnodes
|
from sphinx import addnodes
|
||||||
from sphinx.application import Sphinx
|
from sphinx.application import Sphinx
|
||||||
|
from sphinx.builders import Builder
|
||||||
from sphinx.builders.html import StandaloneHTMLBuilder
|
from sphinx.builders.html import StandaloneHTMLBuilder
|
||||||
|
from sphinx.deprecation import RemovedInSphinx50Warning
|
||||||
from sphinx.environment import BuildEnvironment
|
from sphinx.environment import BuildEnvironment
|
||||||
from sphinx.locale import _, __
|
from sphinx.locale import _, __
|
||||||
from sphinx.pycode import ModuleAnalyzer
|
from sphinx.pycode import ModuleAnalyzer
|
||||||
|
from sphinx.transforms.post_transforms import SphinxPostTransform
|
||||||
from sphinx.util import get_full_modname, logging, status_iterator
|
from sphinx.util import get_full_modname, logging, status_iterator
|
||||||
from sphinx.util.nodes import make_refnode
|
from sphinx.util.nodes import make_refnode
|
||||||
|
|
||||||
@ -32,6 +36,15 @@ logger = logging.getLogger(__name__)
|
|||||||
OUTPUT_DIRNAME = '_modules'
|
OUTPUT_DIRNAME = '_modules'
|
||||||
|
|
||||||
|
|
||||||
|
class viewcode_anchor(Element):
|
||||||
|
"""Node for viewcode anchors.
|
||||||
|
|
||||||
|
This node will be processed in the resolving phase.
|
||||||
|
For viewcode supported builders, they will be all converted to the anchors.
|
||||||
|
For not supported builders, they will be removed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
def _get_full_modname(app: Sphinx, modname: str, attribute: str) -> Optional[str]:
|
def _get_full_modname(app: Sphinx, modname: str, attribute: str) -> Optional[str]:
|
||||||
try:
|
try:
|
||||||
return get_full_modname(modname, attribute)
|
return get_full_modname(modname, attribute)
|
||||||
@ -50,14 +63,21 @@ def _get_full_modname(app: Sphinx, modname: str, attribute: str) -> Optional[str
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def is_supported_builder(builder: Builder) -> bool:
|
||||||
|
if builder.format != 'html':
|
||||||
|
return False
|
||||||
|
elif builder.name == 'singlehtml':
|
||||||
|
return False
|
||||||
|
elif builder.name.startswith('epub') and not builder.config.viewcode_enable_epub:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def doctree_read(app: Sphinx, doctree: Node) -> None:
|
def doctree_read(app: Sphinx, doctree: Node) -> None:
|
||||||
env = app.builder.env
|
env = app.builder.env
|
||||||
if not hasattr(env, '_viewcode_modules'):
|
if not hasattr(env, '_viewcode_modules'):
|
||||||
env._viewcode_modules = {} # type: ignore
|
env._viewcode_modules = {} # type: ignore
|
||||||
if app.builder.name == "singlehtml":
|
|
||||||
return
|
|
||||||
if app.builder.name.startswith("epub") and not env.config.viewcode_enable_epub:
|
|
||||||
return
|
|
||||||
|
|
||||||
def has_tag(modname: str, fullname: str, docname: str, refname: str) -> bool:
|
def has_tag(modname: str, fullname: str, docname: str, refname: str) -> bool:
|
||||||
entry = env._viewcode_modules.get(modname, None) # type: ignore
|
entry = env._viewcode_modules.get(modname, None) # type: ignore
|
||||||
@ -115,12 +135,7 @@ def doctree_read(app: Sphinx, doctree: Node) -> None:
|
|||||||
continue
|
continue
|
||||||
names.add(fullname)
|
names.add(fullname)
|
||||||
pagename = posixpath.join(OUTPUT_DIRNAME, modname.replace('.', '/'))
|
pagename = posixpath.join(OUTPUT_DIRNAME, modname.replace('.', '/'))
|
||||||
inline = nodes.inline('', _('[source]'), classes=['viewcode-link'])
|
signode += viewcode_anchor(reftarget=pagename, refid=fullname, refdoc=env.docname)
|
||||||
onlynode = addnodes.only(expr='html')
|
|
||||||
onlynode += addnodes.pending_xref('', inline, reftype='viewcode', refdomain='std',
|
|
||||||
refexplicit=False, reftarget=pagename,
|
|
||||||
refid=fullname, refdoc=env.docname)
|
|
||||||
signode += onlynode
|
|
||||||
|
|
||||||
|
|
||||||
def env_merge_info(app: Sphinx, env: BuildEnvironment, docnames: Iterable[str],
|
def env_merge_info(app: Sphinx, env: BuildEnvironment, docnames: Iterable[str],
|
||||||
@ -134,10 +149,34 @@ def env_merge_info(app: Sphinx, env: BuildEnvironment, docnames: Iterable[str],
|
|||||||
env._viewcode_modules.update(other._viewcode_modules) # type: ignore
|
env._viewcode_modules.update(other._viewcode_modules) # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
class ViewcodeAnchorTransform(SphinxPostTransform):
|
||||||
|
"""Convert or remove viewcode_anchor nodes depends on builder."""
|
||||||
|
default_priority = 100
|
||||||
|
|
||||||
|
def run(self, **kwargs: Any) -> None:
|
||||||
|
if is_supported_builder(self.app.builder):
|
||||||
|
self.convert_viewcode_anchors()
|
||||||
|
else:
|
||||||
|
self.remove_viewcode_anchors()
|
||||||
|
|
||||||
|
def convert_viewcode_anchors(self) -> None:
|
||||||
|
for node in self.document.traverse(viewcode_anchor):
|
||||||
|
anchor = nodes.inline('', _('[source]'), classes=['viewcode-link'])
|
||||||
|
refnode = make_refnode(self.app.builder, node['refdoc'], node['reftarget'],
|
||||||
|
node['refid'], anchor)
|
||||||
|
node.replace_self(refnode)
|
||||||
|
|
||||||
|
def remove_viewcode_anchors(self) -> None:
|
||||||
|
for node in self.document.traverse(viewcode_anchor):
|
||||||
|
node.parent.remove(node)
|
||||||
|
|
||||||
|
|
||||||
def missing_reference(app: Sphinx, env: BuildEnvironment, node: Element, contnode: Node
|
def missing_reference(app: Sphinx, env: BuildEnvironment, node: Element, contnode: Node
|
||||||
) -> Optional[Node]:
|
) -> Optional[Node]:
|
||||||
# resolve our "viewcode" reference nodes -- they need special treatment
|
# resolve our "viewcode" reference nodes -- they need special treatment
|
||||||
if node['reftype'] == 'viewcode':
|
if node['reftype'] == 'viewcode':
|
||||||
|
warnings.warn('viewcode extension is no longer use pending_xref node. '
|
||||||
|
'Please update your extension.', RemovedInSphinx50Warning)
|
||||||
return make_refnode(app.builder, node['refdoc'], node['reftarget'],
|
return make_refnode(app.builder, node['refdoc'], node['reftarget'],
|
||||||
node['refid'], contnode)
|
node['refid'], contnode)
|
||||||
|
|
||||||
@ -182,9 +221,7 @@ def collect_pages(app: Sphinx) -> Generator[Tuple[str, Dict[str, Any], str], Non
|
|||||||
env = app.builder.env
|
env = app.builder.env
|
||||||
if not hasattr(env, '_viewcode_modules'):
|
if not hasattr(env, '_viewcode_modules'):
|
||||||
return
|
return
|
||||||
if app.builder.name == "singlehtml":
|
if not is_supported_builder(app.builder):
|
||||||
return
|
|
||||||
if app.builder.name.startswith("epub") and not env.config.viewcode_enable_epub:
|
|
||||||
return
|
return
|
||||||
highlighter = app.builder.highlighter # type: ignore
|
highlighter = app.builder.highlighter # type: ignore
|
||||||
urito = app.builder.get_relative_uri
|
urito = app.builder.get_relative_uri
|
||||||
@ -292,6 +329,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
|||||||
# app.add_config_value('viewcode_exclude_modules', [], 'env')
|
# app.add_config_value('viewcode_exclude_modules', [], 'env')
|
||||||
app.add_event('viewcode-find-source')
|
app.add_event('viewcode-find-source')
|
||||||
app.add_event('viewcode-follow-imported')
|
app.add_event('viewcode-follow-imported')
|
||||||
|
app.add_post_transform(ViewcodeAnchorTransform)
|
||||||
return {
|
return {
|
||||||
'version': sphinx.__display_version__,
|
'version': sphinx.__display_version__,
|
||||||
'env_version': 1,
|
'env_version': 1,
|
||||||
|
@ -55,6 +55,9 @@ def test_viewcode_epub_default(app, status, warning):
|
|||||||
|
|
||||||
assert not (app.outdir / '_modules/spam/mod1.xhtml').exists()
|
assert not (app.outdir / '_modules/spam/mod1.xhtml').exists()
|
||||||
|
|
||||||
|
result = (app.outdir / 'index.xhtml').read_text()
|
||||||
|
assert result.count('href="_modules/spam/mod1.xhtml#func1"') == 0
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.sphinx('epub', testroot='ext-viewcode',
|
@pytest.mark.sphinx('epub', testroot='ext-viewcode',
|
||||||
confoverrides={'viewcode_enable_epub': True})
|
confoverrides={'viewcode_enable_epub': True})
|
||||||
@ -63,6 +66,9 @@ def test_viewcode_epub_enabled(app, status, warning):
|
|||||||
|
|
||||||
assert (app.outdir / '_modules/spam/mod1.xhtml').exists()
|
assert (app.outdir / '_modules/spam/mod1.xhtml').exists()
|
||||||
|
|
||||||
|
result = (app.outdir / 'index.xhtml').read_text()
|
||||||
|
assert result.count('href="_modules/spam/mod1.xhtml#func1"') == 2
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.sphinx(testroot='ext-viewcode', tags=['test_linkcode'])
|
@pytest.mark.sphinx(testroot='ext-viewcode', tags=['test_linkcode'])
|
||||||
def test_linkcode(app, status, warning):
|
def test_linkcode(app, status, warning):
|
||||||
|
Loading…
Reference in New Issue
Block a user