diff --git a/doc/source/whatsnew/v0.17.0.txt b/doc/source/whatsnew/v0.17.0.txt index aa8241e3cc272..c97f143cb63c2 100644 --- a/doc/source/whatsnew/v0.17.0.txt +++ b/doc/source/whatsnew/v0.17.0.txt @@ -367,7 +367,7 @@ Bug Fixes - Bug in ``Index.drop_duplicates`` dropping name(s) (:issue:`10115`) - Bug in ``pd.Series`` when setting a value on an empty ``Series`` whose index has a frequency. (:issue:`10193`) - Bug in ``DataFrame.plot`` raises ``ValueError`` when color name is specified by multiple characters (:issue:`10387`) - +- Bug in ``Index`` construction with a mixed list of tuples (:issue:`10697`) - Bug in ``DataFrame.reset_index`` when index contains `NaT`. (:issue:`10388`) - Bug in ``ExcelReader`` when worksheet is empty (:issue:`6403`) - Bug in ``Table.select_column`` where name is not preserved (:issue:`10392`) diff --git a/pandas/core/index.py b/pandas/core/index.py index ea9d1f38b92c1..ce6c60df2fd94 100644 --- a/pandas/core/index.py +++ b/pandas/core/index.py @@ -164,16 +164,21 @@ def __new__(cls, data=None, dtype=None, copy=False, name=None, fastpath=False, cls._scalar_data_error(data) else: if tupleize_cols and isinstance(data, list) and data and isinstance(data[0], tuple): - try: - # must be orderable in py3 - if compat.PY3: - sorted(data) - return MultiIndex.from_tuples( - data, names=name or kwargs.get('names')) - except (TypeError, KeyError): - # python2 - MultiIndex fails on mixed types - pass + # we must be all tuples, otherwise don't construct + # 10697 + if all( isinstance(e, tuple) for e in data ): + + try: + + # must be orderable in py3 + if compat.PY3: + sorted(data) + return MultiIndex.from_tuples( + data, names=name or kwargs.get('names')) + except (TypeError, KeyError): + # python2 - MultiIndex fails on mixed types + pass # other iterable of some kind subarr = com._asarray_tuplesafe(data, dtype=object) diff --git a/pandas/tests/test_index.py b/pandas/tests/test_index.py index 87e06bad7fbe1..2699e780f0edb 100644 --- a/pandas/tests/test_index.py +++ b/pandas/tests/test_index.py @@ -553,6 +553,15 @@ def test_constructor_corner(self): # corner case self.assertRaises(TypeError, Index, 0) + def test_consruction_list_mixed_tuples(self): + # 10697 + # if we are constructing from a mixed list of tuples, make sure that we + # are independent of the sorting order + idx1 = Index([('A',1),'B']) + self.assertIsInstance(idx1, Index) and self.assertNotInstance(idx1, MultiIndex) + idx2 = Index(['B',('A',1)]) + self.assertIsInstance(idx2, Index) and self.assertNotInstance(idx2, MultiIndex) + def test_constructor_from_series(self): expected = DatetimeIndex([Timestamp('20110101'),Timestamp('20120101'),Timestamp('20130101')]) diff --git a/pandas/tools/tests/test_merge.py b/pandas/tools/tests/test_merge.py index af2373a72fb9d..8b1457e7fd490 100644 --- a/pandas/tools/tests/test_merge.py +++ b/pandas/tools/tests/test_merge.py @@ -2002,6 +2002,13 @@ def test_dups_index(self): result = df.append(df) assert_frame_equal(result, expected) + def test_with_mixed_tuples(self): + # 10697 + # columns have mixed tuples, so handle properly + df1 = DataFrame({ u'A' : 'foo', (u'B',1) : 'bar' },index=range(2)) + df2 = DataFrame({ u'B' : 'foo', (u'B',1) : 'bar' },index=range(2)) + result = concat([df1,df2]) + def test_join_dups(self): # joining dups