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>``).
|
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)
|
v1.8.1 (2021-04-24)
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
@ -380,6 +380,15 @@ class PythonSphinxMapper(SphinxMapperBase):
|
|||||||
)
|
)
|
||||||
obj.url_root = self.url_root
|
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)
|
lines = sphinx.util.docstrings.prepare_docstring(obj.docstring)
|
||||||
if lines and "autodoc-process-docstring" in self.app.events.events:
|
if lines and "autodoc-process-docstring" in self.app.events.events:
|
||||||
self.app.emit(
|
self.app.emit(
|
||||||
@ -388,12 +397,6 @@ class PythonSphinxMapper(SphinxMapperBase):
|
|||||||
obj.docstring = "\n".join(lines)
|
obj.docstring = "\n".join(lines)
|
||||||
self._record_typehints(obj)
|
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
|
# Parser gives children in source order already
|
||||||
if self.app.config.autoapi_member_order == "alphabetical":
|
if self.app.config.autoapi_member_order == "alphabetical":
|
||||||
obj.children.sort(key=operator.attrgetter("name"))
|
obj.children.sort(key=operator.attrgetter("name"))
|
||||||
@ -405,14 +408,25 @@ class PythonSphinxMapper(SphinxMapperBase):
|
|||||||
def _record_typehints(self, obj):
|
def _record_typehints(self, obj):
|
||||||
if isinstance(
|
if isinstance(
|
||||||
obj, (PythonClass, PythonFunction, PythonMethod)
|
obj, (PythonClass, PythonFunction, PythonMethod)
|
||||||
) and not obj.obj.get("overloads"):
|
) and not obj.overloads:
|
||||||
obj_annotations = {}
|
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:
|
if name and annotation:
|
||||||
obj_annotations[name] = annotation
|
obj_annotations[name] = annotation
|
||||||
|
|
||||||
return_annotation = obj.obj.get("return_annotation")
|
return_annotation = obj_data["return_annotation"]
|
||||||
if return_annotation:
|
if include_return_annotation and return_annotation:
|
||||||
obj_annotations["return"] = return_annotation
|
obj_annotations["return"] = return_annotation
|
||||||
|
|
||||||
self.app.env.autoapi_annotations[obj.id] = obj_annotations
|
self.app.env.autoapi_annotations[obj.id] = obj_annotations
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import functools
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
import sphinx.util.logging
|
import sphinx.util.logging
|
||||||
@ -174,6 +175,10 @@ class PythonFunction(PythonPythonMapper):
|
|||||||
autodoc_typehints == "description" and not obj["overloads"]
|
autodoc_typehints == "description" and not obj["overloads"]
|
||||||
)
|
)
|
||||||
self.args = _format_args(obj["args"], show_annotations)
|
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
|
self.return_annotation = obj["return_annotation"] if show_annotations else None
|
||||||
"""The type annotation for the return type of this function.
|
"""The type annotation for the return type of this function.
|
||||||
@ -199,18 +204,6 @@ class PythonFunction(PythonPythonMapper):
|
|||||||
:type: list(tuple(str, str))
|
: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):
|
class PythonMethod(PythonFunction):
|
||||||
"""The representation of a method."""
|
"""The representation of a method."""
|
||||||
@ -343,8 +336,6 @@ class PythonClass(PythonPythonMapper):
|
|||||||
def __init__(self, obj, **kwargs):
|
def __init__(self, obj, **kwargs):
|
||||||
super(PythonClass, self).__init__(obj, **kwargs)
|
super(PythonClass, self).__init__(obj, **kwargs)
|
||||||
|
|
||||||
self.args = obj["args"]
|
|
||||||
|
|
||||||
self.bases = obj["bases"]
|
self.bases = obj["bases"]
|
||||||
"""The fully qualified names of all base classes.
|
"""The fully qualified names of all base classes.
|
||||||
|
|
||||||
@ -357,20 +348,34 @@ class PythonClass(PythonPythonMapper):
|
|||||||
|
|
||||||
:type: str
|
:type: str
|
||||||
"""
|
"""
|
||||||
args = self._args
|
args = ""
|
||||||
|
|
||||||
constructor = self.constructor
|
if self.constructor:
|
||||||
if constructor:
|
autodoc_typehints = getattr(self.app.config, "autodoc_typehints", "signature")
|
||||||
args = constructor.args
|
show_annotations = autodoc_typehints != "none" and not (
|
||||||
|
autodoc_typehints == "description" and not self.constructor.overloads
|
||||||
if args.startswith("self"):
|
)
|
||||||
args = args[4:].lstrip(",").lstrip()
|
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
|
return args
|
||||||
|
|
||||||
@args.setter
|
@property
|
||||||
def args(self, value):
|
def overloads(self):
|
||||||
self._args = value
|
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
|
@property
|
||||||
def docstring(self):
|
def docstring(self):
|
||||||
@ -404,6 +409,7 @@ class PythonClass(PythonPythonMapper):
|
|||||||
return self._children_of_type("class")
|
return self._children_of_type("class")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@functools.lru_cache()
|
||||||
def constructor(self):
|
def constructor(self):
|
||||||
for child in self.children:
|
for child in self.children:
|
||||||
if child.short_name == "__init__":
|
if child.short_name == "__init__":
|
||||||
|
@ -86,22 +86,12 @@ class Parser:
|
|||||||
if astroid_utils.is_exception(node):
|
if astroid_utils.is_exception(node):
|
||||||
type_ = "exception"
|
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))
|
basenames = list(astroid_utils.get_full_basenames(node))
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"type": type_,
|
"type": type_,
|
||||||
"name": node.name,
|
"name": node.name,
|
||||||
"full_name": self._get_full_name(node.name),
|
"full_name": self._get_full_name(node.name),
|
||||||
"args": args,
|
|
||||||
"bases": basenames,
|
"bases": basenames,
|
||||||
"doc": astroid_utils.get_class_docstring(node),
|
"doc": astroid_utils.get_class_docstring(node),
|
||||||
"from_line_no": node.fromlineno,
|
"from_line_no": node.fromlineno,
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
{% if obj.display %}
|
{% if obj.display %}
|
||||||
.. {{ obj.type }}:: {{ obj.short_name }}{% if obj.args %}({{ obj.args }}){% endif %}
|
.. {{ obj.type }}:: {{ obj.short_name }}{% if obj.args %}({{ obj.args }}){% endif %}
|
||||||
{% if obj.constructor %}
|
{% for (args, return_annotation) in obj.overloads %}
|
||||||
|
|
||||||
{% for (args, return_annotation) in obj.constructor.overloads %}
|
|
||||||
{% if args and args.startswith("self, ") %}{% set args = args[6:] %}{% endif %}
|
|
||||||
{{ " " * (obj.type | length) }} {{ obj.short_name }}{% if args %}({{ args }}){% endif %}
|
{{ " " * (obj.type | length) }} {{ obj.short_name }}{% if args %}({{ args }}){% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
||||||
{% if obj.bases %}
|
{% if obj.bases %}
|
||||||
|
@ -13,7 +13,6 @@ exclude_patterns = ["_build"]
|
|||||||
pygments_style = "sphinx"
|
pygments_style = "sphinx"
|
||||||
todo_include_todos = False
|
todo_include_todos = False
|
||||||
html_theme = "alabaster"
|
html_theme = "alabaster"
|
||||||
html_static_path = ["_static"]
|
|
||||||
htmlhelp_basename = "pyexampledoc"
|
htmlhelp_basename = "pyexampledoc"
|
||||||
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
|
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
|
||||||
autoapi_type = "python"
|
autoapi_type = "python"
|
||||||
|
@ -13,7 +13,6 @@ exclude_patterns = ["_build"]
|
|||||||
pygments_style = "sphinx"
|
pygments_style = "sphinx"
|
||||||
todo_include_todos = False
|
todo_include_todos = False
|
||||||
html_theme = "alabaster"
|
html_theme = "alabaster"
|
||||||
html_static_path = ["_static"]
|
|
||||||
htmlhelp_basename = "pyexampledoc"
|
htmlhelp_basename = "pyexampledoc"
|
||||||
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
|
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
|
||||||
autoapi_type = "python"
|
autoapi_type = "python"
|
||||||
|
@ -13,7 +13,6 @@ exclude_patterns = ["_build"]
|
|||||||
pygments_style = "sphinx"
|
pygments_style = "sphinx"
|
||||||
todo_include_todos = False
|
todo_include_todos = False
|
||||||
html_theme = "alabaster"
|
html_theme = "alabaster"
|
||||||
html_static_path = ["_static"]
|
|
||||||
htmlhelp_basename = "py3implicitnamespacedoc"
|
htmlhelp_basename = "py3implicitnamespacedoc"
|
||||||
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
|
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
|
||||||
autoapi_type = "python"
|
autoapi_type = "python"
|
||||||
|
@ -13,7 +13,6 @@ exclude_patterns = ["_build"]
|
|||||||
pygments_style = "sphinx"
|
pygments_style = "sphinx"
|
||||||
todo_include_todos = False
|
todo_include_todos = False
|
||||||
html_theme = "alabaster"
|
html_theme = "alabaster"
|
||||||
html_static_path = ["_static"]
|
|
||||||
htmlhelp_basename = "pyexampledoc"
|
htmlhelp_basename = "pyexampledoc"
|
||||||
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
|
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
|
||||||
autoapi_type = "python"
|
autoapi_type = "python"
|
||||||
|
@ -13,7 +13,6 @@ exclude_patterns = ["_build"]
|
|||||||
pygments_style = "sphinx"
|
pygments_style = "sphinx"
|
||||||
todo_include_todos = False
|
todo_include_todos = False
|
||||||
html_theme = "alabaster"
|
html_theme = "alabaster"
|
||||||
html_static_path = ["_static"]
|
|
||||||
htmlhelp_basename = "pyexampledoc"
|
htmlhelp_basename = "pyexampledoc"
|
||||||
extensions = ["sphinx.ext.autodoc", "autoapi.extension", "sphinx.ext.napoleon"]
|
extensions = ["sphinx.ext.autodoc", "autoapi.extension", "sphinx.ext.napoleon"]
|
||||||
autoapi_type = "python"
|
autoapi_type = "python"
|
||||||
|
@ -13,7 +13,6 @@ exclude_patterns = ["_build"]
|
|||||||
pygments_style = "sphinx"
|
pygments_style = "sphinx"
|
||||||
todo_include_todos = False
|
todo_include_todos = False
|
||||||
html_theme = "alabaster"
|
html_theme = "alabaster"
|
||||||
html_static_path = ["_static"]
|
|
||||||
htmlhelp_basename = "pyexampledoc"
|
htmlhelp_basename = "pyexampledoc"
|
||||||
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
|
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
|
||||||
autoapi_type = "python"
|
autoapi_type = "python"
|
||||||
|
@ -107,3 +107,7 @@ def decorator_okay(func):
|
|||||||
class Bar(Foo):
|
class Bar(Foo):
|
||||||
def method_okay(self, foo=None, bar=None):
|
def method_okay(self, foo=None, bar=None):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ClassWithNoInit:
|
||||||
|
pass
|
||||||
|
@ -7,3 +7,4 @@ Autodoc Directives
|
|||||||
|
|
||||||
|
|
||||||
.. autoapidecorator:: example.decorator_okay
|
.. autoapidecorator:: example.decorator_okay
|
||||||
|
:noindex:
|
||||||
|
@ -13,7 +13,6 @@ exclude_patterns = ["_build"]
|
|||||||
pygments_style = "sphinx"
|
pygments_style = "sphinx"
|
||||||
todo_include_todos = False
|
todo_include_todos = False
|
||||||
html_theme = "alabaster"
|
html_theme = "alabaster"
|
||||||
html_static_path = ["_static"]
|
|
||||||
htmlhelp_basename = "pyexampledoc"
|
htmlhelp_basename = "pyexampledoc"
|
||||||
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
|
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
|
||||||
autoapi_type = "python"
|
autoapi_type = "python"
|
||||||
|
@ -13,7 +13,6 @@ exclude_patterns = ["_build"]
|
|||||||
pygments_style = "sphinx"
|
pygments_style = "sphinx"
|
||||||
todo_include_todos = False
|
todo_include_todos = False
|
||||||
html_theme = "alabaster"
|
html_theme = "alabaster"
|
||||||
html_static_path = ["_static"]
|
|
||||||
htmlhelp_basename = "pyexampledoc"
|
htmlhelp_basename = "pyexampledoc"
|
||||||
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
|
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
|
||||||
autoapi_type = "python"
|
autoapi_type = "python"
|
||||||
|
@ -13,7 +13,6 @@ exclude_patterns = ["_build"]
|
|||||||
pygments_style = "sphinx"
|
pygments_style = "sphinx"
|
||||||
todo_include_todos = False
|
todo_include_todos = False
|
||||||
html_theme = "alabaster"
|
html_theme = "alabaster"
|
||||||
html_static_path = ["_static"]
|
|
||||||
htmlhelp_basename = "pypackagecomplexdoc"
|
htmlhelp_basename = "pypackagecomplexdoc"
|
||||||
extensions = ["autoapi.extension"]
|
extensions = ["autoapi.extension"]
|
||||||
autoapi_type = "python"
|
autoapi_type = "python"
|
||||||
|
@ -13,7 +13,6 @@ exclude_patterns = ["_build"]
|
|||||||
pygments_style = "sphinx"
|
pygments_style = "sphinx"
|
||||||
todo_include_todos = False
|
todo_include_todos = False
|
||||||
html_theme = "alabaster"
|
html_theme = "alabaster"
|
||||||
html_static_path = ["_static"]
|
|
||||||
htmlhelp_basename = "pypackageexampledoc"
|
htmlhelp_basename = "pypackageexampledoc"
|
||||||
extensions = ["autoapi.extension"]
|
extensions = ["autoapi.extension"]
|
||||||
autoapi_type = "python"
|
autoapi_type = "python"
|
||||||
|
@ -13,7 +13,6 @@ exclude_patterns = ["_build"]
|
|||||||
pygments_style = "sphinx"
|
pygments_style = "sphinx"
|
||||||
todo_include_todos = False
|
todo_include_todos = False
|
||||||
html_theme = "alabaster"
|
html_theme = "alabaster"
|
||||||
html_static_path = ["_static"]
|
|
||||||
htmlhelp_basename = "pyexampledoc"
|
htmlhelp_basename = "pyexampledoc"
|
||||||
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
|
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
|
||||||
autoapi_type = "python"
|
autoapi_type = "python"
|
||||||
|
@ -51,7 +51,7 @@ def builder():
|
|||||||
class TestSimpleModule:
|
class TestSimpleModule:
|
||||||
@pytest.fixture(autouse=True, scope="class")
|
@pytest.fixture(autouse=True, scope="class")
|
||||||
def built(self, builder):
|
def built(self, builder):
|
||||||
builder("pyexample")
|
builder("pyexample", warningiserror=True, confoverrides={"suppress_warnings": ["app"]})
|
||||||
|
|
||||||
def test_integration(self):
|
def test_integration(self):
|
||||||
self.check_integration("_build/text/autoapi/example/index.txt")
|
self.check_integration("_build/text/autoapi/example/index.txt")
|
||||||
|
Loading…
Reference in New Issue
Block a user