Repository: pandas-dev/pandas

Issue:
sort_index throws IndexError for some permutations
#### Code Sample

```python
df = pd.DataFrame(list(range(8)))
a.index = pd.MultiIndex.from_product([[0,1]]*3)
a.sort_index(level=[1,2,0])
```
#### Problem description

This throws an `IndexEror: pop index out of range`. 
If I change the order to `[2,0,1]`, it doesn't.

python: 3.6.6.final.0
pandas: 0.24.2
numpy: 1.15.4



Discussion:
Please provide fully reproducible code - it's not clear what `a` here is
```python
## a -> df
import pandas as pd
df = pd.DataFrame(list(range(8)))
df.index = pd.MultiIndex.from_product([[0,1]]*3)
df.sort_index(level=[1,2,0])
```
OK thanks for clarifying. The both seem to fail:

```python
df.sort_index(level=[2,1,0])
df.sort_index(level=[1,2,0])
```

`sort_remaining` doesn't appear to have an impact. One pattern that may be apparent there is that both failures use all of the level and have the initial level as the last of the sort.

May or may not be related to issue - in any case investigation and PRs are always welcome!

Resolving patch:
diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py
--- a/pandas/core/indexes/multi.py
+++ b/pandas/core/indexes/multi.py
@@ -2084,8 +2084,14 @@ def sortlevel(self, level=0, ascending=True, sort_remaining=True):
             shape = list(self.levshape)
 
             # partition codes and shape
-            primary = tuple(codes.pop(lev - i) for i, lev in enumerate(level))
-            primshp = tuple(shape.pop(lev - i) for i, lev in enumerate(level))
+            primary = tuple(codes[lev] for lev in level)
+            primshp = tuple(shape[lev] for lev in level)
+
+            # Reverse sorted to retain the order of
+            # smaller indices that needs to be removed
+            for lev in sorted(level, reverse=True):
+                codes.pop(lev)
+                shape.pop(lev)
 
             if sort_remaining:
                 primary += primary + tuple(codes)


Test patch:
diff --git a/pandas/tests/frame/test_sorting.py b/pandas/tests/frame/test_sorting.py
--- a/pandas/tests/frame/test_sorting.py
+++ b/pandas/tests/frame/test_sorting.py
@@ -496,11 +496,28 @@ def test_sort_index_duplicates(self):
     def test_sort_index_level(self):
         mi = MultiIndex.from_tuples([[1, 1, 3], [1, 1, 1]], names=list('ABC'))
         df = DataFrame([[1, 2], [3, 4]], mi)
-        res = df.sort_index(level='A', sort_remaining=False)
-        assert_frame_equal(df, res)
 
-        res = df.sort_index(level=['A', 'B'], sort_remaining=False)
-        assert_frame_equal(df, res)
+        result = df.sort_index(level='A', sort_remaining=False)
+        expected = df
+        assert_frame_equal(result, expected)
+
+        result = df.sort_index(level=['A', 'B'], sort_remaining=False)
+        expected = df
+        assert_frame_equal(result, expected)
+
+        # Error thrown by sort_index when
+        # first index is sorted last (#26053)
+        result = df.sort_index(level=['C', 'B', 'A'])
+        expected = df.iloc[[1, 0]]
+        assert_frame_equal(result, expected)
+
+        result = df.sort_index(level=['B', 'C', 'A'])
+        expected = df.iloc[[1, 0]]
+        assert_frame_equal(result, expected)
+
+        result = df.sort_index(level=['C', 'A'])
+        expected = df.iloc[[1, 0]]
+        assert_frame_equal(result, expected)
 
     def test_sort_index_categorical_index(self):