Repository: pandas-dev/pandas

Issue:
BUG: strange behavior of .loc indexer: falling back to integer-based indexing with list 
```
Python 2.7.6 (default, Mar 22 2014, 22:59:56) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pandas
>>> a = pandas.Series()
>>> a.loc[1] = 1
>>> a.loc['a'] = 2
>>> a.loc[[-1, -2]]
1    1
a    2
dtype: int64
```

This is ok:

```
>>> a.loc[-1]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/tmp/venv/local/lib/python2.7/site-packages/pandas/core/indexing.py", line 1129, in __getitem__
    return self._getitem_axis(key, axis=0)
  File "/tmp/venv/local/lib/python2.7/site-packages/pandas/core/indexing.py", line 1261, in _getitem_axis
    self._has_valid_type(key, axis)
  File "/tmp/venv/local/lib/python2.7/site-packages/pandas/core/indexing.py", line 1234, in _has_valid_type
    error()
  File "/tmp/venv/local/lib/python2.7/site-packages/pandas/core/indexing.py", line 1221, in error
    (key, self.obj._get_axis_name(axis)))
KeyError: 'the label [-1] is not in the [index]'
```

This is ok too:

```
>>> a.loc[['W']]
W   NaN
dtype: float64
```

But this is not:

```
>>> a.loc[-1] = 3
>>> a.loc[[-1, -2]]
-1    3
1    1
dtype: int64
```

And this is not good at all:

```
>>> a
1    1
-1    3
dtype: int64
>>> a['a'] = 2
>>> a
1     1
-1    3
a     2
dtype: int64
>>> a.loc[[-2]] = 0
>>> a
1     0
-1    3
a     2
dtype: int64
```

Without `'a'` string in the index it raises while I expect new item (`{-2: 0}`) to be added

```
>>> del a['a']
>>> a.loc[[-2]] = 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/tmp/venv/local/lib/python2.7/site-packages/pandas/core/indexing.py", line 117, in __setitem__
    indexer = self._convert_to_indexer(key, is_setter=True)
  File "/tmp/venv/local/lib/python2.7/site-packages/pandas/core/indexing.py", line 1068, in _convert_to_indexer
    raise KeyError('%s not in index' % objarr[mask])
KeyError: '[-2] not in index'
```



Discussion:
hmm.

must not be some quite strict checking; in fact the negative indexers should raise as well (your 2nd example).

2nd example contains indexing with list of strings
Probably it is good idea to replace `'4'` with `'W'`


Resolving patch:
diff --git a/pandas/core/index.py b/pandas/core/index.py
--- a/pandas/core/index.py
+++ b/pandas/core/index.py
@@ -609,7 +609,7 @@ def _convert_list_indexer_for_mixed(self, keyarr, typ=None):
             and we have a mixed index (e.g. number/labels). figure out
             the indexer. return None if we can't help
         """
-        if com.is_integer_dtype(keyarr) and not self.is_floating():
+        if (typ is None or typ in ['iloc','ix']) and (com.is_integer_dtype(keyarr) and not self.is_floating()):
             if self.inferred_type != 'integer':
                 keyarr = np.where(keyarr < 0,
                                   len(self) + keyarr, keyarr)


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
@@ -806,6 +806,38 @@ def test_loc_to_fail(self):
         # raise a KeyError?
         self.assertRaises(KeyError, df.loc.__getitem__, tuple([[1, 2], [1, 2]]))
 
+        # GH  7496
+        # loc should not fallback
+
+        s = Series()
+        s.loc[1] = 1
+        s.loc['a'] = 2
+
+        self.assertRaises(KeyError, lambda : s.loc[-1])
+
+        result = s.loc[[-1, -2]]
+        expected = Series(np.nan,index=[-1,-2])
+        assert_series_equal(result, expected)
+
+        result = s.loc[['4']]
+        expected = Series(np.nan,index=['4'])
+        assert_series_equal(result, expected)
+
+        s.loc[-1] = 3
+        result = s.loc[[-1,-2]]
+        expected = Series([3,np.nan],index=[-1,-2])
+        assert_series_equal(result, expected)
+
+        s['a'] = 2
+        result = s.loc[[-2]]
+        expected = Series([np.nan],index=[-2])
+        assert_series_equal(result, expected)
+
+        del s['a']
+        def f():
+            s.loc[[-2]] = 0
+        self.assertRaises(KeyError, f)
+
     def test_loc_getitem_label_slice(self):
 
         # label slices (with ints)