diff --git a/toolz/functoolz.py b/toolz/functoolz.py index 464aa22a..efcc4a61 100644 --- a/toolz/functoolz.py +++ b/toolz/functoolz.py @@ -422,13 +422,7 @@ def memof(*args, **kwargs): cache[k] = result = func(*args, **kwargs) return result - try: - memof.__name__ = func.__name__ - except AttributeError: - pass - memof.__doc__ = func.__doc__ - memof.__wrapped__ = func - return memof + return _update_wrapper(memof, func) class Compose(object): @@ -1055,3 +1049,31 @@ def is_arity(n, func, sigspec=None): """ from . import _signatures as _sigs + + +_assigned = ( + '__module__', + '__name__', + '__qualname__', + '__doc__', + '__annotations__', +) +_updated = '__dict__', + + +def _update_wrapper(wrapper, wrapped, assigned=_assigned, updated=_updated): + """Update the attributes of a wrapping function. + + Implementation is backported from CPython 3.6 + """ + for attr in assigned: + try: + value = getattr(wrapped, attr) + except AttributeError: + pass + else: + setattr(wrapper, attr, value) + for attr in updated: + getattr(wrapper, attr).update(getattr(wrapped, attr, {})) + wrapper.__wrapped__ = wrapped + return wrapper diff --git a/toolz/tests/test_functoolz.py b/toolz/tests/test_functoolz.py index 6c7cb0ea..0562c670 100644 --- a/toolz/tests/test_functoolz.py +++ b/toolz/tests/test_functoolz.py @@ -158,7 +158,11 @@ def foo(): Docstring """ pass + memoized_foo = memoize(foo) + assert memoized_foo.__name__ == foo.__name__ + assert memoized_foo.__doc__ == foo.__doc__ + assert memoized_foo.__module__ == foo.__module__ == __name__ assert memoized_foo.__wrapped__ is foo