From 92830472a6e2be027b3073668c10366f17ccba56 2014-04-07 23:59:14 From: Min RK Date: 2014-04-07 23:59:14 Subject: [PATCH] Make HasTraits pickleable The main change is storing method names instead of functions in `trait_dyn_inits`. These functions were failing to pickle. --- diff --git a/IPython/utils/tests/test_traitlets.py b/IPython/utils/tests/test_traitlets.py index 83fae6e..a4a5423 100644 --- a/IPython/utils/tests/test_traitlets.py +++ b/IPython/utils/tests/test_traitlets.py @@ -1,26 +1,13 @@ # encoding: utf-8 -""" -Tests for IPython.utils.traitlets. +"""Tests for IPython.utils.traitlets.""" -Authors: - -* Brian Granger -* Enthought, Inc. Some of the code in this file comes from enthought.traits - and is licensed under the BSD license. Also, many of the ideas also come - from enthought.traits even though our implementation is very different. -""" - -#----------------------------------------------------------------------------- -# Copyright (C) 2008-2011 The IPython Development Team -# -# Distributed under the terms of the BSD License. The full license is in -# the file COPYING, distributed as part of this software. -#----------------------------------------------------------------------------- - -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. +# +# Adapted from enthought.traits, Copyright (c) Enthought, Inc., +# also under the terms of the Modified BSD License. +import pickle import re import sys from unittest import TestCase @@ -1093,3 +1080,29 @@ class TestLink(TestCase): a.value = 4 self.assertEqual(''.join(callback_count), 'ab') del callback_count[:] + +class Pickleable(HasTraits): + i = Int() + j = Int() + + def _i_default(self): + return 1 + + def _i_changed(self, name, old, new): + self.j = new + +def test_pickle_hastraits(): + c = Pickleable() + for protocol in range(pickle.HIGHEST_PROTOCOL + 1): + p = pickle.dumps(c, protocol) + c2 = pickle.loads(p) + nt.assert_equal(c2.i, c.i) + nt.assert_equal(c2.j, c.j) + + c.i = 5 + for protocol in range(pickle.HIGHEST_PROTOCOL + 1): + p = pickle.dumps(c, protocol) + c2 = pickle.loads(p) + nt.assert_equal(c2.i, c.i) + nt.assert_equal(c2.j, c.j) + \ No newline at end of file diff --git a/IPython/utils/traitlets.py b/IPython/utils/traitlets.py index b9e2434..172d60e 100644 --- a/IPython/utils/traitlets.py +++ b/IPython/utils/traitlets.py @@ -32,25 +32,13 @@ Inheritance diagram: .. inheritance-diagram:: IPython.utils.traitlets :parts: 3 - -Authors: - -* Brian Granger -* Enthought, Inc. Some of the code in this file comes from enthought.traits - and is licensed under the BSD license. Also, many of the ideas also come - from enthought.traits even though our implementation is very different. """ -#----------------------------------------------------------------------------- -# Copyright (C) 2008-2011 The IPython Development Team +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. # -# Distributed under the terms of the BSD License. The full license is in -# the file COPYING, distributed as part of this software. -#----------------------------------------------------------------------------- - -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- +# Adapted from enthought.traits, Copyright (c) Enthought, Inc., +# also under the terms of the Modified BSD License. import contextlib import inspect @@ -332,8 +320,8 @@ class TraitType(object): obj._trait_values[self.name] = newdv return # Complete the dynamic initialization. - obj._trait_dyn_inits[self.name] = cls.__dict__[meth_name] - + obj._trait_dyn_inits[self.name] = meth_name + def __get__(self, obj, cls=None): """Get the value of the trait by self.name for the instance. @@ -350,7 +338,8 @@ class TraitType(object): except KeyError: # Check for a dynamic initializer. if self.name in obj._trait_dyn_inits: - value = obj._trait_dyn_inits[self.name](obj) + method = getattr(obj, obj._trait_dyn_inits[self.name]) + value = method() # FIXME: Do we really validate here? value = self._validate(obj, value) obj._trait_values[self.name] = value