2014-11-06 02:11:20 -06:00
|
|
|
"""Test the sphinx.apidoc module."""
|
|
|
|
|
2023-07-27 18:39:12 -05:00
|
|
|
import os.path
|
2017-01-03 07:24:00 -06:00
|
|
|
from collections import namedtuple
|
2024-06-20 06:12:37 -05:00
|
|
|
from pathlib import Path
|
2014-11-06 02:11:20 -06:00
|
|
|
|
2017-01-03 07:24:00 -06:00
|
|
|
import pytest
|
2014-11-06 02:11:20 -06:00
|
|
|
|
2022-05-01 00:12:25 -05:00
|
|
|
import sphinx.ext.apidoc
|
2017-07-11 10:24:07 -05:00
|
|
|
from sphinx.ext.apidoc import main as apidoc_main
|
2014-11-06 02:11:20 -06:00
|
|
|
|
2017-01-03 07:24:00 -06:00
|
|
|
|
2024-07-10 08:13:10 -05:00
|
|
|
@pytest.fixture
|
2023-07-27 18:39:12 -05:00
|
|
|
def apidoc(rootdir, tmp_path, apidoc_params):
|
2017-01-03 07:24:00 -06:00
|
|
|
_, kwargs = apidoc_params
|
2017-05-07 02:46:44 -05:00
|
|
|
coderoot = rootdir / kwargs.get('coderoot', 'test-root')
|
2023-07-27 18:39:12 -05:00
|
|
|
outdir = tmp_path / 'out'
|
|
|
|
excludes = [str(coderoot / e) for e in kwargs.get('excludes', [])]
|
2024-03-14 05:26:30 -05:00
|
|
|
args = ['-o', str(outdir), '-F', str(coderoot), *excludes, *kwargs.get('options', [])]
|
2017-01-03 07:24:00 -06:00
|
|
|
apidoc_main(args)
|
|
|
|
return namedtuple('apidoc', 'coderoot,outdir')(coderoot, outdir)
|
|
|
|
|
|
|
|
|
2024-07-10 08:13:10 -05:00
|
|
|
@pytest.fixture
|
2017-01-03 07:24:00 -06:00
|
|
|
def apidoc_params(request):
|
|
|
|
pargs = {}
|
|
|
|
kwargs = {}
|
|
|
|
|
2022-04-22 01:29:53 -05:00
|
|
|
for info in reversed(list(request.node.iter_markers("apidoc"))):
|
2024-01-03 22:01:52 -06:00
|
|
|
pargs |= dict(enumerate(info.args))
|
2022-04-22 01:29:53 -05:00
|
|
|
kwargs.update(info.kwargs)
|
2014-11-06 02:11:20 -06:00
|
|
|
|
2017-01-03 07:24:00 -06:00
|
|
|
args = [pargs[i] for i in sorted(pargs.keys())]
|
|
|
|
return args, kwargs
|
|
|
|
|
|
|
|
|
2017-05-07 02:46:44 -05:00
|
|
|
@pytest.mark.apidoc(coderoot='test-root')
|
2017-01-03 07:24:00 -06:00
|
|
|
def test_simple(make_app, apidoc):
|
|
|
|
outdir = apidoc.outdir
|
2023-07-27 18:39:12 -05:00
|
|
|
assert (outdir / 'conf.py').is_file()
|
|
|
|
assert (outdir / 'index.rst').is_file()
|
2014-11-06 02:11:20 -06:00
|
|
|
|
2017-01-03 07:24:00 -06:00
|
|
|
app = make_app('text', srcdir=outdir)
|
|
|
|
app.build()
|
|
|
|
print(app._status.getvalue())
|
|
|
|
print(app._warning.getvalue())
|
2015-12-25 00:52:51 -06:00
|
|
|
|
2016-09-12 17:17:03 -05:00
|
|
|
|
2017-01-03 07:24:00 -06:00
|
|
|
@pytest.mark.apidoc(
|
2017-07-29 00:59:51 -05:00
|
|
|
coderoot='test-apidoc-pep420/a',
|
2017-01-03 07:24:00 -06:00
|
|
|
options=["--implicit-namespaces"],
|
|
|
|
)
|
|
|
|
def test_pep_0420_enabled(make_app, apidoc):
|
|
|
|
outdir = apidoc.outdir
|
2023-07-27 18:39:12 -05:00
|
|
|
assert (outdir / 'conf.py').is_file()
|
|
|
|
assert (outdir / 'a.b.c.rst').is_file()
|
|
|
|
assert (outdir / 'a.b.e.rst').is_file()
|
|
|
|
assert (outdir / 'a.b.x.rst').is_file()
|
2016-09-12 17:17:03 -05:00
|
|
|
|
2022-04-17 20:32:06 -05:00
|
|
|
with open(outdir / 'a.b.c.rst', encoding='utf-8') as f:
|
2016-09-12 17:17:03 -05:00
|
|
|
rst = f.read()
|
|
|
|
assert "automodule:: a.b.c.d\n" in rst
|
|
|
|
assert "automodule:: a.b.c\n" in rst
|
|
|
|
|
2022-04-17 20:32:06 -05:00
|
|
|
with open(outdir / 'a.b.e.rst', encoding='utf-8') as f:
|
2018-01-17 14:34:33 -06:00
|
|
|
rst = f.read()
|
|
|
|
assert "automodule:: a.b.e.f\n" in rst
|
|
|
|
|
2022-04-17 20:32:06 -05:00
|
|
|
with open(outdir / 'a.b.x.rst', encoding='utf-8') as f:
|
2016-09-12 17:17:03 -05:00
|
|
|
rst = f.read()
|
|
|
|
assert "automodule:: a.b.x.y\n" in rst
|
|
|
|
assert "automodule:: a.b.x\n" not in rst
|
|
|
|
|
2017-01-03 07:24:00 -06:00
|
|
|
app = make_app('text', srcdir=outdir)
|
|
|
|
app.build()
|
|
|
|
print(app._status.getvalue())
|
|
|
|
print(app._warning.getvalue())
|
2016-09-12 17:17:03 -05:00
|
|
|
|
2017-03-24 04:53:01 -05:00
|
|
|
builddir = outdir / '_build' / 'text'
|
2023-07-27 18:39:12 -05:00
|
|
|
assert (builddir / 'a.b.c.txt').is_file()
|
|
|
|
assert (builddir / 'a.b.e.txt').is_file()
|
|
|
|
assert (builddir / 'a.b.x.txt').is_file()
|
2018-01-17 14:34:33 -06:00
|
|
|
|
2022-04-17 20:32:06 -05:00
|
|
|
with open(builddir / 'a.b.c.txt', encoding='utf-8') as f:
|
2018-01-17 14:34:33 -06:00
|
|
|
txt = f.read()
|
|
|
|
assert "a.b.c package\n" in txt
|
|
|
|
|
2022-04-17 20:32:06 -05:00
|
|
|
with open(builddir / 'a.b.e.txt', encoding='utf-8') as f:
|
2018-01-17 14:34:33 -06:00
|
|
|
txt = f.read()
|
|
|
|
assert "a.b.e.f module\n" in txt
|
|
|
|
|
2022-04-17 20:32:06 -05:00
|
|
|
with open(builddir / 'a.b.x.txt', encoding='utf-8') as f:
|
2018-01-17 14:34:33 -06:00
|
|
|
txt = f.read()
|
|
|
|
assert "a.b.x namespace\n" in txt
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.apidoc(
|
2018-01-27 09:18:33 -06:00
|
|
|
coderoot='test-apidoc-pep420/a',
|
2018-01-17 14:34:33 -06:00
|
|
|
options=["--implicit-namespaces", "--separate"],
|
|
|
|
)
|
|
|
|
def test_pep_0420_enabled_separate(make_app, apidoc):
|
|
|
|
outdir = apidoc.outdir
|
2023-07-27 18:39:12 -05:00
|
|
|
assert (outdir / 'conf.py').is_file()
|
|
|
|
assert (outdir / 'a.b.c.rst').is_file()
|
|
|
|
assert (outdir / 'a.b.e.rst').is_file()
|
|
|
|
assert (outdir / 'a.b.e.f.rst').is_file()
|
|
|
|
assert (outdir / 'a.b.x.rst').is_file()
|
|
|
|
assert (outdir / 'a.b.x.y.rst').is_file()
|
2018-01-17 14:34:33 -06:00
|
|
|
|
2022-04-17 20:32:06 -05:00
|
|
|
with open(outdir / 'a.b.c.rst', encoding='utf-8') as f:
|
2018-01-17 14:34:33 -06:00
|
|
|
rst = f.read()
|
2020-03-15 06:02:49 -05:00
|
|
|
assert ".. toctree::\n :maxdepth: 4\n\n a.b.c.d\n" in rst
|
2018-01-17 14:34:33 -06:00
|
|
|
|
2022-04-17 20:32:06 -05:00
|
|
|
with open(outdir / 'a.b.e.rst', encoding='utf-8') as f:
|
2018-01-17 14:34:33 -06:00
|
|
|
rst = f.read()
|
2020-03-15 06:02:49 -05:00
|
|
|
assert ".. toctree::\n :maxdepth: 4\n\n a.b.e.f\n" in rst
|
2018-01-17 14:34:33 -06:00
|
|
|
|
2022-04-17 20:32:06 -05:00
|
|
|
with open(outdir / 'a.b.x.rst', encoding='utf-8') as f:
|
2018-01-17 14:34:33 -06:00
|
|
|
rst = f.read()
|
2020-03-15 06:02:49 -05:00
|
|
|
assert ".. toctree::\n :maxdepth: 4\n\n a.b.x.y\n" in rst
|
2018-01-17 14:34:33 -06:00
|
|
|
|
|
|
|
app = make_app('text', srcdir=outdir)
|
|
|
|
app.build()
|
|
|
|
print(app._status.getvalue())
|
|
|
|
print(app._warning.getvalue())
|
|
|
|
|
|
|
|
builddir = outdir / '_build' / 'text'
|
2023-07-27 18:39:12 -05:00
|
|
|
assert (builddir / 'a.b.c.txt').is_file()
|
|
|
|
assert (builddir / 'a.b.e.txt').is_file()
|
|
|
|
assert (builddir / 'a.b.e.f.txt').is_file()
|
|
|
|
assert (builddir / 'a.b.x.txt').is_file()
|
|
|
|
assert (builddir / 'a.b.x.y.txt').is_file()
|
2016-09-12 17:17:03 -05:00
|
|
|
|
2022-04-17 20:32:06 -05:00
|
|
|
with open(builddir / 'a.b.c.txt', encoding='utf-8') as f:
|
2017-03-24 04:53:01 -05:00
|
|
|
txt = f.read()
|
|
|
|
assert "a.b.c package\n" in txt
|
|
|
|
|
2022-04-17 20:32:06 -05:00
|
|
|
with open(builddir / 'a.b.e.f.txt', encoding='utf-8') as f:
|
2018-01-17 14:34:33 -06:00
|
|
|
txt = f.read()
|
|
|
|
assert "a.b.e.f module\n" in txt
|
|
|
|
|
2022-04-17 20:32:06 -05:00
|
|
|
with open(builddir / 'a.b.x.txt', encoding='utf-8') as f:
|
2017-03-24 04:53:01 -05:00
|
|
|
txt = f.read()
|
|
|
|
assert "a.b.x namespace\n" in txt
|
|
|
|
|
2016-09-12 17:17:03 -05:00
|
|
|
|
2017-07-29 00:59:51 -05:00
|
|
|
@pytest.mark.apidoc(coderoot='test-apidoc-pep420/a')
|
2017-01-03 07:24:00 -06:00
|
|
|
def test_pep_0420_disabled(make_app, apidoc):
|
|
|
|
outdir = apidoc.outdir
|
2023-07-27 18:39:12 -05:00
|
|
|
assert (outdir / 'conf.py').is_file()
|
2016-09-12 17:17:03 -05:00
|
|
|
assert not (outdir / 'a.b.c.rst').exists()
|
|
|
|
assert not (outdir / 'a.b.x.rst').exists()
|
|
|
|
|
2017-01-03 07:24:00 -06:00
|
|
|
app = make_app('text', srcdir=outdir)
|
|
|
|
app.build()
|
|
|
|
print(app._status.getvalue())
|
|
|
|
print(app._warning.getvalue())
|
|
|
|
|
2016-09-12 17:17:03 -05:00
|
|
|
|
2017-03-24 04:44:36 -05:00
|
|
|
@pytest.mark.apidoc(
|
2017-05-07 02:46:44 -05:00
|
|
|
coderoot='test-apidoc-pep420/a/b')
|
2017-01-03 07:24:00 -06:00
|
|
|
def test_pep_0420_disabled_top_level_verify(make_app, apidoc):
|
|
|
|
outdir = apidoc.outdir
|
2023-07-27 18:39:12 -05:00
|
|
|
assert (outdir / 'conf.py').is_file()
|
|
|
|
assert (outdir / 'c.rst').is_file()
|
2016-09-12 17:17:03 -05:00
|
|
|
assert not (outdir / 'x.rst').exists()
|
|
|
|
|
2022-04-17 20:32:06 -05:00
|
|
|
with open(outdir / 'c.rst', encoding='utf-8') as f:
|
2016-09-12 17:17:03 -05:00
|
|
|
rst = f.read()
|
|
|
|
assert "c package\n" in rst
|
|
|
|
assert "automodule:: c.d\n" in rst
|
|
|
|
assert "automodule:: c\n" in rst
|
|
|
|
|
2017-01-03 07:24:00 -06:00
|
|
|
app = make_app('text', srcdir=outdir)
|
|
|
|
app.build()
|
|
|
|
print(app._status.getvalue())
|
|
|
|
print(app._warning.getvalue())
|
|
|
|
|
2017-05-09 07:57:36 -05:00
|
|
|
|
2017-03-24 04:44:36 -05:00
|
|
|
@pytest.mark.apidoc(
|
2017-05-07 02:46:44 -05:00
|
|
|
coderoot='test-apidoc-trailing-underscore')
|
2017-03-22 19:21:04 -05:00
|
|
|
def test_trailing_underscore(make_app, apidoc):
|
|
|
|
outdir = apidoc.outdir
|
2023-07-27 18:39:12 -05:00
|
|
|
assert (outdir / 'conf.py').is_file()
|
|
|
|
assert (outdir / 'package_.rst').is_file()
|
2017-03-24 04:53:01 -05:00
|
|
|
|
|
|
|
app = make_app('text', srcdir=outdir)
|
|
|
|
app.build()
|
|
|
|
print(app._status.getvalue())
|
|
|
|
print(app._warning.getvalue())
|
|
|
|
|
|
|
|
builddir = outdir / '_build' / 'text'
|
2022-04-17 20:32:06 -05:00
|
|
|
with open(builddir / 'package_.txt', encoding='utf-8') as f:
|
2017-03-22 19:21:04 -05:00
|
|
|
rst = f.read()
|
2017-03-24 04:53:01 -05:00
|
|
|
assert "package_ package\n" in rst
|
|
|
|
assert "package_.module_ module\n" in rst
|
2017-01-03 07:24:00 -06:00
|
|
|
|
2017-05-09 07:57:36 -05:00
|
|
|
|
2018-02-11 03:46:01 -06:00
|
|
|
@pytest.mark.apidoc(
|
|
|
|
coderoot='test-apidoc-pep420/a',
|
2018-02-24 04:44:29 -06:00
|
|
|
excludes=["b/c/d.py", "b/e/f.py", "b/e/__init__.py"],
|
2018-02-11 03:46:01 -06:00
|
|
|
options=["--implicit-namespaces", "--separate"],
|
|
|
|
)
|
|
|
|
def test_excludes(apidoc):
|
|
|
|
outdir = apidoc.outdir
|
2023-07-27 18:39:12 -05:00
|
|
|
assert (outdir / 'conf.py').is_file()
|
|
|
|
assert (outdir / 'a.rst').is_file()
|
|
|
|
assert (outdir / 'a.b.rst').is_file()
|
|
|
|
assert (outdir / 'a.b.c.rst').is_file() # generated because not empty
|
|
|
|
assert not (outdir / 'a.b.e.rst').is_file() # skipped because of empty after excludes
|
|
|
|
assert (outdir / 'a.b.x.rst').is_file()
|
|
|
|
assert (outdir / 'a.b.x.y.rst').is_file()
|
2018-02-11 03:46:01 -06:00
|
|
|
|
|
|
|
|
2018-02-24 04:44:29 -06:00
|
|
|
@pytest.mark.apidoc(
|
|
|
|
coderoot='test-apidoc-pep420/a',
|
|
|
|
excludes=["b/e"],
|
|
|
|
options=["--implicit-namespaces", "--separate"],
|
|
|
|
)
|
|
|
|
def test_excludes_subpackage_should_be_skipped(apidoc):
|
|
|
|
"""Subpackage exclusion should work."""
|
|
|
|
outdir = apidoc.outdir
|
2023-07-27 18:39:12 -05:00
|
|
|
assert (outdir / 'conf.py').is_file()
|
|
|
|
assert (outdir / 'a.rst').is_file()
|
|
|
|
assert (outdir / 'a.b.rst').is_file()
|
|
|
|
assert (outdir / 'a.b.c.rst').is_file() # generated because not empty
|
|
|
|
assert not (outdir / 'a.b.e.f.rst').is_file() # skipped because 'b/e' subpackage is skipped
|
2018-02-24 04:44:29 -06:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.apidoc(
|
|
|
|
coderoot='test-apidoc-pep420/a',
|
|
|
|
excludes=["b/e/f.py"],
|
|
|
|
options=["--implicit-namespaces", "--separate"],
|
|
|
|
)
|
|
|
|
def test_excludes_module_should_be_skipped(apidoc):
|
|
|
|
"""Module exclusion should work."""
|
|
|
|
outdir = apidoc.outdir
|
2023-07-27 18:39:12 -05:00
|
|
|
assert (outdir / 'conf.py').is_file()
|
|
|
|
assert (outdir / 'a.rst').is_file()
|
|
|
|
assert (outdir / 'a.b.rst').is_file()
|
|
|
|
assert (outdir / 'a.b.c.rst').is_file() # generated because not empty
|
|
|
|
assert not (outdir / 'a.b.e.f.rst').is_file() # skipped because of empty after excludes
|
2018-02-24 04:44:29 -06:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.apidoc(
|
|
|
|
coderoot='test-apidoc-pep420/a',
|
|
|
|
excludes=[],
|
|
|
|
options=["--implicit-namespaces", "--separate"],
|
|
|
|
)
|
|
|
|
def test_excludes_module_should_not_be_skipped(apidoc):
|
|
|
|
"""Module should be included if no excludes are used."""
|
|
|
|
outdir = apidoc.outdir
|
2023-07-27 18:39:12 -05:00
|
|
|
assert (outdir / 'conf.py').is_file()
|
|
|
|
assert (outdir / 'a.rst').is_file()
|
|
|
|
assert (outdir / 'a.b.rst').is_file()
|
|
|
|
assert (outdir / 'a.b.c.rst').is_file() # generated because not empty
|
|
|
|
assert (outdir / 'a.b.e.f.rst').is_file() # skipped because of empty after excludes
|
2018-02-24 04:44:29 -06:00
|
|
|
|
|
|
|
|
2017-01-03 07:24:00 -06:00
|
|
|
@pytest.mark.apidoc(
|
2017-05-07 02:46:44 -05:00
|
|
|
coderoot='test-root',
|
2017-01-03 07:24:00 -06:00
|
|
|
options=[
|
2018-12-15 08:02:28 -06:00
|
|
|
'--doc-project', 'プロジェクト名',
|
|
|
|
'--doc-author', '著者名',
|
|
|
|
'--doc-version', 'バージョン',
|
|
|
|
'--doc-release', 'リリース',
|
2017-01-03 07:24:00 -06:00
|
|
|
],
|
|
|
|
)
|
|
|
|
def test_multibyte_parameters(make_app, apidoc):
|
|
|
|
outdir = apidoc.outdir
|
2023-07-27 18:39:12 -05:00
|
|
|
assert (outdir / 'conf.py').is_file()
|
|
|
|
assert (outdir / 'index.rst').is_file()
|
2015-12-25 00:52:51 -06:00
|
|
|
|
2022-04-26 21:04:19 -05:00
|
|
|
conf_py = (outdir / 'conf.py').read_text(encoding='utf8')
|
2019-01-02 22:27:33 -06:00
|
|
|
assert "project = 'プロジェクト名'" in conf_py
|
|
|
|
assert "author = '著者名'" in conf_py
|
|
|
|
assert "version = 'バージョン'" in conf_py
|
|
|
|
assert "release = 'リリース'" in conf_py
|
2017-01-03 07:24:00 -06:00
|
|
|
|
|
|
|
app = make_app('text', srcdir=outdir)
|
|
|
|
app.build()
|
|
|
|
print(app._status.getvalue())
|
|
|
|
print(app._warning.getvalue())
|
2017-01-11 04:23:34 -06:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.apidoc(
|
2017-05-07 02:46:44 -05:00
|
|
|
coderoot='test-root',
|
2017-01-11 04:23:34 -06:00
|
|
|
options=['--ext-mathjax'],
|
|
|
|
)
|
|
|
|
def test_extension_parsed(make_app, apidoc):
|
|
|
|
outdir = apidoc.outdir
|
2023-07-27 18:39:12 -05:00
|
|
|
assert (outdir / 'conf.py').is_file()
|
2017-01-11 04:23:34 -06:00
|
|
|
|
2022-04-17 20:32:06 -05:00
|
|
|
with open(outdir / 'conf.py', encoding='utf-8') as f:
|
2017-01-11 04:23:34 -06:00
|
|
|
rst = f.read()
|
|
|
|
assert "sphinx.ext.mathjax" in rst
|
2017-12-21 12:06:17 -06:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.apidoc(
|
2018-01-06 21:09:41 -06:00
|
|
|
coderoot='test-apidoc-toc/mypackage',
|
2017-12-21 12:06:17 -06:00
|
|
|
options=["--implicit-namespaces"],
|
|
|
|
)
|
|
|
|
def test_toc_all_references_should_exist_pep420_enabled(make_app, apidoc):
|
|
|
|
"""All references in toc should exist. This test doesn't say if
|
2024-01-14 15:13:46 -06:00
|
|
|
directories with empty __init__.py and and nothing else should be
|
|
|
|
skipped, just ensures consistency between what's referenced in the toc
|
|
|
|
and what is created. This is the variant with pep420 enabled.
|
2017-12-21 12:06:17 -06:00
|
|
|
"""
|
|
|
|
outdir = apidoc.outdir
|
2023-07-27 18:39:12 -05:00
|
|
|
assert (outdir / 'conf.py').is_file()
|
2017-12-21 12:06:17 -06:00
|
|
|
|
|
|
|
toc = extract_toc(outdir / 'mypackage.rst')
|
|
|
|
|
|
|
|
refs = [l.strip() for l in toc.splitlines() if l.strip()]
|
|
|
|
found_refs = []
|
|
|
|
missing_files = []
|
|
|
|
for ref in refs:
|
|
|
|
if ref and ref[0] in (':', '#'):
|
|
|
|
continue
|
|
|
|
found_refs.append(ref)
|
2022-10-17 09:54:59 -05:00
|
|
|
filename = f"{ref}.rst"
|
2023-07-27 18:39:12 -05:00
|
|
|
if not (outdir / filename).is_file():
|
2017-12-21 12:06:17 -06:00
|
|
|
missing_files.append(filename)
|
|
|
|
|
|
|
|
assert len(missing_files) == 0, \
|
|
|
|
'File(s) referenced in TOC not found: {}\n' \
|
|
|
|
'TOC:\n{}'.format(", ".join(missing_files), toc)
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.apidoc(
|
2018-01-06 21:09:41 -06:00
|
|
|
coderoot='test-apidoc-toc/mypackage',
|
2017-12-21 12:06:17 -06:00
|
|
|
)
|
|
|
|
def test_toc_all_references_should_exist_pep420_disabled(make_app, apidoc):
|
|
|
|
"""All references in toc should exist. This test doesn't say if
|
2024-01-14 15:13:46 -06:00
|
|
|
directories with empty __init__.py and and nothing else should be
|
|
|
|
skipped, just ensures consistency between what's referenced in the toc
|
|
|
|
and what is created. This is the variant with pep420 disabled.
|
2017-12-21 12:06:17 -06:00
|
|
|
"""
|
|
|
|
outdir = apidoc.outdir
|
2023-07-27 18:39:12 -05:00
|
|
|
assert (outdir / 'conf.py').is_file()
|
2017-12-21 12:06:17 -06:00
|
|
|
|
|
|
|
toc = extract_toc(outdir / 'mypackage.rst')
|
|
|
|
|
|
|
|
refs = [l.strip() for l in toc.splitlines() if l.strip()]
|
|
|
|
found_refs = []
|
|
|
|
missing_files = []
|
|
|
|
for ref in refs:
|
|
|
|
if ref and ref[0] in (':', '#'):
|
|
|
|
continue
|
2022-10-17 09:54:59 -05:00
|
|
|
filename = f"{ref}.rst"
|
2017-12-21 12:06:17 -06:00
|
|
|
found_refs.append(ref)
|
2023-07-27 18:39:12 -05:00
|
|
|
if not (outdir / filename).is_file():
|
2017-12-21 12:06:17 -06:00
|
|
|
missing_files.append(filename)
|
|
|
|
|
|
|
|
assert len(missing_files) == 0, \
|
|
|
|
'File(s) referenced in TOC not found: {}\n' \
|
|
|
|
'TOC:\n{}'.format(", ".join(missing_files), toc)
|
|
|
|
|
|
|
|
|
|
|
|
def extract_toc(path):
|
|
|
|
"""Helper: Extract toc section from package rst file"""
|
2022-04-17 20:32:06 -05:00
|
|
|
with open(path, encoding='utf-8') as f:
|
2017-12-21 12:06:17 -06:00
|
|
|
rst = f.read()
|
|
|
|
|
|
|
|
# Read out the part containing the toctree
|
|
|
|
toctree_start = "\n.. toctree::\n"
|
|
|
|
toctree_end = "\nSubmodules"
|
|
|
|
|
|
|
|
start_idx = rst.index(toctree_start)
|
|
|
|
end_idx = rst.index(toctree_end, start_idx)
|
|
|
|
toctree = rst[start_idx + len(toctree_start):end_idx]
|
|
|
|
|
|
|
|
return toctree
|
2018-02-24 04:44:29 -06:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.apidoc(
|
|
|
|
coderoot='test-apidoc-subpackage-in-toc',
|
2023-02-17 16:11:14 -06:00
|
|
|
options=['--separate'],
|
2018-02-24 04:44:29 -06:00
|
|
|
)
|
|
|
|
def test_subpackage_in_toc(make_app, apidoc):
|
|
|
|
"""Make sure that empty subpackages with non-empty subpackages in them
|
2024-01-14 15:13:46 -06:00
|
|
|
are not skipped (issue #4520)
|
2018-02-24 04:44:29 -06:00
|
|
|
"""
|
|
|
|
outdir = apidoc.outdir
|
2023-07-27 18:39:12 -05:00
|
|
|
assert (outdir / 'conf.py').is_file()
|
2018-02-24 04:44:29 -06:00
|
|
|
|
2023-07-27 18:39:12 -05:00
|
|
|
assert (outdir / 'parent.rst').is_file()
|
2022-04-17 20:32:06 -05:00
|
|
|
with open(outdir / 'parent.rst', encoding='utf-8') as f:
|
2018-02-24 04:44:29 -06:00
|
|
|
parent = f.read()
|
|
|
|
assert 'parent.child' in parent
|
|
|
|
|
2023-07-27 18:39:12 -05:00
|
|
|
assert (outdir / 'parent.child.rst').is_file()
|
2022-04-17 20:32:06 -05:00
|
|
|
with open(outdir / 'parent.child.rst', encoding='utf-8') as f:
|
2018-02-24 04:44:29 -06:00
|
|
|
parent_child = f.read()
|
|
|
|
assert 'parent.child.foo' in parent_child
|
|
|
|
|
2023-07-27 18:39:12 -05:00
|
|
|
assert (outdir / 'parent.child.foo.rst').is_file()
|
2019-05-02 05:31:28 -05:00
|
|
|
|
|
|
|
|
2023-07-27 18:39:12 -05:00
|
|
|
def test_private(tmp_path):
|
|
|
|
(tmp_path / 'hello.py').write_text('', encoding='utf8')
|
|
|
|
(tmp_path / '_world.py').write_text('', encoding='utf8')
|
2019-05-03 08:59:49 -05:00
|
|
|
|
|
|
|
# without --private option
|
2023-07-27 18:39:12 -05:00
|
|
|
apidoc_main(['-o', str(tmp_path), str(tmp_path)])
|
|
|
|
assert (tmp_path / 'hello.rst').exists()
|
|
|
|
assert ':private-members:' not in (tmp_path / 'hello.rst').read_text(encoding='utf8')
|
|
|
|
assert not (tmp_path / '_world.rst').exists()
|
2019-05-03 08:59:49 -05:00
|
|
|
|
|
|
|
# with --private option
|
2023-07-27 18:39:12 -05:00
|
|
|
apidoc_main(['--private', '-f', '-o', str(tmp_path), str(tmp_path)])
|
|
|
|
assert (tmp_path / 'hello.rst').exists()
|
|
|
|
assert ':private-members:' in (tmp_path / 'hello.rst').read_text(encoding='utf8')
|
|
|
|
assert (tmp_path / '_world.rst').exists()
|
2019-05-03 08:59:49 -05:00
|
|
|
|
|
|
|
|
2023-07-27 18:39:12 -05:00
|
|
|
def test_toc_file(tmp_path):
|
|
|
|
outdir = tmp_path
|
|
|
|
(outdir / 'module').mkdir(parents=True, exist_ok=True)
|
2022-04-26 21:11:08 -05:00
|
|
|
(outdir / 'example.py').write_text('', encoding='utf8')
|
|
|
|
(outdir / 'module' / 'example.py').write_text('', encoding='utf8')
|
2023-07-27 18:39:12 -05:00
|
|
|
apidoc_main(['-o', str(tmp_path), str(tmp_path)])
|
2019-05-02 08:40:36 -05:00
|
|
|
assert (outdir / 'modules.rst').exists()
|
|
|
|
|
2022-04-26 21:04:19 -05:00
|
|
|
content = (outdir / 'modules.rst').read_text(encoding='utf8')
|
2019-05-02 08:40:36 -05:00
|
|
|
assert content == ("test_toc_file0\n"
|
|
|
|
"==============\n"
|
|
|
|
"\n"
|
|
|
|
".. toctree::\n"
|
|
|
|
" :maxdepth: 4\n"
|
|
|
|
"\n"
|
|
|
|
" example\n")
|
|
|
|
|
|
|
|
|
2023-07-27 18:39:12 -05:00
|
|
|
def test_module_file(tmp_path):
|
|
|
|
outdir = tmp_path
|
2022-04-26 21:11:08 -05:00
|
|
|
(outdir / 'example.py').write_text('', encoding='utf8')
|
2023-07-27 18:39:12 -05:00
|
|
|
apidoc_main(['-o', str(tmp_path), str(tmp_path)])
|
2019-05-02 05:31:28 -05:00
|
|
|
assert (outdir / 'example.rst').exists()
|
|
|
|
|
2022-04-26 21:04:19 -05:00
|
|
|
content = (outdir / 'example.rst').read_text(encoding='utf8')
|
2019-05-02 05:31:28 -05:00
|
|
|
assert content == ("example module\n"
|
|
|
|
"==============\n"
|
|
|
|
"\n"
|
|
|
|
".. automodule:: example\n"
|
|
|
|
" :members:\n"
|
|
|
|
" :undoc-members:\n"
|
|
|
|
" :show-inheritance:\n")
|
|
|
|
|
|
|
|
|
2023-07-27 18:39:12 -05:00
|
|
|
def test_module_file_noheadings(tmp_path):
|
|
|
|
outdir = tmp_path
|
2022-04-26 21:11:08 -05:00
|
|
|
(outdir / 'example.py').write_text('', encoding='utf8')
|
2023-07-27 18:39:12 -05:00
|
|
|
apidoc_main(['--no-headings', '-o', str(tmp_path), str(tmp_path)])
|
2019-05-02 05:31:28 -05:00
|
|
|
assert (outdir / 'example.rst').exists()
|
|
|
|
|
2022-04-26 21:04:19 -05:00
|
|
|
content = (outdir / 'example.rst').read_text(encoding='utf8')
|
2019-05-02 05:31:28 -05:00
|
|
|
assert content == (".. automodule:: example\n"
|
|
|
|
" :members:\n"
|
|
|
|
" :undoc-members:\n"
|
|
|
|
" :show-inheritance:\n")
|
2019-05-03 11:16:07 -05:00
|
|
|
|
|
|
|
|
2023-07-27 18:39:12 -05:00
|
|
|
def test_package_file(tmp_path):
|
|
|
|
outdir = tmp_path
|
|
|
|
(outdir / 'testpkg').mkdir(parents=True, exist_ok=True)
|
2022-04-26 21:11:08 -05:00
|
|
|
(outdir / 'testpkg' / '__init__.py').write_text('', encoding='utf8')
|
|
|
|
(outdir / 'testpkg' / 'hello.py').write_text('', encoding='utf8')
|
|
|
|
(outdir / 'testpkg' / 'world.py').write_text('', encoding='utf8')
|
2023-07-27 18:39:12 -05:00
|
|
|
(outdir / 'testpkg' / 'subpkg').mkdir(parents=True, exist_ok=True)
|
2022-04-26 21:11:08 -05:00
|
|
|
(outdir / 'testpkg' / 'subpkg' / '__init__.py').write_text('', encoding='utf8')
|
2023-07-27 18:39:12 -05:00
|
|
|
apidoc_main(['-o', str(outdir), str(outdir / 'testpkg')])
|
2019-05-03 11:16:07 -05:00
|
|
|
assert (outdir / 'testpkg.rst').exists()
|
|
|
|
assert (outdir / 'testpkg.subpkg.rst').exists()
|
|
|
|
|
2022-04-26 21:04:19 -05:00
|
|
|
content = (outdir / 'testpkg.rst').read_text(encoding='utf8')
|
2019-05-03 11:16:07 -05:00
|
|
|
assert content == ("testpkg package\n"
|
|
|
|
"===============\n"
|
|
|
|
"\n"
|
|
|
|
"Subpackages\n"
|
|
|
|
"-----------\n"
|
|
|
|
"\n"
|
|
|
|
".. toctree::\n"
|
2020-03-15 06:02:49 -05:00
|
|
|
" :maxdepth: 4\n"
|
2019-05-03 11:16:07 -05:00
|
|
|
"\n"
|
|
|
|
" testpkg.subpkg\n"
|
|
|
|
"\n"
|
|
|
|
"Submodules\n"
|
|
|
|
"----------\n"
|
|
|
|
"\n"
|
2019-06-04 10:19:43 -05:00
|
|
|
"testpkg.hello module\n"
|
|
|
|
"--------------------\n"
|
2019-05-03 11:16:07 -05:00
|
|
|
"\n"
|
2019-06-04 10:19:43 -05:00
|
|
|
".. automodule:: testpkg.hello\n"
|
|
|
|
" :members:\n"
|
|
|
|
" :undoc-members:\n"
|
|
|
|
" :show-inheritance:\n"
|
|
|
|
"\n"
|
|
|
|
"testpkg.world module\n"
|
|
|
|
"--------------------\n"
|
|
|
|
"\n"
|
|
|
|
".. automodule:: testpkg.world\n"
|
2019-05-03 11:16:07 -05:00
|
|
|
" :members:\n"
|
|
|
|
" :undoc-members:\n"
|
|
|
|
" :show-inheritance:\n"
|
|
|
|
"\n"
|
|
|
|
"Module contents\n"
|
|
|
|
"---------------\n"
|
|
|
|
"\n"
|
|
|
|
".. automodule:: testpkg\n"
|
|
|
|
" :members:\n"
|
|
|
|
" :undoc-members:\n"
|
|
|
|
" :show-inheritance:\n")
|
|
|
|
|
2022-04-26 21:04:19 -05:00
|
|
|
content = (outdir / 'testpkg.subpkg.rst').read_text(encoding='utf8')
|
2019-05-03 11:16:07 -05:00
|
|
|
assert content == ("testpkg.subpkg package\n"
|
|
|
|
"======================\n"
|
|
|
|
"\n"
|
|
|
|
"Module contents\n"
|
|
|
|
"---------------\n"
|
|
|
|
"\n"
|
|
|
|
".. automodule:: testpkg.subpkg\n"
|
|
|
|
" :members:\n"
|
|
|
|
" :undoc-members:\n"
|
|
|
|
" :show-inheritance:\n")
|
|
|
|
|
|
|
|
|
2023-07-27 18:39:12 -05:00
|
|
|
def test_package_file_separate(tmp_path):
|
|
|
|
outdir = tmp_path
|
|
|
|
(outdir / 'testpkg').mkdir(parents=True, exist_ok=True)
|
2022-04-26 21:11:08 -05:00
|
|
|
(outdir / 'testpkg' / '__init__.py').write_text('', encoding='utf8')
|
|
|
|
(outdir / 'testpkg' / 'example.py').write_text('', encoding='utf8')
|
2023-07-27 18:39:12 -05:00
|
|
|
apidoc_main(['--separate', '-o', str(tmp_path), str(tmp_path / 'testpkg')])
|
2019-05-03 11:16:07 -05:00
|
|
|
assert (outdir / 'testpkg.rst').exists()
|
|
|
|
assert (outdir / 'testpkg.example.rst').exists()
|
|
|
|
|
2022-04-26 21:04:19 -05:00
|
|
|
content = (outdir / 'testpkg.rst').read_text(encoding='utf8')
|
2019-05-03 11:16:07 -05:00
|
|
|
assert content == ("testpkg package\n"
|
|
|
|
"===============\n"
|
|
|
|
"\n"
|
|
|
|
"Submodules\n"
|
|
|
|
"----------\n"
|
|
|
|
"\n"
|
|
|
|
".. toctree::\n"
|
2020-03-15 06:02:49 -05:00
|
|
|
" :maxdepth: 4\n"
|
2019-05-03 11:16:07 -05:00
|
|
|
"\n"
|
|
|
|
" testpkg.example\n"
|
|
|
|
"\n"
|
|
|
|
"Module contents\n"
|
|
|
|
"---------------\n"
|
|
|
|
"\n"
|
|
|
|
".. automodule:: testpkg\n"
|
|
|
|
" :members:\n"
|
|
|
|
" :undoc-members:\n"
|
|
|
|
" :show-inheritance:\n")
|
|
|
|
|
2022-04-26 21:04:19 -05:00
|
|
|
content = (outdir / 'testpkg.example.rst').read_text(encoding='utf8')
|
2019-05-03 11:16:07 -05:00
|
|
|
assert content == ("testpkg.example module\n"
|
|
|
|
"======================\n"
|
|
|
|
"\n"
|
|
|
|
".. automodule:: testpkg.example\n"
|
|
|
|
" :members:\n"
|
|
|
|
" :undoc-members:\n"
|
|
|
|
" :show-inheritance:\n")
|
|
|
|
|
|
|
|
|
2023-07-27 18:39:12 -05:00
|
|
|
def test_package_file_module_first(tmp_path):
|
|
|
|
outdir = tmp_path
|
|
|
|
(outdir / 'testpkg').mkdir(parents=True, exist_ok=True)
|
2022-04-26 21:11:08 -05:00
|
|
|
(outdir / 'testpkg' / '__init__.py').write_text('', encoding='utf8')
|
|
|
|
(outdir / 'testpkg' / 'example.py').write_text('', encoding='utf8')
|
2023-07-27 18:39:12 -05:00
|
|
|
apidoc_main(['--module-first', '-o', str(tmp_path), str(tmp_path)])
|
2019-05-03 11:16:07 -05:00
|
|
|
|
2022-04-26 21:04:19 -05:00
|
|
|
content = (outdir / 'testpkg.rst').read_text(encoding='utf8')
|
2019-05-03 11:16:07 -05:00
|
|
|
assert content == ("testpkg package\n"
|
|
|
|
"===============\n"
|
|
|
|
"\n"
|
|
|
|
".. automodule:: testpkg\n"
|
|
|
|
" :members:\n"
|
|
|
|
" :undoc-members:\n"
|
|
|
|
" :show-inheritance:\n"
|
|
|
|
"\n"
|
|
|
|
"Submodules\n"
|
|
|
|
"----------\n"
|
|
|
|
"\n"
|
|
|
|
"testpkg.example module\n"
|
|
|
|
"----------------------\n"
|
|
|
|
"\n"
|
|
|
|
".. automodule:: testpkg.example\n"
|
|
|
|
" :members:\n"
|
|
|
|
" :undoc-members:\n"
|
2020-07-10 16:19:07 -05:00
|
|
|
" :show-inheritance:\n")
|
2019-05-03 11:16:07 -05:00
|
|
|
|
|
|
|
|
2023-07-27 18:39:12 -05:00
|
|
|
def test_package_file_without_submodules(tmp_path):
|
|
|
|
outdir = tmp_path
|
|
|
|
(outdir / 'testpkg').mkdir(parents=True, exist_ok=True)
|
2022-04-26 21:11:08 -05:00
|
|
|
(outdir / 'testpkg' / '__init__.py').write_text('', encoding='utf8')
|
2023-07-27 18:39:12 -05:00
|
|
|
apidoc_main(['-o', str(tmp_path), str(tmp_path / 'testpkg')])
|
2019-05-03 11:16:07 -05:00
|
|
|
assert (outdir / 'testpkg.rst').exists()
|
|
|
|
|
2022-04-26 21:04:19 -05:00
|
|
|
content = (outdir / 'testpkg.rst').read_text(encoding='utf8')
|
2019-05-03 11:16:07 -05:00
|
|
|
assert content == ("testpkg package\n"
|
|
|
|
"===============\n"
|
|
|
|
"\n"
|
|
|
|
"Module contents\n"
|
|
|
|
"---------------\n"
|
|
|
|
"\n"
|
|
|
|
".. automodule:: testpkg\n"
|
|
|
|
" :members:\n"
|
|
|
|
" :undoc-members:\n"
|
|
|
|
" :show-inheritance:\n")
|
|
|
|
|
|
|
|
|
2023-07-27 18:39:12 -05:00
|
|
|
def test_namespace_package_file(tmp_path):
|
|
|
|
outdir = tmp_path
|
|
|
|
(outdir / 'testpkg').mkdir(parents=True, exist_ok=True)
|
2022-04-26 21:11:08 -05:00
|
|
|
(outdir / 'testpkg' / 'example.py').write_text('', encoding='utf8')
|
2023-07-27 18:39:12 -05:00
|
|
|
apidoc_main(['--implicit-namespace', '-o', str(tmp_path), str(tmp_path / 'testpkg')])
|
2019-05-03 11:16:07 -05:00
|
|
|
assert (outdir / 'testpkg.rst').exists()
|
|
|
|
|
2022-04-26 21:04:19 -05:00
|
|
|
content = (outdir / 'testpkg.rst').read_text(encoding='utf8')
|
2019-05-03 11:16:07 -05:00
|
|
|
assert content == ("testpkg namespace\n"
|
|
|
|
"=================\n"
|
|
|
|
"\n"
|
2021-09-04 08:07:28 -05:00
|
|
|
".. py:module:: testpkg\n"
|
|
|
|
"\n"
|
2019-05-03 11:16:07 -05:00
|
|
|
"Submodules\n"
|
|
|
|
"----------\n"
|
|
|
|
"\n"
|
|
|
|
"testpkg.example module\n"
|
|
|
|
"----------------------\n"
|
|
|
|
"\n"
|
|
|
|
".. automodule:: testpkg.example\n"
|
|
|
|
" :members:\n"
|
|
|
|
" :undoc-members:\n"
|
2020-07-10 16:19:07 -05:00
|
|
|
" :show-inheritance:\n")
|
2022-05-01 00:12:25 -05:00
|
|
|
|
|
|
|
|
2023-07-27 18:39:12 -05:00
|
|
|
def test_no_duplicates(rootdir, tmp_path):
|
2022-05-01 00:12:25 -05:00
|
|
|
"""Make sure that a ".pyx" and ".so" don't cause duplicate listings.
|
|
|
|
|
|
|
|
We can't use pytest.mark.apidoc here as we use a different set of arguments
|
|
|
|
to apidoc_main
|
|
|
|
"""
|
|
|
|
original_suffixes = sphinx.ext.apidoc.PY_SUFFIXES
|
|
|
|
try:
|
|
|
|
# Ensure test works on Windows
|
|
|
|
sphinx.ext.apidoc.PY_SUFFIXES += ('.so',)
|
|
|
|
|
|
|
|
package = rootdir / 'test-apidoc-duplicates' / 'fish_licence'
|
2023-07-27 18:39:12 -05:00
|
|
|
outdir = tmp_path / 'out'
|
|
|
|
apidoc_main(['-o', str(outdir), "-T", str(package), "--implicit-namespaces"])
|
2022-05-01 00:12:25 -05:00
|
|
|
|
|
|
|
# Ensure the module has been documented
|
2023-07-27 18:39:12 -05:00
|
|
|
assert os.path.isfile(outdir / 'fish_licence.rst')
|
2022-05-01 00:12:25 -05:00
|
|
|
|
|
|
|
# Ensure the submodule only appears once
|
|
|
|
text = (outdir / 'fish_licence.rst').read_text(encoding="utf-8")
|
|
|
|
count_submodules = text.count(r'fish\_licence.halibut module')
|
|
|
|
assert count_submodules == 1
|
|
|
|
|
|
|
|
finally:
|
|
|
|
sphinx.ext.apidoc.PY_SUFFIXES = original_suffixes
|
2024-06-20 06:12:37 -05:00
|
|
|
|
|
|
|
|
|
|
|
def test_remove_old_files(tmp_path: Path):
|
|
|
|
"""Test that old files are removed when using the -r option.
|
|
|
|
|
|
|
|
Also ensure that pre-existing files are not re-written, if unchanged.
|
|
|
|
This is required to avoid unnecessary rebuilds.
|
|
|
|
"""
|
|
|
|
module_dir = tmp_path / 'module'
|
|
|
|
module_dir.mkdir()
|
|
|
|
(module_dir / 'example.py').write_text('', encoding='utf8')
|
|
|
|
gen_dir = tmp_path / 'gen'
|
|
|
|
gen_dir.mkdir()
|
|
|
|
(gen_dir / 'other.rst').write_text('', encoding='utf8')
|
|
|
|
apidoc_main(['-o', str(gen_dir), str(module_dir)])
|
|
|
|
assert set(gen_dir.iterdir()) == {gen_dir / 'modules.rst', gen_dir / 'example.rst', gen_dir / 'other.rst'}
|
2024-07-23 08:52:31 -05:00
|
|
|
example_mtime = (gen_dir / 'example.rst').stat().st_mtime_ns
|
2024-06-20 06:12:37 -05:00
|
|
|
apidoc_main(['--remove-old', '-o', str(gen_dir), str(module_dir)])
|
|
|
|
assert set(gen_dir.iterdir()) == {gen_dir / 'modules.rst', gen_dir / 'example.rst'}
|
2024-07-23 08:52:31 -05:00
|
|
|
assert (gen_dir / 'example.rst').stat().st_mtime_ns == example_mtime
|