|
19 | 19 | import typing
|
20 | 20 | from contextlib import contextmanager
|
21 | 21 | from copy import copy
|
22 |
| -from functools import lru_cache, reduce, partial, wraps |
| 22 | +from functools import cached_property, lru_cache, reduce, partial, wraps |
23 | 23 | from itertools import tee, groupby
|
24 |
| -from types import ModuleType |
| 24 | +from types import FunctionType, ModuleType |
25 | 25 | from typing import ( # noqa: F401
|
26 | 26 | cast, Any, Callable, Dict, Generator, Iterable, List, Literal, Mapping, NewType,
|
27 | 27 | Optional, Set, Tuple, Type, TypeVar, Union,
|
@@ -421,11 +421,22 @@ def _is_descriptor(obj):
|
421 | 421 | inspect.ismemberdescriptor(obj))
|
422 | 422 |
|
423 | 423 |
|
424 |
| -def _unwrap_descriptor(obj): |
| 424 | +def _unwrap_descriptor(dobj): |
| 425 | + obj = dobj.obj |
425 | 426 | if isinstance(obj, property):
|
426 | 427 | return (getattr(obj, 'fget', False) or
|
427 | 428 | getattr(obj, 'fset', False) or
|
428 | 429 | 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 |
429 | 440 | return getattr(obj, '__get__', obj)
|
430 | 441 |
|
431 | 442 |
|
@@ -550,7 +561,7 @@ def source(self) -> str:
|
550 | 561 | available, an empty string.
|
551 | 562 | """
|
552 | 563 | try:
|
553 |
| - lines, _ = inspect.getsourcelines(_unwrap_descriptor(self.obj)) |
| 564 | + lines, _ = inspect.getsourcelines(_unwrap_descriptor(self)) |
554 | 565 | except (ValueError, TypeError, OSError):
|
555 | 566 | return ''
|
556 | 567 | return inspect.cleandoc(''.join(['\n'] + lines))
|
@@ -1402,7 +1413,7 @@ def return_annotation(self, *, link=None) -> str:
|
1402 | 1413 | # global variables
|
1403 | 1414 | lambda: _get_type_hints(not self.cls and self.module.obj)[self.name],
|
1404 | 1415 | # properties
|
1405 |
| - lambda: inspect.signature(_unwrap_descriptor(self.obj)).return_annotation, |
| 1416 | + lambda: inspect.signature(_unwrap_descriptor(self)).return_annotation, |
1406 | 1417 | # Use raw annotation strings in unmatched forward declarations
|
1407 | 1418 | lambda: cast(Class, self.cls).obj.__annotations__[self.name],
|
1408 | 1419 | # Extract annotation from the docstring for C builtin function
|
|
0 commit comments