diff --git a/dill/_dill.py b/dill/_dill.py index 27ab56c6..48a2f75f 100644 --- a/dill/_dill.py +++ b/dill/_dill.py @@ -2031,7 +2031,7 @@ def save_function(pickler, obj): fattr = getattr(obj, fattrname, None) if fattr is not None: state_dict[fattrname] = fattr - if obj.__qualname__ != obj.__name__: + if obj.__qualname__ != getattr(obj.__code__, "co_qualname", obj.__code__.co_name): state_dict['__qualname__'] = obj.__qualname__ if '__name__' not in globs or obj.__module__ != globs['__name__']: state_dict['__module__'] = obj.__module__ diff --git a/dill/tests/test_functions.py b/dill/tests/test_functions.py index f3db1a4f..8f3c0580 100644 --- a/dill/tests/test_functions.py +++ b/dill/tests/test_functions.py @@ -64,6 +64,45 @@ def f2(self): assert f1.f2() is f1 +@functools.wraps(function_a) +def function_wrapped(a): + return function_a(a) + +def test_issue_602(): + # Check that __qualname__ is set correctly when functools.wraps is used. + # Different code paths are used for module-level and local functions, so + # we test the various combinations. + + # Global wrapping global + + copied_global = dill.copy(function_wrapped) + assert copied_global.__name__ == function_a.__name__ + assert copied_global.__qualname__ == function_a.__qualname__ + + # Local wrapping global + + @functools.wraps(function_a) + def function_wrapped_local(a): + return function_a(a) + + copied_local = dill.copy(function_wrapped_local) + assert copied_local.__name__ == function_a.__name__ + assert copied_local.__qualname__ == function_a.__qualname__ + + # Local wrapping local + + def local(): + pass + + @functools.wraps(local) + def wrapped_local(): + local() + + copied_local = dill.copy(wrapped_local) + assert copied_local.__name__ == local.__name__ + assert copied_local.__qualname__ == local.__qualname__ + + def test_functions(): dumped_func_a = dill.dumps(function_a) assert dill.loads(dumped_func_a)(0) == 0 @@ -138,4 +177,5 @@ def test_code_object(): if __name__ == '__main__': test_functions() test_issue_510() + test_issue_602() test_code_object()