# -*- coding: utf-8 -*- import pytest import pandas as pd from pandas import MultiIndex import pandas.util.testing as tm def check_level_names(index, names): assert [level.name for level in index.levels] == list(names) def test_slice_keep_name(): x = MultiIndex.from_tuples([('a', 'b'), (1, 2), ('c', 'd')], names=['x', 'y']) assert x[1:].names == x.names def test_index_name_retained(): # GH9857 result = pd.DataFrame({'x': [1, 2, 6], 'y': [2, 2, 8], 'z': [-5, 0, 5]}) result = result.set_index('z') result.loc[10] = [9, 10] df_expected = pd.DataFrame({'x': [1, 2, 6, 9], 'y': [2, 2, 8, 10], 'z': [-5, 0, 5, 10]}) df_expected = df_expected.set_index('z') tm.assert_frame_equal(result, df_expected) def test_changing_names(idx): # names should be applied to levels level_names = [level.name for level in idx.levels] check_level_names(idx, idx.names) view = idx.view() copy = idx.copy() shallow_copy = idx._shallow_copy() # changing names should change level names on object new_names = [name + "a" for name in idx.names] idx.names = new_names check_level_names(idx, new_names) # but not on copies check_level_names(view, level_names) check_level_names(copy, level_names) check_level_names(shallow_copy, level_names) # and copies shouldn't change original shallow_copy.names = [name + "c" for name in shallow_copy.names] check_level_names(idx, new_names) def test_take_preserve_name(idx): taken = idx.take([3, 0, 1]) assert taken.names == idx.names def test_copy_names(): # Check that adding a "names" parameter to the copy is honored # GH14302 multi_idx = pd.Index([(1, 2), (3, 4)], names=['MyName1', 'MyName2']) multi_idx1 = multi_idx.copy() assert multi_idx.equals(multi_idx1) assert multi_idx.names == ['MyName1', 'MyName2'] assert multi_idx1.names == ['MyName1', 'MyName2'] multi_idx2 = multi_idx.copy(names=['NewName1', 'NewName2']) assert multi_idx.equals(multi_idx2) assert multi_idx.names == ['MyName1', 'MyName2'] assert multi_idx2.names == ['NewName1', 'NewName2'] multi_idx3 = multi_idx.copy(name=['NewName1', 'NewName2']) assert multi_idx.equals(multi_idx3) assert multi_idx.names == ['MyName1', 'MyName2'] assert multi_idx3.names == ['NewName1', 'NewName2'] def test_names(idx, index_names): # names are assigned in setup names = index_names level_names = [level.name for level in idx.levels] assert names == level_names # setting bad names on existing index = idx with pytest.raises(ValueError, match="^Length of names"): setattr(index, "names", list(index.names) + ["third"]) with pytest.raises(ValueError, match="^Length of names"): setattr(index, "names", []) # initializing with bad names (should always be equivalent) major_axis, minor_axis = idx.levels major_codes, minor_codes = idx.codes with pytest.raises(ValueError, match="^Length of names"): MultiIndex(levels=[major_axis, minor_axis], codes=[major_codes, minor_codes], names=['first']) with pytest.raises(ValueError, match="^Length of names"): MultiIndex(levels=[major_axis, minor_axis], codes=[major_codes, minor_codes], names=['first', 'second', 'third']) # names are assigned index.names = ["a", "b"] ind_names = list(index.names) level_names = [level.name for level in index.levels] assert ind_names == level_names def test_duplicate_level_names_access_raises(idx): # GH19029 idx.names = ['foo', 'foo'] with pytest.raises(ValueError, match='name foo occurs multiple times'): idx._get_level_number('foo')