From 93fb571a7e3b23c028564cbd694514f10b663391 Mon Sep 17 00:00:00 2001 From: Ashley Whetter Date: Mon, 15 Jan 2024 20:41:21 -0800 Subject: [PATCH] Basic tests for single page rendering --- autoapi/extension.py | 2 +- autoapi/mappers/base.py | 79 ++--- autoapi/mappers/python/mapper.py | 10 +- autoapi/mappers/python/objects.py | 1 + autoapi/settings.py | 12 - autoapi/templates/python/class.rst | 7 +- autoapi/templates/python/data.rst | 5 + autoapi/templates/python/function.rst | 8 +- autoapi/templates/python/method.rst | 8 +- autoapi/templates/python/module.rst | 230 +++++++------ autoapi/templates/python/property.rst | 7 +- docs/reference/config.rst | 2 +- docs/reference/templates.rst | 2 + .../pypackagecomplex/complex/__init__.py | 2 +- tests/python/pypackagecomplex/complex/foo.py | 2 +- .../complex/subpackage/__init__.py | 2 +- .../complex/wildall/simple/__init__.py | 2 +- .../complex/wildchain/__init__.py | 2 +- .../autoapi/example/_private_module/index.rst | 34 ++ .../autoapi/example/foo/index.rst | 110 +++++++ .../autoapi/example/index.rst | 40 +++ .../python/pypackageexample/autoapi/index.rst | 11 + .../pypackageexample/example/__init__.py | 2 +- tests/python/pypackageexample/example/foo.py | 2 + tests/python/test_pyintegration.py | 305 +++++++++++++++++- 25 files changed, 697 insertions(+), 190 deletions(-) create mode 100644 tests/python/pypackageexample/autoapi/example/_private_module/index.rst create mode 100644 tests/python/pypackageexample/autoapi/example/foo/index.rst create mode 100644 tests/python/pypackageexample/autoapi/example/index.rst create mode 100644 tests/python/pypackageexample/autoapi/index.rst diff --git a/autoapi/extension.py b/autoapi/extension.py index 57cbf72..fef422f 100644 --- a/autoapi/extension.py +++ b/autoapi/extension.py @@ -271,7 +271,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_single_page_level", "module", "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) diff --git a/autoapi/mappers/base.py b/autoapi/mappers/base.py index 59d4133..956d2e5 100644 --- a/autoapi/mappers/base.py +++ b/autoapi/mappers/base.py @@ -13,9 +13,20 @@ from sphinx.util.display import status_iterator from sphinx.util.osutil import ensuredir import sphinx.util.logging -from ..settings import API_ROOT, TEMPLATE_DIR, SINGLE_PAGE_LEVELS +from ..settings import API_ROOT, TEMPLATE_DIR LOGGER = sphinx.util.logging.getLogger(__name__) +_OWN_PAGE_LEVELS = [ + "package", + "module", + "exception", + "class", + "function", + "method", + "property", + "attribute", + "data", +] Path = namedtuple("Path", ["absolute", "relative"]) @@ -90,10 +101,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, } @@ -191,18 +207,20 @@ 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.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.""" @@ -280,7 +298,9 @@ class SphinxMapperBase: Args: obj: Instance of a AutoAPI object """ - self.objects[obj.id] = obj + if 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: @@ -307,67 +327,26 @@ class SphinxMapperBase: """ raise NotImplementedError - def output_child_rst(self, obj, obj_parent, detail_dir, single_page_level, source_suffix): - - if not obj.display: - return - - obj_child_page_level = SINGLE_PAGE_LEVELS.index(obj.type) - desired_page_level = SINGLE_PAGE_LEVELS.index(single_page_level) - needs_single_page = obj_child_page_level <= desired_page_level - if not needs_single_page: - return - - obj_child_rst = obj.render( - needs_single_page=needs_single_page, - ) - if not obj_child_rst: - return - - ensuredir(os.path.join(detail_dir, obj.short_name)) - path = os.path.join( - detail_dir, obj.short_name, f"index{source_suffix}" - ) - - with open(path, "wb+") as obj_child_detail_file: - obj_child_detail_file.write(obj_child_rst.encode("utf-8")) - - for obj_child in obj.children: - child_detail_dir = os.path.join(detail_dir, obj.name) - self.output_child_rst(obj_child, obj, child_detail_dir, single_page_level, source_suffix) - - def output_rst(self, root, source_suffix): - # Evaluate which object types should render in a single page - single_page_level = self.app.config.autoapi_single_page_level - desired_page_level = SINGLE_PAGE_LEVELS.index(single_page_level) - single_page_objects = SINGLE_PAGE_LEVELS[:desired_page_level+1] - 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]), ): if not obj.display: continue - rst = obj.render(single_page_objects=single_page_objects) + 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}") - with open(path, "wb+") as detail_file: detail_file.write(rst.encode("utf-8")) - - for obj_child in obj.children: - self.output_child_rst(obj_child, obj, detail_dir=detail_dir, - single_page_level=single_page_level, - source_suffix=source_suffix) if self.app.config.autoapi_add_toctree_entry: self._output_top_rst(root) @@ -375,7 +354,7 @@ class SphinxMapperBase: def _output_top_rst(self, root): # Render Top Index top_level_index = os.path.join(root, "index.rst") - pages = self.objects.values() + pages = self.objects_to_render.values() 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")) diff --git a/autoapi/mappers/python/mapper.py b/autoapi/mappers/python/mapper.py index 43c8f03..23d84e0 100644 --- a/autoapi/mappers/python/mapper.py +++ b/autoapi/mappers/python/mapper.py @@ -24,6 +24,7 @@ from .objects import ( PythonAttribute, PythonData, PythonException, + TopLevelPythonPythonMapper, ) LOGGER = sphinx.util.logging.getLogger(__name__) @@ -345,19 +346,20 @@ class PythonSphinxMapper(SphinxMapperBase): 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 self.objects_to_render.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): diff --git a/autoapi/mappers/python/objects.py b/autoapi/mappers/python/objects.py index 564e613..7b8b722 100644 --- a/autoapi/mappers/python/objects.py +++ b/autoapi/mappers/python/objects.py @@ -38,6 +38,7 @@ 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) diff --git a/autoapi/settings.py b/autoapi/settings.py index ad03fa5..58704b4 100644 --- a/autoapi/settings.py +++ b/autoapi/settings.py @@ -10,15 +10,3 @@ SITE_ROOT = os.path.dirname(os.path.realpath(__file__)) TEMPLATE_DIR = os.path.join(SITE_ROOT, "templates") API_ROOT = "autoapi" - -SINGLE_PAGE_LEVELS = [ - "package", - "module", - "exception", - "class", - "function", - "method", - "property", - "attribute", - "data", -] diff --git a/autoapi/templates/python/class.rst b/autoapi/templates/python/class.rst index 2b69313..81678cb 100644 --- a/autoapi/templates/python/class.rst +++ b/autoapi/templates/python/class.rst @@ -1,7 +1,7 @@ {% if obj.display %} -{% if needs_single_page %} -{{ obj.short_name }} -{{ "=" * obj.short_name | length }} +{% if is_own_page %} +{{ obj.name }} +{{ "=" * obj.name | length }} {% endif %} .. py:{{ obj.type }}:: {{ obj.short_name }}{% if obj.args %}({{ obj.args }}){% endif %} @@ -30,6 +30,7 @@ {% if obj.docstring %} {{ obj.docstring|indent(3) }} {% endif %} + {# TODO: Rendering of all children below this line must be conditional on own_page_types #} {% if "inherited-members" in autoapi_options %} {% set visible_classes = obj.classes|selectattr("display")|list %} {% else %} diff --git a/autoapi/templates/python/data.rst b/autoapi/templates/python/data.rst index 3d12b2d..3851d6c 100644 --- a/autoapi/templates/python/data.rst +++ b/autoapi/templates/python/data.rst @@ -1,4 +1,9 @@ {% if obj.display %} +{% if is_own_page %} +{{ obj.name }} +{{ "=" * obj.name | length }} + +{% endif %} .. py:{{ obj.type }}:: {{ obj.name }} {%- if obj.annotation is not none %} diff --git a/autoapi/templates/python/function.rst b/autoapi/templates/python/function.rst index c7a7abe..2d58b1e 100644 --- a/autoapi/templates/python/function.rst +++ b/autoapi/templates/python/function.rst @@ -1,9 +1,9 @@ {% if obj.display %} -{% if needs_single_page %} -{{ obj.short_name }} -{{ "=" * obj.short_name | length }} -{% endif %} +{% if is_own_page %} +{{ obj.name }} +{{ "=" * obj.name | length }} +{% endif %} .. py:function:: {{ obj.short_name }}({{ obj.args }}){% if obj.return_annotation is not none %} -> {{ obj.return_annotation }}{% endif %} {% for (args, return_annotation) in obj.overloads %} diff --git a/autoapi/templates/python/method.rst b/autoapi/templates/python/method.rst index e27ad18..f6e008f 100644 --- a/autoapi/templates/python/method.rst +++ b/autoapi/templates/python/method.rst @@ -1,9 +1,9 @@ {%- if obj.display %} -{% if needs_single_page %} -{{ obj.short_name }} -{{ "=" * obj.short_name | length }} -{% endif %} +{% if is_own_page %} +{{ obj.name }} +{{ "=" * obj.name | length }} +{% endif %} .. py:method:: {{ obj.short_name }}({{ obj.args }}){% if obj.return_annotation is not none %} -> {{ obj.return_annotation }}{% endif %} {% for (args, return_annotation) in obj.overloads %} diff --git a/autoapi/templates/python/module.rst b/autoapi/templates/python/module.rst index d7ecf8c..bc28282 100644 --- a/autoapi/templates/python/module.rst +++ b/autoapi/templates/python/module.rst @@ -1,147 +1,183 @@ -{% if not obj.display %} -:orphan: - -{% endif %} +{% if obj.display %} + {% if is_own_page %} :py:mod:`{{ obj.name }}` =========={{ "=" * obj.name|length }} + {% endif %} .. 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 + :hidden: -{% for subpackage in visible_subpackages %} + {% for subpackage in visible_subpackages %} {{ subpackage.short_name }}/index.rst -{% endfor %} + {% endfor %} +.. autoapisummary:: -{% endif %} -{% endblock %} -{% block submodules %} -{% set visible_submodules = obj.submodules|selectattr("display")|list %} -{% if visible_submodules %} + {% for subpackage in visible_subpackages %} + {{ subpackage.id }} + {% endfor %} + + + {% endif %} + {% endblock %} + {% block submodules %} + {% set visible_submodules = obj.submodules|selectattr("display")|list %} + {% if visible_submodules %} + {% if "module" in own_page_types %} Submodules ---------- .. toctree:: - :titlesonly: - :maxdepth: 1 + :hidden: -{% for submodule in visible_submodules %} + {% for submodule in visible_submodules %} {{ submodule.short_name }}/index.rst -{% endfor %} + {% endfor %} +.. autoapisummary:: -{% 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 %} -{{ obj.type|title }} Contents -{{ "-" * obj.type|length }}--------- + {% for submodule in visible_submodules %} + {{ submodule.id }} + {% endfor %} + {% else %} + {% for submodule in visible_submodules %} + {{ submodule.render() }} + {% endfor %} + {% endif %} + + + {% 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 %} + {% if is_own_page %} + {% 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: -{% 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 -~~~~~~~ + {% for attribute in visible_attributes %} + {{ attribute.short_name }}/index.rst + {% endfor %} + {% endif%} .. autoapisummary:: -{% for klass in visible_classes %} - {{ klass.id }} -{% endfor %} + {% for attribute in visible_attributes %} + {{ attribute.id }} + {% endfor %} + {% endif %} -{% if "class" in single_page_objects %} -{% for klass in visible_classes %} + + {% 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:: - :titlesonly: - :maxdepth: 1 :hidden: - {{ klass.name }} - -{% endfor %} -{%- endif -%} -{%- endif -%} -{% endblock %} - -{% block functions scoped %} -{% if visible_functions %} -Functions -~~~~~~~~~ + {% for exception in visible_exceptions %} + {{ exception.short_name }}/index.rst + {% endfor %} + {% endif %} .. autoapisummary:: -{% for function in visible_functions %} - {{ function.id }} -{% endfor %} + {% for exception in visible_exceptions %} + {{ exception.id }} + {% endfor %} + {% endif %} + -{% if "function" in single_page_objects %} + {% 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:: - :titlesonly: - :maxdepth: 1 :hidden: -{% for function in visible_functions %} - {{ function.name }} -{% endfor %} - -{%- endif -%} -{%- endif -%} -{% endblock %} -{% block attributes scoped %} -{%- if visible_attributes -%} -Attributes -~~~~~~~~~~ + {% for klass in visible_classes %} + {{ klass.short_name }}/index.rst + {% endfor %} + {% endif %} .. autoapisummary:: -{% for attribute in visible_attributes %} - {{ attribute.id }} -{% endfor %} + {% for klass in visible_classes %} + {{ klass.id }} + {% endfor %} + {% endif %} + -{% if "attribute" in single_page_objects %} + {% 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 "class" in own_page_types %} .. toctree:: - :titlesonly: - :maxdepth: 1 :hidden: -{% for attr in visible_attributes %} - {{ attr.name }} -{% endfor %} + {% for function in visible_functions %} + {{ function.short_name }}/index.rst + {% endfor %} -{%- endif -%} -{%- endif -%} -{% endblock %} -{% endif %} + {% endif %} +.. autoapisummary:: -{% for obj_item in visible_children %} -{% if obj_item.type not in single_page_objects %} -{{ obj_item.render()|indent(0) }} -{% endif %} -{% endfor %} + {% for function in visible_functions %} + {{ function.id }} + {% endfor %} + {% endif %} + + {% endif %} +{{ obj.type|title }} Contents +{{ "-" * obj.type|length }}--------- + + {% for obj_item in visible_children %} + {% if obj_item.type not in own_page_types %} +{{ obj_item.render()|indent(0) }} + {% endif %} + {% endfor %} + {% else %} + {# If this is not its own page, the children won't have their own page either. #} + {# So render them as normal, without needing to check if they have their own page. #} + {% for obj_item in visible_children %} + {{ obj_item.render()|indent(3) }} + {% endfor %} + {% endif %} + {% endif %} + {% endblock %} {% endif %} -{% endblock %} diff --git a/autoapi/templates/python/property.rst b/autoapi/templates/python/property.rst index 07146d4..d2eb0b8 100644 --- a/autoapi/templates/python/property.rst +++ b/autoapi/templates/python/property.rst @@ -1,7 +1,8 @@ {%- if obj.display %} -{% if needs_single_page %} -{{ obj.short_name }} -{{ "=" * obj.short_name | length }} +{% if is_own_page %} +{{ obj.name }} +{{ "=" * obj.name | length }} + {% endif %} .. py:property:: {{ obj.short_name }} {% if obj.annotation %} diff --git a/docs/reference/config.rst b/docs/reference/config.rst index 016c281..26b47bb 100644 --- a/docs/reference/config.rst +++ b/docs/reference/config.rst @@ -181,7 +181,7 @@ Customisation Options :noindex: -.. confval:: autoapi_single_page_level +.. confval:: autoapi_own_page_level Default: ``'module'`` diff --git a/docs/reference/templates.rst b/docs/reference/templates.rst index a18c867..93836ab 100644 --- a/docs/reference/templates.rst +++ b/docs/reference/templates.rst @@ -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 diff --git a/tests/python/pypackagecomplex/complex/__init__.py b/tests/python/pypackagecomplex/complex/__init__.py index cd392ca..8d52f39 100644 --- a/tests/python/pypackagecomplex/complex/__init__.py +++ b/tests/python/pypackagecomplex/complex/__init__.py @@ -7,6 +7,6 @@ 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 diff --git a/tests/python/pypackagecomplex/complex/foo.py b/tests/python/pypackagecomplex/complex/foo.py index da60ce6..4737d8e 100644 --- a/tests/python/pypackagecomplex/complex/foo.py +++ b/tests/python/pypackagecomplex/complex/foo.py @@ -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"] diff --git a/tests/python/pypackagecomplex/complex/subpackage/__init__.py b/tests/python/pypackagecomplex/complex/subpackage/__init__.py index f3dfce8..7d38cb5 100644 --- a/tests/python/pypackagecomplex/complex/subpackage/__init__.py +++ b/tests/python/pypackagecomplex/complex/subpackage/__init__.py @@ -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 diff --git a/tests/python/pypackagecomplex/complex/wildall/simple/__init__.py b/tests/python/pypackagecomplex/complex/wildall/simple/__init__.py index acd2a9c..1a2c7fb 100644 --- a/tests/python/pypackagecomplex/complex/wildall/simple/__init__.py +++ b/tests/python/pypackagecomplex/complex/wildall/simple/__init__.py @@ -4,7 +4,7 @@ __all__ = [ "SimpleClass", "simple_function", "public_chain", - "module_level_method", + "module_level_function", "does_not_exist", ] diff --git a/tests/python/pypackagecomplex/complex/wildchain/__init__.py b/tests/python/pypackagecomplex/complex/wildchain/__init__.py index 07e16bd..bd82152 100644 --- a/tests/python/pypackagecomplex/complex/wildchain/__init__.py +++ b/tests/python/pypackagecomplex/complex/wildchain/__init__.py @@ -1,2 +1,2 @@ -from ..wildcard import module_level_method +from ..wildcard import module_level_function from ..wildcard import public_chain diff --git a/tests/python/pypackageexample/autoapi/example/_private_module/index.rst b/tests/python/pypackageexample/autoapi/example/_private_module/index.rst new file mode 100644 index 0000000..86fed2a --- /dev/null +++ b/tests/python/pypackageexample/autoapi/example/_private_module/index.rst @@ -0,0 +1,34 @@ +:py:mod:`example._private_module` +================================= + +.. py:module:: example._private_module + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + example._private_module.PrivateClass + + + + +.. py:class:: PrivateClass + + + Bases: :py:obj:`object` + + A private class with public facing methods. + + + .. py:method:: public_method() + + This is public. + + + + diff --git a/tests/python/pypackageexample/autoapi/example/foo/index.rst b/tests/python/pypackageexample/autoapi/example/foo/index.rst new file mode 100644 index 0000000..6bde069 --- /dev/null +++ b/tests/python/pypackageexample/autoapi/example/foo/index.rst @@ -0,0 +1,110 @@ +:py:mod:`example.foo` +===================== + +.. py:module:: example.foo + +.. autoapi-nested-parse:: + + Example module + + This is a description + + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + example.foo.Foo + + + + +.. py:class:: Foo + + + Bases: :py:obj:`object` + + + .. py:class:: Meta + + + Bases: :py:obj:`object` + + A nested class just to test things out + + + .. py:method:: foo() + :classmethod: + + The foo class method + + + + .. py:attribute:: class_var + :value: 42 + + + + .. py:attribute:: another_class_var + :value: 42 + + Another class var docstring + + + + .. py:method:: method_okay(foo=None, bar=None) + + This method should parse okay + + + + .. py:method:: method_multiline(foo=None, bar=None, baz=None) + + This is on multiple lines, but should parse okay too + + pydocstyle gives us lines of source. Test if this means that multiline + definitions are covered in the way we're anticipating here + + + + .. py:method:: method_tricky(foo=None, bar=dict(foo=1, bar=2)) + + This will likely fail our argument testing + + We parse naively on commas, so the nested dictionary will throw this off + + + + .. py:method:: method_sphinx_docs(foo, bar=0) + + This method is documented with sphinx style docstrings. + + :param foo: The first argument. + :type foo: int + + :param int bar: The second argument. + + :returns: The sum of foo and bar. + :rtype: int + + + + .. py:method:: method_google_docs(foo, bar=0) + + This method is documented with google style docstrings. + + Args: + foo (int): The first argument. + bar (int): The second argument. + + Returns: + int: The sum of foo and bar. + + + + diff --git a/tests/python/pypackageexample/autoapi/example/index.rst b/tests/python/pypackageexample/autoapi/example/index.rst new file mode 100644 index 0000000..0b4a96d --- /dev/null +++ b/tests/python/pypackageexample/autoapi/example/index.rst @@ -0,0 +1,40 @@ +:py:mod:`example` +================= + +.. py:module:: example + +.. autoapi-nested-parse:: + + This is a docstring. + + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + _private_module/index.rst + foo/index.rst + + +Package Contents +---------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + example.module_level_function + + + +.. py:function:: module_level_function(foo, bar) + + A module level method + + + diff --git a/tests/python/pypackageexample/autoapi/index.rst b/tests/python/pypackageexample/autoapi/index.rst new file mode 100644 index 0000000..55f9ebe --- /dev/null +++ b/tests/python/pypackageexample/autoapi/index.rst @@ -0,0 +1,11 @@ +API Reference +============= + +This page contains auto-generated API reference documentation [#f1]_. + +.. toctree:: + :titlesonly: + + /autoapi/example/index + +.. [#f1] Created with `sphinx-autoapi `_ \ No newline at end of file diff --git a/tests/python/pypackageexample/example/__init__.py b/tests/python/pypackageexample/example/__init__.py index 44c208d..1b58595 100644 --- a/tests/python/pypackageexample/example/__init__.py +++ b/tests/python/pypackageexample/example/__init__.py @@ -3,6 +3,6 @@ from . import foo -def module_level_method(foo, bar): +def module_level_function(foo, bar): """A module level method""" pass diff --git a/tests/python/pypackageexample/example/foo.py b/tests/python/pypackageexample/example/foo.py index 5523d52..0a87d32 100644 --- a/tests/python/pypackageexample/example/foo.py +++ b/tests/python/pypackageexample/example/foo.py @@ -3,6 +3,8 @@ This is a description """ +MODULE_DATA = 42 + class Foo(object): class_var = 42 #: Class var docstring diff --git a/tests/python/test_pyintegration.py b/tests/python/test_pyintegration.py index c0d6e37..1afa2ee 100644 --- a/tests/python/test_pyintegration.py +++ b/tests/python/test_pyintegration.py @@ -674,7 +674,7 @@ class TestSimplePackage: 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 example_file.find(id="example.module_level_function") example_foo_file = parse("_build/html/autoapi/example/foo/index.html") @@ -689,7 +689,7 @@ class TestSimplePackage: 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 == "module_level_function()" for item in toctree) def test_simple_no_false_warnings(builder, caplog): @@ -977,7 +977,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") @@ -988,12 +988,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") @@ -1208,3 +1208,298 @@ class TestMemberOrder: method_sphinx_docs = example_file.find(id="example.Foo.method_sphinx_docs") assert method_tricky.sourceline < method_sphinx_docs.sourceline + + +# TODO: This might be easier to understand with its own test case. +# Eg make a package named "package", subpackage named "subpackage", +# submodule named "submodule", etc. +class TestOwnPageLevel: + def test_package(self, builder, parse): + builder( + "pypackageexample", + warningiserror=True, + confoverrides={"autoapi_own_page_level": "package"}, + ) + + example_path = "_build/html/autoapi/example/index.html" + example_file = parse(example_path) + + # TODO: Look for expected contents + + subpackage_path = "_build/html/autoapi/example/subpackage/index.html" + subpackage_file = parse(subpackage_path) + + # TODO: Look for expected contents + + assert not os.path.exists("_build/html/autoapi/example/foo/index.html") + assert not os.path.exists("_build/html/autoapi/example/foo/FooError.html") + assert not os.path.exists("_build/html/autoapi/example/foo/Foo.html") + assert not os.path.exists("_build/html/autoapi/example/foo/module_level_function.html") + assert not os.path.exists("_build/html/autoapi/example/foo/Foo/method_okay.html") + assert not os.path.exists("_build/html/autoapi/example/foo/Foo/property.html") + assert not os.path.exists("_build/html/autoapi/example/foo/Foo/class_var.html") + assert not os.path.exists("_build/html/autoapi/example/foo/MODULE_DATA.html") + + def test_module(self, builder, parse): + builder( + "pypackageexample", + warningiserror=True, + confoverrides={"autoapi_own_page_level": "module"}, + ) + + example_path = "_build/html/autoapi/example/index.html" + example_file = parse(example_path) + + # TODO: Look for expected contents + + subpackage_path = "_build/html/autoapi/example/subpackage/index.html" + subpackage_file = parse(subpackage_path) + + # TODO: Look for expected contents + + foo_path = "_build/html/autoapi/example/foo/index.html" + foo_file = parse(foo_path) + + # TODO: Look for expected contents + + assert not os.path.exists("_build/html/autoapi/example/foo/FooError.html") + assert not os.path.exists("_build/html/autoapi/example/foo/Foo.html") + assert not os.path.exists("_build/html/autoapi/example/foo/module_level_function.html") + assert not os.path.exists("_build/html/autoapi/example/foo/Foo/method_okay.html") + assert not os.path.exists("_build/html/autoapi/example/foo/Foo/property.html") + assert not os.path.exists("_build/html/autoapi/example/foo/Foo/class_var.html") + assert not os.path.exists("_build/html/autoapi/example/foo/MODULE_DATA.html") + + def test_class(self, builder, parse): + builder( + "pypackageexample", + warningiserror=True, + confoverrides={"autoapi_own_page_level": "class"}, + ) + example_path = "_build/html/autoapi/example/index.html" + example_file = parse(example_path) + + # TODO: Look for expected contents + + subpackage_path = "_build/html/autoapi/example/subpackage/index.html" + subpackage_file = parse(subpackage_path) + + # TODO: Look for expected contents + + foo_path = "_build/html/autoapi/example/foo/index.html" + foo_file = parse(foo_path) + + # TODO: Look for expected contents + + error_path = "_build/html/autoapi/example/foo/FooError.html" + error_file = parse(error_path) + + # TODO: Look for expected contents + + foo_path = "_build/html/autoapi/example/foo/Foo.html" + foo_file = parse(foo_path) + + # TODO: Look for expected contents + + assert not os.path.exists("_build/html/autoapi/example/foo/module_level_function.html") + assert not os.path.exists("_build/html/autoapi/example/foo/Foo/method_okay.html") + assert not os.path.exists("_build/html/autoapi/example/foo/Foo/property.html") + assert not os.path.exists("_build/html/autoapi/example/foo/Foo/class_var.html") + assert not os.path.exists("_build/html/autoapi/example/foo/MODULE_DATA.html") + + def test_function(self, builder, parse): + builder( + "pypackageexample", + warningiserror=True, + confoverrides={"autoapi_own_page_level": "function"}, + ) + example_path = "_build/html/autoapi/example/index.html" + example_file = parse(example_path) + + # TODO: Look for expected contents + + subpackage_path = "_build/html/autoapi/example/subpackage/index.html" + subpackage_file = parse(subpackage_path) + + # TODO: Look for expected contents + + foo_path = "_build/html/autoapi/example/foo/index.html" + foo_file = parse(foo_path) + + # TODO: Look for expected contents + + error_path = "_build/html/autoapi/example/foo/FooError.html" + error_file = parse(error_path) + + # TODO: Look for expected contents + + foo_path = "_build/html/autoapi/example/foo/Foo.html" + foo_file = parse(foo_path) + + # TODO: Look for expected contents + + func_path = "_build/html/autoapi/example/foo/module_level_function.html" + func_file = parse(func_path) + + # TODO: Look for expected contents + + assert not os.path.exists("_build/html/autoapi/example/foo/Foo/method_okay.html") + assert not os.path.exists("_build/html/autoapi/example/foo/Foo/property.html") + assert not os.path.exists("_build/html/autoapi/example/foo/Foo/class_var.html") + assert not os.path.exists("_build/html/autoapi/example/foo/MODULE_DATA.html") + + def test_method(self, builder, parse): + builder( + "pypackageexample", + warningiserror=True, + confoverrides={"autoapi_own_page_level": "method"}, + ) + example_path = "_build/html/autoapi/example/index.html" + example_file = parse(example_path) + + # TODO: Look for expected contents + + subpackage_path = "_build/html/autoapi/example/subpackage/index.html" + subpackage_file = parse(subpackage_path) + + # TODO: Look for expected contents + + foo_path = "_build/html/autoapi/example/foo/index.html" + foo_file = parse(foo_path) + + # TODO: Look for expected contents + + error_path = "_build/html/autoapi/example/foo/FooError.html" + error_file = parse(error_path) + + # TODO: Look for expected contents + + foo_path = "_build/html/autoapi/example/foo/Foo.html" + foo_file = parse(foo_path) + + # TODO: Look for expected contents + + func_path = "_build/html/autoapi/example/foo/module_level_function.html" + func_file = parse(func_path) + + # TODO: Look for expected contents + + method_path = "_build/html/autoapi/example/foo/Foo/method_okay.html" + method_file = parse(method_path) + + # TODO: Look for expected contents + + assert not os.path.exists("_build/html/autoapi/example/foo/Foo/property.html") + assert not os.path.exists("_build/html/autoapi/example/foo/Foo/class_var.html") + assert not os.path.exists("_build/html/autoapi/example/foo/MODULE_DATA.html") + + def test_attribute(self, builder, parse): + builder( + "pypackageexample", + warningiserror=True, + confoverrides={"autoapi_own_page_level": "attribute"}, + ) + example_path = "_build/html/autoapi/example/index.html" + example_file = parse(example_path) + + # TODO: Look for expected contents + + subpackage_path = "_build/html/autoapi/example/subpackage/index.html" + subpackage_file = parse(subpackage_path) + + # TODO: Look for expected contents + + foo_path = "_build/html/autoapi/example/foo/index.html" + foo_file = parse(foo_path) + + # TODO: Look for expected contents + + error_path = "_build/html/autoapi/example/foo/FooError.html" + error_file = parse(error_path) + + # TODO: Look for expected contents + + foo_path = "_build/html/autoapi/example/foo/Foo.html" + foo_file = parse(foo_path) + + # TODO: Look for expected contents + + func_path = "_build/html/autoapi/example/foo/module_level_function.html" + func_file = parse(func_path) + + # TODO: Look for expected contents + + method_path = "_build/html/autoapi/example/foo/Foo/method_okay.html" + method_file = parse(method_path) + + # TODO: Look for expected contents + + property_path = "_build/html/autoapi/example/foo/Foo/property.html" + property_file = parse(property_path) + + # TODO: Look for expected contents + + attribute_path = "_build/html/autoapi/example/foo/Foo/class_var.html" + attribute_file = parse(attribute_path) + + # TODO: Look for expected contents + + assert not os.path.exists("_build/html/autoapi/example/foo/MODULE_DATA.html") + + + def test_data(self, builder, parse): + builder( + "pypackageexample", + warningiserror=True, + confoverrides={"autoapi_own_page_level": "data"}, + ) + + example_path = "_build/html/autoapi/example/index.html" + example_file = parse(example_path) + + # TODO: Look for expected contents + + subpackage_path = "_build/html/autoapi/example/subpackage/index.html" + subpackage_file = parse(subpackage_path) + + # TODO: Look for expected contents + + foo_path = "_build/html/autoapi/example/foo/index.html" + foo_file = parse(foo_path) + + # TODO: Look for expected contents + + error_path = "_build/html/autoapi/example/foo/FooError.html" + error_file = parse(error_path) + + # TODO: Look for expected contents + + foo_path = "_build/html/autoapi/example/foo/Foo.html" + foo_file = parse(foo_path) + + # TODO: Look for expected contents + + func_path = "_build/html/autoapi/example/foo/module_level_function.html" + func_file = parse(func_path) + + # TODO: Look for expected contents + + method_path = "_build/html/autoapi/example/foo/Foo/method_okay.html" + method_file = parse(method_path) + + # TODO: Look for expected contents + + property_path = "_build/html/autoapi/example/foo/Foo/property.html" + property_file = parse(property_path) + + # TODO: Look for expected contents + + attribute_path = "_build/html/autoapi/example/foo/Foo/class_var.html" + attribute_file = parse(attribute_path) + + # TODO: Look for expected contents + + data_path = "_build/html/autoapi/example/foo/MODULE_DATA.html" + data_file = parse(data_path) + + # TODO: Look for expected contents