Skip to content

Commit 2b6fe6e

Browse files
Add Support For Attributes In Docstrings
This allows class attributes to be defined in docstrings without causing an exception while linking the source code. Due to the non-static nature of attributes, it's not trivial to link their actual definition, so the chosen lines will actually be all the lines of the parent class. Signed-off-by: Hassan Abouelela <hassan@hassanamr.com>
1 parent 3f55e71 commit 2b6fe6e

File tree

3 files changed

+169
-134
lines changed

3 files changed

+169
-134
lines changed

docs/utils.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
import inspect
66
import os
77
import subprocess
8+
import types
89
import typing
910
from pathlib import Path
1011

12+
import docstring_parser
1113
import docutils.nodes
1214
import docutils.parsers.rst.states
1315
import git
@@ -25,6 +27,18 @@ def get_build_root() -> Path:
2527
return root
2628

2729

30+
def is_attribute(module: types.ModuleType, parameter: str) -> bool:
31+
"""Returns true if `parameter` is an attribute of `module`."""
32+
docs = docstring_parser.parse(inspect.getdoc(module), docstring_parser.DocstringStyle.GOOGLE)
33+
for param in docs.params:
34+
# The docstring_parser library can mis-parse arguments like `arg (:obj:`str`)` as `arg (`
35+
# which would create a false-negative below, so we just strip away the extra parenthesis.
36+
if param.args[0] == "attribute" and param.arg_name.rstrip(" (") == parameter:
37+
return True
38+
39+
return False
40+
41+
2842
def linkcode_resolve(repo_link: str, domain: str, info: dict[str, str]) -> typing.Optional[str]:
2943
"""
3044
Function called by linkcode to get the URL for a given resource.
@@ -59,7 +73,15 @@ def linkcode_resolve(repo_link: str, domain: str, info: dict[str, str]) -> typin
5973

6074
symbol = [module]
6175
for name in symbol_name.split("."):
62-
symbol.append(getattr(symbol[-1], name))
76+
try:
77+
symbol.append(getattr(symbol[-1], name))
78+
except AttributeError as e:
79+
# This could be caused by trying to link a class attribute
80+
if is_attribute(symbol[-1], name):
81+
break
82+
else:
83+
raise e
84+
6385
symbol_name = name
6486

6587
try:

0 commit comments

Comments
 (0)