Repository: pandas-dev/pandas

Issue:
BUG: del in Series gives strange errors 
I'm not sure whether `del someseries[something]` is supposed to work or not, although there is a `Series.__delitem__` method so maybe at some point it was.  And `.drop()` seems to work, so it's not super-important.  But ISTM users shouldn't see this:

```
>>> pd.__version__
'0.12.0-1114-g4d0632b'
>>> ser = pd.Series(range(5))
>>> del ser[0]
Traceback (most recent call last):
  File "<ipython-input-62-e967e45427c2>", line 1, in <module>
    del ser[0]
  File "/usr/local/lib/python2.7/dist-packages/pandas-0.12.0_1114_g4d0632b-py2.7-linux-i686.egg/pandas/core/generic.py", line 1057, in __delitem__
    self._data.delete(key)
  File "/usr/local/lib/python2.7/dist-packages/pandas-0.12.0_1114_g4d0632b-py2.7-linux-i686.egg/pandas/core/internals.py", line 2818, in delete
    self.set_items_norename(new_items)
  File "/usr/local/lib/python2.7/dist-packages/pandas-0.12.0_1114_g4d0632b-py2.7-linux-i686.egg/pandas/core/internals.py", line 2923, in set_items_norename
    self.set_axis(0, value, maybe_rename=False, check_axis=False)
TypeError: set_axis() got an unexpected keyword argument 'maybe_rename'

>>> del ser[0]
Traceback (most recent call last):
  File "<ipython-input-63-e967e45427c2>", line 1, in <module>
    del ser[0]
  File "/usr/local/lib/python2.7/dist-packages/pandas-0.12.0_1114_g4d0632b-py2.7-linux-i686.egg/pandas/core/generic.py", line 1057, in __delitem__
    self._data.delete(key)
  File "/usr/local/lib/python2.7/dist-packages/pandas-0.12.0_1114_g4d0632b-py2.7-linux-i686.egg/pandas/core/internals.py", line 2814, in delete
    self._delete_from_all_blocks(loc, item)
  File "/usr/local/lib/python2.7/dist-packages/pandas-0.12.0_1114_g4d0632b-py2.7-linux-i686.egg/pandas/core/internals.py", line 2945, in _delete_from_all_blocks
    i, _ = self._find_block(item)
TypeError: 'NoneType' object is not iterable
```

That the error message isn't the same both times is a little disturbing in any case, because that suggests something stateful changed, which it's hard to believe can be right.



Discussion:
this should deleted the item with index 0
inplace

prob no tests on it

prob didn't work in 0.12 and prior

Well, that's reassuring, anyway -- an in-place deletion of index 0 was exactly what I was expecting to happen. :^)


Resolving patch:
diff --git a/pandas/core/internals.py b/pandas/core/internals.py
--- a/pandas/core/internals.py
+++ b/pandas/core/internals.py
@@ -1969,7 +1969,7 @@ def ndim(self):
             self._ndim = len(self.axes)
         return self._ndim
 
-    def set_axis(self, axis, value, maybe_rename=True, check_axis=True):
+    def _set_axis(self, axis, value, check_axis=True):
         cur_axis = self.axes[axis]
         value = _ensure_index(value)
 
@@ -1980,6 +1980,10 @@ def set_axis(self, axis, value, maybe_rename=True, check_axis=True):
 
         self.axes[axis] = value
         self._shape = None
+        return cur_axis, value
+
+    def set_axis(self, axis, value, maybe_rename=True, check_axis=True):
+        cur_axis, value = self._set_axis(axis, value, check_axis)
 
         if axis == 0:
 
@@ -3473,24 +3477,22 @@ def reindex_axis0_with_method(self, new_axis, indexer=None, method=None,
         return self.reindex(new_axis, indexer=indexer, method=method,
                             fill_value=fill_value, limit=limit, copy=copy)
 
+    def _delete_from_block(self, i, item):
+        super(SingleBlockManager, self)._delete_from_block(i, item)
+
+        # reset our state
+        self._block = self.blocks[0] if len(self.blocks) else make_block(np.array([],dtype=self._block.dtype),[],[])
+        self._values = self._block.values
+
     def get_slice(self, slobj, raise_on_error=False):
         if raise_on_error:
             _check_slice_bounds(slobj, self.index)
         return self.__class__(self._block._slice(slobj),
                               self.index._getitem_slice(slobj), fastpath=True)
 
-    def set_axis(self, axis, value):
-        cur_axis = self.axes[axis]
-        value = _ensure_index(value)
-
-        if len(value) != len(cur_axis):
-            raise ValueError('Length mismatch: Expected axis has %d elements, '
-                             'new values have %d elements' % (len(cur_axis),
-                                                              len(value)))
-
-        self.axes[axis] = value
-        self._shape = None
-        self._block.set_ref_items(self.items, maybe_rename=True)
+    def set_axis(self, axis, value, maybe_rename=True, check_axis=True):
+        cur_axis, value = self._set_axis(axis, value, check_axis)
+        self._block.set_ref_items(self.items, maybe_rename=maybe_rename)
 
     def set_ref_items(self, ref_items, maybe_rename=True):
         """ we can optimize and our ref_locs are always equal to ref_items """


Test patch:
diff --git a/pandas/tests/test_series.py b/pandas/tests/test_series.py
--- a/pandas/tests/test_series.py
+++ b/pandas/tests/test_series.py
@@ -113,6 +113,35 @@ def test_combine_first_dt64(self):
         xp = Series([datetime(2010, 1, 1), '2011'])
         assert_series_equal(rs, xp)
 
+    def test_delitem(self):
+
+        # GH 5542
+        # should delete the item inplace
+        s = Series(lrange(5))
+        del s[0]
+
+        expected = Series(lrange(1,5),index=lrange(1,5))
+        assert_series_equal(s, expected)
+
+        del s[1]
+        expected = Series(lrange(2,5),index=lrange(2,5))
+        assert_series_equal(s, expected)
+
+        # empty
+        s = Series()
+        def f():
+            del s[0]
+        self.assertRaises(KeyError, f)
+
+        # only 1 left, del, add, del
+        s = Series(1)
+        del s[0]
+        assert_series_equal(s, Series(dtype='int64'))
+        s[0] = 1
+        assert_series_equal(s, Series(1))
+        del s[0]
+        assert_series_equal(s, Series(dtype='int64'))
+
     def test_getitem_preserve_name(self):
         result = self.ts[self.ts > 0]
         self.assertEquals(result.name, self.ts.name)