sphinx-autoapi/tests/python/test_pyintegration.py

399 lines
14 KiB
Python
Raw Normal View History

import io
import os
import shutil
import sys
import pytest
import sphinx
from sphinx.application import Sphinx
import sphinx.util.logging
2019-01-27 05:20:45 +00:00
@pytest.fixture(scope="class")
def builder():
cwd = os.getcwd()
def build(test_dir, confoverrides=None):
2019-01-27 05:20:45 +00:00
os.chdir("tests/python/{0}".format(test_dir))
app = Sphinx(
2019-01-27 05:20:45 +00:00
srcdir=".",
confdir=".",
outdir="_build/text",
doctreedir="_build/.doctrees",
buildername="text",
confoverrides=confoverrides,
)
app.build(force_all=True)
yield build
try:
2019-01-27 05:20:45 +00:00
shutil.rmtree("_build")
finally:
os.chdir(cwd)
class TestSimpleModule(object):
2019-01-27 05:20:45 +00:00
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
2019-01-27 05:20:45 +00:00
builder("pyexample")
def test_integration(self):
2019-01-27 05:20:45 +00:00
self.check_integration("_build/text/autoapi/example/index.txt")
def test_manual_directives(self):
# The manual directives should contain the same information
2019-01-27 05:20:45 +00:00
self.check_integration("_build/text/manualapi.txt")
def check_integration(self, example_path):
2019-01-27 05:20:45 +00:00
with io.open(example_path, encoding="utf8") as example_handle:
example_file = example_handle.read()
2019-01-27 05:20:45 +00:00
assert "class example.Foo" in example_file
assert "class Meta" in example_file
assert "attr2" in example_file
assert "This is the docstring of an instance attribute." in example_file
assert "method_okay(self, foo=None, bar=None)" in example_file
assert "method_multiline(self, foo=None, bar=None, baz=None)" in example_file
assert "method_tricky(self, foo=None, bar=dict(foo=1, bar=2))" in example_file
# Are constructor arguments from the class docstring parsed?
2019-01-27 05:20:45 +00:00
assert "Set an attribute" in example_file
# "self" should not be included in constructor arguments
2019-01-27 05:20:45 +00:00
assert "Foo(self" not in example_file
2019-01-27 05:20:45 +00:00
assert not os.path.exists("_build/text/autoapi/method_multiline")
2019-01-27 05:20:45 +00:00
index_path = "_build/text/index.txt"
with io.open(index_path, encoding="utf8") as index_handle:
index_file = index_handle.read()
2019-04-06 18:15:18 +00:00
assert "API Reference" in index_file
2019-01-27 05:20:45 +00:00
assert "Foo" in index_file
assert "Meta" in index_file
def test_napoleon_integration_not_loaded(self, builder):
2019-01-27 05:20:45 +00:00
example_path = "_build/text/autoapi/example/index.txt"
with io.open(example_path, encoding="utf8") as example_handle:
example_file = example_handle.read()
# Check that docstrings are not transformed without napoleon loaded
2019-01-27 05:20:45 +00:00
assert "Args" in example_file
2019-01-27 05:20:45 +00:00
assert "Returns" in example_file
@pytest.mark.skipif(
sys.version_info < (3,), reason="Ellipsis is invalid method contents in Python 2"
)
class TestSimpleStubModule(object):
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
builder("pyiexample")
def test_integration(self):
example_path = "_build/text/autoapi/example/index.txt"
with io.open(example_path, encoding="utf8") as example_handle:
example_file = example_handle.read()
assert "class example.Foo" in example_file
assert "class Meta" in example_file
assert "Another class var docstring" in example_file
assert "A class var without a value." in example_file
assert "method_okay(self, foo=None, bar=None)" in example_file
assert "method_multiline(self, foo=None, bar=None, baz=None)" in example_file
assert "method_without_docstring(self)" in example_file
# Are constructor arguments from the class docstring parsed?
assert "Set an attribute" in example_file
@pytest.mark.skipif(
sys.version_info < (3, 6), reason="Annotations are invalid in Python <3.5"
)
class TestPy3Module(object):
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
builder("py3example")
def test_annotations(self):
example_path = "_build/text/autoapi/example/index.txt"
with io.open(example_path, encoding="utf8") as example_handle:
example_file = example_handle.read()
assert "max_rating :int = 10" in example_file
assert "is_valid" in example_file
assert "ratings" in example_file
assert "List[int]" in example_file
assert "Dict[int, str]" in example_file
assert "start:int" in example_file
assert "Iterable[int]" in example_file
assert "List[Union[str, int]]" in example_file
# TODO: This should not display as a string
# after we do proper formatting
assert "not_yet_a:'A'" in example_file
assert "is_an_a" in example_file
assert "ClassVar" in example_file
assert "instance_var" in example_file
assert "global_a :A" in example_file
def test_async(self):
example_path = "_build/text/autoapi/example/index.txt"
with io.open(example_path, encoding="utf8") as example_handle:
example_file = example_handle.read()
if sphinx.version_info >= (2, 1):
assert "async async_method" in example_file
assert "async example.async_function" in example_file
else:
assert "async_method" in example_file
assert "async_function" in example_file
@pytest.mark.skipif(
sys.version_info < (3,), reason="Annotations are not supported in astroid<2"
)
class TestAnnotationCommentsModule(object):
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
builder("pyannotationcommentsexample")
def test_integration(self):
example_path = "_build/text/autoapi/example/index.txt"
with io.open(example_path, encoding="utf8") as example_handle:
example_file = example_handle.read()
assert "max_rating :int = 10" in example_file
assert "ratings" in example_file
assert "List[int]" in example_file
assert "Dict[int, str]" in example_file
# TODO: Type is currently unsupported by astroid (#665)
assert "start" in example_file
assert "Iterable[int]" in example_file
assert "List[Union[str, int]]" in example_file
# TODO: This should not display the type after we do proper formatting
assert "not_yet_a" in example_file
assert "is_an_a" in example_file
assert "ClassVar" in example_file
assert "instance_var" in example_file
assert "global_a :A" in example_file
def test_napoleon_integration_loaded(builder):
confoverrides = {
2019-01-27 05:20:45 +00:00
"extensions": ["autoapi.extension", "sphinx.ext.autodoc", "sphinx.ext.napoleon"]
}
2019-01-27 05:20:45 +00:00
builder("pyexample", confoverrides=confoverrides)
2019-01-27 05:20:45 +00:00
example_path = "_build/text/autoapi/example/index.txt"
with io.open(example_path, encoding="utf8") as example_handle:
example_file = example_handle.read()
2019-01-27 05:20:45 +00:00
assert "Parameters" in example_file
2019-01-27 05:20:45 +00:00
assert "Return type" in example_file
2019-01-27 05:20:45 +00:00
assert "Args" not in example_file
class TestSimplePackage(object):
2019-01-27 05:20:45 +00:00
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
2019-01-27 05:20:45 +00:00
builder("pypackageexample")
2018-12-18 11:27:43 +00:00
def test_integration_with_package(self):
2019-01-27 05:20:45 +00:00
example_path = "_build/text/autoapi/example/index.txt"
with io.open(example_path, encoding="utf8") as example_handle:
example_file = example_handle.read()
2019-01-27 05:20:45 +00:00
assert "example.foo" in example_file
assert "example.module_level_method(foo, bar)" in example_file
2019-01-27 05:20:45 +00:00
example_foo_path = "_build/text/autoapi/example/foo/index.txt"
with io.open(example_foo_path, encoding="utf8") as example_foo_handle:
example_foo_file = example_foo_handle.read()
2019-01-27 05:20:45 +00:00
assert "class example.foo.Foo" in example_foo_file
assert "method_okay(self, foo=None, bar=None)" in example_foo_file
2019-01-27 05:20:45 +00:00
index_path = "_build/text/index.txt"
with io.open(index_path, encoding="utf8") as index_handle:
index_file = index_handle.read()
2019-04-06 18:15:18 +00:00
assert "API Reference" in index_file
2019-01-27 05:20:45 +00:00
assert "example.foo" in index_file
assert "Foo" in index_file
assert "module_level_method" in index_file
def test_simple_no_false_warnings(builder, caplog):
logger = sphinx.util.logging.getLogger("autoapi")
logger.logger.addHandler(caplog.handler)
builder("pypackageexample")
assert "Cannot resolve" not in caplog.text
def _test_class_content(builder, class_content):
2019-01-27 05:20:45 +00:00
confoverrides = {"autoapi_python_class_content": class_content}
2019-01-27 05:20:45 +00:00
builder("pyexample", confoverrides=confoverrides)
2019-01-27 05:20:45 +00:00
example_path = "_build/text/autoapi/example/index.txt"
with io.open(example_path, encoding="utf8") as example_handle:
example_file = example_handle.read()
2019-01-27 05:20:45 +00:00
if class_content == "init":
assert "Can we parse arguments" not in example_file
else:
2019-01-27 05:20:45 +00:00
assert "Can we parse arguments" in example_file
2019-01-27 05:20:45 +00:00
if class_content not in ("both", "init"):
assert "Constructor docstring" not in example_file
else:
2019-01-27 05:20:45 +00:00
assert "Constructor docstring" in example_file
def test_class_class_content(builder):
2019-01-27 05:20:45 +00:00
_test_class_content(builder, "class")
def test_both_class_content(builder):
2019-01-27 05:20:45 +00:00
_test_class_content(builder, "both")
def test_init_class_content(builder):
2019-01-27 05:20:45 +00:00
_test_class_content(builder, "init")
def test_hiding_private_members(builder):
2019-01-27 05:20:45 +00:00
confoverrides = {"autoapi_options": ["members", "undoc-members", "special-members"]}
builder("pypackageexample", confoverrides=confoverrides)
2019-01-27 05:20:45 +00:00
example_path = "_build/text/autoapi/example/index.txt"
with io.open(example_path, encoding="utf8") as example_handle:
example_file = example_handle.read()
2019-01-27 05:20:45 +00:00
assert "private" not in example_file
2019-01-27 05:20:45 +00:00
private_path = "_build/text/autoapi/example/_private_module/index.txt"
with io.open(private_path, encoding="utf8") as private_handle:
private_file = private_handle.read()
2019-01-27 05:20:45 +00:00
assert "public_method" in private_file
2018-12-18 11:27:43 +00:00
class TestComplexPackage(object):
2019-01-27 05:20:45 +00:00
@pytest.fixture(autouse=True, scope="class")
2018-12-18 11:27:43 +00:00
def built(self, builder):
2019-01-27 05:20:45 +00:00
builder("pypackagecomplex")
2018-12-18 11:27:43 +00:00
def test_public_chain_resolves(self):
2019-01-27 05:20:45 +00:00
submodule_path = "_build/text/autoapi/complex/subpackage/submodule/index.txt"
with io.open(submodule_path, encoding="utf8") as submodule_handle:
2018-12-18 11:27:43 +00:00
submodule_file = submodule_handle.read()
assert "Part of a public resolution chain." in submodule_file
2019-01-27 05:20:45 +00:00
subpackage_path = "_build/text/autoapi/complex/subpackage/index.txt"
with io.open(subpackage_path, encoding="utf8") as subpackage_handle:
2018-12-18 11:27:43 +00:00
subpackage_file = subpackage_handle.read()
assert "Part of a public resolution chain." in subpackage_file
2019-01-27 05:20:45 +00:00
package_path = "_build/text/autoapi/complex/index.txt"
with io.open(package_path, encoding="utf8") as package_handle:
2018-12-18 11:27:43 +00:00
package_file = package_handle.read()
assert "Part of a public resolution chain." in package_file
def test_private_made_public(self):
2019-01-27 05:20:45 +00:00
submodule_path = "_build/text/autoapi/complex/subpackage/submodule/index.txt"
with io.open(submodule_path, encoding="utf8") as submodule_handle:
2018-12-18 11:27:43 +00:00
submodule_file = submodule_handle.read()
assert "A private function made public by import." in submodule_file
def test_multiple_import_locations(self):
2019-01-27 05:20:45 +00:00
submodule_path = "_build/text/autoapi/complex/subpackage/submodule/index.txt"
with io.open(submodule_path, encoding="utf8") as submodule_handle:
2018-12-18 11:27:43 +00:00
submodule_file = submodule_handle.read()
assert "A public function imported in multiple places." in submodule_file
2019-01-27 05:20:45 +00:00
subpackage_path = "_build/text/autoapi/complex/subpackage/index.txt"
with io.open(subpackage_path, encoding="utf8") as subpackage_handle:
2018-12-18 11:27:43 +00:00
subpackage_file = subpackage_handle.read()
assert "A public function imported in multiple places." in subpackage_file
2019-01-27 05:20:45 +00:00
package_path = "_build/text/autoapi/complex/index.txt"
with io.open(package_path, encoding="utf8") as package_handle:
2018-12-18 11:27:43 +00:00
package_file = package_handle.read()
assert "A public function imported in multiple places." in package_file
def test_simple_wildcard_imports(self):
2019-01-27 05:20:45 +00:00
wildcard_path = "_build/text/autoapi/complex/wildcard/index.txt"
with io.open(wildcard_path, encoding="utf8") as wildcard_handle:
2018-12-18 11:27:43 +00:00
wildcard_file = wildcard_handle.read()
assert "public_chain" in wildcard_file
assert "now_public_function" in wildcard_file
assert "public_multiple_imports" in wildcard_file
assert "module_level_method" in wildcard_file
def test_wildcard_chain(self):
2019-01-27 05:20:45 +00:00
wildcard_path = "_build/text/autoapi/complex/wildchain/index.txt"
with io.open(wildcard_path, encoding="utf8") as wildcard_handle:
2018-12-18 11:27:43 +00:00
wildcard_file = wildcard_handle.read()
assert "public_chain" in wildcard_file
assert "module_level_method" in wildcard_file
def test_wildcard_all_imports(self):
2019-01-27 05:20:45 +00:00
wildcard_path = "_build/text/autoapi/complex/wildall/index.txt"
with io.open(wildcard_path, encoding="utf8") as wildcard_handle:
wildcard_file = wildcard_handle.read()
assert "not_all" not in wildcard_file
assert "NotAllClass" not in wildcard_file
assert "does_not_exist" not in wildcard_file
assert "SimpleClass" in wildcard_file
assert "simple_function" in wildcard_file
assert "public_chain" in wildcard_file
assert "module_level_method" in wildcard_file
def test_no_imports_in_module_with_all(self):
foo_path = "_build/text/autoapi/complex/foo/index.txt"
with io.open(foo_path, encoding="utf8") as foo_handle:
foo_file = foo_handle.read()
assert "module_level_method" not in foo_file
def test_all_overrides_import_in_module_with_all(self):
foo_path = "_build/text/autoapi/complex/foo/index.txt"
with io.open(foo_path, encoding="utf8") as foo_handle:
foo_file = foo_handle.read()
assert "PublicClass" in foo_file