Repository: pandas-dev/pandas

Issue:
BUG/TST: Allow generators in DataFrame.from_records
With 0.12 and development version it's not possible fo feed a generator to Dataframe.from_records if nrows = None, it leds to a TypeError exception see: http://stackoverflow.com/questions/18915941/create-a-pandas-dataframe-from-generator

It's no clear whats nrows do, it's not documented.

I've create a PR with a simple fix without touch nrows, and two tests for generator data input.



Discussion:

Resolving patch:
diff --git a/pandas/core/frame.py b/pandas/core/frame.py
--- a/pandas/core/frame.py
+++ b/pandas/core/frame.py
@@ -724,12 +724,17 @@ def from_records(cls, data, index=None, exclude=None, columns=None,
 
             values = [first_row]
 
-            i = 1
-            for row in data:
-                values.append(row)
-                i += 1
-                if i >= nrows:
-                    break
+            #if unknown length iterable (generator)
+            if nrows == None:
+                #consume whole generator
+                values += list(data)
+            else:
+                i = 1
+                for row in data:
+                    values.append(row)
+                    i += 1
+                    if i >= nrows:
+                        break
 
             if dtype is not None:
                 data = np.array(values, dtype=dtype)


Test patch:
diff --git a/pandas/tests/test_frame.py b/pandas/tests/test_frame.py
--- a/pandas/tests/test_frame.py
+++ b/pandas/tests/test_frame.py
@@ -3739,6 +3739,36 @@ def test_from_records_iterator(self):
                                     nrows=2)
         assert_frame_equal(df, xp.reindex(columns=['x','y']), check_dtype=False)
 
+    def test_from_records_tuples_generator(self):
+        def tuple_generator(length):
+            for i in range(length):
+                letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+                yield (i, letters[i % len(letters)], i/length)
+        
+        columns_names = ['Integer', 'String', 'Float']
+        columns = [[i[j] for i in tuple_generator(10)] for j in range(len(columns_names))]
+        data = {'Integer': columns[0], 'String': columns[1], 'Float': columns[2]}
+        expected = DataFrame(data, columns=columns_names)
+	
+        generator = tuple_generator(10)
+        result = DataFrame.from_records(generator, columns=columns_names)
+        assert_frame_equal(result, expected)
+    
+    def test_from_records_lists_generator(self):
+        def list_generator(length):
+            for i in range(length):
+                letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+                yield [i, letters[i % len(letters)], i/length]
+        
+        columns_names = ['Integer', 'String', 'Float']
+        columns = [[i[j] for i in list_generator(10)] for j in range(len(columns_names))]
+        data = {'Integer': columns[0], 'String': columns[1], 'Float': columns[2]}
+        expected = DataFrame(data, columns=columns_names)
+        
+        generator = list_generator(10)
+        result = DataFrame.from_records(generator, columns=columns_names)
+        assert_frame_equal(result, expected)
+    
     def test_from_records_columns_not_modified(self):
         tuples = [(1, 2, 3),
                   (1, 2, 3),