mirror of
https://github.com/readthedocs/sphinx-autoapi
synced 2024-10-31 21:20:17 +00:00
Compare commits
9 Commits
8020036353
...
9e19e4af60
Author | SHA1 | Date | |
---|---|---|---|
|
9e19e4af60 | ||
|
5c0f650913 | ||
|
d5807f4dee | ||
|
35be997aaa | ||
|
fcb0320776 | ||
|
c4db7eb14a | ||
|
422004ea91 | ||
|
823c146b3a | ||
|
bbb50f68ae |
@ -5,6 +5,27 @@ Versions follow `Semantic Versioning <https://semver.org/>`_ (``<major>.<minor>.
|
||||
|
||||
.. towncrier release notes start
|
||||
|
||||
v3.1.0a4 (2024-03-24)
|
||||
---------------------
|
||||
|
||||
Bugfixes
|
||||
^^^^^^^^
|
||||
|
||||
- Children not present in `__all__` are not rendered. (#226)
|
||||
- Fix emitting ignore event twice for methods. (#226)
|
||||
- Corrected documentation around `imported-members` to reflect that it
|
||||
applies only to objects imported into a package, not modules. (#226)
|
||||
- Fix path error on Windows. (#226)
|
||||
- Fix submodule with `__init__.pyi` documented as `__init__` instead of submodule name (#398)
|
||||
- Fix IndexError when a module docstring contains only a heading (#412)
|
||||
|
||||
|
||||
Misc
|
||||
^^^^
|
||||
|
||||
- #388
|
||||
|
||||
|
||||
v3.0.0 (2023-09-26)
|
||||
-------------------
|
||||
|
||||
|
@ -28,13 +28,14 @@ In contrast to the traditional `Sphinx autodoc <https://www.sphinx-doc.org/en/ma
|
||||
which requires manual authoring and uses code imports,
|
||||
AutoAPI finds and generates documentation by parsing source code.
|
||||
|
||||
For more information, see `the full documentation <https://sphinx-autoapi.readthedocs.org>`_.
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
|
||||
The following steps will walk through how to add AutoAPI to an existing Sphinx project.
|
||||
For instructions on how to set up a Sphinx project,
|
||||
see Sphinx's documentation on
|
||||
`Getting Started <https://www.sphinx-doc.org/en/master/usage/quickstart.html>`_.
|
||||
see `Sphinx's documentation <https://www.sphinx-doc.org/en/master/usage/quickstart.html>`_.
|
||||
|
||||
Installation
|
||||
~~~~~~~~~~~~
|
||||
|
@ -3,5 +3,5 @@
|
||||
from .extension import setup
|
||||
|
||||
__all__ = ("setup",)
|
||||
__version__ = "3.0.0"
|
||||
__version__ = "3.0.0a4"
|
||||
__version_info__ = (3, 0, 0)
|
||||
|
@ -41,7 +41,6 @@ class AutoapiSummary(Autosummary):
|
||||
|
||||
|
||||
class NestedParse(Directive):
|
||||
|
||||
"""Nested parsing to remove the first heading of included rST
|
||||
|
||||
This is used to handle the case where we like to remove user supplied
|
||||
@ -49,7 +48,7 @@ class NestedParse(Directive):
|
||||
duplicate headings on sections.
|
||||
"""
|
||||
|
||||
has_content = 1
|
||||
has_content = True
|
||||
required_arguments = 0
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
@ -59,9 +58,10 @@ class NestedParse(Directive):
|
||||
node.document = self.state.document
|
||||
nested_parse_with_titles(self.state, self.content, node)
|
||||
try:
|
||||
title_node = node[0][0]
|
||||
if isinstance(title_node, nodes.title):
|
||||
del node[0][0]
|
||||
if isinstance(node[0], nodes.section) and isinstance(
|
||||
node[0][0], nodes.title
|
||||
):
|
||||
node.children = node[0][1:] + node.children[1:]
|
||||
except IndexError:
|
||||
pass
|
||||
return node.children
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
This extension allows you to automagically generate API documentation from your project.
|
||||
"""
|
||||
|
||||
import io
|
||||
import os
|
||||
import shutil
|
||||
@ -34,6 +35,13 @@ _DEFAULT_OPTIONS = [
|
||||
"special-members",
|
||||
"imported-members",
|
||||
]
|
||||
_VALID_PAGE_LEVELS = [
|
||||
"module",
|
||||
"class",
|
||||
"function",
|
||||
"method",
|
||||
"attribute",
|
||||
]
|
||||
_VIEWCODE_CACHE: Dict[str, Tuple[str, Dict]] = {}
|
||||
"""Caches a module's parse results for use in viewcode."""
|
||||
|
||||
@ -74,6 +82,10 @@ def run_autoapi(app):
|
||||
if app.config.autoapi_include_summaries:
|
||||
app.config.autoapi_options.append("show-module-summary")
|
||||
|
||||
own_page_level = app.config.autoapi_own_page_level
|
||||
if own_page_level not in _VALID_PAGE_LEVELS:
|
||||
raise ValueError(f"Invalid autoapi_own_page_level '{own_page_level}")
|
||||
|
||||
# Make sure the paths are full
|
||||
normalised_dirs = _normalise_autoapi_dirs(app.config.autoapi_dirs, app.srcdir)
|
||||
for _dir in normalised_dirs:
|
||||
@ -100,7 +112,7 @@ def run_autoapi(app):
|
||||
RemovedInAutoAPI3Warning,
|
||||
)
|
||||
sphinx_mapper_obj = PythonSphinxMapper(
|
||||
app, template_dir=template_dir, url_root=url_root
|
||||
app, template_dir=template_dir, dir_root=normalized_root, url_root=url_root
|
||||
)
|
||||
|
||||
if app.config.autoapi_file_patterns:
|
||||
@ -127,7 +139,7 @@ def run_autoapi(app):
|
||||
sphinx_mapper_obj.map(options=app.config.autoapi_options)
|
||||
|
||||
if app.config.autoapi_generate_api_docs:
|
||||
sphinx_mapper_obj.output_rst(root=normalized_root, source_suffix=out_suffix)
|
||||
sphinx_mapper_obj.output_rst(source_suffix=out_suffix)
|
||||
|
||||
|
||||
def build_finished(app, exception):
|
||||
@ -270,6 +282,7 @@ def setup(app):
|
||||
app.add_config_value("autoapi_python_class_content", "class", "html")
|
||||
app.add_config_value("autoapi_generate_api_docs", True, "html")
|
||||
app.add_config_value("autoapi_prepare_jinja_env", None, "html")
|
||||
app.add_config_value("autoapi_own_page_level", "module", "html")
|
||||
app.add_autodocumenter(documenters.AutoapiFunctionDocumenter)
|
||||
app.add_autodocumenter(documenters.AutoapiPropertyDocumenter)
|
||||
app.add_autodocumenter(documenters.AutoapiDecoratorDocumenter)
|
||||
|
@ -1,9 +1,9 @@
|
||||
import os
|
||||
import fnmatch
|
||||
from collections import OrderedDict, namedtuple
|
||||
import fnmatch
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
|
||||
import anyascii
|
||||
from jinja2 import Environment, FileSystemLoader, TemplateNotFound
|
||||
import sphinx
|
||||
import sphinx.util
|
||||
@ -12,29 +12,35 @@ from sphinx.util.display import status_iterator
|
||||
from sphinx.util.osutil import ensuredir
|
||||
import sphinx.util.logging
|
||||
|
||||
from ..settings import API_ROOT, TEMPLATE_DIR
|
||||
from ..settings import TEMPLATE_DIR
|
||||
|
||||
LOGGER = sphinx.util.logging.getLogger(__name__)
|
||||
_OWN_PAGE_LEVELS = [
|
||||
"package",
|
||||
"module",
|
||||
"exception",
|
||||
"class",
|
||||
"function",
|
||||
"method",
|
||||
"property",
|
||||
"data",
|
||||
"attribute",
|
||||
]
|
||||
|
||||
Path = namedtuple("Path", ["absolute", "relative"])
|
||||
|
||||
|
||||
class PythonMapperBase:
|
||||
|
||||
"""Base object for JSON -> Python object mapping.
|
||||
|
||||
Subclasses of this object will handle their language specific JSON input,
|
||||
and map that onto this standard Python object.
|
||||
Subclasses may also include language-specific attributes on this object.
|
||||
|
||||
Arguments:
|
||||
|
||||
Args:
|
||||
obj: JSON object representing this object
|
||||
jinja_env: A template environment for rendering this object
|
||||
|
||||
Required attributes:
|
||||
|
||||
Attributes:
|
||||
id (str): A globally unique identifier for this object.
|
||||
Generally a fully qualified name, including namespace.
|
||||
@ -44,25 +50,21 @@ class PythonMapperBase:
|
||||
children (list): Children of this object
|
||||
parameters (list): Parameters to this object
|
||||
methods (list): Methods on this object
|
||||
|
||||
Optional attributes:
|
||||
|
||||
"""
|
||||
|
||||
language = "base"
|
||||
type = "base"
|
||||
# Create a page in the output for this object.
|
||||
top_level_object = False
|
||||
_RENDER_LOG_LEVEL = "VERBOSE"
|
||||
|
||||
def __init__(self, obj, jinja_env, app, options=None):
|
||||
def __init__(self, obj, jinja_env, app, url_root, options=None):
|
||||
self.app = app
|
||||
self.obj = obj
|
||||
self.options = options
|
||||
self.jinja_env = jinja_env
|
||||
self.url_root = os.path.join("/", API_ROOT)
|
||||
self.url_root = url_root
|
||||
|
||||
self.name = None
|
||||
self.qual_name = None
|
||||
self.id = None
|
||||
|
||||
def __getstate__(self):
|
||||
@ -90,10 +92,15 @@ class PythonMapperBase:
|
||||
return self.render()
|
||||
|
||||
def get_context_data(self):
|
||||
own_page_level = self.app.config.autoapi_own_page_level
|
||||
desired_page_level = _OWN_PAGE_LEVELS.index(own_page_level)
|
||||
own_page_types = set(_OWN_PAGE_LEVELS[: desired_page_level + 1])
|
||||
|
||||
return {
|
||||
"autoapi_options": self.app.config.autoapi_options,
|
||||
"include_summaries": self.app.config.autoapi_include_summaries,
|
||||
"obj": self,
|
||||
"own_page_types": own_page_types,
|
||||
"sphinx_version": sphinx.version_info,
|
||||
}
|
||||
|
||||
@ -111,28 +118,19 @@ class PythonMapperBase:
|
||||
"""Shorten name property"""
|
||||
return self.name.split(".")[-1]
|
||||
|
||||
@property
|
||||
def pathname(self):
|
||||
"""Sluggified path for filenames
|
||||
def output_dir(self, root):
|
||||
"""The directory to render this object."""
|
||||
module = self.id[: -(len("." + self.qual_name))]
|
||||
parts = [root] + module.split(".")
|
||||
return pathlib.PurePosixPath(*parts)
|
||||
|
||||
Slugs to a filename using the follow steps
|
||||
def output_filename(self):
|
||||
"""The name of the file to render into, without a file suffix."""
|
||||
filename = self.qual_name
|
||||
if filename == "index":
|
||||
filename = ".index"
|
||||
|
||||
* Decode unicode to approximate ascii
|
||||
* Remove existing hyphens
|
||||
* Substitute hyphens for non-word characters
|
||||
* Break up the string as paths
|
||||
"""
|
||||
slug = self.name
|
||||
slug = anyascii.anyascii(slug)
|
||||
slug = slug.replace("-", "")
|
||||
slug = re.sub(r"[^\w\.]+", "-", slug).strip("-")
|
||||
return os.path.join(*slug.split("."))
|
||||
|
||||
def include_dir(self, root):
|
||||
"""Return directory of file"""
|
||||
parts = [root]
|
||||
parts.extend(self.pathname.split(os.path.sep))
|
||||
return "/".join(parts)
|
||||
return filename
|
||||
|
||||
@property
|
||||
def include_path(self):
|
||||
@ -141,9 +139,7 @@ class PythonMapperBase:
|
||||
This is used in ``toctree`` directives, as Sphinx always expects Unix
|
||||
path separators
|
||||
"""
|
||||
parts = [self.include_dir(root=self.url_root)]
|
||||
parts.append("index")
|
||||
return "/".join(parts)
|
||||
return str(self.output_dir(self.url_root) / self.output_filename())
|
||||
|
||||
@property
|
||||
def display(self):
|
||||
@ -163,14 +159,13 @@ class PythonMapperBase:
|
||||
|
||||
|
||||
class SphinxMapperBase:
|
||||
|
||||
"""Base class for mapping `PythonMapperBase` objects to Sphinx.
|
||||
|
||||
Args:
|
||||
app: Sphinx application instance
|
||||
"""
|
||||
|
||||
def __init__(self, app, template_dir=None, url_root=None):
|
||||
def __init__(self, app, template_dir=None, dir_root=None, url_root=None):
|
||||
self.app = app
|
||||
|
||||
template_paths = [TEMPLATE_DIR]
|
||||
@ -192,18 +187,21 @@ class SphinxMapperBase:
|
||||
if self.app.config.autoapi_prepare_jinja_env:
|
||||
self.app.config.autoapi_prepare_jinja_env(self.jinja_env)
|
||||
|
||||
own_page_level = self.app.config.autoapi_own_page_level
|
||||
desired_page_level = _OWN_PAGE_LEVELS.index(own_page_level)
|
||||
self.own_page_types = set(_OWN_PAGE_LEVELS[: desired_page_level + 1])
|
||||
|
||||
self.dir_root = dir_root
|
||||
self.url_root = url_root
|
||||
|
||||
# Mapping of {filepath -> raw data}
|
||||
self.paths = OrderedDict()
|
||||
# Mapping of {object id -> Python Object}
|
||||
self.objects = OrderedDict()
|
||||
self.objects_to_render = OrderedDict()
|
||||
# Mapping of {object id -> Python Object}
|
||||
self.all_objects = OrderedDict()
|
||||
# Mapping of {namespace id -> Python Object}
|
||||
self.namespaces = OrderedDict()
|
||||
# Mapping of {namespace id -> Python Object}
|
||||
self.top_level_objects = OrderedDict()
|
||||
|
||||
def load(self, patterns, dirs, ignore=None):
|
||||
"""Load objects from the filesystem into the ``paths`` dictionary."""
|
||||
@ -281,12 +279,17 @@ class SphinxMapperBase:
|
||||
Args:
|
||||
obj: Instance of a AutoAPI object
|
||||
"""
|
||||
self.objects[obj.id] = obj
|
||||
display = obj.display
|
||||
if display and obj.type in self.own_page_types:
|
||||
self.objects_to_render[obj.id] = obj
|
||||
|
||||
self.all_objects[obj.id] = obj
|
||||
child_stack = list(obj.children)
|
||||
while child_stack:
|
||||
child = child_stack.pop()
|
||||
self.all_objects[child.id] = child
|
||||
if display and child.type in self.own_page_types:
|
||||
self.objects_to_render[child.id] = child
|
||||
child_stack.extend(getattr(child, "children", ()))
|
||||
|
||||
def map(self, options=None):
|
||||
@ -308,31 +311,32 @@ class SphinxMapperBase:
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def output_rst(self, root, source_suffix):
|
||||
def output_rst(self, source_suffix):
|
||||
for _, obj in status_iterator(
|
||||
self.objects.items(),
|
||||
self.objects_to_render.items(),
|
||||
colorize("bold", "[AutoAPI] ") + "Rendering Data... ",
|
||||
length=len(self.objects),
|
||||
length=len(self.objects_to_render),
|
||||
verbosity=1,
|
||||
stringify_func=(lambda x: x[0]),
|
||||
):
|
||||
rst = obj.render()
|
||||
rst = obj.render(is_own_page=True)
|
||||
if not rst:
|
||||
continue
|
||||
|
||||
detail_dir = obj.include_dir(root=root)
|
||||
ensuredir(detail_dir)
|
||||
path = os.path.join(detail_dir, f"index{source_suffix}")
|
||||
output_dir = obj.output_dir(self.dir_root)
|
||||
ensuredir(output_dir)
|
||||
output_path = output_dir / obj.output_filename()
|
||||
path = f"{output_path}{source_suffix}"
|
||||
with open(path, "wb+") as detail_file:
|
||||
detail_file.write(rst.encode("utf-8"))
|
||||
|
||||
if self.app.config.autoapi_add_toctree_entry:
|
||||
self._output_top_rst(root)
|
||||
self._output_top_rst()
|
||||
|
||||
def _output_top_rst(self, root):
|
||||
def _output_top_rst(self):
|
||||
# Render Top Index
|
||||
top_level_index = os.path.join(root, "index.rst")
|
||||
pages = self.objects.values()
|
||||
top_level_index = os.path.join(self.dir_root, "index.rst")
|
||||
pages = [obj for obj in self.objects_to_render.values() if obj.display]
|
||||
with open(top_level_index, "wb") as top_level_file:
|
||||
content = self.jinja_env.get_template("index.rst")
|
||||
top_level_file.write(content.render(pages=pages).encode("utf-8"))
|
||||
|
@ -24,6 +24,7 @@ from .objects import (
|
||||
PythonAttribute,
|
||||
PythonData,
|
||||
PythonException,
|
||||
TopLevelPythonPythonMapper,
|
||||
)
|
||||
|
||||
LOGGER = sphinx.util.logging.getLogger(__name__)
|
||||
@ -61,12 +62,14 @@ def _expand_wildcard_placeholder(original_module, originals_map, placeholder):
|
||||
placeholders = []
|
||||
for original in originals:
|
||||
new_full_name = placeholder["full_name"].replace("*", original["name"])
|
||||
new_qual_name = placeholder["qual_name"].replace("*", original["name"])
|
||||
new_original_path = placeholder["original_path"].replace("*", original["name"])
|
||||
if "original_path" in original:
|
||||
new_original_path = original["original_path"]
|
||||
new_placeholder = dict(
|
||||
placeholder,
|
||||
name=original["name"],
|
||||
qual_name=new_qual_name,
|
||||
full_name=new_full_name,
|
||||
original_path=new_original_path,
|
||||
)
|
||||
@ -166,6 +169,7 @@ def _resolve_placeholder(placeholder, original):
|
||||
assert original["type"] != "placeholder"
|
||||
# The name remains the same.
|
||||
new["name"] = placeholder["name"]
|
||||
new["qual_name"] = placeholder["qual_name"]
|
||||
new["full_name"] = placeholder["full_name"]
|
||||
# Record where the placeholder originally came from.
|
||||
new["original_path"] = original["full_name"]
|
||||
@ -216,8 +220,7 @@ def _link_objs(value):
|
||||
|
||||
|
||||
class PythonSphinxMapper(SphinxMapperBase):
|
||||
|
||||
"""Auto API domain handler for Python
|
||||
"""AutoAPI domain handler for Python
|
||||
|
||||
Parses directly from Python files.
|
||||
|
||||
@ -240,8 +243,8 @@ class PythonSphinxMapper(SphinxMapperBase):
|
||||
)
|
||||
}
|
||||
|
||||
def __init__(self, app, template_dir=None, url_root=None):
|
||||
super().__init__(app, template_dir, url_root)
|
||||
def __init__(self, app, template_dir=None, dir_root=None, url_root=None):
|
||||
super().__init__(app, template_dir, dir_root, url_root)
|
||||
|
||||
self.jinja_env.filters["link_objs"] = _link_objs
|
||||
self._use_implicit_namespace = (
|
||||
@ -269,6 +272,7 @@ class PythonSphinxMapper(SphinxMapperBase):
|
||||
dir_root = dir_
|
||||
if (
|
||||
os.path.exists(os.path.join(dir_, "__init__.py"))
|
||||
or os.path.exists(os.path.join(dir_, "__init__.pyi"))
|
||||
or self._use_implicit_namespace
|
||||
):
|
||||
dir_root = os.path.abspath(os.path.join(dir_, os.pardir))
|
||||
@ -339,25 +343,44 @@ class PythonSphinxMapper(SphinxMapperBase):
|
||||
visit_path = collections.OrderedDict()
|
||||
_resolve_module_placeholders(modules, module_name, visit_path, resolved)
|
||||
|
||||
def _hide_yo_kids(self):
|
||||
"""For all direct children of a module/package, hide them if needed."""
|
||||
for module in self.paths.values():
|
||||
if module["all"] is not None:
|
||||
all_names = set(module["all"])
|
||||
for child in module["children"]:
|
||||
if child["qual_name"] not in all_names:
|
||||
child["hide"] = True
|
||||
elif module["type"] == "module":
|
||||
for child in module["children"]:
|
||||
if child.get("imported"):
|
||||
child["hide"] = True
|
||||
|
||||
def map(self, options=None):
|
||||
self._resolve_placeholders()
|
||||
self._hide_yo_kids()
|
||||
self.app.env.autoapi_annotations = {}
|
||||
|
||||
super().map(options)
|
||||
|
||||
parents = {obj.name: obj for obj in self.objects.values()}
|
||||
for obj in self.objects.values():
|
||||
top_level_objects = {
|
||||
obj.id: obj
|
||||
for obj in self.all_objects.values()
|
||||
if isinstance(obj, TopLevelPythonPythonMapper)
|
||||
}
|
||||
parents = {obj.name: obj for obj in top_level_objects.values()}
|
||||
for obj in top_level_objects.values():
|
||||
parent_name = obj.name.rsplit(".", 1)[0]
|
||||
if parent_name in parents and parent_name != obj.name:
|
||||
parent = parents[parent_name]
|
||||
attr = f"sub{obj.type}s"
|
||||
getattr(parent, attr).append(obj)
|
||||
|
||||
for obj in self.objects.values():
|
||||
for obj in top_level_objects.values():
|
||||
obj.submodules.sort()
|
||||
obj.subpackages.sort()
|
||||
|
||||
self.app.env.autoapi_objects = self.objects
|
||||
self.app.env.autoapi_objects = self.objects_to_render
|
||||
self.app.env.autoapi_all_objects = self.all_objects
|
||||
|
||||
def create_class(self, data, options=None, **kwargs):
|
||||
@ -378,9 +401,9 @@ class PythonSphinxMapper(SphinxMapperBase):
|
||||
options=self.app.config.autoapi_options,
|
||||
jinja_env=self.jinja_env,
|
||||
app=self.app,
|
||||
url_root=self.url_root,
|
||||
**kwargs,
|
||||
)
|
||||
obj.url_root = self.url_root
|
||||
|
||||
for child_data in data.get("children", []):
|
||||
for child_obj in self.create_class(
|
||||
|
@ -1,4 +1,5 @@
|
||||
import functools
|
||||
import pathlib
|
||||
from typing import List, Optional
|
||||
|
||||
import sphinx.util.logging
|
||||
@ -38,11 +39,13 @@ class PythonPythonMapper(PythonMapperBase):
|
||||
language = "python"
|
||||
is_callable = False
|
||||
member_order = 0
|
||||
type: str
|
||||
|
||||
def __init__(self, obj, class_content="class", **kwargs) -> None:
|
||||
super().__init__(obj, **kwargs)
|
||||
|
||||
self.name = obj["name"]
|
||||
self.qual_name = obj["qual_name"]
|
||||
self.id = obj.get("full_name", self.name)
|
||||
|
||||
# Optional
|
||||
@ -55,6 +58,7 @@ class PythonPythonMapper(PythonMapperBase):
|
||||
|
||||
:type: bool
|
||||
"""
|
||||
self._hide = obj.get("hide", False)
|
||||
|
||||
# For later
|
||||
self._class_content = class_content
|
||||
@ -80,6 +84,16 @@ class PythonPythonMapper(PythonMapperBase):
|
||||
self._docstring = value
|
||||
self._docstring_resolved = True
|
||||
|
||||
@property
|
||||
def is_top_level_object(self):
|
||||
"""Whether this object is at the very top level (True) or not (False).
|
||||
|
||||
This will be False for subpackages and submodules.
|
||||
|
||||
:type: bool
|
||||
"""
|
||||
return "." not in self.id
|
||||
|
||||
@property
|
||||
def is_undoc_member(self):
|
||||
"""Whether this object has a docstring (False) or not (True).
|
||||
@ -143,12 +157,17 @@ class PythonPythonMapper(PythonMapperBase):
|
||||
self.is_special_member and "special-members" not in self.options
|
||||
)
|
||||
skip_imported_member = self.imported and "imported-members" not in self.options
|
||||
skip_inherited_member = (
|
||||
self.inherited and "inherited-members" not in self.options
|
||||
)
|
||||
|
||||
return (
|
||||
skip_undoc_member
|
||||
self._hide
|
||||
or skip_undoc_member
|
||||
or skip_private_member
|
||||
or skip_special_member
|
||||
or skip_imported_member
|
||||
or skip_inherited_member
|
||||
)
|
||||
|
||||
def _ask_ignore(self, skip): # type: (bool) -> bool
|
||||
@ -228,11 +247,10 @@ class PythonMethod(PythonFunction):
|
||||
"""
|
||||
|
||||
def _should_skip(self): # type: () -> bool
|
||||
skip = super()._should_skip() or self.name in (
|
||||
return super()._should_skip() or self.name in (
|
||||
"__new__",
|
||||
"__init__",
|
||||
)
|
||||
return self._ask_ignore(skip)
|
||||
|
||||
|
||||
class PythonProperty(PythonPythonMapper):
|
||||
@ -299,14 +317,6 @@ class TopLevelPythonPythonMapper(PythonPythonMapper):
|
||||
def __init__(self, obj, **kwargs):
|
||||
super().__init__(obj, **kwargs)
|
||||
|
||||
self.top_level_object = "." not in self.name
|
||||
"""Whether this object is at the very top level (True) or not (False).
|
||||
|
||||
This will be False for subpackages and submodules.
|
||||
|
||||
:type: bool
|
||||
"""
|
||||
|
||||
self.subpackages = []
|
||||
self.submodules = []
|
||||
self.all = obj["all"]
|
||||
@ -334,6 +344,15 @@ class TopLevelPythonPythonMapper(PythonPythonMapper):
|
||||
"""
|
||||
return self._children_of_type("class")
|
||||
|
||||
def output_dir(self, root):
|
||||
"""The path to the file to render into, without a file suffix."""
|
||||
parts = [root] + self.name.split(".")
|
||||
return pathlib.PurePosixPath(*parts)
|
||||
|
||||
def output_filename(self):
|
||||
"""The path to the file to render into, without a file suffix."""
|
||||
return "index"
|
||||
|
||||
|
||||
class PythonModule(TopLevelPythonPythonMapper):
|
||||
"""The representation of a module."""
|
||||
|
@ -15,16 +15,20 @@ def _prepare_docstring(doc):
|
||||
|
||||
class Parser:
|
||||
def __init__(self):
|
||||
self._name_stack = []
|
||||
self._qual_name_stack = []
|
||||
self._full_name_stack = []
|
||||
self._encoding = None
|
||||
|
||||
def _get_qual_name(self, name):
|
||||
return ".".join(self._qual_name_stack + [name])
|
||||
|
||||
def _get_full_name(self, name):
|
||||
return ".".join(self._name_stack + [name])
|
||||
return ".".join(self._full_name_stack + [name])
|
||||
|
||||
def _parse_file(self, file_path, condition):
|
||||
directory, filename = os.path.split(file_path)
|
||||
module_parts = []
|
||||
if filename != "__init__.py":
|
||||
if filename != "__init__.py" and filename != "__init__.pyi":
|
||||
module_part = os.path.splitext(filename)[0]
|
||||
module_parts = [module_part]
|
||||
module_parts = collections.deque(module_parts)
|
||||
@ -40,7 +44,10 @@ class Parser:
|
||||
def parse_file(self, file_path):
|
||||
return self._parse_file(
|
||||
file_path,
|
||||
lambda directory: os.path.isfile(os.path.join(directory, "__init__.py")),
|
||||
lambda directory: (
|
||||
os.path.isfile(os.path.join(directory, "__init__.py"))
|
||||
or os.path.isfile(os.path.join(directory, "__init__.pyi"))
|
||||
),
|
||||
)
|
||||
|
||||
def parse_file_in_namespace(self, file_path, dir_root):
|
||||
@ -88,6 +95,7 @@ class Parser:
|
||||
data = {
|
||||
"type": type_,
|
||||
"name": target,
|
||||
"qual_name": self._get_qual_name(target),
|
||||
"full_name": self._get_full_name(target),
|
||||
"doc": _prepare_docstring(doc),
|
||||
"value": value,
|
||||
@ -108,6 +116,7 @@ class Parser:
|
||||
data = {
|
||||
"type": type_,
|
||||
"name": node.name,
|
||||
"qual_name": self._get_qual_name(node.name),
|
||||
"full_name": self._get_full_name(node.name),
|
||||
"bases": basenames,
|
||||
"doc": _prepare_docstring(astroid_utils.get_class_docstring(node)),
|
||||
@ -116,7 +125,8 @@ class Parser:
|
||||
"children": [],
|
||||
}
|
||||
|
||||
self._name_stack.append(node.name)
|
||||
self._qual_name_stack.append(node.name)
|
||||
self._full_name_stack.append(node.name)
|
||||
overridden = set()
|
||||
overloads = {}
|
||||
for base in itertools.chain(iter((node,)), node.ancestors()):
|
||||
@ -145,7 +155,8 @@ class Parser:
|
||||
|
||||
overridden.update(seen)
|
||||
|
||||
self._name_stack.pop()
|
||||
self._qual_name_stack.pop()
|
||||
self._full_name_stack.pop()
|
||||
|
||||
return [data]
|
||||
|
||||
@ -182,6 +193,7 @@ class Parser:
|
||||
data = {
|
||||
"type": type_,
|
||||
"name": node.name,
|
||||
"qual_name": self._get_qual_name(node.name),
|
||||
"full_name": self._get_full_name(node.name),
|
||||
"args": astroid_utils.get_args_info(node.args),
|
||||
"doc": _prepare_docstring(astroid_utils.get_func_docstring(node)),
|
||||
@ -206,14 +218,19 @@ class Parser:
|
||||
def _parse_local_import_from(self, node):
|
||||
result = []
|
||||
|
||||
for name, alias in node.names:
|
||||
is_wildcard = (alias or name) == "*"
|
||||
full_name = self._get_full_name(alias or name)
|
||||
original_path = astroid_utils.get_full_import_name(node, alias or name)
|
||||
for import_name, alias in node.names:
|
||||
is_wildcard = (alias or import_name) == "*"
|
||||
original_path = astroid_utils.get_full_import_name(
|
||||
node, alias or import_name
|
||||
)
|
||||
name = original_path if is_wildcard else (alias or import_name)
|
||||
qual_name = self._get_qual_name(alias or import_name)
|
||||
full_name = self._get_full_name(alias or import_name)
|
||||
|
||||
data = {
|
||||
"type": "placeholder",
|
||||
"name": original_path if is_wildcard else (alias or name),
|
||||
"name": name,
|
||||
"qual_name": qual_name,
|
||||
"full_name": full_name,
|
||||
"original_path": original_path,
|
||||
}
|
||||
@ -230,12 +247,13 @@ class Parser:
|
||||
if node.package:
|
||||
type_ = "package"
|
||||
|
||||
self._name_stack = [node.name]
|
||||
self._full_name_stack = [node.name]
|
||||
self._encoding = node.file_encoding
|
||||
|
||||
data = {
|
||||
"type": type_,
|
||||
"name": node.name,
|
||||
"qual_name": node.name,
|
||||
"full_name": node.name,
|
||||
"doc": _prepare_docstring(node.doc_node.value if node.doc_node else ""),
|
||||
"children": [],
|
||||
|
@ -6,10 +6,8 @@ This page contains auto-generated API reference documentation [#f1]_.
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
|
||||
{% for page in pages %}
|
||||
{% if page.top_level_object and page.display %}
|
||||
{% for page in pages|selectattr("is_top_level_object") %}
|
||||
{{ page.include_path }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
.. [#f1] Created with `sphinx-autoapi <https://github.com/readthedocs/sphinx-autoapi>`_
|
||||
|
@ -1,60 +1,104 @@
|
||||
{% if obj.display %}
|
||||
.. py:{{ obj.type }}:: {{ obj.short_name }}{% if obj.args %}({{ obj.args }}){% endif %}
|
||||
{% if is_own_page %}
|
||||
:class:`{{ obj.id }}`
|
||||
========={{ "=" * obj.id | length }}
|
||||
|
||||
{% for (args, return_annotation) in obj.overloads %}
|
||||
{% endif %}
|
||||
{% set visible_children = obj.children|selectattr("display")|list %}
|
||||
{% set own_page_children = visible_children|selectattr("type", "in", own_page_types)|list %}
|
||||
{% if is_own_page and own_page_children %}
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
{% for child in own_page_children %}
|
||||
{{ child.include_path }}
|
||||
{% endfor %}
|
||||
|
||||
{% endif %}
|
||||
.. py:{{ obj.type }}:: {% if is_own_page %}{{ obj.id }}{% else %}{{ obj.short_name }}{% endif %}{% if obj.args %}({{ obj.args }}){% endif %}
|
||||
|
||||
{% for (args, return_annotation) in obj.overloads %}
|
||||
{{ " " * (obj.type | length) }} {{ obj.short_name }}{% if args %}({{ args }}){% endif %}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% endfor %}
|
||||
{% if obj.bases %}
|
||||
{% if "show-inheritance" in autoapi_options %}
|
||||
{% if "show-inheritance" in autoapi_options %}
|
||||
|
||||
Bases: {% for base in obj.bases %}{{ base|link_objs }}{% if not loop.last %}, {% endif %}{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if "show-inheritance-diagram" in autoapi_options and obj.bases != ["object"] %}
|
||||
.. autoapi-inheritance-diagram:: {{ obj.obj["full_name"] }}
|
||||
:parts: 1
|
||||
{% if "private-members" in autoapi_options %}
|
||||
:private-bases:
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% if "show-inheritance-diagram" in autoapi_options and obj.bases != ["object"] %}
|
||||
.. autoapi-inheritance-diagram:: {{ obj.obj["full_name"] }}
|
||||
:parts: 1
|
||||
{% if "private-members" in autoapi_options %}
|
||||
:private-bases:
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if obj.docstring %}
|
||||
|
||||
{{ obj.docstring|indent(3) }}
|
||||
{% endif %}
|
||||
{% if "inherited-members" in autoapi_options %}
|
||||
{% set visible_classes = obj.classes|selectattr("display")|list %}
|
||||
{% else %}
|
||||
{% set visible_classes = obj.classes|rejectattr("inherited")|selectattr("display")|list %}
|
||||
{% endif %}
|
||||
{% for klass in visible_classes %}
|
||||
{{ klass.render()|indent(3) }}
|
||||
{% for obj_item in visible_children %}
|
||||
{% if obj_item.type not in own_page_types %}
|
||||
|
||||
{{ obj_item.render()|indent(3) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if "inherited-members" in autoapi_options %}
|
||||
{% set visible_properties = obj.properties|selectattr("display")|list %}
|
||||
{% else %}
|
||||
{% set visible_properties = obj.properties|rejectattr("inherited")|selectattr("display")|list %}
|
||||
{% if is_own_page and own_page_children %}
|
||||
{% set visible_attributes = own_page_children|selectattr("type", "equalto", "attribute")|list %}
|
||||
{% if visible_attributes %}
|
||||
Attributes
|
||||
----------
|
||||
|
||||
.. autoapisummary::
|
||||
|
||||
{% for attribute in visible_attributes %}
|
||||
{{ attribute.id }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% endif %}
|
||||
{% set visible_exceptions = own_page_children|selectattr("type", "equalto", "exception")|list %}
|
||||
{% if visible_exceptions %}
|
||||
Exceptions
|
||||
----------
|
||||
|
||||
.. autoapisummary::
|
||||
|
||||
{% for exception in visible_exceptions %}
|
||||
{{ exception.id }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% endif %}
|
||||
{% set visible_classes = own_page_children|selectattr("type", "equalto", "class")|list %}
|
||||
{% if visible_classes %}
|
||||
Classes
|
||||
-------
|
||||
|
||||
.. autoapisummary::
|
||||
|
||||
{% for klass in visible_classes %}
|
||||
{{ klass.id }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% endif %}
|
||||
{% set visible_methods = own_page_children|selectattr("type", "equalto", "method")|list %}
|
||||
{% if visible_methods %}
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. autoapisummary::
|
||||
|
||||
{% for method in visible_methods %}
|
||||
{{ method.id }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% for property in visible_properties %}
|
||||
{{ property.render()|indent(3) }}
|
||||
{% endfor %}
|
||||
{% if "inherited-members" in autoapi_options %}
|
||||
{% set visible_attributes = obj.attributes|selectattr("display")|list %}
|
||||
{% else %}
|
||||
{% set visible_attributes = obj.attributes|rejectattr("inherited")|selectattr("display")|list %}
|
||||
{% endif %}
|
||||
{% for attribute in visible_attributes %}
|
||||
{{ attribute.render()|indent(3) }}
|
||||
{% endfor %}
|
||||
{% if "inherited-members" in autoapi_options %}
|
||||
{% set visible_methods = obj.methods|selectattr("display")|list %}
|
||||
{% else %}
|
||||
{% set visible_methods = obj.methods|rejectattr("inherited")|selectattr("display")|list %}
|
||||
{% endif %}
|
||||
{% for method in visible_methods %}
|
||||
{{ method.render()|indent(3) }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
@ -1,37 +1,42 @@
|
||||
{% if obj.display %}
|
||||
.. py:{{ obj.type }}:: {{ obj.name }}
|
||||
{%- if obj.annotation is not none %}
|
||||
{% if is_own_page %}
|
||||
:py:{{ obj.type|truncate(4, True, "", 0) }}:`{{ obj.id }}`
|
||||
==========={{ "=" * obj.id | length }}
|
||||
|
||||
:type: {%- if obj.annotation %} {{ obj.annotation }}{%- endif %}
|
||||
{% endif %}
|
||||
.. py:{{ obj.type }}:: {% if is_own_page %}{{ obj.id }}{% else %}{{ obj.name }}{% endif %}
|
||||
{% if obj.annotation is not none %}
|
||||
|
||||
{%- endif %}
|
||||
:type: {% if obj.annotation %} {{ obj.annotation }}{% endif %}
|
||||
{% endif %}
|
||||
{% if obj.value is not none %}
|
||||
|
||||
{%- if obj.value is not none %}
|
||||
{% if obj.value is string and obj.value.splitlines()|count > 1 %}
|
||||
:value: Multiline-String
|
||||
|
||||
:value: {% if obj.value is string and obj.value.splitlines()|count > 1 -%}
|
||||
Multiline-String
|
||||
.. raw:: html
|
||||
|
||||
.. raw:: html
|
||||
<details><summary>Show Value</summary>
|
||||
|
||||
<details><summary>Show Value</summary>
|
||||
.. code-block:: python
|
||||
|
||||
.. code-block:: python
|
||||
"""{{ obj.value|indent(width=6,blank=true) }}"""
|
||||
|
||||
"""{{ obj.value|indent(width=8,blank=true) }}"""
|
||||
.. raw:: html
|
||||
|
||||
.. raw:: html
|
||||
</details>
|
||||
|
||||
</details>
|
||||
|
||||
{%- else -%}
|
||||
{%- if obj.value is string -%}
|
||||
{{ "%r" % obj.value|string|truncate(100) }}
|
||||
{%- else -%}
|
||||
{{ obj.value|string|truncate(100) }}
|
||||
{%- endif -%}
|
||||
{%- endif %}
|
||||
{%- endif %}
|
||||
{% else %}
|
||||
{% if obj.value is string %}
|
||||
:value: {{ "%r" % obj.value|string|truncate(100) }}
|
||||
{% else %}
|
||||
:value: {{ obj.value|string|truncate(100) }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if obj.docstring %}
|
||||
|
||||
{{ obj.docstring|indent(3) }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
@ -1,15 +1,21 @@
|
||||
{% if obj.display %}
|
||||
.. py:function:: {{ obj.short_name }}({{ obj.args }}){% if obj.return_annotation is not none %} -> {{ obj.return_annotation }}{% endif %}
|
||||
{% if is_own_page %}
|
||||
:py:func:`{{ obj.id }}`
|
||||
==========={{ "=" * obj.id | length }}
|
||||
|
||||
{% for (args, return_annotation) in obj.overloads %}
|
||||
{{ obj.short_name }}({{ args }}){% if return_annotation is not none %} -> {{ return_annotation }}{% endif %}
|
||||
{% endif %}
|
||||
.. py:function:: {% if is_own_page %}{{ obj.id }}{% else %}{{ obj.short_name }}{% endif %}({{ obj.args }}){% if obj.return_annotation is not none %} -> {{ obj.return_annotation }}{% endif %}
|
||||
{% for (args, return_annotation) in obj.overloads %}
|
||||
|
||||
{% endfor %}
|
||||
{%+ if is_own_page %}{{ obj.id }}{% else %}{{ obj.short_name }}{% endif %}({{ args }}){% if return_annotation is not none %} -> {{ return_annotation }}{% endif %}
|
||||
{% endfor %}
|
||||
{% for property in obj.properties %}
|
||||
|
||||
:{{ property }}:
|
||||
{% endfor %}
|
||||
|
||||
{% if obj.docstring %}
|
||||
|
||||
{{ obj.docstring|indent(3) }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
@ -1,19 +1,21 @@
|
||||
{%- if obj.display %}
|
||||
.. py:method:: {{ obj.short_name }}({{ obj.args }}){% if obj.return_annotation is not none %} -> {{ obj.return_annotation }}{% endif %}
|
||||
{% if obj.display %}
|
||||
{% if is_own_page %}
|
||||
:py:meth:`{{ obj.id }}`
|
||||
==========={{ "=" * obj.id | length }}
|
||||
|
||||
{% for (args, return_annotation) in obj.overloads %}
|
||||
{{ obj.short_name }}({{ args }}){% if return_annotation is not none %} -> {{ return_annotation }}{% endif %}
|
||||
{% endif %}
|
||||
.. py:method:: {% if is_own_page %}{{ obj.id }}{% else %}{{ obj.short_name }}{% endif %}({{ obj.args }}){% if obj.return_annotation is not none %} -> {{ obj.return_annotation }}{% endif %}
|
||||
{% for (args, return_annotation) in obj.overloads %}
|
||||
|
||||
{% endfor %}
|
||||
{% if obj.properties %}
|
||||
{%+ if is_own_page %}{{ obj.id }}{% else %}{{ obj.short_name }}{% endif %}({{ args }}){% if return_annotation is not none %} -> {{ return_annotation }}{% endif %}
|
||||
{% endfor %}
|
||||
{% for property in obj.properties %}
|
||||
|
||||
:{{ property }}:
|
||||
{% endfor %}
|
||||
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
{% if obj.docstring %}
|
||||
|
||||
{{ obj.docstring|indent(3) }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
@ -1,114 +1,170 @@
|
||||
{% if not obj.display %}
|
||||
:orphan:
|
||||
|
||||
{% endif %}
|
||||
:py:mod:`{{ obj.name }}`
|
||||
=========={{ "=" * obj.name|length }}
|
||||
{% if obj.display %}
|
||||
{% if is_own_page %}
|
||||
:py:mod:`{{ obj.id }}`
|
||||
=========={{ "=" * obj.id|length }}
|
||||
|
||||
.. py:module:: {{ obj.name }}
|
||||
|
||||
{% if obj.docstring %}
|
||||
{% if obj.docstring %}
|
||||
.. autoapi-nested-parse::
|
||||
|
||||
{{ obj.docstring|indent(3) }}
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% block subpackages %}
|
||||
{% set visible_subpackages = obj.subpackages|selectattr("display")|list %}
|
||||
{% if visible_subpackages %}
|
||||
{% block subpackages %}
|
||||
{% set visible_subpackages = obj.subpackages|selectattr("display")|list %}
|
||||
{% if visible_subpackages %}
|
||||
Subpackages
|
||||
-----------
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
:maxdepth: 3
|
||||
|
||||
{% for subpackage in visible_subpackages %}
|
||||
{{ subpackage.short_name }}/index.rst
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block submodules %}
|
||||
{% set visible_submodules = obj.submodules|selectattr("display")|list %}
|
||||
{% if visible_submodules %}
|
||||
Submodules
|
||||
----------
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
:maxdepth: 1
|
||||
|
||||
{% for submodule in visible_submodules %}
|
||||
{{ submodule.short_name }}/index.rst
|
||||
{% endfor %}
|
||||
{% for subpackage in visible_subpackages %}
|
||||
{{ subpackage.include_path }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
{% if obj.all is not none %}
|
||||
{% set visible_children = obj.children|selectattr("short_name", "in", obj.all)|list %}
|
||||
{% elif obj.type is equalto("package") %}
|
||||
{% set visible_children = obj.children|selectattr("display")|list %}
|
||||
{% else %}
|
||||
{% set visible_children = obj.children|selectattr("display")|rejectattr("imported")|list %}
|
||||
{% endif %}
|
||||
{% if visible_children %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block submodules %}
|
||||
{% set visible_submodules = obj.submodules|selectattr("display")|list %}
|
||||
{% if visible_submodules %}
|
||||
Submodules
|
||||
----------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
{% for submodule in visible_submodules %}
|
||||
{{ submodule.include_path }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
{% set visible_children = obj.children|selectattr("display")|list %}
|
||||
{% if visible_children %}
|
||||
{% set visible_attributes = visible_children|selectattr("type", "equalto", "data")|list %}
|
||||
{% if visible_attributes %}
|
||||
{% if "attribute" in own_page_types or "show-module-summary" in autoapi_options %}
|
||||
Attributes
|
||||
----------
|
||||
|
||||
{% if "attribute" in own_page_types %}
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
{% for attribute in visible_attributes %}
|
||||
{{ attribute.include_path }}
|
||||
{% endfor %}
|
||||
|
||||
{% endif %}
|
||||
.. autoapisummary::
|
||||
|
||||
{% for attribute in visible_attributes %}
|
||||
{{ attribute.id }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% endif %}
|
||||
{% set visible_exceptions = visible_children|selectattr("type", "equalto", "exception")|list %}
|
||||
{% if visible_exceptions %}
|
||||
{% if "exception" in own_page_types or "show-module-summary" in autoapi_options %}
|
||||
Exceptions
|
||||
----------
|
||||
|
||||
{% if "exception" in own_page_types %}
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
{% for exception in visible_exceptions %}
|
||||
{{ exception.include_path }}
|
||||
{% endfor %}
|
||||
|
||||
{% endif %}
|
||||
.. autoapisummary::
|
||||
|
||||
{% for exception in visible_exceptions %}
|
||||
{{ exception.id }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% endif %}
|
||||
{% set visible_classes = visible_children|selectattr("type", "equalto", "class")|list %}
|
||||
{% if visible_classes %}
|
||||
{% if "class" in own_page_types or "show-module-summary" in autoapi_options %}
|
||||
Classes
|
||||
-------
|
||||
|
||||
{% if "class" in own_page_types %}
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
{% for klass in visible_classes %}
|
||||
{{ klass.include_path }}
|
||||
{% endfor %}
|
||||
|
||||
{% endif %}
|
||||
.. autoapisummary::
|
||||
|
||||
{% for klass in visible_classes %}
|
||||
{{ klass.id }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% endif %}
|
||||
{% set visible_functions = visible_children|selectattr("type", "equalto", "function")|list %}
|
||||
{% if visible_functions %}
|
||||
{% if "function" in own_page_types or "show-module-summary" in autoapi_options %}
|
||||
Functions
|
||||
---------
|
||||
|
||||
{% if "function" in own_page_types %}
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
{% for function in visible_functions %}
|
||||
{{ function.include_path }}
|
||||
{% endfor %}
|
||||
|
||||
{% endif %}
|
||||
.. autoapisummary::
|
||||
|
||||
{% for function in visible_functions %}
|
||||
{{ function.id }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% endif %}
|
||||
{% set this_page_children = visible_children|rejectattr("type", "in", own_page_types)|list %}
|
||||
{% if this_page_children %}
|
||||
{{ obj.type|title }} Contents
|
||||
{{ "-" * obj.type|length }}---------
|
||||
|
||||
{% set visible_classes = visible_children|selectattr("type", "equalto", "class")|list %}
|
||||
{% set visible_functions = visible_children|selectattr("type", "equalto", "function")|list %}
|
||||
{% set visible_attributes = visible_children|selectattr("type", "equalto", "data")|list %}
|
||||
{% if "show-module-summary" in autoapi_options and (visible_classes or visible_functions) %}
|
||||
{% block classes scoped %}
|
||||
{% if visible_classes %}
|
||||
Classes
|
||||
~~~~~~~
|
||||
|
||||
.. autoapisummary::
|
||||
|
||||
{% for klass in visible_classes %}
|
||||
{{ klass.id }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block functions scoped %}
|
||||
{% if visible_functions %}
|
||||
Functions
|
||||
~~~~~~~~~
|
||||
|
||||
.. autoapisummary::
|
||||
|
||||
{% for function in visible_functions %}
|
||||
{{ function.id }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block attributes scoped %}
|
||||
{% if visible_attributes %}
|
||||
Attributes
|
||||
~~~~~~~~~~
|
||||
|
||||
.. autoapisummary::
|
||||
|
||||
{% for attribute in visible_attributes %}
|
||||
{{ attribute.id }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% endif %}
|
||||
{% for obj_item in visible_children %}
|
||||
{% for obj_item in this_page_children %}
|
||||
{{ obj_item.render()|indent(0) }}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% else %}
|
||||
.. py:module:: {{ obj.name }}
|
||||
|
||||
{% if obj.docstring %}
|
||||
.. autoapi-nested-parse::
|
||||
|
||||
{{ obj.docstring|indent(6) }}
|
||||
|
||||
{% endif %}
|
||||
{% for obj_item in visible_children %}
|
||||
{{ obj_item.render()|indent(3) }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
@ -1,13 +1,18 @@
|
||||
{%- if obj.display %}
|
||||
.. py:property:: {{ obj.short_name }}
|
||||
{% if obj.display %}
|
||||
{% if is_own_page %}
|
||||
:py:property:`{{ obj.id }}`
|
||||
==============={{ "=" * obj.id | length }}
|
||||
|
||||
{% endif %}
|
||||
.. py:property:: {% if is_own_page %}{{ obj.id}}{% else %}{{ obj.short_name }}{% endif %}
|
||||
{% if obj.annotation %}
|
||||
|
||||
:type: {{ obj.annotation }}
|
||||
{% endif %}
|
||||
{% if obj.properties %}
|
||||
{% for property in obj.properties %}
|
||||
|
||||
:{{ property }}:
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if obj.docstring %}
|
||||
{{ obj.docstring|indent(3) }}
|
||||
|
1
docs/changes/+59dd3b40.misc
Normal file
1
docs/changes/+59dd3b40.misc
Normal file
@ -0,0 +1 @@
|
||||
Made links to the documention in the README less confusing.
|
1
docs/changes/+af2042c3.misc
Normal file
1
docs/changes/+af2042c3.misc
Normal file
@ -0,0 +1 @@
|
||||
Reformatted to latest stable black style.
|
1
docs/changes/398.bugfix
Normal file
1
docs/changes/398.bugfix
Normal file
@ -0,0 +1 @@
|
||||
Fix submodule with `__init__.pyi` documented as `__init__` instead of submodule name
|
1
docs/changes/412.bugfix
Normal file
1
docs/changes/412.bugfix
Normal file
@ -0,0 +1 @@
|
||||
Fix IndexError when a module docstring contains only a heading
|
@ -2,7 +2,7 @@ How-to Guides
|
||||
=============
|
||||
|
||||
These guides will take you through the steps to perform common actions
|
||||
or solve common problems in AutoAPI.
|
||||
or solve common problems in AutoAPI.
|
||||
They will assume that you already have a Sphinx project with AutoAPI
|
||||
set up already.
|
||||
If you don't know how to do this then read the :doc:`tutorials`.
|
||||
|
@ -79,11 +79,9 @@ Customisation Options
|
||||
and requires `Graphviz <https://graphviz.org/>`_ to be installed.
|
||||
* ``show-module-summary``: Whether to include autosummary directives
|
||||
in generated module documentation.
|
||||
* ``imported-members``: Display objects imported from the same
|
||||
top level package or module.
|
||||
The default module template does not include imported objects,
|
||||
even with this option enabled.
|
||||
The default package template does.
|
||||
* ``imported-members``: For objects imported into a package,
|
||||
display objects imported from the same top level package or module.
|
||||
This option does not effect objects imported into a module.
|
||||
|
||||
|
||||
.. confval:: autoapi_ignore
|
||||
@ -181,6 +179,26 @@ Customisation Options
|
||||
:noindex:
|
||||
|
||||
|
||||
.. confval:: autoapi_own_page_level
|
||||
|
||||
Default: ``'module'``
|
||||
|
||||
This configuration value specifies the level at which objects are rendered on
|
||||
a single page. Valid levels, in descending order of hierarchy, are as
|
||||
follows:
|
||||
|
||||
* ``module``: Packages, modules, subpackages, and submodules.
|
||||
|
||||
* ``class``: Classes, exceptions, and all object types mentioned above.
|
||||
|
||||
* ``function``: Functions, and all object types mentioned above.
|
||||
|
||||
* ``method``: Methods, and all object types mentioned above.
|
||||
|
||||
* ``attribute``: Class and module level attributes, properties,
|
||||
and all object types mentioned above.
|
||||
|
||||
|
||||
Events
|
||||
~~~~~~
|
||||
|
||||
|
@ -49,6 +49,8 @@ This contains:
|
||||
* ``include_summaries``: The value of the :confval:`autoapi_include_summaries`
|
||||
configuration option.
|
||||
* ``obj``: A Python object derived from :class:`PythonPythonMapper`.
|
||||
* ``own_page_types``: A set of strings that contains the object types that
|
||||
render on their own page.
|
||||
* ``sphinx_version``: The contents of :attr:`sphinx.version_info`.
|
||||
|
||||
The object in ``obj`` has a number of standard attributes
|
||||
|
@ -10,11 +10,6 @@ ignore_missing_imports = true
|
||||
module = "autoapi.documenters"
|
||||
ignore_errors = true
|
||||
|
||||
[[tool.mypy.overrides]]
|
||||
# https://github.com/anyascii/anyascii/issues/19
|
||||
module = "anyascii"
|
||||
ignore_missing_imports = true
|
||||
|
||||
[tool.ruff.pydocstyle]
|
||||
convention = "google"
|
||||
|
||||
|
@ -33,7 +33,6 @@ packages = find:
|
||||
include_package_data = True
|
||||
python_requires = >=3.8
|
||||
install_requires =
|
||||
anyascii
|
||||
astroid>=2.7;python_version<"3.12"
|
||||
astroid>=3.0.0a1;python_version>="3.12"
|
||||
Jinja2
|
||||
|
68
tests/python/conftest.py
Normal file
68
tests/python/conftest.py
Normal file
@ -0,0 +1,68 @@
|
||||
import io
|
||||
import os
|
||||
import pathlib
|
||||
import shutil
|
||||
from unittest.mock import call
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
import pytest
|
||||
from sphinx.application import Sphinx
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def rebuild():
|
||||
def _rebuild(confdir=".", **kwargs):
|
||||
app = Sphinx(
|
||||
srcdir=".",
|
||||
confdir=confdir,
|
||||
outdir="_build/html",
|
||||
doctreedir="_build/.doctrees",
|
||||
buildername="html",
|
||||
pdb=True,
|
||||
**kwargs,
|
||||
)
|
||||
app.build()
|
||||
|
||||
return _rebuild
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def builder(rebuild):
|
||||
cwd = os.getcwd()
|
||||
|
||||
def build(test_dir, **kwargs):
|
||||
if kwargs.get("warningiserror"):
|
||||
# Add any warnings raised when using `Sphinx` more than once
|
||||
# in a Python session.
|
||||
confoverrides = kwargs.setdefault("confoverrides", {})
|
||||
confoverrides.setdefault("suppress_warnings", [])
|
||||
suppress = confoverrides["suppress_warnings"]
|
||||
suppress.append("app.add_node")
|
||||
suppress.append("app.add_directive")
|
||||
suppress.append("app.add_role")
|
||||
|
||||
os.chdir("tests/python/{0}".format(test_dir))
|
||||
rebuild(**kwargs)
|
||||
|
||||
yield build
|
||||
|
||||
try:
|
||||
shutil.rmtree("_build")
|
||||
if (pathlib.Path("autoapi") / "index.rst").exists():
|
||||
shutil.rmtree("autoapi")
|
||||
finally:
|
||||
os.chdir(cwd)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def parse():
|
||||
cache = {}
|
||||
|
||||
def parser(path):
|
||||
if path not in cache:
|
||||
with io.open(path, encoding="utf8") as file_handle:
|
||||
cache[path] = BeautifulSoup(file_handle, features="html.parser")
|
||||
|
||||
return cache[path]
|
||||
|
||||
yield parser
|
@ -51,26 +51,21 @@ mixed_list: List[Union[str, int]] = [1, "two", 3]
|
||||
"This is mixed"
|
||||
|
||||
|
||||
def f2(not_yet_a: "A") -> int:
|
||||
...
|
||||
def f2(not_yet_a: "A") -> int: ...
|
||||
|
||||
|
||||
def f3(imported: B) -> B:
|
||||
...
|
||||
def f3(imported: B) -> B: ...
|
||||
|
||||
|
||||
class MyGeneric(Generic[T, U]):
|
||||
...
|
||||
class MyGeneric(Generic[T, U]): ...
|
||||
|
||||
|
||||
@overload
|
||||
def overloaded_func(a: float) -> float:
|
||||
...
|
||||
def overloaded_func(a: float) -> float: ...
|
||||
|
||||
|
||||
@typing.overload
|
||||
def overloaded_func(a: str) -> str:
|
||||
...
|
||||
def overloaded_func(a: str) -> str: ...
|
||||
|
||||
|
||||
def overloaded_func(a: Union[float, str]) -> Union[float, str]:
|
||||
@ -79,8 +74,7 @@ def overloaded_func(a: Union[float, str]) -> Union[float, str]:
|
||||
|
||||
|
||||
@overload
|
||||
def undoc_overloaded_func(a: str) -> str:
|
||||
...
|
||||
def undoc_overloaded_func(a: str) -> str: ...
|
||||
|
||||
|
||||
def undoc_overloaded_func(a: str) -> str:
|
||||
@ -112,33 +106,28 @@ class A:
|
||||
return "method"
|
||||
|
||||
@overload
|
||||
def overloaded_method(self, a: float) -> float:
|
||||
...
|
||||
def overloaded_method(self, a: float) -> float: ...
|
||||
|
||||
@typing.overload
|
||||
def overloaded_method(self, a: str) -> str:
|
||||
...
|
||||
def overloaded_method(self, a: str) -> str: ...
|
||||
|
||||
def overloaded_method(self, a: Union[float, str]) -> Union[float, str]:
|
||||
"""Overloaded method"""
|
||||
return a * 2
|
||||
|
||||
@overload
|
||||
def undoc_overloaded_method(self, a: float) -> float:
|
||||
...
|
||||
def undoc_overloaded_method(self, a: float) -> float: ...
|
||||
|
||||
def undoc_overloaded_method(self, a: float) -> float:
|
||||
return a * 2
|
||||
|
||||
@typing.overload
|
||||
@classmethod
|
||||
def overloaded_class_method(cls, a: float) -> float:
|
||||
...
|
||||
def overloaded_class_method(cls, a: float) -> float: ...
|
||||
|
||||
@overload
|
||||
@classmethod
|
||||
def overloaded_class_method(cls, a: str) -> str:
|
||||
...
|
||||
def overloaded_class_method(cls, a: str) -> str: ...
|
||||
|
||||
@classmethod
|
||||
def overloaded_class_method(cls, a: Union[float, str]) -> Union[float, str]:
|
||||
@ -148,23 +137,18 @@ class A:
|
||||
|
||||
class C:
|
||||
@overload
|
||||
def __init__(self, a: int) -> None:
|
||||
...
|
||||
def __init__(self, a: int) -> None: ...
|
||||
|
||||
@typing.overload
|
||||
def __init__(self, a: float) -> None:
|
||||
...
|
||||
def __init__(self, a: float) -> None: ...
|
||||
|
||||
def __init__(self, a: str):
|
||||
...
|
||||
def __init__(self, a: str): ...
|
||||
|
||||
|
||||
class D(C):
|
||||
class Da:
|
||||
...
|
||||
class Da: ...
|
||||
|
||||
class DB(Da):
|
||||
...
|
||||
class DB(Da): ...
|
||||
|
||||
...
|
||||
|
||||
@ -184,5 +168,4 @@ async def async_function(wait: bool) -> int:
|
||||
global_a: A = A()
|
||||
|
||||
|
||||
class SomeMetaclass(type):
|
||||
...
|
||||
class SomeMetaclass(type): ...
|
||||
|
@ -17,3 +17,4 @@ htmlhelp_basename = "pyexampledoc"
|
||||
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
|
||||
autoapi_dirs = ["example"]
|
||||
autoapi_file_pattern = "*.py"
|
||||
autoapi_keep_files = True
|
||||
|
@ -26,12 +26,15 @@ class Foo(object):
|
||||
def foo():
|
||||
"""The foo class method"""
|
||||
...
|
||||
|
||||
def __init__(self, attr):
|
||||
"""Constructor docstring"""
|
||||
...
|
||||
|
||||
def method_okay(self, foo=None, bar=None):
|
||||
"""This method should parse okay"""
|
||||
...
|
||||
|
||||
def method_multiline(self, foo=None, bar=None, baz=None):
|
||||
"""This is on multiple lines, but should parse okay too
|
||||
|
||||
@ -39,4 +42,5 @@ class Foo(object):
|
||||
definitions are covered in the way we're anticipating here
|
||||
"""
|
||||
...
|
||||
|
||||
def method_without_docstring(self): ...
|
||||
|
18
tests/python/pyisubmoduleinit/conf.py
Normal file
18
tests/python/pyisubmoduleinit/conf.py
Normal file
@ -0,0 +1,18 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
templates_path = ["_templates"]
|
||||
source_suffix = ".rst"
|
||||
master_doc = "index"
|
||||
project = "pyisubmoduleinit"
|
||||
copyright = "2015, readthedocs"
|
||||
author = "readthedocs"
|
||||
version = "0.1"
|
||||
release = "0.1"
|
||||
language = "en"
|
||||
exclude_patterns = ["_build"]
|
||||
pygments_style = "sphinx"
|
||||
todo_include_todos = False
|
||||
html_theme = "alabaster"
|
||||
htmlhelp_basename = "pyisubmoduleinitdoc"
|
||||
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
|
||||
autoapi_dirs = ["example"]
|
0
tests/python/pyisubmoduleinit/example/example.py
Normal file
0
tests/python/pyisubmoduleinit/example/example.py
Normal file
@ -0,0 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Example __init__ in submodule foo
|
||||
|
||||
Documentation generated for this file
|
||||
should be titled submodule_foo instead of __init__
|
||||
|
||||
This is a description
|
||||
"""
|
||||
|
||||
class Foo(object):
|
||||
"""
|
||||
This is a description
|
||||
"""
|
||||
|
||||
def bar(self, a: int) -> None:
|
||||
"""
|
||||
This is a description
|
||||
"""
|
||||
...
|
15
tests/python/pyisubmoduleinit/index.rst
Normal file
15
tests/python/pyisubmoduleinit/index.rst
Normal file
@ -0,0 +1,15 @@
|
||||
Welcome to pyisubmoduleinit's documentation!
|
||||
============================================
|
||||
|
||||
.. toctree::
|
||||
|
||||
autoapi/index
|
||||
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
@ -1,7 +1,12 @@
|
||||
"""
|
||||
This heading will be removed
|
||||
============================
|
||||
"""
|
||||
|
||||
from .subpackage import public_chain
|
||||
from .subpackage.submodule import public_multiple_imports
|
||||
|
||||
|
||||
def module_level_method(foo, bar):
|
||||
def module_level_function(foo, bar):
|
||||
"""A module level method"""
|
||||
pass
|
||||
|
@ -4,7 +4,7 @@ This is a description
|
||||
"""
|
||||
|
||||
from ._private_module import PrivateClass as PublicClass
|
||||
from ._subpackage import module_level_method
|
||||
from ._subpackage import module_level_function
|
||||
|
||||
__all__ = ["PublicClass", "Foo"]
|
||||
|
||||
|
@ -3,6 +3,6 @@ from .submodule import _private_made_public as now_public_function
|
||||
from .submodule import public_multiple_imports
|
||||
|
||||
|
||||
def module_level_method(foo, bar):
|
||||
def module_level_function(foo, bar):
|
||||
"""A module level method"""
|
||||
pass
|
||||
|
@ -1,3 +1,11 @@
|
||||
"""
|
||||
This heading will be removed
|
||||
============================
|
||||
|
||||
This docstring will not be removed.
|
||||
"""
|
||||
|
||||
|
||||
def public_chain():
|
||||
"""Part of a public resolution chain."""
|
||||
return 5
|
||||
|
@ -4,7 +4,7 @@ __all__ = [
|
||||
"SimpleClass",
|
||||
"simple_function",
|
||||
"public_chain",
|
||||
"module_level_method",
|
||||
"module_level_function",
|
||||
"does_not_exist",
|
||||
]
|
||||
|
||||
|
@ -1,2 +1,2 @@
|
||||
from ..wildcard import module_level_method
|
||||
from ..wildcard import module_level_function
|
||||
from ..wildcard import public_chain
|
||||
|
@ -15,6 +15,6 @@ todo_include_todos = False
|
||||
html_theme = "alabaster"
|
||||
htmlhelp_basename = "pypackageexampledoc"
|
||||
extensions = ["autoapi.extension"]
|
||||
autoapi_dirs = ["example"]
|
||||
autoapi_dirs = ["package"]
|
||||
autoapi_file_pattern = "*.py"
|
||||
autoapi_keep_files = True
|
||||
|
@ -1,7 +0,0 @@
|
||||
"""This is a docstring."""
|
||||
from . import foo
|
||||
|
||||
|
||||
def module_level_method(foo, bar):
|
||||
"""A module level method"""
|
||||
pass
|
32
tests/python/pypackageexample/package/__init__.py
Normal file
32
tests/python/pypackageexample/package/__init__.py
Normal file
@ -0,0 +1,32 @@
|
||||
"""This is a docstring."""
|
||||
|
||||
from . import submodule
|
||||
|
||||
DATA = 42
|
||||
|
||||
|
||||
def function(foo, bar):
|
||||
"""A module level function"""
|
||||
|
||||
|
||||
class Class(object):
|
||||
"""This is a class."""
|
||||
|
||||
class_var = 42
|
||||
"""Class var docstring"""
|
||||
|
||||
class NestedClass(object):
|
||||
"""A nested class just to test things out"""
|
||||
|
||||
@classmethod
|
||||
def a_classmethod():
|
||||
"""A class method"""
|
||||
return True
|
||||
|
||||
def method_okay(self, foo=None, bar=None):
|
||||
"""This method should parse okay"""
|
||||
return True
|
||||
|
||||
|
||||
class MyException(Exception):
|
||||
"""This is an exception."""
|
@ -3,19 +3,25 @@
|
||||
This is a description
|
||||
"""
|
||||
|
||||
DATA = 42
|
||||
|
||||
class Foo(object):
|
||||
class_var = 42 #: Class var docstring
|
||||
|
||||
another_class_var = 42
|
||||
"""Another class var docstring"""
|
||||
def function(foo, bar):
|
||||
"""A module level function"""
|
||||
|
||||
class Meta(object):
|
||||
|
||||
class Class(object):
|
||||
"""This is a class."""
|
||||
|
||||
class_var = 42
|
||||
"""Class var docstring"""
|
||||
|
||||
class NestedClass(object):
|
||||
"""A nested class just to test things out"""
|
||||
|
||||
@classmethod
|
||||
def foo():
|
||||
"""The foo class method"""
|
||||
def a_classmethod():
|
||||
"""A class method"""
|
||||
return True
|
||||
|
||||
def method_okay(self, foo=None, bar=None):
|
||||
@ -61,3 +67,7 @@ class Foo(object):
|
||||
int: The sum of foo and bar.
|
||||
"""
|
||||
return foo + bar
|
||||
|
||||
|
||||
class MyException(Exception):
|
||||
"""This is an exception."""
|
@ -0,0 +1,5 @@
|
||||
"""This is a docstring."""
|
||||
|
||||
|
||||
def function(foo, bar):
|
||||
"""A module level function"""
|
@ -0,0 +1,33 @@
|
||||
"""Example module
|
||||
|
||||
This is a description
|
||||
"""
|
||||
|
||||
DATA = 42
|
||||
|
||||
|
||||
def function(foo, bar):
|
||||
"""A module level function"""
|
||||
|
||||
|
||||
class Class(object):
|
||||
"""This is a class."""
|
||||
|
||||
class_var = 42
|
||||
"""Class var docstring"""
|
||||
|
||||
class NestedClass(object):
|
||||
"""A nested class just to test things out"""
|
||||
|
||||
@classmethod
|
||||
def a_classmethod():
|
||||
"""A class method"""
|
||||
return True
|
||||
|
||||
def method_okay(self, foo=None, bar=None):
|
||||
"""This method should parse okay"""
|
||||
return True
|
||||
|
||||
|
||||
class MyException(Exception):
|
||||
"""This is an exception."""
|
950
tests/python/test_own_page_option.py
Normal file
950
tests/python/test_own_page_option.py
Normal file
@ -0,0 +1,950 @@
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
class TestModule:
|
||||
@pytest.fixture(autouse=True, scope="class")
|
||||
def built(self, builder):
|
||||
builder(
|
||||
"pypackageexample",
|
||||
warningiserror=True,
|
||||
confoverrides={
|
||||
"autoapi_own_page_level": "module",
|
||||
"autoapi_options": [
|
||||
"members",
|
||||
"undoc-members",
|
||||
"show-inheritance",
|
||||
"imported-members",
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
def test_package(self, parse):
|
||||
package_path = "_build/html/autoapi/package/index.html"
|
||||
package_file = parse(package_path)
|
||||
|
||||
docstring = package_file.find("p")
|
||||
assert docstring.text == "This is a docstring."
|
||||
|
||||
# There should be links to the children with their own page
|
||||
subpackages = package_file.find(id="subpackages")
|
||||
assert subpackages
|
||||
assert subpackages.find("a", string="package.subpackage")
|
||||
submodules = package_file.find(id="submodules")
|
||||
assert submodules
|
||||
assert submodules.find("a", string="package.submodule")
|
||||
|
||||
# There should not be links to the children without their own page
|
||||
assert not package_file.find(id="attributes")
|
||||
assert not package_file.find(id="exceptions")
|
||||
assert not package_file.find(id="classes")
|
||||
assert not package_file.find(id="functions")
|
||||
|
||||
# Children without their own page should be rendered on this page,
|
||||
# and children with their own page should not be rendered on this page.
|
||||
contents = package_file.find(id="package-contents")
|
||||
assert contents.find(id="package.DATA")
|
||||
assert contents.find(id="package.MyException")
|
||||
assert contents.find(id="package.Class")
|
||||
assert contents.find(id="package.Class.class_var")
|
||||
assert contents.find(id="package.Class.NestedClass")
|
||||
assert contents.find(id="package.Class.method_okay")
|
||||
assert contents.find(id="package.Class.NestedClass")
|
||||
assert contents.find(id="package.Class.NestedClass.a_classmethod")
|
||||
assert contents.find(id="package.function")
|
||||
|
||||
def test_subpackage(self, parse):
|
||||
subpackage_path = "_build/html/autoapi/package/subpackage/index.html"
|
||||
subpackage_file = parse(subpackage_path)
|
||||
|
||||
docstring = subpackage_file.find("p")
|
||||
assert docstring.text == "This is a docstring."
|
||||
|
||||
# There should be links to the children with their own page
|
||||
assert not subpackage_file.find(id="subpackages")
|
||||
submodules = subpackage_file.find(id="submodules")
|
||||
assert submodules
|
||||
assert submodules.find("a", string="package.subpackage.submodule")
|
||||
|
||||
# There should not be links to the children without their own page
|
||||
assert not subpackage_file.find(id="attributes")
|
||||
assert not subpackage_file.find(id="exceptions")
|
||||
assert not subpackage_file.find(id="classes")
|
||||
assert not subpackage_file.find(id="functions")
|
||||
|
||||
# Children without their own page should be rendered on this page,
|
||||
# and children with their own page should not be rendered on this page.
|
||||
contents = subpackage_file.find(id="package-contents")
|
||||
assert contents.find(id="package.subpackage.function")
|
||||
|
||||
def test_module(self, parse):
|
||||
submodule_path = "_build/html/autoapi/package/submodule/index.html"
|
||||
submodule_file = parse(submodule_path)
|
||||
|
||||
docstring = submodule_file.find("p")
|
||||
assert docstring.text == "Example module"
|
||||
|
||||
# There should be links to the children with their own page
|
||||
pass # there are no children with their own page
|
||||
|
||||
# There should not be links to the children without their own page
|
||||
assert not submodule_file.find(id="submodules")
|
||||
assert not submodule_file.find(id="subpackages")
|
||||
assert not submodule_file.find(id="attributes")
|
||||
assert not submodule_file.find(id="exceptions")
|
||||
assert not submodule_file.find(id="classes")
|
||||
assert not submodule_file.find(id="functions")
|
||||
|
||||
# Children without their own page should be rendered on this page,
|
||||
# and children with their own page should not be rendered on this page.
|
||||
contents = submodule_file.find(id="module-contents")
|
||||
assert contents.find(id="package.submodule.DATA")
|
||||
assert contents.find(id="package.submodule.MyException")
|
||||
assert contents.find(id="package.submodule.Class")
|
||||
assert contents.find(id="package.submodule.Class.class_var")
|
||||
assert contents.find(id="package.submodule.Class.NestedClass")
|
||||
assert contents.find(id="package.submodule.Class.method_okay")
|
||||
assert contents.find(id="package.submodule.Class.NestedClass")
|
||||
assert contents.find(id="package.submodule.Class.NestedClass.a_classmethod")
|
||||
assert contents.find(id="package.submodule.function")
|
||||
|
||||
def test_rendered_only_expected_pages(self):
|
||||
_, dirs, files = next(os.walk("_build/html/autoapi/package"))
|
||||
assert sorted(dirs) == ["submodule", "subpackage"]
|
||||
assert files == ["index.html"]
|
||||
|
||||
_, dirs, files = next(os.walk("_build/html/autoapi/package/submodule"))
|
||||
assert not dirs
|
||||
assert files == ["index.html"]
|
||||
|
||||
_, dirs, files = next(os.walk("_build/html/autoapi/package/subpackage"))
|
||||
assert dirs == ["submodule"]
|
||||
assert files == ["index.html"]
|
||||
|
||||
_, dirs, files = next(
|
||||
os.walk("_build/html/autoapi/package/subpackage/submodule")
|
||||
)
|
||||
assert not dirs
|
||||
assert files == ["index.html"]
|
||||
|
||||
def test_index(self, parse):
|
||||
index_path = "_build/html/autoapi/index.html"
|
||||
index_file = parse(index_path)
|
||||
|
||||
top_links = index_file.find_all(class_="toctree-l1")
|
||||
top_hrefs = sorted(link.a["href"] for link in top_links)
|
||||
assert top_hrefs == [
|
||||
"#",
|
||||
"package/index.html",
|
||||
]
|
||||
|
||||
|
||||
class TestClass:
|
||||
@pytest.fixture(autouse=True, scope="class")
|
||||
def built(self, builder):
|
||||
builder(
|
||||
"pypackageexample",
|
||||
warningiserror=True,
|
||||
confoverrides={
|
||||
"autoapi_own_page_level": "class",
|
||||
"autoapi_options": [
|
||||
"members",
|
||||
"undoc-members",
|
||||
"show-inheritance",
|
||||
"imported-members",
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
def test_package(self, parse):
|
||||
package_path = "_build/html/autoapi/package/index.html"
|
||||
package_file = parse(package_path)
|
||||
|
||||
docstring = package_file.find("p")
|
||||
assert docstring.text == "This is a docstring."
|
||||
|
||||
# There should be links to the children with their own page
|
||||
subpackages = package_file.find(id="subpackages")
|
||||
assert subpackages
|
||||
assert subpackages.find("a", string="package.subpackage")
|
||||
submodules = package_file.find(id="submodules")
|
||||
assert submodules
|
||||
assert submodules.find("a", string="package.submodule")
|
||||
exceptions = package_file.find(id="exceptions")
|
||||
assert exceptions
|
||||
assert exceptions.find("a", title="package.MyException")
|
||||
classes = package_file.find(id="classes")
|
||||
assert classes
|
||||
assert classes.find("a", title="package.Class")
|
||||
assert not classes.find("a", title="package.Class.NestedClass")
|
||||
|
||||
# There should not be links to the children without their own page
|
||||
assert not package_file.find(id="attributes")
|
||||
assert not package_file.find(id="functions")
|
||||
|
||||
# Children without their own page should be rendered on this page,
|
||||
# and children with their own page should not be rendered on this page.
|
||||
contents = package_file.find(id="package-contents")
|
||||
assert contents.find(id="package.DATA")
|
||||
assert not contents.find(id="package.MyException")
|
||||
assert not contents.find(id="package.Class")
|
||||
assert not contents.find(id="package.Class.class_var")
|
||||
assert not contents.find(id="package.Class.NestedClass")
|
||||
assert not contents.find(id="package.Class.method_okay")
|
||||
assert not contents.find(id="package.Class.NestedClass")
|
||||
assert not contents.find(id="package.Class.NestedClass.a_classmethod")
|
||||
assert contents.find(id="package.function")
|
||||
|
||||
def test_module(self, parse):
|
||||
submodule_path = "_build/html/autoapi/package/submodule/index.html"
|
||||
submodule_file = parse(submodule_path)
|
||||
|
||||
docstring = submodule_file.find("p")
|
||||
assert docstring.text == "Example module"
|
||||
|
||||
# There should be links to the children with their own page
|
||||
exceptions = submodule_file.find(id="exceptions")
|
||||
assert exceptions
|
||||
assert exceptions.find("a", title="package.submodule.MyException")
|
||||
classes = submodule_file.find(id="classes")
|
||||
assert classes
|
||||
assert classes.find("a", title="package.submodule.Class")
|
||||
assert not classes.find("a", title="package.submodule.Class.NestedClass")
|
||||
|
||||
# There should not be links to the children without their own page
|
||||
assert not submodule_file.find(id="submodules")
|
||||
assert not submodule_file.find(id="subpackages")
|
||||
assert not submodule_file.find(id="attributes")
|
||||
assert not submodule_file.find(id="functions")
|
||||
|
||||
# Children without their own page should be rendered on this page,
|
||||
# and children with their own page should not be rendered on this page.
|
||||
contents = submodule_file.find(id="module-contents")
|
||||
assert contents.find(id="package.submodule.DATA")
|
||||
assert not contents.find(id="package.submodule.MyException")
|
||||
assert not contents.find(id="package.submodule.Class")
|
||||
assert not contents.find(id="package.submodule.Class.class_var")
|
||||
assert not contents.find(id="package.submodule.Class.NestedClass")
|
||||
assert not contents.find(id="package.submodule.Class.method_okay")
|
||||
assert not contents.find(id="package.submodule.Class.NestedClass")
|
||||
assert not contents.find(id="package.submodule.Class.NestedClass.a_classmethod")
|
||||
assert contents.find(id="package.submodule.function")
|
||||
|
||||
def test_class(self, parse):
|
||||
class_path = "_build/html/autoapi/package/Class.html"
|
||||
class_file = parse(class_path)
|
||||
|
||||
class_sig = class_file.find(id="package.Class")
|
||||
assert class_sig
|
||||
class_ = class_sig.parent
|
||||
docstring = class_.find_all("p")[1]
|
||||
assert docstring.text == "This is a class."
|
||||
|
||||
# There should be links to the children with their own page
|
||||
classes = class_file.find(id="classes")
|
||||
assert classes
|
||||
assert classes.find("a", title="package.Class.NestedClass")
|
||||
|
||||
# There should not be links to the children without their own page
|
||||
assert not class_file.find(id="attributes")
|
||||
assert not class_file.find(id="exceptions")
|
||||
assert not class_file.find(id="methods")
|
||||
|
||||
# Children without their own page should be rendered on this page,
|
||||
# and children with their own page should not be rendered on this page.
|
||||
assert class_.find(id="package.Class.class_var")
|
||||
assert class_.find(id="package.Class.method_okay")
|
||||
|
||||
nested_class_path = "_build/html/autoapi/package/Class.NestedClass.html"
|
||||
nested_class_file = parse(nested_class_path)
|
||||
|
||||
nested_class_sig = nested_class_file.find(id="package.Class.NestedClass")
|
||||
assert nested_class_sig
|
||||
nested_class = nested_class_sig.parent
|
||||
|
||||
# There should be links to the children with their own page
|
||||
pass # there are no children with their own page
|
||||
|
||||
# There should not be links to the children without their own page
|
||||
assert not class_file.find(id="attributes")
|
||||
assert not class_file.find(id="exceptions")
|
||||
assert not class_file.find(id="methods")
|
||||
|
||||
# Children without their own page should be rendered on this page,
|
||||
# and children with their own page should not be rendered on this page.
|
||||
assert nested_class.find(id="package.Class.NestedClass.a_classmethod")
|
||||
|
||||
def test_exception(self, parse):
|
||||
exception_path = "_build/html/autoapi/package/MyException.html"
|
||||
exception_file = parse(exception_path)
|
||||
|
||||
exception_sig = exception_file.find(id="package.MyException")
|
||||
assert exception_sig
|
||||
exception = exception_sig.parent
|
||||
docstring = exception.find_all("p")[1]
|
||||
assert docstring.text == "This is an exception."
|
||||
|
||||
# There should be links to the children with their own page
|
||||
pass # there are no children with their own page
|
||||
|
||||
# There should not be links to the children without their own page
|
||||
assert not exception_file.find(id="attributes")
|
||||
assert not exception_file.find(id="exceptions")
|
||||
assert not exception_file.find(id="methods")
|
||||
|
||||
# Children without their own page should be rendered on this page,
|
||||
# and children with their own page should not be rendered on this page.
|
||||
pass # there are no children without their own page
|
||||
|
||||
def test_rendered_only_expected_pages(self):
|
||||
_, dirs, files = next(os.walk("_build/html/autoapi/package"))
|
||||
assert sorted(dirs) == ["submodule", "subpackage"]
|
||||
assert sorted(files) == [
|
||||
"Class.NestedClass.html",
|
||||
"Class.html",
|
||||
"MyException.html",
|
||||
"index.html",
|
||||
]
|
||||
|
||||
_, dirs, files = next(os.walk("_build/html/autoapi/package/submodule"))
|
||||
assert not dirs
|
||||
assert sorted(files) == [
|
||||
"Class.NestedClass.html",
|
||||
"Class.html",
|
||||
"MyException.html",
|
||||
"index.html",
|
||||
]
|
||||
|
||||
_, dirs, files = next(os.walk("_build/html/autoapi/package/subpackage"))
|
||||
assert dirs == ["submodule"]
|
||||
assert files == ["index.html"]
|
||||
|
||||
_, dirs, files = next(
|
||||
os.walk("_build/html/autoapi/package/subpackage/submodule")
|
||||
)
|
||||
assert not dirs
|
||||
assert sorted(files) == [
|
||||
"Class.NestedClass.html",
|
||||
"Class.html",
|
||||
"MyException.html",
|
||||
"index.html",
|
||||
]
|
||||
|
||||
def test_index(self, parse):
|
||||
index_path = "_build/html/autoapi/index.html"
|
||||
index_file = parse(index_path)
|
||||
|
||||
top_links = index_file.find_all(class_="toctree-l1")
|
||||
top_hrefs = sorted(link.a["href"] for link in top_links)
|
||||
assert top_hrefs == [
|
||||
"#",
|
||||
"package/index.html",
|
||||
]
|
||||
|
||||
|
||||
class TestFunction:
|
||||
@pytest.fixture(autouse=True, scope="class")
|
||||
def built(self, builder):
|
||||
builder(
|
||||
"pypackageexample",
|
||||
warningiserror=True,
|
||||
confoverrides={
|
||||
"autoapi_own_page_level": "function",
|
||||
"autoapi_options": [
|
||||
"members",
|
||||
"undoc-members",
|
||||
"show-inheritance",
|
||||
"imported-members",
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
def test_package(self, parse):
|
||||
package_path = "_build/html/autoapi/package/index.html"
|
||||
package_file = parse(package_path)
|
||||
|
||||
docstring = package_file.find("p")
|
||||
assert docstring.text == "This is a docstring."
|
||||
|
||||
# There should be links to the children with their own page
|
||||
subpackages = package_file.find(id="subpackages")
|
||||
assert subpackages
|
||||
assert subpackages.find("a", string="package.subpackage")
|
||||
submodules = package_file.find(id="submodules")
|
||||
assert submodules
|
||||
assert submodules.find("a", string="package.submodule")
|
||||
classes = package_file.find(id="classes")
|
||||
assert classes
|
||||
assert classes.find("a", title="package.Class")
|
||||
exceptions = package_file.find(id="exceptions")
|
||||
assert exceptions
|
||||
assert exceptions.find("a", title="package.MyException")
|
||||
functions = package_file.find(id="functions")
|
||||
assert functions
|
||||
assert functions.find("a", title="package.function")
|
||||
|
||||
# There should not be links to the children without their own page
|
||||
assert not package_file.find(id="attributes")
|
||||
|
||||
# Children without their own page should be rendered on this page,
|
||||
# and children with their own page should not be rendered on this page.
|
||||
contents = package_file.find(id="package-contents")
|
||||
assert contents.find(id="package.DATA")
|
||||
assert not contents.find(id="package.MyException")
|
||||
assert not contents.find(id="package.Class")
|
||||
assert not contents.find(id="package.Class.class_var")
|
||||
assert not contents.find(id="package.Class.NestedClass")
|
||||
assert not contents.find(id="package.Class.method_okay")
|
||||
assert not contents.find(id="package.Class.NestedClass")
|
||||
assert not contents.find(id="package.Class.NestedClass.a_classmethod")
|
||||
assert not contents.find(id="package.function")
|
||||
|
||||
def test_module(self, parse):
|
||||
submodule_path = "_build/html/autoapi/package/submodule/index.html"
|
||||
submodule_file = parse(submodule_path)
|
||||
|
||||
docstring = submodule_file.find("p")
|
||||
assert docstring.text == "Example module"
|
||||
|
||||
# There should be links to the children with their own page
|
||||
exceptions = submodule_file.find(id="exceptions")
|
||||
assert exceptions
|
||||
assert exceptions.find("a", title="package.submodule.MyException")
|
||||
classes = submodule_file.find(id="classes")
|
||||
assert classes
|
||||
assert classes.find("a", title="package.submodule.Class")
|
||||
assert not classes.find("a", title="package.submodule.Class.NestedClass")
|
||||
functions = submodule_file.find(id="functions")
|
||||
assert functions
|
||||
assert functions.find("a", title="package.submodule.function")
|
||||
|
||||
# There should not be links to the children without their own page
|
||||
assert not submodule_file.find(id="submodules")
|
||||
assert not submodule_file.find(id="subpackages")
|
||||
assert not submodule_file.find(id="attributes")
|
||||
|
||||
# Children without their own page should be rendered on this page,
|
||||
# and children with their own page should not be rendered on this page.
|
||||
contents = submodule_file.find(id="module-contents")
|
||||
assert contents.find(id="package.submodule.DATA")
|
||||
assert not contents.find(id="package.submodule.MyException")
|
||||
assert not contents.find(id="package.submodule.Class")
|
||||
assert not contents.find(id="package.submodule.Class.class_var")
|
||||
assert not contents.find(id="package.submodule.Class.NestedClass")
|
||||
assert not contents.find(id="package.submodule.Class.method_okay")
|
||||
assert not contents.find(id="package.submodule.Class.NestedClass")
|
||||
assert not contents.find(id="package.submodule.Class.NestedClass.a_classmethod")
|
||||
assert not contents.find(id="package.submodule.function")
|
||||
|
||||
def test_class(self, parse):
|
||||
class_path = "_build/html/autoapi/package/Class.html"
|
||||
class_file = parse(class_path)
|
||||
|
||||
class_sig = class_file.find(id="package.Class")
|
||||
assert class_sig
|
||||
class_ = class_sig.parent
|
||||
docstring = class_.find_all("p")[1]
|
||||
assert docstring.text == "This is a class."
|
||||
|
||||
# There should be links to the children with their own page
|
||||
classes = class_file.find(id="classes")
|
||||
assert classes
|
||||
assert classes.find("a", title="package.Class.NestedClass")
|
||||
|
||||
# There should not be links to the children without their own page
|
||||
assert not class_file.find(id="attributes")
|
||||
assert not class_file.find(id="exceptions")
|
||||
assert not class_file.find(id="methods")
|
||||
|
||||
# Children without their own page should be rendered on this page,
|
||||
# and children with their own page should not be rendered on this page.
|
||||
assert class_.find(id="package.Class.class_var")
|
||||
assert class_.find(id="package.Class.method_okay")
|
||||
|
||||
def test_function(self, parse):
|
||||
function_path = "_build/html/autoapi/package/function.html"
|
||||
function_file = parse(function_path)
|
||||
|
||||
function_sig = function_file.find(id="package.function")
|
||||
assert function_sig
|
||||
|
||||
function_path = "_build/html/autoapi/package/submodule/function.html"
|
||||
function_file = parse(function_path)
|
||||
assert function_file.find(id="package.submodule.function")
|
||||
|
||||
def test_rendered_only_expected_pages(self):
|
||||
_, dirs, files = next(os.walk("_build/html/autoapi/package"))
|
||||
assert sorted(dirs) == ["submodule", "subpackage"]
|
||||
assert sorted(files) == [
|
||||
"Class.NestedClass.html",
|
||||
"Class.html",
|
||||
"MyException.html",
|
||||
"function.html",
|
||||
"index.html",
|
||||
]
|
||||
|
||||
_, dirs, files = next(os.walk("_build/html/autoapi/package/submodule"))
|
||||
assert not dirs
|
||||
assert sorted(files) == [
|
||||
"Class.NestedClass.html",
|
||||
"Class.html",
|
||||
"MyException.html",
|
||||
"function.html",
|
||||
"index.html",
|
||||
]
|
||||
|
||||
_, dirs, files = next(os.walk("_build/html/autoapi/package/subpackage"))
|
||||
assert dirs == ["submodule"]
|
||||
assert sorted(files) == ["function.html", "index.html"]
|
||||
|
||||
_, dirs, files = next(
|
||||
os.walk("_build/html/autoapi/package/subpackage/submodule")
|
||||
)
|
||||
assert not dirs
|
||||
assert sorted(files) == [
|
||||
"Class.NestedClass.html",
|
||||
"Class.html",
|
||||
"MyException.html",
|
||||
"function.html",
|
||||
"index.html",
|
||||
]
|
||||
|
||||
def test_index(self, parse):
|
||||
index_path = "_build/html/autoapi/index.html"
|
||||
index_file = parse(index_path)
|
||||
|
||||
top_links = index_file.find_all(class_="toctree-l1")
|
||||
top_hrefs = sorted(link.a["href"] for link in top_links)
|
||||
assert top_hrefs == [
|
||||
"#",
|
||||
"package/index.html",
|
||||
]
|
||||
|
||||
|
||||
class TestMethod:
|
||||
@pytest.fixture(autouse=True, scope="class")
|
||||
def built(self, builder):
|
||||
builder(
|
||||
"pypackageexample",
|
||||
warningiserror=True,
|
||||
confoverrides={
|
||||
"autoapi_own_page_level": "method",
|
||||
"autoapi_options": [
|
||||
"members",
|
||||
"undoc-members",
|
||||
"show-inheritance",
|
||||
"imported-members",
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
def test_package(self, parse):
|
||||
package_path = "_build/html/autoapi/package/index.html"
|
||||
package_file = parse(package_path)
|
||||
|
||||
docstring = package_file.find("p")
|
||||
assert docstring.text == "This is a docstring."
|
||||
|
||||
# There should be links to the children with their own page
|
||||
subpackages = package_file.find(id="subpackages")
|
||||
assert subpackages
|
||||
assert subpackages.find("a", string="package.subpackage")
|
||||
submodules = package_file.find(id="submodules")
|
||||
assert submodules
|
||||
assert submodules.find("a", string="package.submodule")
|
||||
classes = package_file.find(id="classes")
|
||||
assert classes
|
||||
assert classes.find("a", title="package.Class")
|
||||
exceptions = package_file.find(id="exceptions")
|
||||
assert exceptions
|
||||
assert exceptions.find("a", title="package.MyException")
|
||||
functions = package_file.find(id="functions")
|
||||
assert functions
|
||||
assert functions.find("a", title="package.function")
|
||||
|
||||
# There should not be links to the children without their own page
|
||||
assert not package_file.find(id="attributes")
|
||||
|
||||
# Children without their own page should be rendered on this page,
|
||||
# and children with their own page should not be rendered on this page.
|
||||
contents = package_file.find(id="package-contents")
|
||||
assert contents.find(id="package.DATA")
|
||||
assert not contents.find(id="package.MyException")
|
||||
assert not contents.find(id="package.Class")
|
||||
assert not contents.find(id="package.Class.class_var")
|
||||
assert not contents.find(id="package.Class.NestedClass")
|
||||
assert not contents.find(id="package.Class.method_okay")
|
||||
assert not contents.find(id="package.Class.NestedClass")
|
||||
assert not contents.find(id="package.Class.NestedClass.a_classmethod")
|
||||
assert not contents.find(id="package.function")
|
||||
|
||||
def test_module(self, parse):
|
||||
submodule_path = "_build/html/autoapi/package/submodule/index.html"
|
||||
submodule_file = parse(submodule_path)
|
||||
|
||||
docstring = submodule_file.find("p")
|
||||
assert docstring.text == "Example module"
|
||||
|
||||
# There should be links to the children with their own page
|
||||
exceptions = submodule_file.find(id="exceptions")
|
||||
assert exceptions
|
||||
assert exceptions.find("a", title="package.submodule.MyException")
|
||||
classes = submodule_file.find(id="classes")
|
||||
assert classes
|
||||
assert classes.find("a", title="package.submodule.Class")
|
||||
assert not classes.find("a", title="package.submodule.Class.NestedClass")
|
||||
functions = submodule_file.find(id="functions")
|
||||
assert functions
|
||||
assert functions.find("a", title="package.submodule.function")
|
||||
|
||||
# There should not be links to the children without their own page
|
||||
assert not submodule_file.find(id="submodules")
|
||||
assert not submodule_file.find(id="subpackages")
|
||||
assert not submodule_file.find(id="attributes")
|
||||
|
||||
# Children without their own page should be rendered on this page,
|
||||
# and children with their own page should not be rendered on this page.
|
||||
contents = submodule_file.find(id="module-contents")
|
||||
assert contents.find(id="package.submodule.DATA")
|
||||
assert not contents.find(id="package.submodule.MyException")
|
||||
assert not contents.find(id="package.submodule.Class")
|
||||
assert not contents.find(id="package.submodule.Class.class_var")
|
||||
assert not contents.find(id="package.submodule.Class.NestedClass")
|
||||
assert not contents.find(id="package.submodule.Class.method_okay")
|
||||
assert not contents.find(id="package.submodule.Class.NestedClass")
|
||||
assert not contents.find(id="package.submodule.Class.NestedClass.a_classmethod")
|
||||
assert not contents.find(id="package.submodule.function")
|
||||
|
||||
def test_class(self, parse):
|
||||
class_path = "_build/html/autoapi/package/Class.html"
|
||||
class_file = parse(class_path)
|
||||
|
||||
class_sig = class_file.find(id="package.Class")
|
||||
assert class_sig
|
||||
class_ = class_sig.parent
|
||||
docstring = class_.find_all("p")[1]
|
||||
assert docstring.text == "This is a class."
|
||||
|
||||
# There should be links to the children with their own page
|
||||
classes = class_file.find(id="classes")
|
||||
assert classes
|
||||
assert classes.find("a", title="package.Class.NestedClass")
|
||||
methods = class_file.find(id="methods")
|
||||
assert methods
|
||||
assert methods.find("a", title="package.Class.method_okay")
|
||||
|
||||
# There should not be links to the children without their own page
|
||||
assert not class_file.find(id="attributes")
|
||||
assert not class_file.find(id="exceptions")
|
||||
|
||||
# Children without their own page should be rendered on this page,
|
||||
# and children with their own page should not be rendered on this page.
|
||||
assert class_.find(id="package.Class.class_var")
|
||||
assert not class_.find(id="package.Class.method_okay")
|
||||
|
||||
def test_function(self, parse):
|
||||
function_path = "_build/html/autoapi/package/function.html"
|
||||
function_file = parse(function_path)
|
||||
|
||||
function_sig = function_file.find(id="package.function")
|
||||
assert function_sig
|
||||
|
||||
function_path = "_build/html/autoapi/package/submodule/function.html"
|
||||
function_file = parse(function_path)
|
||||
assert function_file.find(id="package.submodule.function")
|
||||
|
||||
def test_method(self, parse):
|
||||
method_path = "_build/html/autoapi/package/Class.method_okay.html"
|
||||
method_file = parse(method_path)
|
||||
|
||||
method_sig = method_file.find(id="package.Class.method_okay")
|
||||
assert method_sig
|
||||
|
||||
method_path = "_build/html/autoapi/package/submodule/Class.method_okay.html"
|
||||
method_file = parse(method_path)
|
||||
assert method_file.find(id="package.submodule.Class.method_okay")
|
||||
|
||||
def test_rendered_only_expected_pages(self):
|
||||
_, dirs, files = next(os.walk("_build/html/autoapi/package"))
|
||||
assert sorted(dirs) == ["submodule", "subpackage"]
|
||||
assert sorted(files) == [
|
||||
"Class.NestedClass.a_classmethod.html",
|
||||
"Class.NestedClass.html",
|
||||
"Class.html",
|
||||
"Class.method_okay.html",
|
||||
"MyException.html",
|
||||
"function.html",
|
||||
"index.html",
|
||||
]
|
||||
|
||||
_, dirs, files = next(os.walk("_build/html/autoapi/package/submodule"))
|
||||
assert not dirs
|
||||
assert sorted(files) == [
|
||||
"Class.NestedClass.a_classmethod.html",
|
||||
"Class.NestedClass.html",
|
||||
"Class.html",
|
||||
"Class.method_google_docs.html",
|
||||
"Class.method_multiline.html",
|
||||
"Class.method_okay.html",
|
||||
"Class.method_sphinx_docs.html",
|
||||
"Class.method_tricky.html",
|
||||
"MyException.html",
|
||||
"function.html",
|
||||
"index.html",
|
||||
]
|
||||
|
||||
_, dirs, files = next(os.walk("_build/html/autoapi/package/subpackage"))
|
||||
assert dirs == ["submodule"]
|
||||
assert sorted(files) == ["function.html", "index.html"]
|
||||
|
||||
_, dirs, files = next(
|
||||
os.walk("_build/html/autoapi/package/subpackage/submodule")
|
||||
)
|
||||
assert not dirs
|
||||
assert sorted(files) == [
|
||||
"Class.NestedClass.a_classmethod.html",
|
||||
"Class.NestedClass.html",
|
||||
"Class.html",
|
||||
"Class.method_okay.html",
|
||||
"MyException.html",
|
||||
"function.html",
|
||||
"index.html",
|
||||
]
|
||||
|
||||
def test_index(self, parse):
|
||||
index_path = "_build/html/autoapi/index.html"
|
||||
index_file = parse(index_path)
|
||||
|
||||
top_links = index_file.find_all(class_="toctree-l1")
|
||||
top_hrefs = sorted(link.a["href"] for link in top_links)
|
||||
assert top_hrefs == [
|
||||
"#",
|
||||
"package/index.html",
|
||||
]
|
||||
|
||||
|
||||
class TestAttribute:
|
||||
@pytest.fixture(autouse=True, scope="class")
|
||||
def built(self, builder):
|
||||
builder(
|
||||
"pypackageexample",
|
||||
warningiserror=True,
|
||||
confoverrides={
|
||||
"autoapi_own_page_level": "attribute",
|
||||
"autoapi_options": [
|
||||
"members",
|
||||
"undoc-members",
|
||||
"show-inheritance",
|
||||
"imported-members",
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
# TODO: Include a test for a property
|
||||
def test_package(self, parse):
|
||||
package_path = "_build/html/autoapi/package/index.html"
|
||||
package_file = parse(package_path)
|
||||
|
||||
docstring = package_file.find("p")
|
||||
assert docstring.text == "This is a docstring."
|
||||
|
||||
# There should be links to the children with their own page
|
||||
subpackages = package_file.find(id="subpackages")
|
||||
assert subpackages
|
||||
assert subpackages.find("a", string="package.subpackage")
|
||||
submodules = package_file.find(id="submodules")
|
||||
assert submodules
|
||||
assert submodules.find("a", string="package.submodule")
|
||||
classes = package_file.find(id="classes")
|
||||
assert classes
|
||||
assert classes.find("a", title="package.Class")
|
||||
exceptions = package_file.find(id="exceptions")
|
||||
assert exceptions
|
||||
assert exceptions.find("a", title="package.MyException")
|
||||
functions = package_file.find(id="functions")
|
||||
assert functions
|
||||
assert functions.find("a", title="package.function")
|
||||
attributes = package_file.find(id="attributes")
|
||||
assert attributes
|
||||
assert attributes.find("a", title="package.DATA")
|
||||
|
||||
# There should not be links to the children without their own page
|
||||
pass # there are no children without their own page
|
||||
|
||||
# Children without their own page should be rendered on this page,
|
||||
# and children with their own page should not be rendered on this page.
|
||||
assert not package_file.find(id="package-contents")
|
||||
|
||||
def test_module(self, parse):
|
||||
submodule_path = "_build/html/autoapi/package/submodule/index.html"
|
||||
submodule_file = parse(submodule_path)
|
||||
|
||||
docstring = submodule_file.find("p")
|
||||
assert docstring.text == "Example module"
|
||||
|
||||
# There should be links to the children with their own page
|
||||
exceptions = submodule_file.find(id="exceptions")
|
||||
assert exceptions
|
||||
assert exceptions.find("a", title="package.submodule.MyException")
|
||||
classes = submodule_file.find(id="classes")
|
||||
assert classes
|
||||
assert classes.find("a", title="package.submodule.Class")
|
||||
assert not classes.find("a", title="package.submodule.Class.NestedClass")
|
||||
functions = submodule_file.find(id="functions")
|
||||
assert functions
|
||||
assert functions.find("a", title="package.submodule.function")
|
||||
attributes = submodule_file.find(id="attributes")
|
||||
assert attributes
|
||||
assert attributes.find("a", title="package.submodule.DATA")
|
||||
|
||||
# There should not be links to the children without their own page
|
||||
assert not submodule_file.find(id="submodules")
|
||||
assert not submodule_file.find(id="subpackages")
|
||||
|
||||
# Children without their own page should be rendered on this page,
|
||||
# and children with their own page should not be rendered on this page.
|
||||
assert not submodule_file.find(id="module-contents")
|
||||
|
||||
def test_class(self, parse):
|
||||
class_path = "_build/html/autoapi/package/Class.html"
|
||||
class_file = parse(class_path)
|
||||
|
||||
class_sig = class_file.find(id="package.Class")
|
||||
assert class_sig
|
||||
class_ = class_sig.parent
|
||||
docstring = class_.find_all("p")[1]
|
||||
assert docstring.text == "This is a class."
|
||||
|
||||
# There should be links to the children with their own page
|
||||
classes = class_file.find(id="classes")
|
||||
assert classes
|
||||
assert classes.find("a", title="package.Class.NestedClass")
|
||||
methods = class_file.find(id="methods")
|
||||
assert methods
|
||||
assert methods.find("a", title="package.Class.method_okay")
|
||||
attributes = class_file.find(id="attributes")
|
||||
assert attributes
|
||||
assert attributes.find("a", title="package.Class.class_var")
|
||||
|
||||
# There should not be links to the children without their own page
|
||||
assert not class_file.find(id="exceptions")
|
||||
|
||||
# Children without their own page should be rendered on this page,
|
||||
# and children with their own page should not be rendered on this page.
|
||||
assert not class_.find(id="package.Class.class_var")
|
||||
assert not class_.find(id="package.Class.method_okay")
|
||||
|
||||
def test_function(self, parse):
|
||||
function_path = "_build/html/autoapi/package/function.html"
|
||||
function_file = parse(function_path)
|
||||
|
||||
function_sig = function_file.find(id="package.function")
|
||||
assert function_sig
|
||||
|
||||
function_path = "_build/html/autoapi/package/submodule/function.html"
|
||||
function_file = parse(function_path)
|
||||
assert function_file.find(id="package.submodule.function")
|
||||
|
||||
def test_method(self, parse):
|
||||
method_path = "_build/html/autoapi/package/Class.method_okay.html"
|
||||
method_file = parse(method_path)
|
||||
|
||||
method_sig = method_file.find(id="package.Class.method_okay")
|
||||
assert method_sig
|
||||
|
||||
method_path = "_build/html/autoapi/package/submodule/Class.method_okay.html"
|
||||
method_file = parse(method_path)
|
||||
assert method_file.find(id="package.submodule.Class.method_okay")
|
||||
|
||||
def test_data(self, parse):
|
||||
data_path = "_build/html/autoapi/package/DATA.html"
|
||||
data_file = parse(data_path)
|
||||
|
||||
data_sig = data_file.find(id="package.DATA")
|
||||
assert data_sig
|
||||
|
||||
def test_attribute(self, parse):
|
||||
attribute_path = "_build/html/autoapi/package/Class.class_var.html"
|
||||
attribute_file = parse(attribute_path)
|
||||
|
||||
attribute_sig = attribute_file.find(id="package.Class.class_var")
|
||||
assert attribute_sig
|
||||
|
||||
def test_rendered_only_expected_pages(self):
|
||||
_, dirs, files = next(os.walk("_build/html/autoapi/package"))
|
||||
assert sorted(dirs) == ["submodule", "subpackage"]
|
||||
assert sorted(files) == [
|
||||
"Class.NestedClass.a_classmethod.html",
|
||||
"Class.NestedClass.html",
|
||||
"Class.class_var.html",
|
||||
"Class.html",
|
||||
"Class.method_okay.html",
|
||||
"DATA.html",
|
||||
"MyException.html",
|
||||
"function.html",
|
||||
"index.html",
|
||||
]
|
||||
|
||||
_, dirs, files = next(os.walk("_build/html/autoapi/package/submodule"))
|
||||
assert not dirs
|
||||
assert sorted(files) == [
|
||||
"Class.NestedClass.a_classmethod.html",
|
||||
"Class.NestedClass.html",
|
||||
"Class.class_var.html",
|
||||
"Class.html",
|
||||
"Class.method_google_docs.html",
|
||||
"Class.method_multiline.html",
|
||||
"Class.method_okay.html",
|
||||
"Class.method_sphinx_docs.html",
|
||||
"Class.method_tricky.html",
|
||||
"DATA.html",
|
||||
"MyException.html",
|
||||
"function.html",
|
||||
"index.html",
|
||||
]
|
||||
|
||||
_, dirs, files = next(os.walk("_build/html/autoapi/package/subpackage"))
|
||||
assert dirs == ["submodule"]
|
||||
assert sorted(files) == ["function.html", "index.html"]
|
||||
|
||||
_, dirs, files = next(
|
||||
os.walk("_build/html/autoapi/package/subpackage/submodule")
|
||||
)
|
||||
assert not dirs
|
||||
assert sorted(files) == [
|
||||
"Class.NestedClass.a_classmethod.html",
|
||||
"Class.NestedClass.html",
|
||||
"Class.class_var.html",
|
||||
"Class.html",
|
||||
"Class.method_okay.html",
|
||||
"DATA.html",
|
||||
"MyException.html",
|
||||
"function.html",
|
||||
"index.html",
|
||||
]
|
||||
|
||||
def test_index(self, parse):
|
||||
index_path = "_build/html/autoapi/index.html"
|
||||
index_file = parse(index_path)
|
||||
|
||||
top_links = index_file.find_all(class_="toctree-l1")
|
||||
top_hrefs = sorted(link.a["href"] for link in top_links)
|
||||
assert top_hrefs == [
|
||||
"#",
|
||||
"package/index.html",
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"value", ["package", "exception", "property", "data", "not_a_value"]
|
||||
)
|
||||
def test_invalid_values(builder, value):
|
||||
"""Test failure when autoapi_own_page_level is invalid."""
|
||||
with pytest.raises(ValueError):
|
||||
builder(
|
||||
"pypackageexample",
|
||||
confoverrides={
|
||||
"autoapi_own_page_level": value,
|
||||
},
|
||||
)
|
@ -1,7 +1,6 @@
|
||||
import io
|
||||
import os
|
||||
import pathlib
|
||||
import shutil
|
||||
import sys
|
||||
from unittest.mock import Mock, call
|
||||
|
||||
@ -13,7 +12,6 @@ from autoapi.mappers.python import (
|
||||
PythonMethod,
|
||||
PythonModule,
|
||||
)
|
||||
from bs4 import BeautifulSoup
|
||||
from packaging import version
|
||||
import pytest
|
||||
import sphinx
|
||||
@ -24,60 +22,6 @@ import sphinx.util.logging
|
||||
sphinx_version = version.parse(sphinx.__version__).release
|
||||
|
||||
|
||||
def rebuild(confdir=".", **kwargs):
|
||||
app = Sphinx(
|
||||
srcdir=".",
|
||||
confdir=confdir,
|
||||
outdir="_build/html",
|
||||
doctreedir="_build/.doctrees",
|
||||
buildername="html",
|
||||
**kwargs,
|
||||
)
|
||||
app.build()
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def builder():
|
||||
cwd = os.getcwd()
|
||||
|
||||
def build(test_dir, **kwargs):
|
||||
if kwargs.get("warningiserror"):
|
||||
# Add any warnings raised when using `Sphinx` more than once
|
||||
# in a Python session.
|
||||
confoverrides = kwargs.setdefault("confoverrides", {})
|
||||
confoverrides.setdefault("suppress_warnings", [])
|
||||
suppress = confoverrides["suppress_warnings"]
|
||||
suppress.append("app.add_node")
|
||||
suppress.append("app.add_directive")
|
||||
suppress.append("app.add_role")
|
||||
|
||||
os.chdir("tests/python/{0}".format(test_dir))
|
||||
rebuild(**kwargs)
|
||||
|
||||
yield build
|
||||
|
||||
try:
|
||||
shutil.rmtree("_build")
|
||||
if (pathlib.Path("autoapi") / "index.rst").exists():
|
||||
shutil.rmtree("autoapi")
|
||||
finally:
|
||||
os.chdir(cwd)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def parse():
|
||||
cache = {}
|
||||
|
||||
def parser(path):
|
||||
if path not in cache:
|
||||
with io.open(path, encoding="utf8") as file_handle:
|
||||
cache[path] = BeautifulSoup(file_handle, features="html.parser")
|
||||
|
||||
return cache[path]
|
||||
|
||||
yield parser
|
||||
|
||||
|
||||
class TestSimpleModule:
|
||||
@pytest.fixture(autouse=True, scope="class")
|
||||
def built(self, builder):
|
||||
@ -200,7 +144,7 @@ class TestSimpleModule:
|
||||
def test_long_signature(self, parse):
|
||||
example_file = parse("_build/html/autoapi/example/index.html")
|
||||
|
||||
summary_row = example_file.find_all(class_="autosummary")[1].find_all("tr")[-1]
|
||||
summary_row = example_file.find_all(class_="autosummary")[-1].find_all("tr")[-1]
|
||||
assert summary_row
|
||||
cells = summary_row.find_all("td")
|
||||
assert (
|
||||
@ -300,6 +244,20 @@ class TestSimpleStubModuleNotPreferred:
|
||||
assert foo_sig
|
||||
|
||||
|
||||
class TestStubInitModuleInSubmodule:
|
||||
@pytest.fixture(autouse=True, scope="class")
|
||||
def built(self, builder):
|
||||
builder("pyisubmoduleinit", warningiserror=True)
|
||||
|
||||
def test_integration(self, parse):
|
||||
example_file = parse("_build/html/autoapi/example/index.html")
|
||||
|
||||
# Documentation should list
|
||||
# submodule_foo instead of __init__
|
||||
assert example_file.find(title="submodule_foo")
|
||||
assert not example_file.find(title="__init__")
|
||||
|
||||
|
||||
class TestPy3Module:
|
||||
@pytest.fixture(autouse=True, scope="class")
|
||||
def built(self, builder):
|
||||
@ -656,26 +614,26 @@ class TestSimplePackage:
|
||||
builder("pypackageexample", warningiserror=True)
|
||||
|
||||
def test_integration_with_package(self, parse):
|
||||
example_file = parse("_build/html/autoapi/example/index.html")
|
||||
example_file = parse("_build/html/autoapi/package/index.html")
|
||||
|
||||
entries = example_file.find_all(class_="toctree-l1")
|
||||
assert any(entry.text == "example.foo" for entry in entries)
|
||||
assert example_file.find(id="example.module_level_method")
|
||||
assert any(entry.text == "package.submodule" for entry in entries)
|
||||
assert example_file.find(id="package.function")
|
||||
|
||||
example_foo_file = parse("_build/html/autoapi/example/foo/index.html")
|
||||
example_foo_file = parse("_build/html/autoapi/package/submodule/index.html")
|
||||
|
||||
foo = example_foo_file.find(id="example.foo.Foo")
|
||||
assert foo
|
||||
method_okay = foo.parent.find(id="example.foo.Foo.method_okay")
|
||||
submodule = example_foo_file.find(id="package.submodule.Class")
|
||||
assert submodule
|
||||
method_okay = submodule.parent.find(id="package.submodule.Class.method_okay")
|
||||
assert method_okay
|
||||
|
||||
index_file = parse("_build/html/index.html")
|
||||
|
||||
toctree = index_file.select("li > a")
|
||||
assert any(item.text == "API Reference" for item in toctree)
|
||||
assert any(item.text == "example.foo" for item in toctree)
|
||||
assert any(item.text == "Foo" for item in toctree)
|
||||
assert any(item.text == "module_level_method()" for item in toctree)
|
||||
assert any(item.text == "package.submodule" for item in toctree)
|
||||
assert any(item.text == "Class" for item in toctree)
|
||||
assert any(item.text == "function()" for item in toctree)
|
||||
|
||||
|
||||
def test_simple_no_false_warnings(builder, caplog):
|
||||
@ -724,14 +682,14 @@ def test_hiding_private_members(builder, parse):
|
||||
confoverrides = {"autoapi_options": ["members", "undoc-members", "special-members"]}
|
||||
builder("pypackageexample", warningiserror=True, confoverrides=confoverrides)
|
||||
|
||||
example_file = parse("_build/html/autoapi/example/index.html")
|
||||
example_file = parse("_build/html/autoapi/package/index.html")
|
||||
|
||||
entries = example_file.find_all(class_="toctree-l1")
|
||||
assert all("private" not in entry.text for entry in entries)
|
||||
|
||||
private_file = parse("_build/html/autoapi/example/_private_module/index.html")
|
||||
|
||||
assert private_file.find(id="example._private_module.PrivateClass.public_method")
|
||||
assert not pathlib.Path(
|
||||
"_build/html/autoapi/package/_private_module/index.html"
|
||||
).exists()
|
||||
|
||||
|
||||
def test_hiding_inheritance(builder, parse):
|
||||
@ -963,7 +921,7 @@ class TestComplexPackage:
|
||||
assert wildcard_file.find(id="complex.wildcard.public_chain")
|
||||
assert wildcard_file.find(id="complex.wildcard.now_public_function")
|
||||
assert wildcard_file.find(id="complex.wildcard.public_multiple_imports")
|
||||
assert wildcard_file.find(id="complex.wildcard.module_level_method")
|
||||
assert wildcard_file.find(id="complex.wildcard.module_level_function")
|
||||
|
||||
def test_wildcard_all_imports(self, parse):
|
||||
wildcard_file = parse("_build/html/autoapi/complex/wildall/index.html")
|
||||
@ -974,12 +932,12 @@ class TestComplexPackage:
|
||||
assert wildcard_file.find(id="complex.wildall.SimpleClass")
|
||||
assert wildcard_file.find(id="complex.wildall.simple_function")
|
||||
assert wildcard_file.find(id="complex.wildall.public_chain")
|
||||
assert wildcard_file.find(id="complex.wildall.module_level_method")
|
||||
assert wildcard_file.find(id="complex.wildall.module_level_function")
|
||||
|
||||
def test_no_imports_in_module_with_all(self, parse):
|
||||
foo_file = parse("_build/html/autoapi/complex/foo/index.html")
|
||||
|
||||
assert not foo_file.find(id="complex.foo.module_level_method")
|
||||
assert not foo_file.find(id="complex.foo.module_level_function")
|
||||
|
||||
def test_all_overrides_import_in_module_with_all(self, parse):
|
||||
foo_file = parse("_build/html/autoapi/complex/foo/index.html")
|
||||
@ -991,6 +949,13 @@ class TestComplexPackage:
|
||||
|
||||
assert foo_file.find(id="complex.unicode_data.unicode_str")
|
||||
|
||||
def test_nested_parse_directive(self, parse):
|
||||
package_file = parse("_build/html/autoapi/complex/index.html")
|
||||
|
||||
complex = package_file.find(id="complex")
|
||||
assert "This heading will be removed" not in complex.parent.text
|
||||
assert complex.parent.find("section")["id"] != "this-heading-will-be-removed"
|
||||
|
||||
|
||||
class TestComplexPackageParallel(TestComplexPackage):
|
||||
@pytest.fixture(autouse=True, scope="class")
|
||||
@ -998,7 +963,7 @@ class TestComplexPackageParallel(TestComplexPackage):
|
||||
builder("pypackagecomplex", parallel=2)
|
||||
|
||||
|
||||
def test_caching(builder):
|
||||
def test_caching(builder, rebuild):
|
||||
mtimes = (0, 0)
|
||||
|
||||
def record_mtime():
|
||||
@ -1104,25 +1069,25 @@ def test_string_module_attributes(builder):
|
||||
".. py:data:: code_snippet",
|
||||
" :value: Multiline-String",
|
||||
"",
|
||||
" .. raw:: html",
|
||||
" .. raw:: html",
|
||||
"",
|
||||
" <details><summary>Show Value</summary>",
|
||||
" <details><summary>Show Value</summary>",
|
||||
"",
|
||||
" .. code-block:: python",
|
||||
" .. code-block:: python",
|
||||
"",
|
||||
' """The following is some code:',
|
||||
" ", # <--- Line array monstrosity to preserve these leading spaces
|
||||
" # -*- coding: utf-8 -*-",
|
||||
" from __future__ import absolute_import, division, print_function, unicode_literals",
|
||||
" # from future.builtins.disabled import *",
|
||||
" # from builtins import *",
|
||||
" ",
|
||||
""" print("chunky o'block")""",
|
||||
' """',
|
||||
' """The following is some code:',
|
||||
" ", # <--- Line array monstrosity to preserve these leading spaces
|
||||
" # -*- coding: utf-8 -*-",
|
||||
" from __future__ import absolute_import, division, print_function, unicode_literals",
|
||||
" # from future.builtins.disabled import *",
|
||||
" # from builtins import *",
|
||||
" ",
|
||||
""" print("chunky o'block")""",
|
||||
' """',
|
||||
"",
|
||||
" .. raw:: html",
|
||||
" .. raw:: html",
|
||||
"",
|
||||
" </details>",
|
||||
" </details>",
|
||||
]
|
||||
assert "\n".join(code_snippet_contents) in example_file
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user