API: better error-handling for df.set_index
State: closed

- [x] closes #22484
- [x] tests added / passed
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [x] whatsnew entry

split off of #22236, and so builds on top of it.


Labels:
name: Indexing
description: Related to indexing on series/frames, not to indexes themselves
name: Error Reporting
description: Incorrect or improved errors from pandas

Comments:
@gfyoung, thanks for the review. This is based on #22236, and so it will be easier to review once that is in.

About the number of times iterating over the columns, it would IMO be very complicated and unreadable to do it in one loop, and - to me - not worth the performance gain, because the number of columns used for an index is generally so negligibly small, that traversing that list is a non-issue performance-wise.
@gfyoung 
> In that case, unless there are other objections, I would suggest using the single for-loop instead. It seems pretty readable IMO.

Incorporated your feedback, coming with the next commit after rebasing on top of #22236 
Hello @h-vetinari! Thanks for updating the PR.

 - There are no PEP8 issues in the file [`pandas/core/frame.py`](https://github.com/h-vetinari/pandas/blob/dd8d0004fd5154619331894c982fbc3a145c70aa/pandas/core/frame.py) !

 - There are no PEP8 issues in the file [`pandas/tests/frame/conftest.py`](https://github.com/h-vetinari/pandas/blob/dd8d0004fd5154619331894c982fbc3a145c70aa/pandas/tests/frame/conftest.py) !

 - There are no PEP8 issues in the file [`pandas/tests/frame/test_alter_axes.py`](https://github.com/h-vetinari/pandas/blob/dd8d0004fd5154619331894c982fbc3a145c70aa/pandas/tests/frame/test_alter_axes.py) !



##### Comment last updated on October 05, 2018 at 21:48 Hours UTC
> this is not true. either all have to be scalars, or all list-likes (yes they don't have to be the same, just list-convertible).

This is wrong on both counts. On master, a mix of column labels and a list:

```
>>> df = pd.DataFrame({'a': [1, 2], 'b': [11, 12]})
>>> df
   a   b
0  1  11
1  2  12
>>> df.set_index(['a', [101, 102]])
        b
a
1 101  11
2 102  12
```

Regarding the argument types, the list I wrote (and test) is exhaustive (see https://github.com/pandas-dev/pandas/blob/master/pandas/core/frame.py#L3908) - currently only `Series/Index/MultiIndex/list/ndarray` are allowed, everything else gets tried as a frame key. This is one of the points in #22484.
```
>>> from pandas.core.dtypes.common import is_list_like
>>> LL = iter([21, 22])
>>> is_list_like(LL)
True
>>> df.set_index(LL)
KeyError: "None of [Int64Index([21, 22], dtype='int64')] are in the [columns]"
```
# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/22486?src=pr&el=h1) Report
> Merging [#22486](https://codecov.io/gh/pandas-dev/pandas/pull/22486?src=pr&el=desc) into [master](https://codecov.io/gh/pandas-dev/pandas/commit/5e06c84c8994b625407293ff6c80b8d9ddaaca5d?src=pr&el=desc) will **increase** coverage by `<.01%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/pandas-dev/pandas/pull/22486/graphs/tree.svg?width=650&token=eZ4WkYLtcO&height=150&src=pr)](https://codecov.io/gh/pandas-dev/pandas/pull/22486?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master   #22486      +/-   ##
==========================================
+ Coverage   92.19%   92.19%   +<.01%     
==========================================
  Files         169      169              
  Lines       50956    50966      +10     
==========================================
+ Hits        46978    46988      +10     
  Misses       3978     3978
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `90.61% <100%> (ø)` | :arrow_up: |
| #single | `42.27% <54.16%> (ø)` | :arrow_up: |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/22486?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/core/frame.py](https://codecov.io/gh/pandas-dev/pandas/pull/22486/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZnJhbWUucHk=) | `97.12% <100%> (+0.01%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/22486?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/22486?src=pr&el=footer). Last update [5e06c84...42d5f2a](https://codecov.io/gh/pandas-dev/pandas/pull/22486?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

@jreback 
Reworded the warning and rewrote the test - hopefully both clearer now.
@jreback 
Green
@jreback 
While you're at it with the reviewing, please don't forget this one. :)
@jreback 

I implemented the list-likes, like you requested. I'm excluding two-dimensional data and sets (didn't know they are even list-like, as they have no determined order?!). I also added a column with a tuple label to the fixture in conftest to test that case.

BTW, the test results are not as grim as they look, there were 2x `CondaHTTPError: HTTP 504 GATEWAY_TIMEOUT` in CircleCI, and one doctest-failure in a file I didn't touch.
@jreback 

PTAL
@jreback 
PTAL here :)
@h-vetinari why don't you try (separate PR) excluding set from is_list_like and see what the implications of that are.
@jreback 
> @h-vetinari why don't you try (separate PR) excluding set from is_list_like and see what the implications of that are.

I did, seems doable: #23061 #23065
@jreback 
All green. After merging and incorporating #23065, all comments here should now be addressed.
thanks!