Skip to content

Commit 9b64f7f

Browse files
ENH: Discern properties from variables (#277)
* Possible way to address issue 276. This shows "property" if a variable is a property with a setter and/or a deleter and "ro-property" (read only property) if it is a property which does not have either a setter or getter. * Shorten comment line * Rename "vartype" to "kind". Also make property now show get/set/del depending on what is defined, e.g. propert/get/set * Remove unnecessary comment. * Make linter happy about line length. * REF: Make pdoc.Doc.obj point to raw property/descriptor * ENH: Introduce `Variable.kind: Literal["var","prop"]`
1 parent c3fb554 commit 9b64f7f

File tree

2 files changed

+24
-7
lines changed

2 files changed

+24
-7
lines changed

pdoc/__init__.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from itertools import tee, groupby
2424
from types import ModuleType
2525
from typing import ( # noqa: F401
26-
cast, Any, Callable, Dict, Generator, Iterable, List, Mapping, NewType,
26+
cast, Any, Callable, Dict, Generator, Iterable, List, Literal, Mapping, NewType,
2727
Optional, Set, Tuple, Type, TypeVar, Union,
2828
)
2929
from unittest.mock import Mock
@@ -421,6 +421,14 @@ def _is_descriptor(obj):
421421
inspect.ismemberdescriptor(obj))
422422

423423

424+
def _unwrap_descriptor(obj):
425+
if isinstance(obj, property):
426+
return (getattr(obj, 'fget', False) or
427+
getattr(obj, 'fset', False) or
428+
getattr(obj, 'fdel', obj))
429+
return getattr(obj, '__get__', obj)
430+
431+
424432
def _filter_type(type: Type[T],
425433
values: Union[Iterable['Doc'], Mapping[str, 'Doc']]) -> List[T]:
426434
"""
@@ -542,7 +550,7 @@ def source(self) -> str:
542550
available, an empty string.
543551
"""
544552
try:
545-
lines, _ = inspect.getsourcelines(self.obj)
553+
lines, _ = inspect.getsourcelines(_unwrap_descriptor(self.obj))
546554
except (ValueError, TypeError, OSError):
547555
return ''
548556
return inspect.cleandoc(''.join(['\n'] + lines))
@@ -1079,7 +1087,8 @@ def definition_order_index(
10791087
var_docstrings.get(name) or
10801088
(inspect.isclass(obj) or _is_descriptor(obj)) and inspect.getdoc(obj)),
10811089
cls=self,
1082-
obj=getattr(obj, 'fget', getattr(obj, '__get__', None)),
1090+
kind="prop" if isinstance(obj, property) else "var",
1091+
obj=_is_descriptor(obj) and obj or None,
10831092
instance_var=(_is_descriptor(obj) or
10841093
name in getattr(self.obj, '__slots__', ())))
10851094

@@ -1392,7 +1401,8 @@ def return_annotation(self, *, link=None) -> str:
13921401
lambda: _get_type_hints(cast(Class, self.cls).obj)[self.name],
13931402
# global variables
13941403
lambda: _get_type_hints(not self.cls and self.module.obj)[self.name],
1395-
lambda: inspect.signature(self.obj).return_annotation,
1404+
# properties
1405+
lambda: inspect.signature(_unwrap_descriptor(self.obj)).return_annotation,
13961406
# Use raw annotation strings in unmatched forward declarations
13971407
lambda: cast(Class, self.cls).obj.__annotations__[self.name],
13981408
# Extract annotation from the docstring for C builtin function
@@ -1593,10 +1603,11 @@ class Variable(Doc):
15931603
Representation of a variable's documentation. This includes
15941604
module, class, and instance variables.
15951605
"""
1596-
__slots__ = ('cls', 'instance_var')
1606+
__slots__ = ('cls', 'instance_var', 'kind')
15971607

15981608
def __init__(self, name: str, module: Module, docstring, *,
1599-
obj=None, cls: Optional[Class] = None, instance_var: bool = False):
1609+
obj=None, cls: Optional[Class] = None, instance_var: bool = False,
1610+
kind: Literal["prop", "var"] = 'var'):
16001611
"""
16011612
Same as `pdoc.Doc`, except `cls` should be provided
16021613
as a `pdoc.Class` object when this is a class or instance
@@ -1616,6 +1627,12 @@ def __init__(self, name: str, module: Module, docstring, *,
16161627
opposed to class variable).
16171628
"""
16181629

1630+
self.kind = kind
1631+
"""
1632+
`prop` if variable is a dynamic property (has getter/setter or deleter),
1633+
or `var` otherwise.
1634+
"""
1635+
16191636
@property
16201637
def qualname(self) -> str:
16211638
if self.cls:

pdoc/templates/html.mako

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@
236236
<dl>
237237
% for v in inst_vars:
238238
<% return_type = get_annotation(v.type_annotation) %>
239-
<dt id="${v.refname}"><code class="name">var ${ident(v.name)}${return_type}</code></dt>
239+
<dt id="${v.refname}"><code class="name">${v.kind} ${ident(v.name)}${return_type}</code></dt>
240240
<dd>${show_desc(v)}</dd>
241241
% endfor
242242
</dl>

0 commit comments

Comments
 (0)