mirror of
https://github.com/readthedocs/sphinx-autoapi
synced 2024-11-10 01:10:27 +00:00
Fixed error when parsing a class with no constructor
This commit is contained in:
parent
83b1260e67
commit
5faec73073
@ -3,6 +3,15 @@ Changelog
|
||||
|
||||
Versions follow `Semantic Versioning <https://semver.org/>`_ (``<major>.<minor>.<patch>``).
|
||||
|
||||
v1.8.2 (TBC)
|
||||
-------------------
|
||||
|
||||
Bug Fixes
|
||||
^^^^^^^^^
|
||||
|
||||
* Fixed error when parsing a class with no constructor.
|
||||
|
||||
|
||||
v1.8.1 (2021-04-24)
|
||||
-------------------
|
||||
|
||||
|
@ -380,6 +380,15 @@ class PythonSphinxMapper(SphinxMapperBase):
|
||||
)
|
||||
obj.url_root = self.url_root
|
||||
|
||||
for child_data in data.get("children", []):
|
||||
for child_obj in self.create_class(
|
||||
child_data, options=options, **kwargs
|
||||
):
|
||||
obj.children.append(child_obj)
|
||||
|
||||
# Some objects require children to establish their docstring
|
||||
# or type annotations (eg classes with inheritance),
|
||||
# so do this after all children have been created.
|
||||
lines = sphinx.util.docstrings.prepare_docstring(obj.docstring)
|
||||
if lines and "autodoc-process-docstring" in self.app.events.events:
|
||||
self.app.emit(
|
||||
@ -388,12 +397,6 @@ class PythonSphinxMapper(SphinxMapperBase):
|
||||
obj.docstring = "\n".join(lines)
|
||||
self._record_typehints(obj)
|
||||
|
||||
for child_data in data.get("children", []):
|
||||
for child_obj in self.create_class(
|
||||
child_data, options=options, **kwargs
|
||||
):
|
||||
obj.children.append(child_obj)
|
||||
|
||||
# Parser gives children in source order already
|
||||
if self.app.config.autoapi_member_order == "alphabetical":
|
||||
obj.children.sort(key=operator.attrgetter("name"))
|
||||
@ -405,14 +408,25 @@ class PythonSphinxMapper(SphinxMapperBase):
|
||||
def _record_typehints(self, obj):
|
||||
if isinstance(
|
||||
obj, (PythonClass, PythonFunction, PythonMethod)
|
||||
) and not obj.obj.get("overloads"):
|
||||
) and not obj.overloads:
|
||||
obj_annotations = {}
|
||||
for _, name, annotation, _ in obj.obj["args"]:
|
||||
|
||||
include_return_annotation = True
|
||||
obj_data = obj.obj
|
||||
if isinstance(obj, PythonClass):
|
||||
constructor = obj.constructor
|
||||
if constructor:
|
||||
include_return_annotation = False
|
||||
obj_data = constructor.obj
|
||||
else:
|
||||
return
|
||||
|
||||
for _, name, annotation, _ in obj_data["args"]:
|
||||
if name and annotation:
|
||||
obj_annotations[name] = annotation
|
||||
|
||||
return_annotation = obj.obj.get("return_annotation")
|
||||
if return_annotation:
|
||||
return_annotation = obj_data["return_annotation"]
|
||||
if include_return_annotation and return_annotation:
|
||||
obj_annotations["return"] = return_annotation
|
||||
|
||||
self.app.env.autoapi_annotations[obj.id] = obj_annotations
|
||||
|
@ -1,3 +1,4 @@
|
||||
import functools
|
||||
from typing import Optional
|
||||
|
||||
import sphinx.util.logging
|
||||
@ -174,6 +175,10 @@ class PythonFunction(PythonPythonMapper):
|
||||
autodoc_typehints == "description" and not obj["overloads"]
|
||||
)
|
||||
self.args = _format_args(obj["args"], show_annotations)
|
||||
"""The arguments to this object, formatted as a string.
|
||||
|
||||
:type: str
|
||||
"""
|
||||
|
||||
self.return_annotation = obj["return_annotation"] if show_annotations else None
|
||||
"""The type annotation for the return type of this function.
|
||||
@ -199,18 +204,6 @@ class PythonFunction(PythonPythonMapper):
|
||||
:type: list(tuple(str, str))
|
||||
"""
|
||||
|
||||
@property
|
||||
def args(self):
|
||||
"""The arguments to this object, formatted as a string.
|
||||
|
||||
:type: str
|
||||
"""
|
||||
return self._args
|
||||
|
||||
@args.setter
|
||||
def args(self, value):
|
||||
self._args = value
|
||||
|
||||
|
||||
class PythonMethod(PythonFunction):
|
||||
"""The representation of a method."""
|
||||
@ -343,8 +336,6 @@ class PythonClass(PythonPythonMapper):
|
||||
def __init__(self, obj, **kwargs):
|
||||
super(PythonClass, self).__init__(obj, **kwargs)
|
||||
|
||||
self.args = obj["args"]
|
||||
|
||||
self.bases = obj["bases"]
|
||||
"""The fully qualified names of all base classes.
|
||||
|
||||
@ -357,20 +348,34 @@ class PythonClass(PythonPythonMapper):
|
||||
|
||||
:type: str
|
||||
"""
|
||||
args = self._args
|
||||
args = ""
|
||||
|
||||
constructor = self.constructor
|
||||
if constructor:
|
||||
args = constructor.args
|
||||
|
||||
if args.startswith("self"):
|
||||
args = args[4:].lstrip(",").lstrip()
|
||||
if self.constructor:
|
||||
autodoc_typehints = getattr(self.app.config, "autodoc_typehints", "signature")
|
||||
show_annotations = autodoc_typehints != "none" and not (
|
||||
autodoc_typehints == "description" and not self.constructor.overloads
|
||||
)
|
||||
args_data = self.constructor.obj["args"]
|
||||
if args_data and args_data[0][1] == "self":
|
||||
args_data = args_data[1:]
|
||||
args = _format_args(args_data, show_annotations)
|
||||
|
||||
return args
|
||||
|
||||
@args.setter
|
||||
def args(self, value):
|
||||
self._args = value
|
||||
@property
|
||||
def overloads(self):
|
||||
overloads = []
|
||||
|
||||
if self.constructor:
|
||||
overload_data = self.constructor.obj["overloads"]
|
||||
if overload_data and overload_data[0][1] == "self":
|
||||
overload_data = overload_data[1:]
|
||||
overloads = [
|
||||
(_format_args(args), return_annotation)
|
||||
for args, return_annotation in overload_data
|
||||
]
|
||||
|
||||
return overloads
|
||||
|
||||
@property
|
||||
def docstring(self):
|
||||
@ -404,6 +409,7 @@ class PythonClass(PythonPythonMapper):
|
||||
return self._children_of_type("class")
|
||||
|
||||
@property
|
||||
@functools.lru_cache()
|
||||
def constructor(self):
|
||||
for child in self.children:
|
||||
if child.short_name == "__init__":
|
||||
|
@ -86,22 +86,12 @@ class Parser:
|
||||
if astroid_utils.is_exception(node):
|
||||
type_ = "exception"
|
||||
|
||||
args = []
|
||||
try:
|
||||
constructor = node.lookup("__init__")[1]
|
||||
except IndexError:
|
||||
pass
|
||||
else:
|
||||
if isinstance(constructor, astroid.nodes.FunctionDef):
|
||||
args = astroid_utils.get_args_info(constructor.args)
|
||||
|
||||
basenames = list(astroid_utils.get_full_basenames(node))
|
||||
|
||||
data = {
|
||||
"type": type_,
|
||||
"name": node.name,
|
||||
"full_name": self._get_full_name(node.name),
|
||||
"args": args,
|
||||
"bases": basenames,
|
||||
"doc": astroid_utils.get_class_docstring(node),
|
||||
"from_line_no": node.fromlineno,
|
||||
|
@ -1,12 +1,8 @@
|
||||
{% if obj.display %}
|
||||
.. {{ obj.type }}:: {{ obj.short_name }}{% if obj.args %}({{ obj.args }}){% endif %}
|
||||
{% if obj.constructor %}
|
||||
|
||||
{% for (args, return_annotation) in obj.constructor.overloads %}
|
||||
{% if args and args.startswith("self, ") %}{% set args = args[6:] %}{% endif %}
|
||||
{% for (args, return_annotation) in obj.overloads %}
|
||||
{{ " " * (obj.type | length) }} {{ obj.short_name }}{% if args %}({{ args }}){% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if obj.bases %}
|
||||
|
@ -13,7 +13,6 @@ exclude_patterns = ["_build"]
|
||||
pygments_style = "sphinx"
|
||||
todo_include_todos = False
|
||||
html_theme = "alabaster"
|
||||
html_static_path = ["_static"]
|
||||
htmlhelp_basename = "pyexampledoc"
|
||||
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
|
||||
autoapi_type = "python"
|
||||
|
@ -13,7 +13,6 @@ exclude_patterns = ["_build"]
|
||||
pygments_style = "sphinx"
|
||||
todo_include_todos = False
|
||||
html_theme = "alabaster"
|
||||
html_static_path = ["_static"]
|
||||
htmlhelp_basename = "pyexampledoc"
|
||||
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
|
||||
autoapi_type = "python"
|
||||
|
@ -13,7 +13,6 @@ exclude_patterns = ["_build"]
|
||||
pygments_style = "sphinx"
|
||||
todo_include_todos = False
|
||||
html_theme = "alabaster"
|
||||
html_static_path = ["_static"]
|
||||
htmlhelp_basename = "py3implicitnamespacedoc"
|
||||
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
|
||||
autoapi_type = "python"
|
||||
|
@ -13,7 +13,6 @@ exclude_patterns = ["_build"]
|
||||
pygments_style = "sphinx"
|
||||
todo_include_todos = False
|
||||
html_theme = "alabaster"
|
||||
html_static_path = ["_static"]
|
||||
htmlhelp_basename = "pyexampledoc"
|
||||
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
|
||||
autoapi_type = "python"
|
||||
|
@ -13,7 +13,6 @@ exclude_patterns = ["_build"]
|
||||
pygments_style = "sphinx"
|
||||
todo_include_todos = False
|
||||
html_theme = "alabaster"
|
||||
html_static_path = ["_static"]
|
||||
htmlhelp_basename = "pyexampledoc"
|
||||
extensions = ["sphinx.ext.autodoc", "autoapi.extension", "sphinx.ext.napoleon"]
|
||||
autoapi_type = "python"
|
||||
|
@ -13,7 +13,6 @@ exclude_patterns = ["_build"]
|
||||
pygments_style = "sphinx"
|
||||
todo_include_todos = False
|
||||
html_theme = "alabaster"
|
||||
html_static_path = ["_static"]
|
||||
htmlhelp_basename = "pyexampledoc"
|
||||
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
|
||||
autoapi_type = "python"
|
||||
|
@ -107,3 +107,7 @@ def decorator_okay(func):
|
||||
class Bar(Foo):
|
||||
def method_okay(self, foo=None, bar=None):
|
||||
pass
|
||||
|
||||
|
||||
class ClassWithNoInit:
|
||||
pass
|
||||
|
@ -7,3 +7,4 @@ Autodoc Directives
|
||||
|
||||
|
||||
.. autoapidecorator:: example.decorator_okay
|
||||
:noindex:
|
||||
|
@ -13,7 +13,6 @@ exclude_patterns = ["_build"]
|
||||
pygments_style = "sphinx"
|
||||
todo_include_todos = False
|
||||
html_theme = "alabaster"
|
||||
html_static_path = ["_static"]
|
||||
htmlhelp_basename = "pyexampledoc"
|
||||
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
|
||||
autoapi_type = "python"
|
||||
|
@ -13,7 +13,6 @@ exclude_patterns = ["_build"]
|
||||
pygments_style = "sphinx"
|
||||
todo_include_todos = False
|
||||
html_theme = "alabaster"
|
||||
html_static_path = ["_static"]
|
||||
htmlhelp_basename = "pyexampledoc"
|
||||
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
|
||||
autoapi_type = "python"
|
||||
|
@ -13,7 +13,6 @@ exclude_patterns = ["_build"]
|
||||
pygments_style = "sphinx"
|
||||
todo_include_todos = False
|
||||
html_theme = "alabaster"
|
||||
html_static_path = ["_static"]
|
||||
htmlhelp_basename = "pypackagecomplexdoc"
|
||||
extensions = ["autoapi.extension"]
|
||||
autoapi_type = "python"
|
||||
|
@ -13,7 +13,6 @@ exclude_patterns = ["_build"]
|
||||
pygments_style = "sphinx"
|
||||
todo_include_todos = False
|
||||
html_theme = "alabaster"
|
||||
html_static_path = ["_static"]
|
||||
htmlhelp_basename = "pypackageexampledoc"
|
||||
extensions = ["autoapi.extension"]
|
||||
autoapi_type = "python"
|
||||
|
@ -13,7 +13,6 @@ exclude_patterns = ["_build"]
|
||||
pygments_style = "sphinx"
|
||||
todo_include_todos = False
|
||||
html_theme = "alabaster"
|
||||
html_static_path = ["_static"]
|
||||
htmlhelp_basename = "pyexampledoc"
|
||||
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
|
||||
autoapi_type = "python"
|
||||
|
@ -51,7 +51,7 @@ def builder():
|
||||
class TestSimpleModule:
|
||||
@pytest.fixture(autouse=True, scope="class")
|
||||
def built(self, builder):
|
||||
builder("pyexample")
|
||||
builder("pyexample", warningiserror=True, confoverrides={"suppress_warnings": ["app"]})
|
||||
|
||||
def test_integration(self):
|
||||
self.check_integration("_build/text/autoapi/example/index.txt")
|
||||
|
Loading…
Reference in New Issue
Block a user