Repository: pandas-dev/pandas

Issue:
ENH: Improve error message when using DataFrame.from_items instead of DataFrame.from_records
User reported from an early version of pandas, but this is still present in master:

```
import pandas

counters = [
    ('a', 98172247543414),
    ('b', 7805009),
    ('c', 1172983),
    ]

df = pandas.DataFrame.from_items(counters)


# Traceback (most recent call last):                                                                                                                
#   File "/home/user/ptest.py", line 12, in <module>                                                                                               
#     df = pandas.DataFrame.from_items(counters)                                                                                                    
#   File "/usr/local/lib/python2.7/dist-packages/pandas-0.13.1-py2.7-linux-x86_64.egg/pandas/core/frame.py", line 932, in from_items                
#   File "/usr/local/lib/python2.7/dist-packages/pandas-0.13.1-py2.7-linux-x86_64.egg/pandas/core/frame.py", line 947, in _from_arrays              
#   File "/usr/local/lib/python2.7/dist-packages/pandas-0.13.1-py2.7-linux-x86_64.egg/pandas/core/frame.py", line 4463, in _arrays_to_mgr           
#   File "/usr/local/lib/python2.7/dist-packages/pandas-0.13.1-py2.7-linux-x86_64.egg/pandas/core/frame.py", line 4502, in extract_index            
# ValueError: If using all scalar values, you must must pass an index  
```


Discussion:
xref #4916 - not sure there are many usecases left where `from_items` is needed, possibly could be deprecated in favor of `pd.DataFrame(dict(items))`  (that's what I personally use)
@chris-b1 can you open an issue for the deprecation.
I've been looking at this issue and the problem seems to be that the value in each (key, value) pair should be an array or a Series as noted in the ``from_items`` docstring. Would it make sense to raise a ValueError with this message if the user passes a scalar instead of an array or Series as a value?
The problem is the user passed a dict, with keys that are all scalars; *maybe* meant to use a Series (or of course meant to pass values that are array-like)

```
In [6]: Series(dict(counters))
Out[6]: 
a    98172247543414
b           7805009
c           1172983
dtype: int64
```

I suppose the error message could be improved 


Resolving patch:
diff --git a/pandas/core/frame.py b/pandas/core/frame.py
--- a/pandas/core/frame.py
+++ b/pandas/core/frame.py
@@ -54,6 +54,7 @@
     _ensure_int64,
     _ensure_platform_int,
     is_list_like,
+    is_nested_list_like,
     is_iterator,
     is_sequence,
     is_named_tuple)
@@ -1271,16 +1272,34 @@ def from_items(cls, items, columns=None, orient='columns'):
                 columns = _ensure_index(keys)
                 arrays = values
 
-            return cls._from_arrays(arrays, columns, None)
+            # GH 17312
+            # Provide more informative error msg when scalar values passed
+            try:
+                return cls._from_arrays(arrays, columns, None)
+
+            except ValueError:
+                if not is_nested_list_like(values):
+                    raise ValueError('The value in each (key, value) pair '
+                                     'must be an array, Series, or dict')
+
         elif orient == 'index':
             if columns is None:
                 raise TypeError("Must pass columns with orient='index'")
 
             keys = _ensure_index(keys)
 
-            arr = np.array(values, dtype=object).T
-            data = [lib.maybe_convert_objects(v) for v in arr]
-            return cls._from_arrays(data, columns, keys)
+            # GH 17312
+            # Provide more informative error msg when scalar values passed
+            try:
+                arr = np.array(values, dtype=object).T
+                data = [lib.maybe_convert_objects(v) for v in arr]
+                return cls._from_arrays(data, columns, keys)
+
+            except TypeError:
+                if not is_nested_list_like(values):
+                    raise ValueError('The value in each (key, value) pair '
+                                     'must be an array, Series, or dict')
+
         else:  # pragma: no cover
             raise ValueError("'orient' must be either 'columns' or 'index'")
 


Test patch:
diff --git a/pandas/tests/frame/test_constructors.py b/pandas/tests/frame/test_constructors.py
--- a/pandas/tests/frame/test_constructors.py
+++ b/pandas/tests/frame/test_constructors.py
@@ -268,13 +268,14 @@ def test_constructor_dict(self):
 
         # GH10856
         # dict with scalar values should raise error, even if columns passed
-        with pytest.raises(ValueError):
+        msg = 'If using all scalar values, you must pass an index'
+        with tm.assert_raises_regex(ValueError, msg):
             DataFrame({'a': 0.7})
 
-        with pytest.raises(ValueError):
+        with tm.assert_raises_regex(ValueError, msg):
             DataFrame({'a': 0.7}, columns=['a'])
 
-        with pytest.raises(ValueError):
+        with tm.assert_raises_regex(ValueError, msg):
             DataFrame({'a': 0.7}, columns=['b'])
 
     def test_constructor_multi_index(self):
@@ -1204,6 +1205,19 @@ def test_constructor_from_items(self):
                        columns=['one', 'two', 'three'])
         tm.assert_frame_equal(rs, xp)
 
+    def test_constructor_from_items_scalars(self):
+        # GH 17312
+        with tm.assert_raises_regex(ValueError,
+                                    'The value in each \(key, value\) '
+                                    'pair must be an array, Series, or dict'):
+            DataFrame.from_items([('A', 1), ('B', 4)])
+
+        with tm.assert_raises_regex(ValueError,
+                                    'The value in each \(key, value\) '
+                                    'pair must be an array, Series, or dict'):
+            DataFrame.from_items([('A', 1), ('B', 2)], columns=['col1'],
+                                 orient='index')
+
     def test_constructor_mix_series_nonseries(self):
         df = DataFrame({'A': self.frame['A'],
                         'B': list(self.frame['B'])}, columns=['A', 'B'])