Skip to content

Commit

Permalink
BUG: Fix Index construction when given empty generator (#21470). (#21481
Browse files Browse the repository at this point in the history
)

(cherry picked from commit 076635a)
  • Loading branch information
Liam3851 authored and jorisvandenbossche committed Jul 2, 2018
1 parent 76551c2 commit eb6f368
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 16 deletions.
3 changes: 2 additions & 1 deletion doc/source/whatsnew/v0.23.2.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@ Bug Fixes

**Conversion**

- Bug in constructing :class:`Index` with an iterator or generator (:issue:`21470`)
- Bug in :meth:`Series.nlargest` for signed and unsigned integer dtypes when the minimum value is present (:issue:`21426`)
-


**Indexing**

Expand Down
5 changes: 2 additions & 3 deletions pandas/core/arrays/categorical.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import numpy as np
from warnings import warn
import textwrap
import types

from pandas import compat
from pandas.compat import u, lzip
Expand All @@ -28,7 +27,7 @@
is_categorical,
is_categorical_dtype,
is_list_like, is_sequence,
is_scalar,
is_scalar, is_iterator,
is_dict_like)

from pandas.core.algorithms import factorize, take_1d, unique1d, take
Expand Down Expand Up @@ -2473,7 +2472,7 @@ def _convert_to_list_like(list_like):
if isinstance(list_like, list):
return list_like
if (is_sequence(list_like) or isinstance(list_like, tuple) or
isinstance(list_like, types.GeneratorType)):
is_iterator(list_like)):
return list(list_like)
elif is_scalar(list_like):
return [list_like]
Expand Down
10 changes: 6 additions & 4 deletions pandas/core/indexes/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -436,12 +436,14 @@ def __new__(cls, data=None, dtype=None, copy=False, name=None,
elif data is None or is_scalar(data):
cls._scalar_data_error(data)
else:
if tupleize_cols and is_list_like(data) and data:
if tupleize_cols and is_list_like(data):
# GH21470: convert iterable to list before determining if empty
if is_iterator(data):
data = list(data)
# we must be all tuples, otherwise don't construct
# 10697
if all(isinstance(e, tuple) for e in data):

if data and all(isinstance(e, tuple) for e in data):
# we must be all tuples, otherwise don't construct
# 10697
from .multi import MultiIndex
return MultiIndex.from_tuples(
data, names=name or kwargs.get('names'))
Expand Down
19 changes: 11 additions & 8 deletions pandas/tests/indexes/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -419,21 +419,24 @@ def test_constructor_dtypes_timedelta(self, attr, klass):
result = klass(list(values), dtype=dtype)
tm.assert_index_equal(result, index)

def test_constructor_empty_gen(self):
skip_index_keys = ["repeats", "periodIndex", "rangeIndex",
"tuples"]
for key, index in self.generate_index_types(skip_index_keys):
empty = index.__class__([])
assert isinstance(empty, index.__class__)
assert not len(empty)
@pytest.mark.parametrize("value", [[], iter([]), (x for x in [])])
@pytest.mark.parametrize("klass",
[Index, Float64Index, Int64Index, UInt64Index,
CategoricalIndex, DatetimeIndex, TimedeltaIndex])
def test_constructor_empty(self, value, klass):
empty = klass(value)
assert isinstance(empty, klass)
assert not len(empty)

@pytest.mark.parametrize("empty,klass", [
(PeriodIndex([], freq='B'), PeriodIndex),
(PeriodIndex(iter([]), freq='B'), PeriodIndex),
(PeriodIndex((x for x in []), freq='B'), PeriodIndex),
(RangeIndex(step=1), pd.RangeIndex),
(MultiIndex(levels=[[1, 2], ['blue', 'red']],
labels=[[], []]), MultiIndex)
])
def test_constructor_empty(self, empty, klass):
def test_constructor_empty_special(self, empty, klass):
assert isinstance(empty, klass)
assert not len(empty)

Expand Down

0 comments on commit eb6f368

Please sign in to comment.