|
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,
|
@@ -429,11 +429,22 @@ def _is_descriptor(obj):
|
429 | 429 | inspect.ismemberdescriptor(obj))
|
430 | 430 |
|
431 | 431 |
|
432 |
| -def _unwrap_descriptor(obj): |
| 432 | +def _unwrap_descriptor(dobj): |
| 433 | + obj = dobj.obj |
433 | 434 | if isinstance(obj, property):
|
434 | 435 | return (getattr(obj, 'fget', False) or
|
435 | 436 | getattr(obj, 'fset', False) or
|
436 | 437 | getattr(obj, 'fdel', obj))
|
| 438 | + if isinstance(obj, cached_property): |
| 439 | + return obj.func |
| 440 | + if isinstance(obj, FunctionType): |
| 441 | + return obj |
| 442 | + if (inspect.ismemberdescriptor(obj) or |
| 443 | + getattr(getattr(obj, '__class__', 0), '__name__', 0) == '_tuplegetter'): |
| 444 | + class_name = dobj.qualname.rsplit('.', 1)[0] |
| 445 | + obj = getattr(dobj.module.obj, class_name) |
| 446 | + return obj |
| 447 | + # XXX: Follow descriptor protocol? Already proved buggy in conditions above |
437 | 448 | return getattr(obj, '__get__', obj)
|
438 | 449 |
|
439 | 450 |
|
@@ -558,7 +569,7 @@ def source(self) -> str:
|
558 | 569 | available, an empty string.
|
559 | 570 | """
|
560 | 571 | try:
|
561 |
| - lines, _ = inspect.getsourcelines(_unwrap_descriptor(self.obj)) |
| 572 | + lines, _ = inspect.getsourcelines(_unwrap_descriptor(self)) |
562 | 573 | except (ValueError, TypeError, OSError):
|
563 | 574 | return ''
|
564 | 575 | return inspect.cleandoc(''.join(['\n'] + lines))
|
@@ -1432,7 +1443,7 @@ def return_annotation(self, *, link=None) -> str:
|
1432 | 1443 | # global variables
|
1433 | 1444 | lambda: _get_type_hints(not self.cls and self.module.obj)[self.name],
|
1434 | 1445 | # properties
|
1435 |
| - lambda: inspect.signature(_unwrap_descriptor(self.obj)).return_annotation, |
| 1446 | + lambda: inspect.signature(_unwrap_descriptor(self)).return_annotation, |
1436 | 1447 | # Use raw annotation strings in unmatched forward declarations
|
1437 | 1448 | lambda: cast(Class, self.cls).obj.__annotations__[self.name],
|
1438 | 1449 | # Extract annotation from the docstring for C builtin function
|
|
0 commit comments