Skip to content

Commit a6c3d9c

Browse files
committed
Fix viewcode test
Previously the viewcode test was doing string comparisons for HTML tags, this was not very robust and resulted in failures once the sphinx generated html added more attributes. The tests now utilize beautiful soup to find the tags and compares the text of the tags.
1 parent 299e321 commit a6c3d9c

File tree

4 files changed

+40
-21
lines changed

4 files changed

+40
-21
lines changed

src/sphinx_c_autodoc/__init__.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -286,9 +286,7 @@ def get_compilation_database(self) -> Optional[str]:
286286

287287
return None
288288

289-
def get_doc(
290-
self, encoding: Optional[str] = None, ignore: int = None
291-
) -> List[List[str]]:
289+
def get_doc(self, ignore: int = None) -> Optional[List[List[str]]]:
292290
"""Decode and return lines of the docstring(s) for the object."""
293291
docstring = self.object.get_doc()
294292
tab_width = self.directive.state.document.settings.tab_width

src/sphinx_c_autodoc/viewcode/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ def missing_reference(
9898
"""
9999
# pylint: disable=unused-argument
100100
if node["reftype"] == f"{C_DOMAIN_LINK_PREFIX}viewcode":
101+
assert app.builder is not None
101102
# We have to wait until here to see if the module actually exists as a
102103
# plain c directive could be reference a module before the auto c
103104
# directives are encountered.
@@ -135,6 +136,7 @@ def add_source_listings(app: Sphinx) -> Iterator[Tuple[str, Dict[str, Any], str]
135136
of the page, the name of the template to use for generating the final
136137
page.
137138
"""
139+
assert app.builder is not None
138140
modules_to_list = getattr(app.builder.env, "_viewcode_c_modules", {})
139141

140142
iterator = status_iterator(
@@ -189,6 +191,7 @@ def _insert_documentation_backlinks(
189191
code_listing (ViewCodeListing):
190192
Contains the documentation locations which documented `highlighted_code`.
191193
"""
194+
assert app.builder is not None
192195
for doc in code_listing.doc_links.values():
193196
construct = _find_construct(doc.fullname, code_listing.ast)
194197

@@ -411,6 +414,9 @@ def _add_pending_source_cross_reference(
411414
if module is None:
412415
return
413416

417+
assert app.builder is not None
418+
assert app.builder.env is not None
419+
414420
source_page = _get_source_page_name(module)
415421

416422
# Using the `viewcode-link` to be consistent with the python versions in
@@ -453,6 +459,9 @@ def _add_pending_back_reference(app: Sphinx, signode: Node, fullname: str) -> No
453459
if module is None:
454460
return
455461

462+
assert app.builder is not None
463+
assert app.builder.env is not None
464+
456465
env = app.builder.env
457466
code_listing = env._viewcode_c_modules.get(module) # type: ignore
458467
if code_listing is None:

tests/viewcode/test_viewcode.py

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import re
1111
import os
1212
from sphinx.cmd.build import main
13+
from bs4 import BeautifulSoup
1314

1415

1516
SCRIPT_DIR = os.path.dirname(__file__)
@@ -41,51 +42,61 @@ def test_viewcode_of_sphinx_project(tmp_path):
4142
with file_name.open() as f:
4243
contents = f.read()
4344

45+
# Looking for tags of the form
46+
#
47+
# <a class="reference internal" href="_modules/example.c.html#c.MY_COOL_MACRO"><span class="viewcode-link"><span class="pre">[source]</span></span></a>
4448
chosen_links = (
45-
'<dt id="c.MY_COOL_MACRO">',
46-
'<a class="reference internal" href="_modules/example.c.html#c.MY_COOL_MACRO"><span class="viewcode-link">[source]</span></a>',
47-
'<dt id="c.members_documented_with_napoleon.two.nested_two">',
48-
'<a class="reference internal" href="_modules/example.c.html#c.members_documented_with_napoleon.two.nested_two"><span class="viewcode-link">[source]</span></a>',
49+
"_modules/example.c.html#c.MY_COOL_MACRO",
50+
"_modules/example.c.html#c.members_documented_with_napoleon.two.nested_two",
4951
)
50-
for l in chosen_links:
51-
assert l in contents
52+
53+
soup = BeautifulSoup(contents)
54+
for href in chosen_links:
55+
tag = soup.find("a", {"href": href})
56+
assert "[source]" == tag.text
5257

5358
file_name = tmp_path / "sub_dir" / "file_2.html"
5459
with file_name.open() as f:
5560
contents = f.read()
5661

5762
chosen_links = (
58-
'<a class="reference internal" href="../_modules/file_2.c.html#c.unknown_member.foo"><span class="viewcode-link">[source]</span></a>',
59-
'<a class="reference internal" href="../_modules/file_2.c.html#c.file_level_variable"><span class="viewcode-link">[source]</span></a>',
63+
"../_modules/file_2.c.html#c.unknown_member.foo",
64+
"../_modules/file_2.c.html#c.file_level_variable",
6065
)
61-
for l in chosen_links:
62-
assert l in contents
66+
soup = BeautifulSoup(contents)
67+
for href in chosen_links:
68+
tag = soup.find("a", {"href": href})
69+
assert "[source]" == tag.text
6370

6471
# Test the back links
6572
file_name = tmp_path / "_modules" / "example.c.html"
6673
with file_name.open() as f:
6774
contents = f.read()
6875

6976
chosen_links = (
70-
'<div class="viewcode-block" id="c.members_documented_with_napoleon.two.nested_two"><a class="viewcode-back" href="../example.html#c.members_documented_with_napoleon.two.nested_two">[docs]</a>',
71-
'<div class="viewcode-block" id="c.MY_COOL_MACRO"><a class="viewcode-back" href="../example.html#c.MY_COOL_MACRO">[docs]</a>',
77+
"../example.html#c.members_documented_with_napoleon.two.nested_two",
78+
"../example.html#c.MY_COOL_MACRO",
7279
)
73-
for l in chosen_links:
74-
assert l in contents
80+
soup = BeautifulSoup(contents)
81+
for href in chosen_links:
82+
tag = soup.find("a", {"href": href})
83+
assert "[docs]" == tag.text
7584

7685
# Test normal C constructs elsewhere in docs
7786
file_name = tmp_path / "viewcode.html"
7887
with file_name.open() as f:
7988
contents = f.read()
8089

8190
chosen_links = (
82-
'<a class="reference internal" href="_modules/example.c.html#c.napoleon_documented_function"><span class="viewcode-link">[source]</span></a>',
91+
"_modules/example.c.html#c.napoleon_documented_function",
8392
# One needs to use noindex in order to avoid sphinx warning and once
8493
# one uses noindex then the permalinks are no longer generated :(
85-
# '<a class="headerlink" href="#c.napoleon_documented_function" title="Permalink to this definition">',
94+
# "#c.napoleon_documented_function"
8695
)
87-
for l in chosen_links:
88-
assert l in contents
96+
soup = BeautifulSoup(contents)
97+
for href in chosen_links:
98+
tag = soup.find("a", {"href": href})
99+
assert "[source]" == tag.text
89100

90101
# Ensure only the one function that actually had a source file to be able to link to creates a link
91102
link_count = len(re.findall("viewcode-link", contents))

tox.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ deps =
3333
# Lock clang back to a specific version for reliable github action builds
3434
clang==6.0
3535
sphinxcontrib.autoprogram
36+
types-docutils
3637
commands =
3738
pylint: pylint {toxinidir}/src/sphinx_c_autodoc -r n
3839
pycodestyle: pycodestyle {toxinidir}/src/sphinx_c_autodoc

0 commit comments

Comments
 (0)