Skip to content

Commit 071c819

Browse files
committed
BUG: Creating Index with the names argument
1 parent c271d4d commit 071c819

File tree

2 files changed

+49
-7
lines changed

2 files changed

+49
-7
lines changed

pandas/core/indexes/base.py

+25-7
Original file line numberDiff line numberDiff line change
@@ -113,14 +113,18 @@ class Index(IndexOpsMixin, PandasObject):
113113
dtype : NumPy dtype (default: object)
114114
copy : bool
115115
Make a copy of input ndarray
116-
name : object
116+
name : object, optional
117117
Name to be stored in the index
118+
names : sequence of objects, optional
119+
Names for the index levels
118120
tupleize_cols : bool (default: True)
119121
When True, attempt to create a MultiIndex if possible
120122
121123
Notes
122124
-----
123-
An Index instance can **only** contain hashable objects
125+
An Index instance can **only** contain hashable objects.
126+
127+
Only one of `name` and `names` can be specified at the same time.
124128
125129
Examples
126130
--------
@@ -176,10 +180,25 @@ class Index(IndexOpsMixin, PandasObject):
176180
str = CachedAccessor("str", StringMethods)
177181

178182
def __new__(cls, data=None, dtype=None, copy=False, name=None,
179-
fastpath=False, tupleize_cols=True, **kwargs):
183+
fastpath=False, tupleize_cols=True, names=None,
184+
**kwargs):
185+
186+
# The main purpose of `names` is to use it with a `MultiIndex`.
187+
# Although for consistency it's also used to retrieve `name` for a
188+
# one-level indices if `name` is not provided (see GH 19082).
189+
190+
if names is not None and name is not None:
191+
raise TypeError("Can provide only one of names and name arguments")
192+
193+
if names is not None and not is_list_like(names):
194+
raise TypeError("names must be list-like")
180195

181-
if name is None and hasattr(data, 'name'):
182-
name = data.name
196+
if name is None:
197+
if hasattr(data, 'name'):
198+
name = data.name
199+
# extract `name` from `names` in case MultiIndex cannot be created
200+
elif names:
201+
name = names[0]
183202

184203
if fastpath:
185204
return cls._simple_new(data, name)
@@ -358,8 +377,7 @@ def __new__(cls, data=None, dtype=None, copy=False, name=None,
358377
# 10697
359378
if all(isinstance(e, tuple) for e in data):
360379
from .multi import MultiIndex
361-
return MultiIndex.from_tuples(
362-
data, names=name or kwargs.get('names'))
380+
return MultiIndex.from_tuples(data, names=names or name)
363381
# other iterable of some kind
364382
subarr = _asarray_tuplesafe(data, dtype=object)
365383
return Index(subarr, dtype=dtype, copy=copy, name=name, **kwargs)

pandas/tests/indexes/test_base.py

+24
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,30 @@ def test_constructor_simple_new(self):
305305
result = idx._simple_new(idx, 'obj')
306306
tm.assert_index_equal(result, idx)
307307

308+
def test_constructor_names(self):
309+
# test both `name` and `names` provided
310+
with pytest.raises(TypeError):
311+
idx = Index([1, 2, 3], name='a', names=('a',))
312+
313+
# test non-list-like `names`
314+
with pytest.raises(TypeError):
315+
idx = Index([1, 2, 3], names='a')
316+
317+
# test using `name` for a flat `Index`
318+
idx = Index([1, 2, 3], name='a')
319+
assert idx.name == 'a'
320+
assert idx.names == ('a',)
321+
322+
# test using `names` for a flat `Index`
323+
idx = Index([1, 2, 3], names=('a',))
324+
assert idx.name == 'a'
325+
assert idx.names == ('a',)
326+
327+
# test using `names` for `MultiIndex` creation
328+
idx = Index([('A', 1), ('A', 2)], names=('a', 'b'))
329+
midx = MultiIndex.from_tuples([('A', 1), ('A', 2)], names=('a', 'b'))
330+
tm.assert_index_equal(idx, midx, check_names=True)
331+
308332
def test_constructor_dtypes(self):
309333

310334
for idx in [Index(np.array([1, 2, 3], dtype=int)),

0 commit comments

Comments
 (0)