Skip to content

Commit 10ab34a

Browse files
committed
BUG: Exception when frame constructed from dict of iterators
1 parent 80bddaf commit 10ab34a

File tree

5 files changed

+40
-6
lines changed

5 files changed

+40
-6
lines changed

doc/source/whatsnew/v0.25.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,7 @@ Reshaping
457457
- Bug in :func:`pivot_table` where columns with ``NaN`` values are dropped even if ``dropna`` argument is ``False``, when the ``aggfunc`` argument contains a ``list`` (:issue:`22159`)
458458
- Bug in :func:`concat` where the resulting ``freq`` of two :class:`DatetimeIndex` with the same ``freq`` would be dropped (:issue:`3232`).
459459
- Bug in :func:`merge` where merging with equivalent Categorical dtypes was raising an error (:issue:`22501`)
460+
- bug in :class:`DataFrame` instantiating with a dict of iterators or generators (e.g. ``pd.DataFrame({'A': reversed(range(3))})``) raised an error (:issue:`26349`).
460461
- bug in :class:`DataFrame` instantiating with a ``range`` (e.g. ``pd.DataFrame(range(3))``) raised an error (:issue:`26342`).
461462
- Bug in :class:`DataFrame` constructor when passing non-empty tuples would cause a segmentation fault (:issue:`25691`)
462463
- Bug in :func:`pandas.cut` where large bins could incorrectly raise an error due to an integer overflow (:issue:`26045`)

pandas/core/common.py

+9
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,15 @@ def maybe_make_list(obj):
289289
return obj
290290

291291

292+
def maybe_itarable_to_list(obj: Any) -> Any:
293+
"""
294+
If obj is Iterable but not list-like, consume into list.
295+
"""
296+
if isinstance(obj, abc.Iterable) and not isinstance(obj, abc.Sized):
297+
return list(obj)
298+
return obj
299+
300+
292301
def is_null_slice(obj):
293302
"""
294303
We have a null slice.

pandas/core/internals/construction.py

+2
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,8 @@ def init_dict(data, index, columns, dtype=None):
195195
arrays.loc[missing] = [val] * missing.sum()
196196

197197
else:
198+
data = OrderedDict((col_name, com.maybe_itarable_to_list(col))
199+
for col_name, col in data.items())
198200
keys = com.dict_keys_to_ordered_list(data)
199201
columns = data_names = Index(keys)
200202
# GH#24096 need copy to be deep for datetime64tz case

pandas/core/series.py

+5-6
Original file line numberDiff line numberDiff line change
@@ -219,15 +219,14 @@ def __init__(self, data=None, index=None, dtype=None, name=None,
219219
elif isinstance(data, (set, frozenset)):
220220
raise TypeError("{0!r} type is unordered"
221221
"".format(data.__class__.__name__))
222-
# If data is Iterable but not list-like, consume into list.
223222
elif (isinstance(data, abc.Iterable) and
224223
not isinstance(data, abc.Sized)):
225-
data = list(data)
226-
else:
227-
224+
data = com.maybe_itarable_to_list(data)
225+
elif isinstance(data, ABCSparseArray):
228226
# handle sparse passed here (and force conversion)
229-
if isinstance(data, ABCSparseArray):
230-
data = data.to_dense()
227+
data = data.to_dense()
228+
else:
229+
pass
231230

232231
if index is None:
233232
if not is_list_like(data):

pandas/tests/frame/test_constructors.py

+23
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,29 @@ def test_constructor_dict_of_tuples(self):
533533
expected = DataFrame({k: list(v) for k, v in data.items()})
534534
tm.assert_frame_equal(result, expected, check_dtype=False)
535535

536+
def test_constructor_dict_of_ranges(self):
537+
data = {'a': range(3), 'b': range(3, 6)}
538+
539+
result = DataFrame(data)
540+
expected = DataFrame({'a': [0, 1, 2], 'b': [3, 4, 5]})
541+
tm.assert_frame_equal(result, expected)
542+
543+
def test_constructor_dict_of_iterators(self):
544+
# GH 26349
545+
data = {'a': iter(range(3)), 'b': reversed(range(3))}
546+
547+
result = DataFrame(data)
548+
expected = DataFrame({'a': [0, 1, 2], 'b': [2, 1, 0]})
549+
tm.assert_frame_equal(result, expected)
550+
551+
def test_constructor_dict_of_generators(self):
552+
# GH 26349
553+
data = {'a': (i for i in (range(3))),
554+
'b': (i for i in reversed(range(3)))}
555+
result = DataFrame(data)
556+
expected = DataFrame({'a': [0, 1, 2], 'b': [2, 1, 0]})
557+
tm.assert_frame_equal(result, expected)
558+
536559
def test_constructor_dict_multiindex(self):
537560
def check(result, expected):
538561
return tm.assert_frame_equal(result, expected, check_dtype=True,

0 commit comments

Comments
 (0)