From d19ccf1b866255118f647ebd9d5b1a7c755e6f6a Mon Sep 17 00:00:00 2001 From: Olivier Bellone Date: Fri, 20 Oct 2017 16:53:57 +0200 Subject: [PATCH] Fix unpickling in Python 3 --- stripe/stripe_object.py | 22 +++++++++++++++++++++ stripe/test/resources/test_stripe_object.py | 9 ++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/stripe/stripe_object.py b/stripe/stripe_object.py index 8b1351aca..b86435369 100644 --- a/stripe/stripe_object.py +++ b/stripe/stripe_object.py @@ -115,6 +115,28 @@ def __delitem__(self, k): if hasattr(self, '_unsaved_values'): self._unsaved_values.remove(k) + # Custom unpickling method that uses `update` to update the dictionary + # without calling __setitem__, which would fail if any value is an empty + # string + def __setstate__(self, state): + self.update(state) + + # Custom pickling method to ensure the instance is pickled as a custom + # class and not as a dict, otherwise __setstate__ would not be called when + # unpickling. + def __reduce__(self): + reduce_value = ( + type(self), # callable + ( # args + self.get('id', None), + self.api_key, + self.stripe_version, + self.stripe_account + ), + dict(self), # state + ) + return reduce_value + @classmethod def construct_from(cls, values, key, stripe_version=None, stripe_account=None): diff --git a/stripe/test/resources/test_stripe_object.py b/stripe/test/resources/test_stripe_object.py index 0afb500f0..089b22d65 100644 --- a/stripe/test/resources/test_stripe_object.py +++ b/stripe/test/resources/test_stripe_object.py @@ -142,7 +142,13 @@ def test_pickling(self): 'foo', 'bar', myparam=5) obj['object'] = 'boo' - obj.refresh_from({'fala': 'lalala'}, api_key='bar', partial=True) + obj.refresh_from( + { + 'fala': 'lalala', + 'emptystring': '', + }, + api_key='bar', partial=True + ) self.assertEqual('lalala', obj.fala) @@ -153,6 +159,7 @@ def test_pickling(self): self.assertEqual('bar', newobj.api_key) self.assertEqual('boo', newobj['object']) self.assertEqual('lalala', newobj.fala) + self.assertEqual('', newobj.emptystring) def test_deletion(self): obj = stripe.stripe_object.StripeObject('id', 'key')