Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions pdoc/doc.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,21 @@ def members(self) -> dict[str, Doc]:
taken_from=taken_from,
)

if isinstance(doc, Variable) and not is_property:
_ast_info = doc_ast.walk_tree(self.obj)
if name in _ast_info.var_source_lines:
start, end = _ast_info.var_source_lines[name]
parent_source = doc_ast.get_source(self.obj)
if parent_source:
src_lines = parent_source.splitlines(True)
doc.source = "".join(src_lines[start - 1 : end])
parent_start = self.source_lines[0] if self.source_lines else 1
doc.source_lines = (
parent_start + start - 1,
parent_start + end - 1,
)
doc.source_file = self.source_file

if _doc := _pydantic.get_field_docstring(cast(type, self.obj), name):
doc.docstring = _doc
elif self._var_docstrings.get(name):
Expand Down
12 changes: 11 additions & 1 deletion pdoc/doc_ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,12 @@ class AstInfo:
"""A qualname -> docstring mapping for functions."""
annotations: dict[str, str | type[pdoc.doc_types.empty]]
"""A qualname -> annotation mapping.

Annotations are not evaluated by this module and only returned as strings."""
var_source_lines: dict[str, tuple[int, int]]
"""A qualname -> (start_line, end_line) mapping for variable assignments.

Line numbers are 1-based and relative to the parsed source."""


def walk_tree(obj: types.ModuleType | type) -> AstInfo:
Expand All @@ -111,6 +115,7 @@ def _walk_tree(
var_docstrings = {}
func_docstrings = {}
annotations = {}
var_source_lines: dict[str, tuple[int, int]] = {}
for a, b in _pairwise_longest(_nodes(tree)):
if isinstance(a, ast_TypeAlias):
name = a.name.id
Expand Down Expand Up @@ -139,6 +144,10 @@ def _walk_tree(
continue
else:
continue
# Record source line info for variables (skip synthetic nodes from _init_nodes)
lineno = getattr(a, "lineno", None)
if lineno is not None:
var_source_lines[name] = (lineno, getattr(a, "end_lineno", None) or lineno)
if (
isinstance(b, ast.Expr)
and isinstance(b.value, ast.Constant)
Expand All @@ -149,6 +158,7 @@ def _walk_tree(
var_docstrings,
func_docstrings,
annotations,
var_source_lines,
)


Expand Down
11 changes: 8 additions & 3 deletions test/testdata/collections_abc.html
Original file line number Diff line number Diff line change
Expand Up @@ -131,14 +131,19 @@ <h1 class="modulename">

</section>
<section id="var">
<div class="attr variable">
<input id="var-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
<div class="attr variable">
<span class="name">var</span><span class="annotation">: Container[str]</span> =
<span class="default_value">&#39;baz&#39;</span>


<label class="view-source-button" for="var-view-source"><span>View Source</span></label>

</div>
<a class="headerlink" href="#var"></a>

<div class="pdoc-code codehilite"><pre><span></span><span id="var-21"><a href="#var-21"><span class="linenos">21</span></a><span class="n">var</span><span class="p">:</span> <span class="n">Container</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;baz&quot;</span>
</span></pre></div>




</section>
Expand Down
22 changes: 16 additions & 6 deletions test/testdata/demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -141,26 +141,36 @@ <h1 class="modulename">

</div>
<div id="Dog.name" class="classattr">
<div class="attr variable">
<input id="Dog.name-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
<div class="attr variable">
<span class="name">name</span><span class="annotation">: str</span>


<label class="view-source-button" for="Dog.name-view-source"><span>View Source</span></label>

</div>
<a class="headerlink" href="#Dog.name"></a>

<div class="pdoc-code codehilite"><pre><span></span><span id="Dog.name-8"><a href="#Dog.name-8"><span class="linenos">8</span></a> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span>
</span></pre></div>


<div class="docstring"><p>The name of our dog.</p>
</div>


</div>
<div id="Dog.friends" class="classattr">
<div class="attr variable">
<input id="Dog.friends-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
<div class="attr variable">
<span class="name">friends</span><span class="annotation">: list[<a href="#Dog">Dog</a>]</span>


<label class="view-source-button" for="Dog.friends-view-source"><span>View Source</span></label>

</div>
<a class="headerlink" href="#Dog.friends"></a>

<div class="pdoc-code codehilite"><pre><span></span><span id="Dog.friends-10"><a href="#Dog.friends-10"><span class="linenos">10</span></a> <span class="n">friends</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="s2">&quot;Dog&quot;</span><span class="p">]</span>
</span></pre></div>


<div class="docstring"><p>The friends of our dog.</p>
</div>

Expand Down
Loading
Loading