From 65d5e0d2248a27f32a386f48cf86fa3b80888629 Mon Sep 17 00:00:00 2001 From: Pierre Glaser Date: Tue, 23 Apr 2019 15:03:47 +0200 Subject: [PATCH 1/3] FIX pass __kwdefaults__ to state in python3 --- cloudpickle/cloudpickle.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cloudpickle/cloudpickle.py b/cloudpickle/cloudpickle.py index b5f414ac2..7df5f6c74 100644 --- a/cloudpickle/cloudpickle.py +++ b/cloudpickle/cloudpickle.py @@ -591,6 +591,8 @@ def save_function_tuple(self, func): state['annotations'] = func.__annotations__ if hasattr(func, '__qualname__'): state['qualname'] = func.__qualname__ + if hasattr(func, '__kwdefaults__'): + state['kwdefaults'] = func.__kwdefaults__ save(state) write(pickle.TUPLE) write(pickle.REDUCE) # applies _fill_function on the tuple @@ -1075,6 +1077,8 @@ def _fill_function(*args): func.__module__ = state['module'] if 'qualname' in state: func.__qualname__ = state['qualname'] + if 'kwdefaults' in state: + func.__kwdefaults__ = state['kwdefaults'] cells = func.__closure__ if cells is not None: From e792b2a89d1be2df206577615f09002917ae8400 Mon Sep 17 00:00:00 2001 From: Pierre Glaser Date: Tue, 23 Apr 2019 15:04:05 +0200 Subject: [PATCH 2/3] TST test roundtripping a function with kwonly args --- tests/cloudpickle_test.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/cloudpickle_test.py b/tests/cloudpickle_test.py index caa222ed3..e5afc3dd6 100644 --- a/tests/cloudpickle_test.py +++ b/tests/cloudpickle_test.py @@ -1392,6 +1392,28 @@ def g(): cloned_func = pickle_depickle(func, protocol=self.protocol) assert cloned_func() == "hello from a {}!".format(source) + @pytest.mark.skipif(sys.version_info[0] < 3, + reason="keyword only arguments were introduced in " + "python 3") + def test_interactively_defined_func_with_keyword_only_argument(self): + # fixes https://github.com/cloudpipe/cloudpickle/issues/263 + # The source code of this test is bundled in a string and is ran from + # the __main__ module of a subprocess in order to avoid a SyntaxError + # in python2 when pytest imports this file, as the keyword-only syntax + # is python3-only. + code = """ + from cloudpickle import loads, dumps + + def f(a, *, b=1): + return a + b + + depickled_f = loads(dumps(f, protocol={protocol})) + + for func in (f, depickled_f): + assert func(2) == 3 + assert func.__kwdefaults__ == {{'b': 1}} + """.format(protocol=self.protocol) + assert_run_python_script(textwrap.dedent(code)) class Protocol2CloudPickleTest(CloudPickleTest): From c41b94fb34820e42b6e6b284a5c94f6feffebf86 Mon Sep 17 00:00:00 2001 From: Pierre Glaser Date: Tue, 23 Apr 2019 16:01:54 +0200 Subject: [PATCH 3/3] MNT changelog --- CHANGES.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 9658a676b..a09f105b3 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,10 @@ +0.9.0 +===== + +- Fix a bug making functions with keyword-only arguments forget the default + values of these arguments after being pickled. + ([issue #264](https://github.com/cloudpipe/cloudpickle/pull/264)) + 0.8.1 =====