From 9f7dbdd056f59bd5e007a66377e09a469a76a2e6 Mon Sep 17 00:00:00 2001 From: jreback Date: Sun, 22 Sep 2013 19:58:51 -0400 Subject: [PATCH] BUG: Fixed a bug in DataFrame/Panel cache insertion and subsequent indexing GH4939 --- doc/source/release.rst | 1 + pandas/core/generic.py | 14 ++++++++++---- pandas/core/indexing.py | 4 ++++ pandas/tests/test_indexing.py | 15 +++++++++++++++ 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/doc/source/release.rst b/doc/source/release.rst index 789fbd0fe4ccc..b7b5c8835a265 100644 --- a/doc/source/release.rst +++ b/doc/source/release.rst @@ -438,6 +438,7 @@ Bug Fixes - Fixed a bug in ``Series.hist`` where two figures were being created when the ``by`` argument was passed (:issue:`4112`, :issue:`4113`). - Fixed a bug in ``convert_objects`` for > 2 ndims (:issue:`4937`) + - Fixed a bug in DataFrame/Panel cache insertion and subsequent indexing (:issue:`4939`) pandas 0.12.0 ------------- diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 53d3687854cac..36c3ff9085d87 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -825,14 +825,20 @@ def _maybe_cache_changed(self, item, value): maybe it has changed """ self._data.set(item, value) - def _maybe_update_cacher(self): - """ see if we need to update our parent cacher """ + def _maybe_update_cacher(self, clear=False): + """ see if we need to update our parent cacher + if clear, then clear our cache """ cacher = getattr(self,'_cacher',None) if cacher is not None: cacher[1]()._maybe_cache_changed(cacher[0],self) + if clear: + self._clear_item_cache() - def _clear_item_cache(self): - self._item_cache.clear() + def _clear_item_cache(self, i=None): + if i is not None: + self._item_cache.pop(i,None) + else: + self._item_cache.clear() def _set_item(self, key, value): self._data.set(key, value) diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 4f5e6623e1512..3779e78599bde 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -190,12 +190,14 @@ def _setitem_with_indexer(self, indexer, value): new_values = np.concatenate([self.obj.values, [value]]) self.obj._data = self.obj._constructor(new_values, index=new_index, name=self.obj.name) + self.obj._maybe_update_cacher(clear=True) return self.obj elif self.ndim == 2: index = self.obj._get_axis(0) labels = _safe_append_to_index(index, indexer) self.obj._data = self.obj.reindex_axis(labels,0)._data + self.obj._maybe_update_cacher(clear=True) return getattr(self.obj,self.name).__setitem__(indexer,value) # set using setitem (Panel and > dims) @@ -255,6 +257,7 @@ def setter(item, v): # set the item, possibly having a dtype change s = s.copy() s._data = s._data.setitem(pi,v) + s._maybe_update_cacher(clear=True) self.obj[item] = s def can_do_equal_len(): @@ -327,6 +330,7 @@ def can_do_equal_len(): value = self._align_panel(indexer, value) self.obj._data = self.obj._data.setitem(indexer,value) + self.obj._maybe_update_cacher(clear=True) def _align_series(self, indexer, ser): # indexer to assign Series can be tuple or scalar diff --git a/pandas/tests/test_indexing.py b/pandas/tests/test_indexing.py index aad9fb2f95483..267cc8605366c 100644 --- a/pandas/tests/test_indexing.py +++ b/pandas/tests/test_indexing.py @@ -1480,6 +1480,21 @@ def test_series_partial_set(self): result = ser.iloc[[1,1,0,0]] assert_series_equal(result, expected) + def test_cache_updating(self): + # GH 4939, make sure to update the cache on setitem + + df = tm.makeDataFrame() + df['A'] # cache series + df.ix["Hello Friend"] = df.ix[0] + self.assert_("Hello Friend" in df['A'].index) + self.assert_("Hello Friend" in df['B'].index) + + panel = tm.makePanel() + panel.ix[0] # get first item into cache + panel.ix[:, :, 'A+1'] = panel.ix[:, :, 'A'] + 1 + self.assert_("A+1" in panel.ix[0].columns) + self.assert_("A+1" in panel.ix[1].columns) + if __name__ == '__main__': import nose nose.runmodule(argv=[__file__, '-vvs', '-x', '--pdb', '--pdb-failure'],