Repository: pandas-dev/pandas

Issue:
BUG: loc is not expanding an integer slice as labels
see #2904 at the end



Discussion:

Resolving patch:
diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py
--- a/pandas/core/indexing.py
+++ b/pandas/core/indexing.py
@@ -647,6 +647,19 @@ def _getbool_axis(self, key, axis=0):
                 return self.obj.take(inds, axis=axis)
             except (Exception), detail:
                 raise self._exception(detail)
+    def _get_slice_axis(self, slice_obj, axis=0):
+        """ this is pretty simple as we just have to deal with labels """
+        obj = self.obj
+        if not _need_slice(slice_obj):
+            return obj
+
+        labels = obj._get_axis(axis)
+        indexer = labels.slice_indexer(slice_obj.start, slice_obj.stop, slice_obj.step)
+
+        if isinstance(indexer, slice):
+            return self._slice(indexer, axis=axis)
+        else:
+            return self.obj.take(indexer, axis=axis)
 
 class _LocIndexer(_LocationIndexer):
     """ purely label based location based indexing """
@@ -667,11 +680,8 @@ def _has_valid_type(self, key, axis):
                 if key.start not in ax:
                     raise KeyError("start bound [%s] is not the [%s]" % (key.start,self.obj._get_axis_name(axis)))
             if key.stop is not None:
-                stop = key.stop
-                if com.is_integer(stop):
-                    stop -= 1
-                if stop not in ax:
-                    raise KeyError("stop bound [%s] is not in the [%s]" % (stop,self.obj._get_axis_name(axis)))
+                if key.stop not in ax:
+                    raise KeyError("stop bound [%s] is not in the [%s]" % (key.stop,self.obj._get_axis_name(axis)))
 
         elif com._is_bool_indexer(key):
                 return True
@@ -700,9 +710,6 @@ def _getitem_axis(self, key, axis=0):
         labels = self.obj._get_axis(axis)
 
         if isinstance(key, slice):
-            ltype = labels.inferred_type
-            if ltype == 'mixed-integer-float' or ltype == 'mixed-integer':
-                raise ValueError('cannot slice with a non-single type label array')
             return self._get_slice_axis(key, axis=axis)
         elif com._is_bool_indexer(key):
             return self._getbool_axis(key, axis=axis)


Test patch:
diff --git a/pandas/tests/test_indexing.py b/pandas/tests/test_indexing.py
--- a/pandas/tests/test_indexing.py
+++ b/pandas/tests/test_indexing.py
@@ -450,12 +450,38 @@ def test_loc_getitem_bool(self):
     def test_loc_getitem_int_slice(self):
 
         # int slices in int 
-        self.check_result('int slice1', 'loc', slice(1,3), 'ix', { 0 : [2,4], 1: [3,6], 2: [4,8] }, typs = ['ints'], fails=KeyError)
+        self.check_result('int slice1', 'loc', slice(2,4), 'ix', { 0 : [2,4], 1: [3,6], 2: [4,8] }, typs = ['ints'], fails=KeyError)
 
         # ok 
-        self.check_result('int slice2', 'loc', slice(2,5), 'ix', [2,4], typs = ['ints'], axes = 0)
-        self.check_result('int slice2', 'loc', slice(3,7), 'ix', [3,6], typs = ['ints'], axes = 1)
-        self.check_result('int slice2', 'loc', slice(4,9), 'ix', [4,8], typs = ['ints'], axes = 2)
+        self.check_result('int slice2', 'loc', slice(2,4), 'ix', [2,4], typs = ['ints'], axes = 0)
+        self.check_result('int slice2', 'loc', slice(3,6), 'ix', [3,6], typs = ['ints'], axes = 1)
+        self.check_result('int slice2', 'loc', slice(4,8), 'ix', [4,8], typs = ['ints'], axes = 2)
+
+        # GH 3053
+        # loc should treat integer slices like label slices
+        from itertools import product
+
+        index = MultiIndex.from_tuples([t for t in product([6,7,8], ['a', 'b'])])
+        df = DataFrame(np.random.randn(6, 6), index, index)
+        result = df.loc[6:8,:]
+        expected = df.ix[6:8,:]
+        assert_frame_equal(result,expected)
+
+        index = MultiIndex.from_tuples([t for t in product([10, 20, 30], ['a', 'b'])])
+        df = DataFrame(np.random.randn(6, 6), index, index)
+        result = df.loc[20:30,:]
+        expected = df.ix[20:30,:]
+        assert_frame_equal(result,expected)
+
+        # doc examples
+        result = df.loc[10,:]
+        expected = df.ix[10,:]
+        assert_frame_equal(result,expected)
+
+        result = df.loc[:,10]
+        #expected = df.ix[:,10] (this fails)
+        expected = df[10]
+        assert_frame_equal(result,expected)
 
     def test_loc_getitem_label_slice(self):
 
@@ -475,8 +501,7 @@ def test_loc_getitem_label_slice(self):
         self.check_result('mixed slice', 'loc', slice(2,8), 'ix', slice(2,8), typs = ['mixed'], axes=1, fails=KeyError)
         self.check_result('mixed slice', 'loc', slice(2,8), 'ix', slice(2,8), typs = ['mixed'], axes=2, fails=KeyError)
 
-        # you would think this would work, but we don't have an ordering, so fail
-        self.check_result('mixed slice', 'loc', slice(2,5,2), 'ix', slice(2,4,2), typs = ['mixed'], axes=0, fails=ValueError)
+        self.check_result('mixed slice', 'loc', slice(2,4,2), 'ix', slice(2,4,2), typs = ['mixed'], axes=0)
 
     def test_loc_general(self):