Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ccb4545

Browse files
author
y-p
committedApr 9, 2013
ENH: add .meta attribute to frame and series, which gets de/serialized
1 parent 1569838 commit ccb4545

File tree

6 files changed

+91
-6
lines changed

6 files changed

+91
-6
lines changed
 

‎pandas/core/frame.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,7 @@ def __init__(self, data=None, index=None, columns=None, dtype=None,
450450
raise PandasError('DataFrame constructor not properly called!')
451451

452452
NDFrame.__init__(self, mgr)
453+
self.meta=dict()
453454

454455
@classmethod
455456
def _from_axes(cls, data, axes):
@@ -1696,10 +1697,20 @@ def swapaxes(self, i, j):
16961697
# Picklability
16971698

16981699
def __getstate__(self):
1699-
return self._data
1700+
return self._data,dict(meta=self.meta)
17001701

17011702
def __setstate__(self, state):
17021703
# old DataFrame pickle
1704+
attrs = {}
1705+
if ( isinstance(state, tuple)
1706+
and isinstance(state[0],BlockManager)
1707+
and isinstance(state[1],dict)):
1708+
attrs=state[1]
1709+
1710+
# put things back to the prev version and
1711+
# reuse the old path
1712+
state = state[0]
1713+
17031714
if isinstance(state, BlockManager):
17041715
self._data = state
17051716
elif isinstance(state[0], dict): # pragma: no cover
@@ -1711,6 +1722,9 @@ def __setstate__(self, state):
17111722
# ordinarily created in NDFrame
17121723
self._item_cache = {}
17131724

1725+
for k,v in attrs.items():
1726+
setattr(self,k,v)
1727+
17141728
# legacy pickle formats
17151729
def _unpickle_frame_compat(self, state): # pragma: no cover
17161730
from pandas.core.common import _unpickle_array

‎pandas/core/panel.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ def __init__(self, data=None, items=None, major_axis=None, minor_axis=None,
238238
self._init_data(
239239
data=data, items=items, major_axis=major_axis, minor_axis=minor_axis,
240240
copy=copy, dtype=dtype)
241+
self.meta = {}
241242

242243
def _init_data(self, data, copy, dtype, **kwargs):
243244
""" generate ND initialization; axes are passed as required objects to __init__ """
@@ -706,10 +707,21 @@ def pop(self, item):
706707

707708
def __getstate__(self):
708709
"Returned pickled representation of the panel"
709-
return self._data
710+
return self._data,dict(meta=self.meta)
710711

711712
def __setstate__(self, state):
712713
# old Panel pickle
714+
attrs = {}
715+
print( state)
716+
if ( isinstance(state, tuple)
717+
and isinstance(state[0],BlockManager)
718+
and isinstance(state[1],dict)):
719+
attrs = state[1]
720+
721+
# put things back to the prev version and
722+
# reuse the old path
723+
state = state[0]
724+
713725
if isinstance(state, BlockManager):
714726
self._data = state
715727
elif len(state) == 4: # pragma: no cover
@@ -718,6 +730,9 @@ def __setstate__(self, state):
718730
raise ValueError('unrecognized pickle')
719731
self._item_cache = {}
720732

733+
for k,v in attrs.items():
734+
setattr(self,k,v)
735+
721736
def _unpickle_panel_compat(self, state): # pragma: no cover
722737
"Unpickle the panel"
723738
_unpickle = com._unpickle_array

‎pandas/core/series.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,7 @@ def __init__(self, data=None, index=None, dtype=None, name=None,
509509
input data
510510
copy : boolean, default False
511511
"""
512+
self.meta = {}
512513
pass
513514

514515
@property
@@ -539,7 +540,7 @@ def __contains__(self, key):
539540
def __reduce__(self):
540541
"""Necessary for making this object picklable"""
541542
object_state = list(ndarray.__reduce__(self))
542-
subclass_state = (self.index, self.name)
543+
subclass_state = (self.index, dict(name=self.name,meta=self.meta))
543544
object_state[2] = (object_state[2], subclass_state)
544545
return tuple(object_state)
545546

@@ -548,6 +549,16 @@ def __setstate__(self, state):
548549
nd_state, own_state = state
549550
ndarray.__setstate__(self, nd_state)
550551

552+
attrs = {}
553+
if len(own_state) > 1 and isinstance(own_state[1],dict):
554+
attrs = own_state[1]
555+
556+
# and put things back they the previous pickle
557+
# schema worked
558+
own_state = (own_state[0],attrs.get('name'))
559+
560+
index, dict_or_name = own_state[0], None
561+
551562
# backwards compat
552563
index, name = own_state[0], None
553564
if len(own_state) > 1:
@@ -556,6 +567,9 @@ def __setstate__(self, state):
556567
self.index = _handle_legacy_indexes([index])[0]
557568
self.name = name
558569

570+
for k,v in attrs.items():
571+
setattr(self,k,v)
572+
559573
# indexers
560574
@property
561575
def axes(self):

‎pandas/tests/test_frame.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
from pandas.util.testing import (assert_almost_equal,
2828
assert_series_equal,
2929
assert_frame_equal,
30-
ensure_clean)
30+
ensure_clean,
31+
makeCustomDataframe as mkdf )
3132
from pandas.util import py3compat
3233
from pandas.util.compat import OrderedDict
3334

@@ -4616,7 +4617,6 @@ def test_to_csv_from_csv(self):
46164617

46174618
@slow
46184619
def test_to_csv_moar(self):
4619-
from pandas.util.testing import makeCustomDataframe as mkdf
46204620
path = '__tmp_to_csv_moar__'
46214621
chunksize=1000
46224622

@@ -6021,7 +6021,6 @@ def test_replace_mixed(self):
60216021
assert_frame_equal(result,expected)
60226022

60236023
# test case from
6024-
from pandas.util.testing import makeCustomDataframe as mkdf
60256024
df = DataFrame({'A' : Series([3,0],dtype='int64'), 'B' : Series([0,3],dtype='int64') })
60266025
result = df.replace(3, df.mean().to_dict())
60276026
expected = df.copy().astype('float64')
@@ -9428,6 +9427,20 @@ def test_any_all(self):
94289427
# df.any(1, bool_only=True)
94299428
# df.all(1, bool_only=True)
94309429

9430+
def test_meta_serialization(self):
9431+
import pandas as pd
9432+
df=mkdf(10,5)
9433+
df.meta == {}
9434+
# create some kv pairs for serialization
9435+
df.meta['Im']="persistent"
9436+
# roundtrip
9437+
with ensure_clean() as path:
9438+
df.save(path)
9439+
dfrt =pd.load(path)
9440+
9441+
# still here
9442+
self.assertEqual(dfrt.meta['Im'],'persistent')
9443+
94319444
def test_consolidate_datetime64(self):
94329445
# numpy vstack bug
94339446

‎pandas/tests/test_panel.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,21 @@ def test_pickle(self):
4040
unpickled = cPickle.loads(pickled)
4141
assert_frame_equal(unpickled['ItemA'], self.panel['ItemA'])
4242

43+
def test_meta_serialization(self):
44+
import pandas as pd
45+
46+
p = self.panel
47+
p.meta = {}
48+
# create some kv pairs for serialization
49+
p.meta['Im']="persistent"
50+
# roundtrip
51+
with ensure_clean() as path:
52+
p.save(path)
53+
prt =pd.load(path)
54+
55+
# still here
56+
self.assertEqual(prt.meta['Im'],'persistent')
57+
4358
def test_cumsum(self):
4459
cumsum = self.panel.cumsum()
4560
assert_frame_equal(cumsum['ItemA'], self.panel['ItemA'].cumsum())

‎pandas/tests/test_series.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,20 @@ def test_fromDict(self):
540540
series = Series(data, dtype=float)
541541
self.assert_(series.dtype == np.float64)
542542

543+
def test_meta_serialization(self):
544+
import pandas as pd
545+
s=Series([np.random.randn(100)])
546+
s.meta == {}
547+
# create some kv pairs for serialization
548+
s.meta['Im']="persistent"
549+
# roundtrip
550+
with ensure_clean() as path:
551+
s.save(path)
552+
srt =pd.load(path)
553+
554+
# still here
555+
self.assertEqual(srt.meta['Im'],'persistent')
556+
543557
def test_from_json_to_json(self):
544558
raise nose.SkipTest
545559

0 commit comments

Comments
 (0)
Please sign in to comment.