Skip to content

Commit c358e87

Browse files
committed
fixup! API: Have MultiIndex constructors return MI
1 parent 6ed5edd commit c358e87

File tree

8 files changed

+59
-27
lines changed

8 files changed

+59
-27
lines changed

pandas/core/frame.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
standardize_mapping)
6969
from pandas.core.generic import NDFrame, _shared_docs
7070
from pandas.core.index import (Index, MultiIndex, _ensure_index,
71-
_index_from_sequences)
71+
_ensure_index_from_sequences)
7272
from pandas.core.indexing import (maybe_droplevels, convert_to_index_sliceable,
7373
check_bool_indexer)
7474
from pandas.core.internals import (BlockManager,
@@ -1157,8 +1157,8 @@ def from_records(cls, data, index=None, exclude=None, columns=None,
11571157
try:
11581158
to_remove = [arr_columns.get_loc(field) for field in index]
11591159
index_data = [arrays[i] for i in to_remove]
1160-
result_index = _index_from_sequences(index_data,
1161-
names=index)
1160+
result_index = _ensure_index_from_sequences(index_data,
1161+
names=index)
11621162

11631163
exclude.update(index)
11641164
except Exception:
@@ -3001,7 +3001,7 @@ def set_index(self, keys, drop=True, append=False, inplace=False,
30013001
to_remove.append(col)
30023002
arrays.append(level)
30033003

3004-
index = _index_from_sequences(arrays, names)
3004+
index = _ensure_index_from_sequences(arrays, names)
30053005

30063006
if verify_integrity and not index.is_unique:
30073007
duplicates = index.get_duplicates()

pandas/core/indexes/api.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from pandas.core.indexes.base import (Index,
22
_new_Index,
33
_ensure_index,
4-
_index_from_sequences,
4+
_ensure_index_from_sequences,
55
_get_na_value,
66
InvalidIndexError) # noqa
77
from pandas.core.indexes.category import CategoricalIndex # noqa
@@ -25,7 +25,7 @@
2525
'InvalidIndexError', 'TimedeltaIndex',
2626
'PeriodIndex', 'DatetimeIndex',
2727
'_new_Index', 'NaT',
28-
'_ensure_index', '_index_from_sequences', '_get_na_value',
28+
'_ensure_index', '_ensure_index_from_sequences', '_get_na_value',
2929
'_get_combined_index',
3030
'_get_objs_combined_axis', '_union_indexes',
3131
'_get_consensus_names',

pandas/core/indexes/base.py

+40-6
Original file line numberDiff line numberDiff line change
@@ -4012,19 +4012,28 @@ def invalid_op(self, other=None):
40124012
Index._add_comparison_methods()
40134013

40144014

4015-
def _index_from_sequences(sequences, names=None):
4015+
def _ensure_index_from_sequences(sequences, names=None):
40164016
"""Construct an index from sequences of data.
40174017
4018-
A single sequence returns an Index.
4019-
Many sequences returns a MultiIndex.
4018+
A single sequence returns an Index. Many sequences returns a
4019+
MultiIndex.
4020+
4021+
Parameters
4022+
----------
4023+
sequences : sequence of sequences
4024+
names : sequence of str
4025+
4026+
Returns
4027+
-------
4028+
index : Index or MultiIndex
40204029
40214030
Examples
40224031
--------
4023-
4024-
>>> _index_from_sequences([[1, 2, 3]], names=['name'])
4032+
>>> _ensure_index_from_sequences([[1, 2, 3]], names=['name'])
40254033
Int64Index([1, 2, 3], dtype='int64', name='name')
40264034
4027-
>>> _index_from_sequences([['a', 'a'], ['a', 'b']], names=['L1', 'L2'])
4035+
>>> _ensure_index_from_sequences([['a', 'a'], ['a', 'b']],
4036+
names=['L1', 'L2'])
40284037
MultiIndex(levels=[['a'], ['a', 'b']],
40294038
labels=[[0, 0], [0, 1]],
40304039
names=['L1', 'L2'])
@@ -4040,6 +4049,31 @@ def _index_from_sequences(sequences, names=None):
40404049

40414050

40424051
def _ensure_index(index_like, copy=False):
4052+
"""
4053+
Ensure that we have an index from some index-like object
4054+
4055+
Parameters
4056+
----------
4057+
index : sequence
4058+
An Index or other sequence
4059+
copy : bool
4060+
4061+
Returns
4062+
-------
4063+
index : Index or MultiIndex
4064+
4065+
Examples
4066+
--------
4067+
>>> _ensure_index(['a', 'b'])
4068+
Index(['a', 'b'], dtype='object')
4069+
4070+
>>> _ensure_index([('a', 'a'), ('b', 'c')])
4071+
Index([('a', 'a'), ('b', 'c')], dtype='object')
4072+
4073+
>>> _ensure_index([['a', 'a'], ['b', 'c']])
4074+
MultiIndex(levels=[['a'], ['b', 'c']],
4075+
labels=[[0, 0], [0, 1]])
4076+
"""
40434077
if isinstance(index_like, Index):
40444078
if copy:
40454079
index_like = index_like.copy()

pandas/core/reshape/reshape.py

+3
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ def _unstack_multiple(data, clocs):
312312
xnull=False)
313313

314314
if rlocs == []:
315+
# Everything is in clocs, so the dummy df has a regular index
315316
dummy_index = Index(obs_ids, name='__placeholder__')
316317
else:
317318
dummy_index = MultiIndex(levels=rlevels + [obs_ids],
@@ -450,6 +451,8 @@ def _slow_pivot(index, columns, values):
450451
def unstack(obj, level, fill_value=None):
451452
if isinstance(level, (tuple, list)):
452453
if len(level) == 1:
454+
# unstack_multiple only handles MultiIndexes,
455+
# and isn't needed for a single level
453456
level = level[0]
454457
else:
455458
return _unstack_multiple(obj, level)

pandas/core/strings.py

+2
Original file line numberDiff line numberDiff line change
@@ -1454,6 +1454,8 @@ def cons_row(x):
14541454
result = list(result)
14551455
out = MultiIndex.from_tuples(result, names=name)
14561456
if out.nlevels == 1:
1457+
# We had all tuples of length-one, which are
1458+
# better represented as a regular Index.
14571459
out = out.get_level_values(0)
14581460
return out
14591461
else:

pandas/io/parsers.py

+4-12
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
from pandas.core.dtypes.missing import isna
2525
from pandas.core.dtypes.cast import astype_nansafe
2626
from pandas.core.index import (Index, MultiIndex, RangeIndex,
27-
_index_from_sequences)
27+
_ensure_index_from_sequences)
2828
from pandas.core.series import Series
2929
from pandas.core.frame import DataFrame
3030
from pandas.core.categorical import Categorical
@@ -1446,15 +1446,7 @@ def _agg_index(self, index, try_parse_dates=True):
14461446
arrays.append(arr)
14471447

14481448
names = self.index_names
1449-
index = _index_from_sequences(arrays, names)
1450-
if len(arrays) > 1:
1451-
index = MultiIndex.from_arrays(arrays, names=self.index_names)
1452-
else:
1453-
if self.index_names is None:
1454-
name = None
1455-
else:
1456-
name = self.index_names[0]
1457-
index = Index(arrays[0], name=name)
1449+
index = _ensure_index_from_sequences(arrays, names)
14581450

14591451
return index
14601452

@@ -1818,7 +1810,7 @@ def read(self, nrows=None):
18181810
try_parse_dates=True)
18191811
arrays.append(values)
18201812

1821-
index = _index_from_sequences(arrays)
1813+
index = _ensure_index_from_sequences(arrays)
18221814

18231815
if self.usecols is not None:
18241816
names = self._filter_usecols(names)
@@ -3149,7 +3141,7 @@ def _get_empty_meta(columns, index_col, index_names, dtype=None):
31493141
index = Index([])
31503142
else:
31513143
data = [Series([], dtype=dtype[name]) for name in index_names]
3152-
index = _index_from_sequences(data, names=index_names)
3144+
index = _ensure_index_from_sequences(data, names=index_names)
31533145
index_col.sort()
31543146
for i, n in enumerate(index_col):
31553147
columns.pop(n - i)

pandas/tests/indexes/test_base.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
DataFrame, Float64Index, Int64Index,
1818
CategoricalIndex, DatetimeIndex, TimedeltaIndex,
1919
PeriodIndex, isna)
20-
from pandas.core.index import _get_combined_index, _index_from_sequences
20+
from pandas.core.index import _get_combined_index, _ensure_index_from_sequences
2121
from pandas.util.testing import assert_almost_equal
2222
from pandas.compat.numpy import np_datetime64_compat
2323

@@ -2125,6 +2125,6 @@ class TestIndexUtils(object):
21252125
MultiIndex([['a'], ['c', 'd']], [[0, 0], [0, 1]],
21262126
names=['L1', 'L2'])),
21272127
])
2128-
def test_index_from_sequences(self, data, names, expected):
2129-
result = _index_from_sequences(data, names)
2128+
def test_ensure_index_from_sequences(self, data, names, expected):
2129+
result = _ensure_index_from_sequences(data, names)
21302130
tm.assert_index_equal(result, expected)

pandas/util/testing.py

+1
Original file line numberDiff line numberDiff line change
@@ -1909,6 +1909,7 @@ def keyfunc(x):
19091909

19101910
# convert tuples to index
19111911
if nentries == 1:
1912+
# we have a single level of tuples, i.e. a regular Index
19121913
index = Index(tuples[0], name=names[0])
19131914
elif nlevels == 1:
19141915
name = None if names is None else names[0]

0 commit comments

Comments
 (0)