Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Workaround incorrect __module__ #1

Open
wants to merge 3 commits into
base: attr-typehints
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 23 additions & 2 deletions sphinx_autodoc_typehints.py
Expand Up @@ -204,7 +204,7 @@ def get_all_type_hints(obj, name):

try:
rv = get_type_hints(obj)
except (AttributeError, TypeError, RecursionError):
except (AttributeError, TypeError, RecursionError, KeyError):
# Introspecting a slot wrapper will raise TypeError, and and some recursive type
# definitions will cause a RecursionError (https://github.com/python/typing/issues/574).
pass
Expand All @@ -225,7 +225,7 @@ def get_all_type_hints(obj, name):

try:
rv = get_type_hints(obj)
except (AttributeError, TypeError):
except (AttributeError, TypeError, KeyError):
pass
except NameError as exc:
logger.warning('Cannot resolve forward reference in type annotations of "%s": %s',
Expand Down Expand Up @@ -358,6 +358,27 @@ def process_docstring(app, what, name, obj, options, lines):

if callable(obj):
if inspect.isclass(obj):
# Use type hints from instance and class variables for attributes
outer_obj = inspect.unwrap(obj)
type_hints = get_all_type_hints(outer_obj, name)
for argname, annotation in type_hints.items():
formatted_annotation = format_annotation(
annotation, fully_qualified=app.config.typehints_fully_qualified)

searchfor_attr = '.. attribute:: {}'.format(argname)
searchfor_ivar = ':ivar {}:'.format(argname)
for i, line in enumerate(lines):
if line.startswith(searchfor_attr):
i += 1
while i < len(lines):
if lines[i].startswith(':') or lines[i].startswith('.. '):
break
i += 1
lines.insert(i, ' :type: {}'.format(formatted_annotation))
break
if line.startswith(searchfor_ivar):
lines.insert(i, ':vartype {}: {}'.format(argname, formatted_annotation))
break
obj = getattr(obj, '__init__')

obj = inspect.unwrap(obj)
Expand Down
30 changes: 29 additions & 1 deletion tests/roots/test-dummy/dummy_module.py
@@ -1,6 +1,6 @@
import typing
from mailbox import Mailbox
from typing import Callable, Union
from typing import Callable, ClassVar, Union

try:
from dataclasses import dataclass
Expand All @@ -24,8 +24,26 @@ class Class:
:param x: foo
:param y: bar
:param z: baz

.. attribute:: x

Multiline

Description

.. attribute:: y

bar

.. attribute:: z

baz
"""

x: bool
y: int
z: ClassVar[str]

def __init__(self, x: bool, y: int, z: typing.Optional[str] = None) -> None:
pass

Expand Down Expand Up @@ -88,8 +106,12 @@ def a_property(self) -> str:
class InnerClass:
"""
Inner class.

:ivar x: foo
"""

x: bool

def inner_method(self, x: bool) -> str:
"""
Inner method.
Expand All @@ -111,9 +133,15 @@ class DummyException(Exception):
"""
Exception docstring

.. attribute:: message

Message description

:param message: blah
"""

message: str

def __init__(self, message: str) -> None:
super().__init__(message)

Expand Down
43 changes: 43 additions & 0 deletions tests/test_sphinx_autodoc_typehints.py
Expand Up @@ -246,10 +246,36 @@ class dummy_module.Class(x, y, z=None)

* **z** ("Optional"["str"]) – baz

x

Multiline

Description

Type:
"bool"

y

bar

Type:
"int"

z

baz

Type:
"ClassVar"["str"]

class InnerClass

Inner class.

Variables:
**x** ("bool") -- foo

_InnerClass__dunder_inner_method(x)

Dunder inner method.
Expand All @@ -270,6 +296,8 @@ class InnerClass
Return type:
"str"

x: bool = None

_Class__dunder_method(x)

Dunder method docstring.
Expand Down Expand Up @@ -356,13 +384,28 @@ class InnerClass
Return type:
"str"

x: bool = None

y: int = None

z: ClassVar[str] = None

exception dummy_module.DummyException(message)

Exception docstring

message

Message description

Type:
"str"

Parameters:
**message** ("str") – blah

message: str = None

dummy_module.function(x, y, z_=None)

Function docstring.
Expand Down