Repository: pandas-dev/pandas

Issue:
API: Categorical constructor shouldn't accept scalar for categories
#### Code Sample, a copy-pastable example if possible

I was surprised to find that `Categorical` accepts scalars for `categories`.

```python
In [1]: import pandas as pd
In [2]: pd.Categorical([1, 2], categories=2)
Out[2]:
[NaN, 2.0]
Categories (1, int64): [2]
```

AFAICT, this isn't documented, though we explicitly test it [here](https://github.com/pandas-dev/pandas/blob/8daf9a7e45344dc5a247410e037dccb41b97a3db/pandas/tests/test_categorical.py#L252). Am I missing a use-case where this is desirable, or should we just depreciate it and simplify the constructor?

Anyone want to guess what the categories are on `pd.Categorical(['a', 'b'], categories='abcd')` :)

cc @janschulz 


Discussion:
we generally do this, iow, accept scalars in list-like fields. So ok with this (also ok is to raise a ValueError). Maybe that would be better.
Not sure, I tried to find out if I wrote a message but it's all part of a squashed commit (https://github.com/pandas-dev/pandas/commit/0165d1421dcb76351a99f8ef8bdff59c365b43ad), and none of the preserved comit messages show anything about it :-/ I think @jreback explaination is correct: it uses `levels = _convert_to_list_like(levels)`, so it's the same logic as elsewhere...
I would just raise an error on this, no reason to allow it IMO (and I would just regard it as a bug fix without deprecation, or would there be people doing this?)

Resolving patch:
diff --git a/pandas/core/categorical.py b/pandas/core/categorical.py
--- a/pandas/core/categorical.py
+++ b/pandas/core/categorical.py
@@ -533,6 +533,9 @@ def _validate_categories(cls, categories, fastpath=False):
         if not isinstance(categories, ABCIndexClass):
             dtype = None
             if not hasattr(categories, "dtype"):
+                if not is_list_like(categories):
+                    raise TypeError("`categories` must be list-like. "
+                                    "Got {} instead".format(repr(categories)))
                 categories = _convert_to_list_like(categories)
                 # On categories with NaNs, int values would be converted to
                 # float. Use "object" dtype to prevent this.


Test patch:
diff --git a/pandas/tests/test_categorical.py b/pandas/tests/test_categorical.py
--- a/pandas/tests/test_categorical.py
+++ b/pandas/tests/test_categorical.py
@@ -256,12 +256,6 @@ def f():
         assert len(cat.codes) == 1
         assert cat.codes[0] == 0
 
-        cat = pd.Categorical([1], categories=1)
-        assert len(cat.categories) == 1
-        assert cat.categories[0] == 1
-        assert len(cat.codes) == 1
-        assert cat.codes[0] == 0
-
         # Catch old style constructor useage: two arrays, codes + categories
         # We can only catch two cases:
         #  - when the first is an integer dtype and the second is not
@@ -285,6 +279,11 @@ def f():
             c = Categorical(np.array([], dtype='int64'),  # noqa
                             categories=[3, 2, 1], ordered=True)
 
+    def test_constructor_not_sequence(self):
+        # https://github.com/pandas-dev/pandas/issues/16022
+        with pytest.raises(TypeError):
+            Categorical(['a', 'b'], categories='a')
+
     def test_constructor_with_null(self):
 
         # Cannot have NaN in categories