mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
The anchors for viewcode was generated in the reading phase only if supported builder is used. It causes anchors are missing on the incremental build after the build for non supported builder. This introduces `viewcode_anchor` node to insert the anchor even if non supported builders. They will be converted to the anchor tag in the resolving phase for supported builders. Or, they will be removed for non supported builders.
126 lines
4.8 KiB
Python
126 lines
4.8 KiB
Python
"""
|
|
test_ext_viewcode
|
|
~~~~~~~~~~~~~~~~~
|
|
|
|
Test sphinx.ext.viewcode extension.
|
|
|
|
:copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
|
|
:license: BSD, see LICENSE for details.
|
|
"""
|
|
|
|
import re
|
|
|
|
import pytest
|
|
|
|
|
|
@pytest.mark.sphinx(testroot='ext-viewcode')
|
|
def test_viewcode(app, status, warning):
|
|
app.builder.build_all()
|
|
|
|
warnings = re.sub(r'\\+', '/', warning.getvalue())
|
|
assert re.findall(
|
|
r"index.rst:\d+: WARNING: Object named 'func1' not found in include " +
|
|
r"file .*/spam/__init__.py'",
|
|
warnings
|
|
)
|
|
|
|
result = (app.outdir / 'index.html').read_text()
|
|
assert result.count('href="_modules/spam/mod1.html#func1"') == 2
|
|
assert result.count('href="_modules/spam/mod2.html#func2"') == 2
|
|
assert result.count('href="_modules/spam/mod1.html#Class1"') == 2
|
|
assert result.count('href="_modules/spam/mod2.html#Class2"') == 2
|
|
assert result.count('@decorator') == 1
|
|
|
|
# test that the class attribute is correctly documented
|
|
assert result.count('this is Class3') == 2
|
|
assert 'this is the class attribute class_attr' in result
|
|
# the next assert fails, until the autodoc bug gets fixed
|
|
assert result.count('this is the class attribute class_attr') == 2
|
|
|
|
result = (app.outdir / '_modules/spam/mod1.html').read_text()
|
|
result = re.sub('<span class=".*?">', '<span>', result) # filter pygments classes
|
|
assert ('<div class="viewcode-block" id="Class1"><a class="viewcode-back" '
|
|
'href="../../index.html#spam.Class1">[docs]</a>'
|
|
'<span>@decorator</span>\n'
|
|
'<span>class</span> <span>Class1</span>'
|
|
'<span>(</span><span>object</span><span>):</span>\n'
|
|
' <span>"""</span>\n'
|
|
'<span> this is Class1</span>\n'
|
|
'<span> """</span></div>\n') in result
|
|
|
|
|
|
@pytest.mark.sphinx('epub', testroot='ext-viewcode')
|
|
def test_viewcode_epub_default(app, status, warning):
|
|
app.builder.build_all()
|
|
|
|
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',
|
|
confoverrides={'viewcode_enable_epub': True})
|
|
def test_viewcode_epub_enabled(app, status, warning):
|
|
app.builder.build_all()
|
|
|
|
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'])
|
|
def test_linkcode(app, status, warning):
|
|
app.builder.build(['objects'])
|
|
|
|
stuff = (app.outdir / 'objects.html').read_text()
|
|
|
|
assert 'http://foobar/source/foolib.py' in stuff
|
|
assert 'http://foobar/js/' in stuff
|
|
assert 'http://foobar/c/' in stuff
|
|
assert 'http://foobar/cpp/' in stuff
|
|
|
|
|
|
@pytest.mark.sphinx(testroot='ext-viewcode-find')
|
|
def test_local_source_files(app, status, warning):
|
|
def find_source(app, modname):
|
|
if modname == 'not_a_package':
|
|
source = (app.srcdir / 'not_a_package/__init__.py').read_text()
|
|
tags = {
|
|
'func1': ('def', 1, 1),
|
|
'Class1': ('class', 1, 1),
|
|
'not_a_package.submodule.func1': ('def', 1, 1),
|
|
'not_a_package.submodule.Class1': ('class', 1, 1),
|
|
}
|
|
else:
|
|
source = (app.srcdir / 'not_a_package/submodule.py').read_text()
|
|
tags = {
|
|
'not_a_package.submodule.func1': ('def', 11, 15),
|
|
'Class1': ('class', 19, 22),
|
|
'not_a_package.submodule.Class1': ('class', 19, 22),
|
|
'Class3': ('class', 25, 30),
|
|
'not_a_package.submodule.Class3.class_attr': ('other', 29, 29),
|
|
}
|
|
return (source, tags)
|
|
|
|
app.connect('viewcode-find-source', find_source)
|
|
app.builder.build_all()
|
|
|
|
warnings = re.sub(r'\\+', '/', warning.getvalue())
|
|
assert re.findall(
|
|
r"index.rst:\d+: WARNING: Object named 'func1' not found in include " +
|
|
r"file .*/not_a_package/__init__.py'",
|
|
warnings
|
|
)
|
|
|
|
result = (app.outdir / 'index.html').read_text()
|
|
assert result.count('href="_modules/not_a_package.html#func1"') == 1
|
|
assert result.count('href="_modules/not_a_package.html#not_a_package.submodule.func1"') == 1
|
|
assert result.count('href="_modules/not_a_package/submodule.html#Class1"') == 1
|
|
assert result.count('href="_modules/not_a_package/submodule.html#Class3"') == 1
|
|
assert result.count('href="_modules/not_a_package/submodule.html#not_a_package.submodule.Class1"') == 1
|
|
|
|
assert result.count('href="_modules/not_a_package/submodule.html#not_a_package.submodule.Class3.class_attr"') == 1
|
|
assert result.count('This is the class attribute class_attr') == 1
|