From 381e267677259bc164cc857eecadf397b1e7ecd6 Mon Sep 17 00:00:00 2001 From: Pierre Glaser Date: Mon, 14 Jan 2019 16:16:04 +0100 Subject: [PATCH 1/2] ENH pickle classes and objects with __slots__ --- cloudpickle/cloudpickle.py | 12 ++++++++++++ tests/cloudpickle_test.py | 17 +++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/cloudpickle/cloudpickle.py b/cloudpickle/cloudpickle.py index 41638be9c..0a7645f5a 100644 --- a/cloudpickle/cloudpickle.py +++ b/cloudpickle/cloudpickle.py @@ -55,6 +55,7 @@ import importlib import itertools import traceback +import six from functools import partial @@ -500,6 +501,17 @@ def save_dynamic_class(self, obj): # doc can't participate in a cycle with the original class. type_kwargs = {'__doc__': clsdict.pop('__doc__', None)} + if hasattr(obj, "__slots__"): + type_kwargs['__slots__'] = obj.__slots__ + # pickle string length optimization: member descriptors of obj are + # created automatically from obj's __slots__ attribute, no need to + # save them in obj's state + if isinstance(obj.__slots__, six.string_types): + clsdict.pop(obj.__slots__) + else: + for k in obj.__slots__: + clsdict.pop(k, None) + # If type overrides __dict__ as a property, include it in the type kwargs. # In Python 2, we can't set this attribute after construction. __dict__ = clsdict.pop('__dict__', None) diff --git a/tests/cloudpickle_test.py b/tests/cloudpickle_test.py index d318da7e1..ff7c63703 100644 --- a/tests/cloudpickle_test.py +++ b/tests/cloudpickle_test.py @@ -1310,6 +1310,23 @@ def g(x): self.assertEqual(f2.__annotations__, f.__annotations__) + def test_instance_with_slots(self): + for slots in [["registered_attribute"], "registered_attribute"]: + class ClassWithSlots(object): + __slots__ = slots + + def __init__(self): + self.registered_attribute = 42 + + initial_obj = ClassWithSlots() + depickled_obj = pickle_depickle( + initial_obj, protocol=self.protocol) + + for obj in [initial_obj, depickled_obj]: + self.assertEqual(obj.registered_attribute, 42) + with pytest.raises(AttributeError): + obj.non_registered_attribute = 1 + class Protocol2CloudPickleTest(CloudPickleTest): From 80f03a6c035f257be987820a511e48c9275aa388 Mon Sep 17 00:00:00 2001 From: Pierre Glaser Date: Tue, 15 Jan 2019 16:38:39 +0100 Subject: [PATCH 2/2] DOC updated CHANGES.md --- CHANGES.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index b7499530f..1e6252458 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,11 @@ +0.7.0 +===== + +- Correctly serialize dynamically defined classes that have a `__slots__` + attribute. + ([issue #225](https://github.com/cloudpipe/cloudpickle/issues/225)) + + 0.6.1 =====