Skip to content

Commit 7c2f54c

Browse files
committed
Create extension tests (#6)
1 parent 61e2412 commit 7c2f54c

24 files changed

+429
-13
lines changed

src/sphinx_codeautolink/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@
1010

1111
_version_file = _Path(_os.path.realpath(__file__)).parent / "VERSION"
1212
__version__ = _version_file.read_text().strip()
13-
state = SphinxCodeAutoLink()
1413

1514

1615
def setup(app: Sphinx):
1716
"""Set up extension, directives and events."""
17+
state = SphinxCodeAutoLink()
1818
app.add_css_file('sphinx-codeautolink.css')
1919
app.add_config_value('codeautolink_autodoc_inject', True, 'html', types=[bool])
2020

src/sphinx_codeautolink/extension/__init__.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,6 @@ def once_on_doctree_resolved(self, app):
7070

7171
for transforms in self.cache.transforms.values():
7272
self.filter_and_resolve(transforms, app)
73-
74-
for transforms in self.cache.transforms.values():
7573
for transform in transforms:
7674
for name in transform.names:
7775
self.code_refs.setdefault(name.resolved_location, []).append(
@@ -179,7 +177,7 @@ def resolve_location(chain: Name) -> Optional[str]:
179177
def locate_type(components: Tuple[str]) -> Optional[str]:
180178
"""Find type hint and resolve to new location."""
181179
value, index = closest_module(components)
182-
if index is None or index == len(components) - 1:
180+
if index is None or index == len(components):
183181
return
184182
remaining = components[index:]
185183
real_location = '.'.join(components[:index])
@@ -214,8 +212,12 @@ def fully_qualified_name(type_: type) -> str:
214212
def closest_module(components: Tuple[str]) -> Tuple[Any, Optional[int]]:
215213
"""Find closest importable module."""
216214
mod = None
217-
for i in range(len(components)):
215+
for i in range(1, len(components) + 1):
218216
try:
219-
mod = import_module('.'.join(components[:i + 1]))
217+
mod = import_module('.'.join(components[:i]))
220218
except ImportError:
221-
return mod, i
219+
break
220+
else:
221+
return None, None
222+
223+
return mod, i - 1

src/sphinx_codeautolink/extension/block.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def __init__(self, *args, source_dir: str, **kwargs):
4242
self.title_stack = []
4343
self.current_refid = None
4444
self.implicit_imports = []
45-
self.concat_global = 'off'
45+
self.concat_global = False
4646
self.concat_section = False
4747
self.concat_sources = []
4848
self.autolink_skip = None
@@ -60,7 +60,8 @@ def unknown_visit(self, node):
6060
if node.mode == 'section':
6161
self.concat_section = True
6262
else:
63-
self.concat_global = node.mode
63+
self.concat_section = False
64+
self.concat_global = (node.mode == 'on')
6465
node.parent.remove(node)
6566
elif isinstance(node, ImplicitImportMarker):
6667
if '\n' in node.content:
@@ -143,7 +144,7 @@ def visit_literal_block(self, node: nodes.literal_block):
143144
name.lineno -= hidden_len
144145
name.end_lineno -= hidden_len
145146

146-
if self.concat_section or self.concat_global == 'on':
147+
if self.concat_section or self.concat_global:
147148
self.concat_sources.extend(implicit_imports + [source])
148149

149150
for name in names:

src/sphinx_codeautolink/extension/directive.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,13 @@ class ConcatBlocks(Directive):
5858
"""Toggle and cut literal block concatenation in a document."""
5959

6060
has_content = False
61-
required_arguments = 1
62-
optional_arguments = 0
61+
required_arguments = 0
62+
optional_arguments = 1
6363

6464
def run(self):
6565
"""Insert :class:`ConcatBlocksMarker`."""
66-
return [ConcatBlocksMarker(self.arguments[0])]
66+
arg = self.arguments[0] if self.arguments else 'on'
67+
return [ConcatBlocksMarker(arg)]
6768

6869

6970
class ImplicitImportMarker(nodes.Element):

tests/extension/__init__.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"""
2+
Basic extension tests.
3+
4+
The tests are structured as .txt files, parsed and executed here.
5+
The structure of the file is::
6+
7+
number of expected autolinks
8+
# split
9+
lines to add to the default conf.py
10+
# split
11+
index.html content
12+
"""
13+
import sys
14+
import pytest
15+
16+
from pathlib import Path
17+
from bs4 import BeautifulSoup
18+
from sphinx.cmd.build import main as sphinx_main
19+
20+
# Insert test package root to path for all tests
21+
sys.path.insert(0, str(Path(__file__).parent / "src"))
22+
23+
default_conf = """
24+
extensions = [
25+
"sphinx.ext.autodoc",
26+
"sphinx_codeautolink",
27+
]
28+
29+
autodoc_default_options = {
30+
"members": True,
31+
"undoc-members": True,
32+
}
33+
"""
34+
35+
txt_tests = list(Path(__file__).parent.glob('*.txt'))
36+
37+
38+
@pytest.mark.parametrize('file', txt_tests)
39+
def test_extension(file: Path, tmp_path: Path):
40+
n_links, conf, index = file.read_text('utf-8').split('# split')
41+
src_dir = tmp_path / 'src'
42+
src_dir.mkdir()
43+
(src_dir / 'conf.py').write_text(default_conf + conf, 'utf-8')
44+
(src_dir / 'index.rst').write_text(index, 'utf-8')
45+
46+
build_dir = tmp_path / 'build'
47+
sphinx_main(['-M', 'html', str(src_dir), str(build_dir)])
48+
49+
index_html = build_dir / 'html' / 'index.html'
50+
text = index_html.read_text('utf-8')
51+
soup = BeautifulSoup(text, 'html.parser')
52+
blocks = soup.find_all('a', attrs={'class': 'sphinx-codeautolink-a'})
53+
assert len(blocks) == int(n_links.strip())

tests/extension/concat_off.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
1
2+
# split
3+
# split
4+
Test project
5+
============
6+
7+
.. concat-blocks::
8+
.. code:: python
9+
10+
import test_project
11+
12+
test_project.bar()
13+
14+
.. concat-blocks:: off
15+
.. code:: python
16+
17+
test_project.Foo
18+
19+
.. automodule:: test_project
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
3
2+
# split
3+
# split
4+
Test project
5+
============
6+
7+
.. concat-blocks:: on
8+
.. code:: python
9+
10+
import test_project
11+
12+
test_project.bar()
13+
14+
.. code:: python
15+
16+
test_project.Foo
17+
18+
Subsection
19+
----------
20+
21+
.. code:: python
22+
23+
test_project.Baz
24+
25+
.. automodule:: test_project
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
1
2+
# split
3+
# split
4+
Test project
5+
============
6+
7+
.. concat-blocks:: on
8+
.. code:: python
9+
10+
import test_project
11+
12+
test_project.bar()
13+
14+
.. concat-blocks:: on
15+
16+
.. code:: python
17+
18+
test_project.Foo
19+
20+
.. automodule:: test_project
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2
2+
# split
3+
# split
4+
Test project
5+
============
6+
7+
.. concat-blocks:: section
8+
9+
.. code:: python
10+
11+
import test_project
12+
13+
test_project.bar()
14+
15+
.. code:: python
16+
17+
test_project.Foo
18+
19+
Subsection
20+
----------
21+
22+
.. code:: python
23+
24+
test_project.Baz
25+
26+
.. automodule:: test_project
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
3
2+
# split
3+
# split
4+
Test project
5+
============
6+
7+
.. concat-blocks::
8+
.. concat-blocks:: section
9+
10+
.. code:: python
11+
12+
import test_project
13+
14+
test_project.bar()
15+
16+
.. code:: python
17+
18+
test_project.Foo
19+
20+
Subsection
21+
----------
22+
23+
.. code:: python
24+
25+
import test_project
26+
27+
.. code:: python
28+
29+
test_project.Baz
30+
31+
.. automodule:: test_project

0 commit comments

Comments
 (0)