Get the object wrapped by *func*. Follows the chain of :attr:`__wrapped__` attributes returning the last object in the chain. *stop* is an optional callback accepting an object in the wrapper chain as its sole argument that allows the unwrapping to be terminated early if the
(func, *, stop=None)
| 733 | # -------------------------------------------------------- function helpers |
| 734 | |
| 735 | def unwrap(func, *, stop=None): |
| 736 | """Get the object wrapped by *func*. |
| 737 | |
| 738 | Follows the chain of :attr:`__wrapped__` attributes returning the last |
| 739 | object in the chain. |
| 740 | |
| 741 | *stop* is an optional callback accepting an object in the wrapper chain |
| 742 | as its sole argument that allows the unwrapping to be terminated early if |
| 743 | the callback returns a true value. If the callback never returns a true |
| 744 | value, the last object in the chain is returned as usual. For example, |
| 745 | :func:`signature` uses this to stop unwrapping if any object in the |
| 746 | chain has a ``__signature__`` attribute defined. |
| 747 | |
| 748 | :exc:`ValueError` is raised if a cycle is encountered. |
| 749 | |
| 750 | """ |
| 751 | f = func # remember the original func for error reporting |
| 752 | # Memoise by id to tolerate non-hashable objects, but store objects to |
| 753 | # ensure they aren't destroyed, which would allow their IDs to be reused. |
| 754 | memo = {id(f): f} |
| 755 | recursion_limit = sys.getrecursionlimit() |
| 756 | while not isinstance(func, type) and hasattr(func, '__wrapped__'): |
| 757 | if stop is not None and stop(func): |
| 758 | break |
| 759 | func = func.__wrapped__ |
| 760 | id_func = id(func) |
| 761 | if (id_func in memo) or (len(memo) >= recursion_limit): |
| 762 | raise ValueError('wrapper loop when unwrapping {!r}'.format(f)) |
| 763 | memo[id_func] = func |
| 764 | return func |
| 765 | |
| 766 | # -------------------------------------------------- source code extraction |
| 767 | def indentsize(line): |
no test coverage detected