BUG: CategoricalIndex allows reindexing with non-unique CategoricalIndex
State: closed

`CategoricalIndex.reindex()` throws a `ValueError` if the target index is non-unique *and* not also a `CategoricalIndex`. This means a non-unique `CategoricalIndex` can be used to reindex, resulting in duplicated data:
```
In [1]: import pandas as pd
        categorical_index = pd.CategoricalIndex(['bar', 'foo', 'bar', 'foo'], ['bar', 'foo'])
        s = pd.Series(range(4), index=categorical_index)

In [2]: s
Out[2]: bar    0
        foo    1
        bar    2
        foo    3
        dtype: int64

In [3]: s.reindex(categorical_index.as_ordered())
Out[3]: bar    0
        bar    2
        foo    1
        foo    3
        bar    0
        bar    2
        foo    1
        foo    3
        dtype: int64
```

This PR removes the extraneous type check and adds tests checking that an exception is thrown for non-unique target indexes, regardless of type.

- [ ] closes #21809
- [x] tests added / passed
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [x] whatsnew entry


Labels:
name: Bug
name: Indexing
description: Related to indexing on series/frames, not to indexes themselves
name: Categorical
description: Categorical Data Type

Comments:
Hello @qwhelan! Thanks for updating the PR.

 - There are no PEP8 issues in the file [`pandas/core/indexes/category.py`](https://github.com/qwhelan/pandas/blob/6450827831a06f1d67ba9b9a6a8b2d3d7c03778b/pandas/core/indexes/category.py) !

 - There are no PEP8 issues in the file [`pandas/tests/frame/test_analytics.py`](https://github.com/qwhelan/pandas/blob/6450827831a06f1d67ba9b9a6a8b2d3d7c03778b/pandas/tests/frame/test_analytics.py) !

 - There are no PEP8 issues in the file [`pandas/tests/indexes/test_category.py`](https://github.com/qwhelan/pandas/blob/6450827831a06f1d67ba9b9a6a8b2d3d7c03778b/pandas/tests/indexes/test_category.py) !



##### Comment last updated on November 28, 2018 at 22:26 Hours UTC
# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/23963?src=pr&el=h1) Report
> :exclamation: No coverage uploaded for pull request base (`master@6dd130a`). [Click here to learn what that means](https://docs.codecov.io/docs/error-reference#section-missing-base-commit).
> The diff coverage is `100%`.

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

```diff
@@            Coverage Diff            @@
##             master   #23963   +/-   ##
=========================================
  Coverage          ?    92.3%           
=========================================
  Files             ?      161           
  Lines             ?    51558           
  Branches          ?        0           
=========================================
  Hits              ?    47592           
  Misses            ?     3966           
  Partials          ?        0
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `90.7% <100%> (?)` | |
| #single | `42.43% <57.14%> (?)` | |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/23963?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/core/indexes/category.py](https://codecov.io/gh/pandas-dev/pandas/pull/23963/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvaW5kZXhlcy9jYXRlZ29yeS5weQ==) | `97.88% <100%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/23963?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/23963?src=pr&el=footer). Last update [6dd130a...9550880](https://codecov.io/gh/pandas-dev/pandas/pull/23963?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

@jreback I stumbled across this bug while writing some `asv` benchmarks and only noticed #21809 after opening this PR, so it ended up being a few more lines to handle the `df.round()` case.

As we're now raising on non-unique `CategoricalIndex`es, we need to whitelist non-unique `target`s that are also the current index to allow `df.round()` to run. As the construction of the result involves a `.reindex()` call, we'd otherwise get `ValueError`s when calling `df.round()` on a non-uniquely indexed DataFrame.

This is already done in `Index.reindex()`, so this whitelisting is bringing `CategoricalIndex` back in line with the base implementation.
Additionally, this is the fixed output from #21809:
```
print(dfb.round(3))
         a      b      c
low  0.087  0.230  0.411
low  0.311  0.566  0.545
low  0.807  0.918  0.522
hi   0.425  0.072  0.899
hi   0.421  0.582  0.214
hi   0.447  0.468  0.101
```
@jreback Changes implemented, the one failing test is a flaky hypothesis failure in an unrelated file.
@jreback Green other than the unrelated flaky test
thanks @qwhelan