From 0fa036abe0afb89d7b15e3b763252bff37659fd0 Mon Sep 17 00:00:00 2001 From: Pierre Glaser Date: Fri, 5 Oct 2018 13:09:00 +0200 Subject: [PATCH 1/8] added protocol kw to c implementations of array_dump[s] --- numpy/core/src/multiarray/methods.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/numpy/core/src/multiarray/methods.c b/numpy/core/src/multiarray/methods.c index cb63c7f74607..b8fb58e70fb3 100644 --- a/numpy/core/src/multiarray/methods.c +++ b/numpy/core/src/multiarray/methods.c @@ -1920,15 +1920,18 @@ PyArray_Dumps(PyObject *self, int protocol) static PyObject * -array_dump(PyArrayObject *self, PyObject *args) +array_dump(PyArrayObject *self, PyObject *args, PyObject *kwds) { PyObject *file = NULL; + int protocol = 2; + static char *kwlist[] = {"file", "protocol", NULL}; int ret; - if (!PyArg_ParseTuple(args, "O:dump", &file)) { + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|i:dump", kwlist, + &file, &protocol)) { return NULL; } - ret = PyArray_Dump((PyObject *)self, file, 2); + ret = PyArray_Dump((PyObject *)self, file, protocol); if (ret < 0) { return NULL; } @@ -1937,12 +1940,16 @@ array_dump(PyArrayObject *self, PyObject *args) static PyObject * -array_dumps(PyArrayObject *self, PyObject *args) +array_dumps(PyArrayObject *self, PyObject *args, PyObject *kwds) { - if (!PyArg_ParseTuple(args, "")) { + int protocol = 2; + static char *kwlist[] = {"protocol", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:dumps", kwlist, + &protocol)) { return NULL; } - return PyArray_Dumps((PyObject *)self, 2); + return PyArray_Dumps((PyObject *)self, protocol); } @@ -2512,10 +2519,10 @@ NPY_NO_EXPORT PyMethodDef array_methods[] = { METH_VARARGS, NULL}, {"dumps", (PyCFunction) array_dumps, - METH_VARARGS, NULL}, + METH_VARARGS | METH_KEYWORDS, NULL}, {"dump", (PyCFunction) array_dump, - METH_VARARGS, NULL}, + METH_VARARGS | METH_KEYWORDS, NULL}, {"__complex__", (PyCFunction) array_complex, From 592b22802df74ef7a58d2aaf6f44f45be7e2a9f8 Mon Sep 17 00:00:00 2001 From: Pierre Glaser Date: Fri, 5 Oct 2018 13:12:01 +0200 Subject: [PATCH 2/8] updated documentation for array_dump[s] --- numpy/core/_add_newdocs.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/numpy/core/_add_newdocs.py b/numpy/core/_add_newdocs.py index 1c82cfde4d03..9b99648c95d6 100644 --- a/numpy/core/_add_newdocs.py +++ b/numpy/core/_add_newdocs.py @@ -3761,7 +3761,7 @@ def luf(lamdaexpr, *args, **kwargs): add_newdoc('numpy.core.multiarray', 'ndarray', ('dump', - """a.dump(file) + """a.dump(file, protocol=2) Dump a pickle of the array to the specified file. The array can be read back with pickle.load or numpy.load. @@ -3770,20 +3770,26 @@ def luf(lamdaexpr, *args, **kwargs): ---------- file : str A string naming the dump file. + protocol : int, optional + The pickle protocol used to serialize the array. + The default is 2 (in order to maintain python 2 support). + """)) add_newdoc('numpy.core.multiarray', 'ndarray', ('dumps', """ - a.dumps() + a.dumps(protocol=2) Returns the pickle of the array as a string. pickle.loads or numpy.loads will convert the string back to an array. Parameters ---------- - None + protocol : int, optional + The pickle protocol used to serialize the array. + The default is 2 (in order to maintain python 2 support). """)) From 6655793d735ce6ced5075dcb898737c9756c7937 Mon Sep 17 00:00:00 2001 From: Pierre Glaser Date: Fri, 5 Oct 2018 13:26:59 +0200 Subject: [PATCH 3/8] loop over protocol for pickle tests --- numpy/core/tests/test_datetime.py | 19 +++++---- numpy/core/tests/test_multiarray.py | 32 ++++++++------- numpy/core/tests/test_records.py | 23 ++++++----- numpy/core/tests/test_regression.py | 44 ++++++++++++--------- numpy/matrixlib/tests/test_masked_matrix.py | 9 +++-- 5 files changed, 73 insertions(+), 54 deletions(-) diff --git a/numpy/core/tests/test_datetime.py b/numpy/core/tests/test_datetime.py index c4918f955075..6303c043a027 100644 --- a/numpy/core/tests/test_datetime.py +++ b/numpy/core/tests/test_datetime.py @@ -623,14 +623,17 @@ def test_timedelta_array_str(self): def test_pickle(self): # Check that pickle roundtripping works - dt = np.dtype('M8[7D]') - assert_equal(pickle.loads(pickle.dumps(dt)), dt) - dt = np.dtype('M8[W]') - assert_equal(pickle.loads(pickle.dumps(dt)), dt) - scalar = np.datetime64('2016-01-01T00:00:00.000000000') - assert_equal(pickle.loads(pickle.dumps(scalar)), scalar) - delta = scalar - np.datetime64('2015-01-01T00:00:00.000000000') - assert_equal(pickle.loads(pickle.dumps(delta)), delta) + for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): + dt = np.dtype('M8[7D]') + assert_equal(pickle.loads(pickle.dumps(dt, protocol=proto)), dt) + dt = np.dtype('M8[W]') + assert_equal(pickle.loads(pickle.dumps(dt, protocol=proto)), dt) + scalar = np.datetime64('2016-01-01T00:00:00.000000000') + assert_equal(pickle.loads(pickle.dumps(scalar, protocol=proto)), + scalar) + delta = scalar - np.datetime64('2015-01-01T00:00:00.000000000') + assert_equal(pickle.loads(pickle.dumps(delta, protocol=proto)), + delta) # Check that loading pickles from 1.6 works pkl = b"cnumpy\ndtype\np0\n(S'M8'\np1\nI0\nI1\ntp2\nRp3\n" + \ diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index d17dd8eaeea9..2d3541fc50cc 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -1372,12 +1372,13 @@ def test_view(self): def test_pickle(self): import pickle - for dt in [bytes, np.void, unicode]: - zs = self._zeros(10, dt) - p = pickle.dumps(zs) - zs2 = pickle.loads(p) + for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): + for dt in [bytes, np.void, unicode]: + zs = self._zeros(10, dt) + p = pickle.dumps(zs, protocol=proto) + zs2 = pickle.loads(p) - assert_equal(zs.dtype, zs2.dtype) + assert_equal(zs.dtype, zs2.dtype) class TestMethods(object): @@ -3550,16 +3551,19 @@ def test_test_zero_rank(self): class TestPickling(object): def test_roundtrip(self): import pickle - carray = np.array([[2, 9], [7, 0], [3, 8]]) - DATA = [ - carray, - np.transpose(carray), - np.array([('xxx', 1, 2.0)], dtype=[('a', (str, 3)), ('b', int), - ('c', float)]) - ] + for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): + carray = np.array([[2, 9], [7, 0], [3, 8]]) + DATA = [ + carray, + np.transpose(carray), + np.array([('xxx', 1, 2.0)], dtype=[('a', (str, 3)), ('b', int), + ('c', float)]) + ] - for a in DATA: - assert_equal(a, pickle.loads(a.dumps()), err_msg="%r" % a) + for a in DATA: + assert_equal( + a, pickle.loads(a.dumps(protocol=proto)), + err_msg="%r" % a) def _loads(self, obj): import pickle diff --git a/numpy/core/tests/test_records.py b/numpy/core/tests/test_records.py index d7c7d16e3f74..713b2b398a2e 100644 --- a/numpy/core/tests/test_records.py +++ b/numpy/core/tests/test_records.py @@ -378,22 +378,27 @@ def test_out_of_order_fields(self): def test_pickle_1(self): # Issue #1529 a = np.array([(1, [])], dtype=[('a', np.int32), ('b', np.int32, 0)]) - assert_equal(a, pickle.loads(pickle.dumps(a))) - assert_equal(a[0], pickle.loads(pickle.dumps(a[0]))) + for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): + assert_equal(a, pickle.loads(pickle.dumps(a, protocol=proto))) + assert_equal(a[0], pickle.loads(pickle.dumps(a[0], + protocol=proto))) def test_pickle_2(self): a = self.data - assert_equal(a, pickle.loads(pickle.dumps(a))) - assert_equal(a[0], pickle.loads(pickle.dumps(a[0]))) + for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): + assert_equal(a, pickle.loads(pickle.dumps(a, protocol=proto))) + assert_equal(a[0], pickle.loads(pickle.dumps(a[0], + protocol=proto))) def test_pickle_3(self): # Issue #7140 a = self.data - pa = pickle.loads(pickle.dumps(a[0])) - assert_(pa.flags.c_contiguous) - assert_(pa.flags.f_contiguous) - assert_(pa.flags.writeable) - assert_(pa.flags.aligned) + for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): + pa = pickle.loads(pickle.dumps(a[0], protocol=proto)) + assert_(pa.flags.c_contiguous) + assert_(pa.flags.f_contiguous) + assert_(pa.flags.writeable) + assert_(pa.flags.aligned) def test_objview_record(self): # https://github.com/numpy/numpy/issues/2599 diff --git a/numpy/core/tests/test_regression.py b/numpy/core/tests/test_regression.py index b74216418aef..947ee5f861e4 100644 --- a/numpy/core/tests/test_regression.py +++ b/numpy/core/tests/test_regression.py @@ -818,8 +818,9 @@ def test_unicode_scalar(self): # Ticket #600 x = np.array(["DROND", "DROND1"], dtype="U6") el = x[1] - new = pickle.loads(pickle.dumps(el)) - assert_equal(new, el) + for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): + new = pickle.loads(pickle.dumps(el, protocol=proto)) + assert_equal(new, el) def test_arange_non_native_dtype(self): # Ticket #616 @@ -1066,11 +1067,12 @@ def test_nonnative_endian_fill(self): def test_dot_alignment_sse2(self): # Test for ticket #551, changeset r5140 x = np.zeros((30, 40)) - y = pickle.loads(pickle.dumps(x)) - # y is now typically not aligned on a 8-byte boundary - z = np.ones((1, y.shape[0])) - # This shouldn't cause a segmentation fault: - np.dot(z, y) + for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): + y = pickle.loads(pickle.dumps(x, protocol=proto)) + # y is now typically not aligned on a 8-byte boundary + z = np.ones((1, y.shape[0])) + # This shouldn't cause a segmentation fault: + np.dot(z, y) def test_astype_copy(self): # Ticket #788, changeset r5155 @@ -1280,9 +1282,12 @@ def test_void_scalar_constructor(self): assert_(test_record_void_scalar == test_record) - #Test pickle and unpickle of void and record scalars - assert_(pickle.loads(pickle.dumps(test_string)) == test_string) - assert_(pickle.loads(pickle.dumps(test_record)) == test_record) + # Test pickle and unpickle of void and record scalars + for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): + assert_(pickle.loads( + pickle.dumps(test_string, protocol=proto)) == test_string) + assert_(pickle.loads( + pickle.dumps(test_record, protocol=proto)) == test_record) def test_blasdot_uninitialized_memory(self): # Ticket #950 @@ -1925,11 +1930,12 @@ def test_pickle_string_overwrite(self): def test_pickle_bytes_overwrite(self): if sys.version_info[0] >= 3: - data = np.array([1], dtype='b') - data = pickle.loads(pickle.dumps(data)) - data[0] = 0xdd - bytestring = "\x01 ".encode('ascii') - assert_equal(bytestring[0:1], '\x01'.encode('ascii')) + for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): + data = np.array([1], dtype='b') + data = pickle.loads(pickle.dumps(data, protocol=proto)) + data[0] = 0xdd + bytestring = "\x01 ".encode('ascii') + assert_equal(bytestring[0:1], '\x01'.encode('ascii')) def test_pickle_py2_array_latin1_hack(self): # Check that unpickling hacks in Py3 that support @@ -2231,10 +2237,10 @@ def __eq__(self, other): def test_pickle_empty_string(self): # gh-3926 - - import pickle - test_string = np.string_('') - assert_equal(pickle.loads(pickle.dumps(test_string)), test_string) + for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): + test_string = np.string_('') + assert_equal(pickle.loads( + pickle.dumps(test_string, protocol=proto)), test_string) def test_frompyfunc_many_args(self): # gh-5672 diff --git a/numpy/matrixlib/tests/test_masked_matrix.py b/numpy/matrixlib/tests/test_masked_matrix.py index 5ed8044aa757..219349f93597 100644 --- a/numpy/matrixlib/tests/test_masked_matrix.py +++ b/numpy/matrixlib/tests/test_masked_matrix.py @@ -79,10 +79,11 @@ def test_matrix_indexing(self): def test_pickling_subbaseclass(self): # Test pickling w/ a subclass of ndarray a = masked_array(np.matrix(list(range(10))), mask=[1, 0, 1, 0, 0] * 2) - a_pickled = pickle.loads(a.dumps()) - assert_equal(a_pickled._mask, a._mask) - assert_equal(a_pickled, a) - assert_(isinstance(a_pickled._data, np.matrix)) + for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): + a_pickled = pickle.loads(a.dumps(protocol=proto)) + assert_equal(a_pickled._mask, a._mask) + assert_equal(a_pickled, a) + assert_(isinstance(a_pickled._data, np.matrix)) def test_count_mean_with_matrix(self): m = masked_array(np.matrix([[1, 2], [3, 4]]), mask=np.zeros((2, 2))) From 362d1343124d0c45d934078d1a8ec118a2ae9ebe Mon Sep 17 00:00:00 2001 From: Pierre Glaser Date: Fri, 5 Oct 2018 14:29:09 +0200 Subject: [PATCH 4/8] remove unwanted blank line --- numpy/core/_add_newdocs.py | 1 - 1 file changed, 1 deletion(-) diff --git a/numpy/core/_add_newdocs.py b/numpy/core/_add_newdocs.py index 9b99648c95d6..a2fbd1018283 100644 --- a/numpy/core/_add_newdocs.py +++ b/numpy/core/_add_newdocs.py @@ -3774,7 +3774,6 @@ def luf(lamdaexpr, *args, **kwargs): The pickle protocol used to serialize the array. The default is 2 (in order to maintain python 2 support). - """)) From cc39290df8c41905202cd37cb8ab392a922cce8b Mon Sep 17 00:00:00 2001 From: Pierre Glaser Date: Fri, 5 Oct 2018 15:10:12 +0200 Subject: [PATCH 5/8] empty commit to trigger CI From 02d5619d70bf7bc6bb23c95cba7ef19aaf0b6e32 Mon Sep 17 00:00:00 2001 From: Pierre Glaser Date: Fri, 5 Oct 2018 15:29:33 +0200 Subject: [PATCH 6/8] add the versionadded mention in the docs --- numpy/core/_add_newdocs.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/numpy/core/_add_newdocs.py b/numpy/core/_add_newdocs.py index a2fbd1018283..680bd995843c 100644 --- a/numpy/core/_add_newdocs.py +++ b/numpy/core/_add_newdocs.py @@ -3774,6 +3774,8 @@ def luf(lamdaexpr, *args, **kwargs): The pickle protocol used to serialize the array. The default is 2 (in order to maintain python 2 support). + .. versionadded:: 1.16.0 + """)) @@ -3790,6 +3792,8 @@ def luf(lamdaexpr, *args, **kwargs): The pickle protocol used to serialize the array. The default is 2 (in order to maintain python 2 support). + .. versionadded:: 1.16.0 + """)) From 043eb99687fe0756e50acf62773f475916fc133c Mon Sep 17 00:00:00 2001 From: Pierre Glaser Date: Fri, 5 Oct 2018 16:01:28 +0200 Subject: [PATCH 7/8] removed usage of np.ndarray.dump[s] --- numpy/core/tests/test_multiarray.py | 2 +- numpy/matrixlib/tests/test_masked_matrix.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index 2d3541fc50cc..235e5bc2ecce 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -3562,7 +3562,7 @@ def test_roundtrip(self): for a in DATA: assert_equal( - a, pickle.loads(a.dumps(protocol=proto)), + a, pickle.loads(pickle.dumps(protocol=proto)), err_msg="%r" % a) def _loads(self, obj): diff --git a/numpy/matrixlib/tests/test_masked_matrix.py b/numpy/matrixlib/tests/test_masked_matrix.py index 219349f93597..2f7ea5632316 100644 --- a/numpy/matrixlib/tests/test_masked_matrix.py +++ b/numpy/matrixlib/tests/test_masked_matrix.py @@ -80,7 +80,7 @@ def test_pickling_subbaseclass(self): # Test pickling w/ a subclass of ndarray a = masked_array(np.matrix(list(range(10))), mask=[1, 0, 1, 0, 0] * 2) for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): - a_pickled = pickle.loads(a.dumps(protocol=proto)) + a_pickled = pickle.loads(pickle.dumps(protocol=proto)) assert_equal(a_pickled._mask, a._mask) assert_equal(a_pickled, a) assert_(isinstance(a_pickled._data, np.matrix)) From 02c3a8a2484b24435fb0d9a49dd4051660bf4a33 Mon Sep 17 00:00:00 2001 From: Pierre Glaser Date: Fri, 5 Oct 2018 16:02:52 +0200 Subject: [PATCH 8/8] reverted to previous array_dump and array_dumps version --- numpy/core/_add_newdocs.py | 15 +++----------- numpy/core/src/multiarray/methods.c | 23 +++++++-------------- numpy/core/tests/test_multiarray.py | 2 +- numpy/core/tests/test_records.py | 2 +- numpy/matrixlib/tests/test_masked_matrix.py | 2 +- 5 files changed, 14 insertions(+), 30 deletions(-) diff --git a/numpy/core/_add_newdocs.py b/numpy/core/_add_newdocs.py index 680bd995843c..1c82cfde4d03 100644 --- a/numpy/core/_add_newdocs.py +++ b/numpy/core/_add_newdocs.py @@ -3761,7 +3761,7 @@ def luf(lamdaexpr, *args, **kwargs): add_newdoc('numpy.core.multiarray', 'ndarray', ('dump', - """a.dump(file, protocol=2) + """a.dump(file) Dump a pickle of the array to the specified file. The array can be read back with pickle.load or numpy.load. @@ -3770,29 +3770,20 @@ def luf(lamdaexpr, *args, **kwargs): ---------- file : str A string naming the dump file. - protocol : int, optional - The pickle protocol used to serialize the array. - The default is 2 (in order to maintain python 2 support). - - .. versionadded:: 1.16.0 """)) add_newdoc('numpy.core.multiarray', 'ndarray', ('dumps', """ - a.dumps(protocol=2) + a.dumps() Returns the pickle of the array as a string. pickle.loads or numpy.loads will convert the string back to an array. Parameters ---------- - protocol : int, optional - The pickle protocol used to serialize the array. - The default is 2 (in order to maintain python 2 support). - - .. versionadded:: 1.16.0 + None """)) diff --git a/numpy/core/src/multiarray/methods.c b/numpy/core/src/multiarray/methods.c index b8fb58e70fb3..cb63c7f74607 100644 --- a/numpy/core/src/multiarray/methods.c +++ b/numpy/core/src/multiarray/methods.c @@ -1920,18 +1920,15 @@ PyArray_Dumps(PyObject *self, int protocol) static PyObject * -array_dump(PyArrayObject *self, PyObject *args, PyObject *kwds) +array_dump(PyArrayObject *self, PyObject *args) { PyObject *file = NULL; - int protocol = 2; - static char *kwlist[] = {"file", "protocol", NULL}; int ret; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|i:dump", kwlist, - &file, &protocol)) { + if (!PyArg_ParseTuple(args, "O:dump", &file)) { return NULL; } - ret = PyArray_Dump((PyObject *)self, file, protocol); + ret = PyArray_Dump((PyObject *)self, file, 2); if (ret < 0) { return NULL; } @@ -1940,16 +1937,12 @@ array_dump(PyArrayObject *self, PyObject *args, PyObject *kwds) static PyObject * -array_dumps(PyArrayObject *self, PyObject *args, PyObject *kwds) +array_dumps(PyArrayObject *self, PyObject *args) { - int protocol = 2; - static char *kwlist[] = {"protocol", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:dumps", kwlist, - &protocol)) { + if (!PyArg_ParseTuple(args, "")) { return NULL; } - return PyArray_Dumps((PyObject *)self, protocol); + return PyArray_Dumps((PyObject *)self, 2); } @@ -2519,10 +2512,10 @@ NPY_NO_EXPORT PyMethodDef array_methods[] = { METH_VARARGS, NULL}, {"dumps", (PyCFunction) array_dumps, - METH_VARARGS | METH_KEYWORDS, NULL}, + METH_VARARGS, NULL}, {"dump", (PyCFunction) array_dump, - METH_VARARGS | METH_KEYWORDS, NULL}, + METH_VARARGS, NULL}, {"__complex__", (PyCFunction) array_complex, diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index 235e5bc2ecce..36d148f55a30 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -3562,7 +3562,7 @@ def test_roundtrip(self): for a in DATA: assert_equal( - a, pickle.loads(pickle.dumps(protocol=proto)), + a, pickle.loads(pickle.dumps(a, protocol=proto)), err_msg="%r" % a) def _loads(self, obj): diff --git a/numpy/core/tests/test_records.py b/numpy/core/tests/test_records.py index 713b2b398a2e..056d39db81d3 100644 --- a/numpy/core/tests/test_records.py +++ b/numpy/core/tests/test_records.py @@ -381,7 +381,7 @@ def test_pickle_1(self): for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): assert_equal(a, pickle.loads(pickle.dumps(a, protocol=proto))) assert_equal(a[0], pickle.loads(pickle.dumps(a[0], - protocol=proto))) + protocol=proto))) def test_pickle_2(self): a = self.data diff --git a/numpy/matrixlib/tests/test_masked_matrix.py b/numpy/matrixlib/tests/test_masked_matrix.py index 2f7ea5632316..7f84bb2c9023 100644 --- a/numpy/matrixlib/tests/test_masked_matrix.py +++ b/numpy/matrixlib/tests/test_masked_matrix.py @@ -80,7 +80,7 @@ def test_pickling_subbaseclass(self): # Test pickling w/ a subclass of ndarray a = masked_array(np.matrix(list(range(10))), mask=[1, 0, 1, 0, 0] * 2) for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): - a_pickled = pickle.loads(pickle.dumps(protocol=proto)) + a_pickled = pickle.loads(pickle.dumps(a, protocol=proto)) assert_equal(a_pickled._mask, a._mask) assert_equal(a_pickled, a) assert_(isinstance(a_pickled._data, np.matrix))