Skip to content

Commit df1f5cf

Browse files
committed
Merge pull request #10557 from kjordahl/bug/pickle-subclass-metadata
Pickle subclass metadata
2 parents e660c05 + ece8223 commit df1f5cf

File tree

5 files changed

+23
-18
lines changed

5 files changed

+23
-18
lines changed

doc/source/whatsnew/v0.17.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ Other API Changes
5151
- Enable writing Excel files in :ref:`memory <_io.excel_writing_buffer>` using StringIO/BytesIO (:issue:`7074`)
5252
- Enable serialization of lists and dicts to strings in ExcelWriter (:issue:`8188`)
5353
- Allow passing `kwargs` to the interpolation methods (:issue:`10378`).
54+
- Serialize metadata properties of subclasses of pandas objects (:issue:`10553`).
5455

5556
.. _whatsnew_0170.deprecations:
5657

pandas/core/generic.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ class NDFrame(PandasObject):
8080
"""
8181
_internal_names = ['_data', '_cacher', '_item_cache', '_cache',
8282
'is_copy', '_subtyp', '_index',
83-
'_default_kind', '_default_fill_value',
84-
'__array_struct__','__array_interface__']
83+
'_default_kind', '_default_fill_value', '_metadata',
84+
'__array_struct__', '__array_interface__']
8585
_internal_names_set = set(_internal_names)
8686
_accessors = frozenset([])
8787
_metadata = []
@@ -760,7 +760,9 @@ def to_dense(self):
760760
# Picklability
761761

762762
def __getstate__(self):
763-
return self._data
763+
meta = dict((k, getattr(self, k, None)) for k in self._metadata)
764+
return dict(_data=self._data, _typ=self._typ,
765+
_metadata=self._metadata, **meta)
764766

765767
def __setstate__(self, state):
766768

pandas/core/series.py

-4
Original file line numberDiff line numberDiff line change
@@ -438,10 +438,6 @@ def imag(self, v):
438438
__long__ = _coerce_method(int)
439439
__int__ = _coerce_method(int)
440440

441-
# we are preserving name here
442-
def __getstate__(self):
443-
return dict(_data=self._data, name=self.name)
444-
445441
def _unpickle_series_compat(self, state):
446442
if isinstance(state, dict):
447443
self._data = state['_data']

pandas/tests/test_frame.py

+9-11
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@
4545
assertRaisesRegexp,
4646
assertRaises,
4747
makeCustomDataframe as mkdf,
48-
ensure_clean)
48+
ensure_clean,
49+
SubclassedDataFrame)
4950
from pandas.core.indexing import IndexingError
5051
from pandas.core.common import PandasError
5152

@@ -14501,16 +14502,8 @@ def test_assign_bad(self):
1450114502

1450214503
def test_dataframe_metadata(self):
1450314504

14504-
class TestDataFrame(DataFrame):
14505-
_metadata = ['testattr']
14506-
14507-
@property
14508-
def _constructor(self):
14509-
return TestDataFrame
14510-
14511-
14512-
df = TestDataFrame({'X': [1, 2, 3], 'Y': [1, 2, 3]},
14513-
index=['a', 'b', 'c'])
14505+
df = SubclassedDataFrame({'X': [1, 2, 3], 'Y': [1, 2, 3]},
14506+
index=['a', 'b', 'c'])
1451414507
df.testattr = 'XXX'
1451514508

1451614509
self.assertEqual(df.testattr, 'XXX')
@@ -14519,6 +14512,11 @@ def _constructor(self):
1451914512
self.assertEqual(df.iloc[[0, 1], :].testattr, 'XXX')
1452014513
# GH9776
1452114514
self.assertEqual(df.iloc[0:1, :].testattr, 'XXX')
14515+
# GH10553
14516+
unpickled = self.round_trip_pickle(df)
14517+
assert_frame_equal(df, unpickled)
14518+
self.assertEqual(df._metadata, unpickled._metadata)
14519+
self.assertEqual(df.testattr, unpickled.testattr)
1452214520

1452314521
def test_to_panel_expanddim(self):
1452414522
# GH 9762

pandas/util/testing.py

+8
Original file line numberDiff line numberDiff line change
@@ -1856,3 +1856,11 @@ def inner(*args, **kwargs):
18561856
thread.join()
18571857
return inner
18581858
return wrapper
1859+
1860+
1861+
class SubclassedDataFrame(DataFrame):
1862+
_metadata = ['testattr']
1863+
1864+
@property
1865+
def _constructor(self):
1866+
return SubclassedDataFrame

0 commit comments

Comments
 (0)