Repository: pandas-dev/pandas

Issue:
Index(data=..., dtype=CategoricalDtype(...)) doesn't maintain dtype
#### Code Sample, a copy-pastable example if possible

```pythonc
>>> c = pd.api.types.CategoricalDtype(categories=['German', 'English', 'French'],
...                                   ordered=True)
>>> pd.Index(['German', 'English', 'French'], dtype=c)
CategoricalIndex(['German', 'English', 'French'],
                 categories=['English', 'French', 'German'],
                 ordered=False, dtype='category')
```
#### Problem description

Notice that the index isn't ordered and the categories have changed location.

If construction goes through CategoricalIndex, everything is ok.

#### Expected Output

Expected output is ``CategoricalIndex(['German', 'English', 'French'], categories=['German', 'English', 'French'], ordered=True)``.

#### Output of ``pd.show_versions()``

<details>

INSTALLED VERSIONS
------------------
commit: None
python: 3.6.3.final.0
python-bits: 32
OS: Windows
OS-release: 10
machine: AMD64
processor: Intel64 Family 6 Model 78 Stepping 3, GenuineIntel
byteorder: little
LC_ALL: None
LANG: None
LOCALE: None.None

pandas: 0.21.1
pytest: 3.2.1
pip: 9.0.1
setuptools: 36.5.0.post20170922
Cython: 0.26.1
numpy: 1.11.3
scipy: 1.0.0
pyarrow: None
xarray: None
IPython: 6.1.0
sphinx: 1.6.5
patsy: None
dateutil: 2.6.1
pytz: 2017.2
blosc: None
bottleneck: None
tables: None
numexpr: None
feather: None
matplotlib: 2.1.0
openpyxl: 2.4.8
xlrd: None
xlwt: None
xlsxwriter: None
lxml: None
bs4: None
html5lib: 1.0.1
sqlalchemy: None
pymysql: None
psycopg2: None
jinja2: 2.9.6
s3fs: None
fastparquet: None
pandas_gbq: None
pandas_datareader: None
</details>



Discussion:
thought we had an issue for this one, ok, IIRC cc @jschendel @jorisvandenbossche @TomAugspurger 
 discussed this on the last Cat PR.
My previous PR's related to CDT were in the context of `.astype(CDT)`, so this case wasn't something that was covered.  Fix looks super simple though, `dtype` just isn't being passed through to the CI constructor here:

https://github.com/pandas-dev/pandas/blob/04beec77e5a713dd90ba31dcf7ad43fd64ac55bb/pandas/core/indexes/base.py#L198-L200

Will open a PR to fix it later today.
Could you maybe also do the same for ``IntervalIndex``? That is, if the dtype is a ``pd.api.types.IntervalDtype``, the constructor should be passed to ``IntervalIndex``. (this doesn't do anything useful ATM, but as a principle (IMO) if ``dtype=IntervalDtype()`` should delegate to ``IntervalIndex``.

This should only be 2 lines more....
> Could you maybe also do the same for IntervalIndex?

FWIW, I'm thinking through this type of issue with https://github.com/pandas-dev/pandas/issues/18767

I'd recommend avoiding more

```
if isinstance(foo, extension_type_1): ...
elif isinstance(foo, extension_type_2): ...
```

blocks for now.
> I'd recommend avoiding more blocks for now

The block is actually already there, so it's really just a matter of passing `dtype` through to the `IntervalIndex` constructor.  Won't do anything right now, as the `IntervalIndex` constructor accepts a `dtype` kwarg, but never actually uses it.

Planning to open an issue in the near future to allow subtype conversion for `IntervalIndex`, e.g. converting `interval[int64]` to `interval[float64]`, which currently isn't possible via the constructor or `astype`.  I believe this same issue would come into play then, so it'd need to be addressed at some point in the near term.  Can do it in this PR or later, doesn't really matter to me.
> The block is actually already there, so it's really just a matter of passing dtype through to the IntervalIndex constructor

👍 then.
Great, thanks.

FYI, my use case is combining several series of the same dtype, and there may be several such groups. If I can pre-register the dtype, I can covert to the result index simply by ``Index(..., dtype=my_type)``, while if I explicitly have to supply ``CategoricalIndex``, ``IntervalIndex`` also, it gets more complicated to do this kind of thing.



Resolving patch:
diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py
--- a/pandas/core/indexes/base.py
+++ b/pandas/core/indexes/base.py
@@ -197,13 +197,13 @@ def __new__(cls, data=None, dtype=None, copy=False, name=None,
         # categorical
         if is_categorical_dtype(data) or is_categorical_dtype(dtype):
             from .category import CategoricalIndex
-            return CategoricalIndex(data, copy=copy, name=name, **kwargs)
+            return CategoricalIndex(data, dtype=dtype, copy=copy, name=name,
+                                    **kwargs)
 
         # interval
-        if is_interval_dtype(data):
+        if is_interval_dtype(data) or is_interval_dtype(dtype):
             from .interval import IntervalIndex
-            return IntervalIndex.from_intervals(data, name=name,
-                                                copy=copy)
+            return IntervalIndex(data, dtype=dtype, name=name, copy=copy)
 
         # index-like
         elif isinstance(data, (np.ndarray, Index, ABCSeries)):


Test patch:
diff --git a/pandas/tests/indexes/test_category.py b/pandas/tests/indexes/test_category.py
--- a/pandas/tests/indexes/test_category.py
+++ b/pandas/tests/indexes/test_category.py
@@ -137,18 +137,27 @@ def test_construction_with_categorical_dtype(self):
         data, cats, ordered = 'a a b b'.split(), 'c b a'.split(), True
         dtype = CategoricalDtype(categories=cats, ordered=ordered)
 
-        result = pd.CategoricalIndex(data, dtype=dtype)
-        expected = pd.CategoricalIndex(data, categories=cats,
-                                       ordered=ordered)
+        result = CategoricalIndex(data, dtype=dtype)
+        expected = CategoricalIndex(data, categories=cats, ordered=ordered)
         tm.assert_index_equal(result, expected, exact=True)
 
-        # error to combine categories or ordered and dtype keywords args
-        with pytest.raises(ValueError, match="Cannot specify both `dtype` and "
-                                             "`categories` or `ordered`."):
-            pd.CategoricalIndex(data, categories=cats, dtype=dtype)
-        with pytest.raises(ValueError, match="Cannot specify both `dtype` and "
-                                             "`categories` or `ordered`."):
-            pd.CategoricalIndex(data, ordered=ordered, dtype=dtype)
+        # GH 19032
+        result = Index(data, dtype=dtype)
+        tm.assert_index_equal(result, expected, exact=True)
+
+        # error when combining categories/ordered and dtype kwargs
+        msg = 'Cannot specify both `dtype` and `categories` or `ordered`.'
+        with pytest.raises(ValueError, match=msg):
+            CategoricalIndex(data, categories=cats, dtype=dtype)
+
+        with pytest.raises(ValueError, match=msg):
+            Index(data, categories=cats, dtype=dtype)
+
+        with pytest.raises(ValueError, match=msg):
+            CategoricalIndex(data, ordered=ordered, dtype=dtype)
+
+        with pytest.raises(ValueError, match=msg):
+            Index(data, ordered=ordered, dtype=dtype)
 
     def test_create_categorical(self):
         # https://github.com/pandas-dev/pandas/pull/17513