Skip to content

Commit ce821a3

Browse files
committed
Extend existing _unwrap_descriptor() function
1 parent 9f7a9f4 commit ce821a3

File tree

2 files changed

+18
-20
lines changed

2 files changed

+18
-20
lines changed

pdoc/__init__.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@
1919
import typing
2020
from contextlib import contextmanager
2121
from copy import copy
22-
from functools import lru_cache, reduce, partial, wraps
22+
from functools import cached_property, lru_cache, reduce, partial, wraps
2323
from itertools import tee, groupby
24-
from types import ModuleType
24+
from types import FunctionType, ModuleType
2525
from typing import ( # noqa: F401
2626
cast, Any, Callable, Dict, Generator, Iterable, List, Literal, Mapping, NewType,
2727
Optional, Set, Tuple, Type, TypeVar, Union,
@@ -421,11 +421,22 @@ def _is_descriptor(obj):
421421
inspect.ismemberdescriptor(obj))
422422

423423

424-
def _unwrap_descriptor(obj):
424+
def _unwrap_descriptor(dobj):
425+
obj = dobj.obj
425426
if isinstance(obj, property):
426427
return (getattr(obj, 'fget', False) or
427428
getattr(obj, 'fset', False) or
428429
getattr(obj, 'fdel', obj))
430+
if isinstance(obj, cached_property):
431+
return obj.func
432+
if isinstance(obj, FunctionType):
433+
return obj
434+
if (inspect.ismemberdescriptor(obj) or
435+
getattr(getattr(obj, '__class__', 0), '__name__', 0) == '_tuplegetter'):
436+
class_name = dobj.qualname.rsplit('.', 1)[0]
437+
obj = getattr(dobj.module.obj, class_name)
438+
return obj
439+
# XXX: Follow descriptor protocol? Already proved buggy in conditions above
429440
return getattr(obj, '__get__', obj)
430441

431442

@@ -550,7 +561,7 @@ def source(self) -> str:
550561
available, an empty string.
551562
"""
552563
try:
553-
lines, _ = inspect.getsourcelines(_unwrap_descriptor(self.obj))
564+
lines, _ = inspect.getsourcelines(_unwrap_descriptor(self))
554565
except (ValueError, TypeError, OSError):
555566
return ''
556567
return inspect.cleandoc(''.join(['\n'] + lines))
@@ -1402,7 +1413,7 @@ def return_annotation(self, *, link=None) -> str:
14021413
# global variables
14031414
lambda: _get_type_hints(not self.cls and self.module.obj)[self.name],
14041415
# properties
1405-
lambda: inspect.signature(_unwrap_descriptor(self.obj)).return_annotation,
1416+
lambda: inspect.signature(_unwrap_descriptor(self)).return_annotation,
14061417
# Use raw annotation strings in unmatched forward declarations
14071418
lambda: cast(Class, self.cls).obj.__annotations__[self.name],
14081419
# Extract annotation from the docstring for C builtin function

pdoc/html_helpers.py

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import textwrap
99
import traceback
1010
from contextlib import contextmanager
11-
from functools import partial, lru_cache, cached_property
11+
from functools import partial, lru_cache
1212
from typing import Callable, Match, Optional
1313
from warnings import warn
1414
import xml.etree.ElementTree as etree
@@ -564,20 +564,7 @@ def format_git_link(template: str, dobj: pdoc.Doc):
564564
try:
565565
if 'commit' in _str_template_fields(template):
566566
commit = _git_head_commit()
567-
obj = dobj.obj
568-
569-
# special handlers for properties, cached_properties, and tuples
570-
if isinstance(obj, property):
571-
obj = obj.fget
572-
elif isinstance(obj, cached_property):
573-
obj = obj.func
574-
elif (
575-
(hasattr(obj, '__class__') and obj.__class__.__name__ == '_tuplegetter')
576-
or inspect.ismemberdescriptor(obj)
577-
):
578-
class_name = dobj.qualname.rsplit('.', 1)[0]
579-
obj = getattr(dobj.module.obj, class_name)
580-
567+
obj = pdoc._unwrap_descriptor(dobj)
581568
abs_path = inspect.getfile(inspect.unwrap(obj))
582569
path = _project_relative_path(abs_path)
583570

0 commit comments

Comments
 (0)