From dff3252675e1a46c9875c233d4900ba023674b4e Mon Sep 17 00:00:00 2001 From: Pierre Glaser Date: Sun, 26 Jan 2020 19:11:22 +0100 Subject: [PATCH 1/5] FIX support property pickling in Python3.8 --- cloudpickle/cloudpickle_fast.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cloudpickle/cloudpickle_fast.py b/cloudpickle/cloudpickle_fast.py index dfe554d62..a4a270385 100644 --- a/cloudpickle/cloudpickle_fast.py +++ b/cloudpickle/cloudpickle_fast.py @@ -291,6 +291,10 @@ def _root_logger_reduce(obj): return logging.getLogger, () +def _property_reduce(obj): + return property, (obj.fget, obj.fset, obj.fdel, obj.__doc__) + + def _weakset_reduce(obj): return weakref.WeakSet, (list(obj),) @@ -406,6 +410,7 @@ class CloudPickler(Pickler): dispatch[logging.Logger] = _logger_reduce dispatch[logging.RootLogger] = _root_logger_reduce dispatch[memoryview] = _memoryview_reduce + dispatch[property] = _property_reduce dispatch[staticmethod] = _classmethod_reduce dispatch[types.CellType] = _cell_reduce dispatch[types.CodeType] = _code_reduce From 787dce96e9b34a1869a83876d674ed38adf6b257 Mon Sep 17 00:00:00 2001 From: Pierre Glaser Date: Sun, 26 Jan 2020 19:11:51 +0100 Subject: [PATCH 2/5] TST add a unit-test for property pickling --- tests/cloudpickle_test.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/cloudpickle_test.py b/tests/cloudpickle_test.py index 8bd210abe..f2259ed46 100644 --- a/tests/cloudpickle_test.py +++ b/tests/cloudpickle_test.py @@ -1119,6 +1119,20 @@ def func(x): cloned = pickle_depickle(func, protocol=self.protocol) self.assertEqual(cloned.__qualname__, func.__qualname__) + def test_property(self): + class MyObject: + _value = 1 + + @property + def value(self): + return self._value + + my_object = MyObject() + assert my_object.value == 1 + + depickled_obj = pickle_depickle(my_object) + assert depickled_obj.value == 1 + def test_namedtuple(self): MyTuple = collections.namedtuple('MyTuple', ['a', 'b', 'c']) t1 = MyTuple(1, 2, 3) From aa3d45f6ae076531487283b899c1bbe42f22bff0 Mon Sep 17 00:00:00 2001 From: Pierre Glaser Date: Sun, 26 Jan 2020 19:16:36 +0100 Subject: [PATCH 3/5] MNT changelog --- CHANGES.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 79043afe4..5a2fe96a5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,10 @@ 1.2.3 ===== +- Fix a regression in cloudpickle and python3.8 causing an error when trying to + pickle property objects. + ([PR #329](https://github.com/cloudpipe/cloudpickle/pull/329)). + - Fix a bug when a thread imports a module while cloudpickle iterates over the module list ([PR #322](https://github.com/cloudpipe/cloudpickle/pull/322)). From b4d6bc317d7fb999621ff88055c09d1c3177d511 Mon Sep 17 00:00:00 2001 From: Pierre Glaser Date: Mon, 27 Jan 2020 11:26:38 +0100 Subject: [PATCH 4/5] TST test read-write properties --- tests/cloudpickle_test.py | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/tests/cloudpickle_test.py b/tests/cloudpickle_test.py index f2259ed46..4dd3646d6 100644 --- a/tests/cloudpickle_test.py +++ b/tests/cloudpickle_test.py @@ -1121,17 +1121,43 @@ def func(x): def test_property(self): class MyObject: - _value = 1 + _read_only_value = 1 + _read_write_value = 1 @property - def value(self): - return self._value + def read_only_value(self): + return self._read_only_value + + @property + def read_write_value(self): + return self._read_write_value + + @read_write_value.setter + def read_write_value(self, value): + self._read_write_value = value + + my_object = MyObject() - assert my_object.value == 1 + + assert my_object.read_only_value == 1 + + with pytest.raises(AttributeError): + my_object.read_only_value = 2 + my_object.read_write_value = 2 depickled_obj = pickle_depickle(my_object) - assert depickled_obj.value == 1 + + assert depickled_obj.read_only_value == 1 + assert depickled_obj.read_write_value == 2 + + # make sure the depickled read_only_value attribute is still read-only + with pytest.raises(AttributeError): + my_object.read_only_value = 2 + + # make sure the depickled read_write_value attribute is writeable + depickled_obj.read_write_value = 3 + def test_namedtuple(self): MyTuple = collections.namedtuple('MyTuple', ['a', 'b', 'c']) From 9c331286581fa6683bc45ba1c2d7fe77f2fc785b Mon Sep 17 00:00:00 2001 From: Pierre Glaser Date: Mon, 27 Jan 2020 11:38:55 +0100 Subject: [PATCH 5/5] test the __doc__ entry, add a few assertions --- tests/cloudpickle_test.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/cloudpickle_test.py b/tests/cloudpickle_test.py index 4dd3646d6..9c1f1c355 100644 --- a/tests/cloudpickle_test.py +++ b/tests/cloudpickle_test.py @@ -1126,6 +1126,7 @@ class MyObject: @property def read_only_value(self): + "A read-only attribute" return self._read_only_value @property @@ -1141,6 +1142,7 @@ def read_write_value(self, value): my_object = MyObject() assert my_object.read_only_value == 1 + assert MyObject.read_only_value.__doc__ == "A read-only attribute" with pytest.raises(AttributeError): my_object.read_only_value = 2 @@ -1157,6 +1159,8 @@ def read_write_value(self, value): # make sure the depickled read_write_value attribute is writeable depickled_obj.read_write_value = 3 + assert depickled_obj.read_write_value == 3 + type(depickled_obj).read_only_value.__doc__ == "A read-only attribute" def test_namedtuple(self):