Skip to content

Commit 28c2b86

Browse files
committed
BUG: Exception when frame constructed from dict of iterators
1 parent 4e4f5bd commit 28c2b86

File tree

5 files changed

+41
-9
lines changed

5 files changed

+41
-9
lines changed

doc/source/whatsnew/v0.25.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,7 @@ Reshaping
415415
- 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`)
416416
- Bug in :func:`concat` where the resulting ``freq`` of two :class:`DatetimeIndex` with the same ``freq`` would be dropped (:issue:`3232`).
417417
- Bug in :func:`merge` where merging with equivalent Categorical dtypes was raising an error (:issue:`22501`)
418+
- 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`).
418419
- bug in :class:`DataFrame` instantiating with a ``range`` (e.g. ``pd.DataFrame(range(3))``) raised an error (:issue:`26342`).
419420
- Bug in :class:`DataFrame` constructor when passing non-empty tuples would cause a segmentation fault (:issue:`25691`)
420421
- 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 = {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

+6-9
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""
22
Data structure for 1-dimensional cross-sectional and time series data
33
"""
4-
from collections import OrderedDict, abc
4+
from collections import OrderedDict
55
from io import StringIO
66
from shutil import get_terminal_size
77
from textwrap import dedent
@@ -219,15 +219,12 @@ 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.
223-
elif (isinstance(data, abc.Iterable) and
224-
not isinstance(data, abc.Sized)):
225-
data = list(data)
226-
else:
227-
222+
elif isinstance(data, ABCSparseArray):
228223
# handle sparse passed here (and force conversion)
229-
if isinstance(data, ABCSparseArray):
230-
data = data.to_dense()
224+
data = data.to_dense()
225+
else:
226+
# If data is Iterable but not list-like, consume into list.
227+
data = com.maybe_itarable_to_list(data)
231228

232229
if index is None:
233230
if not is_list_like(data):

pandas/tests/frame/test_constructors.py

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

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

0 commit comments

Comments
 (0)