2323from itertools import tee , groupby
2424from types import ModuleType
2525from 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)
2929from 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+
424432def _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 :
0 commit comments