From 58b9b055937610b8b95d55425239651888b0ed4c Mon Sep 17 00:00:00 2001 From: Gianluca Rossi Date: Tue, 24 Nov 2015 20:13:17 +0000 Subject: [PATCH] BUG: Index does not copy existing Index or DatatetimeIndex object's name, when a new name is not provided fix missing lines in whatsnew cosmetic change in whatsnew refactor unit test, failing for MultiIndex short sentence in whatsnew doc fix unit test remove commented code fix typo add doc string add unit test for multiindex case --- doc/source/whatsnew/v0.18.0.txt | 2 ++ pandas/core/index.py | 6 ++++++ pandas/tests/test_base.py | 5 ++++- pandas/tests/test_index.py | 27 ++++++++++++++++++++++++++- 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v0.18.0.txt b/doc/source/whatsnew/v0.18.0.txt index 5b8c282d3e4ed..ea5c3b6e4c7d0 100644 --- a/doc/source/whatsnew/v0.18.0.txt +++ b/doc/source/whatsnew/v0.18.0.txt @@ -238,4 +238,6 @@ Bug Fixes - Bug in ``df.replace`` while replacing value in mixed dtype ``Dataframe`` (:issue:`11698`) +- Bug in ``Index`` prevent copying name of passed ``Index`` or ``DatetimeIndex`` objects, when a new name is not provided (:issue:`11193`) + - Bug in ``read_excel`` failing to read any non-empty sheets when empty sheets exist and ``sheetname=None`` (:issue:`11711`) diff --git a/pandas/core/index.py b/pandas/core/index.py index 9b75153d9b84b..6da30ffefb41f 100644 --- a/pandas/core/index.py +++ b/pandas/core/index.py @@ -120,6 +120,9 @@ class Index(IndexOpsMixin, StringAccessorMixin, PandasObject): def __new__(cls, data=None, dtype=None, copy=False, name=None, fastpath=False, tupleize_cols=True, **kwargs): + if name is None and hasattr(data, 'name'): + name = data.name + # no class inference! if fastpath: return cls._simple_new(data, name) @@ -128,6 +131,7 @@ def __new__(cls, data=None, dtype=None, copy=False, name=None, fastpath=False, return CategoricalIndex(data, copy=copy, name=name, **kwargs) if isinstance(data, (np.ndarray, Index, ABCSeries)): + if issubclass(data.dtype.type, np.datetime64) or is_datetimetz(data): from pandas.tseries.index import DatetimeIndex result = DatetimeIndex(data, copy=copy, name=name, **kwargs) @@ -4052,6 +4056,8 @@ def __new__(cls, levels=None, labels=None, sortorder=None, names=None, # compat with Index if name is not None: names = name +# elif cls.names is not None: +# names = cls.names if levels is None or labels is None: raise TypeError("Must pass both levels and labels") if len(levels) != len(labels): diff --git a/pandas/tests/test_base.py b/pandas/tests/test_base.py index 5d959892791fe..db391dca7114c 100644 --- a/pandas/tests/test_base.py +++ b/pandas/tests/test_base.py @@ -415,6 +415,7 @@ def test_value_counts_unique_nunique(self): # resets name from Index expected_index = pd.Index(o[::-1]) + expected_index.name = None # attach name to klass o = o.repeat(range(1, len(o) + 1)) @@ -424,16 +425,18 @@ def test_value_counts_unique_nunique(self): # resets name from Index expected_index = pd.Index(o[::-1]) + expected_index.name = None # attach name to klass o = o.repeat(range(1, len(o) + 1)) o.name = 'a' # don't test boolean - elif isinstance(o,Index) and o.is_boolean(): + elif isinstance(o, Index) and o.is_boolean(): continue elif isinstance(o, Index): expected_index = pd.Index(values[::-1]) + expected_index.name = None o = o.repeat(range(1, len(o) + 1)) o.name = 'a' else: diff --git a/pandas/tests/test_index.py b/pandas/tests/test_index.py index e2fa6a90429dc..a240b8c1c1e78 100644 --- a/pandas/tests/test_index.py +++ b/pandas/tests/test_index.py @@ -60,6 +60,31 @@ def test_shift(self): self.assertRaises(NotImplementedError, idx.shift, 1) self.assertRaises(NotImplementedError, idx.shift, 1, 2) + def test_create_index_existing_name(self): + + # GH11193, when an existing index is passed, and a new name is not specified, the new index should inherit the + # previous object name + expected = self.create_index() + if not isinstance(expected, MultiIndex): + expected.name = 'foo' + result = pd.Index(expected) + tm.assert_index_equal(result, expected) + + result = pd.Index(expected, name='bar') + expected.name = 'bar' + tm.assert_index_equal(result, expected) + else: + expected.names = ['foo', 'bar'] + result = pd.Index(expected) + tm.assert_index_equal(result, Index(Index([('foo', 'one'), ('foo', 'two'), ('bar', 'one'), ('baz', 'two'), + ('qux', 'one'), ('qux', 'two')], dtype='object'), + names=['foo', 'bar'])) + + result = pd.Index(expected, names=['A', 'B']) + tm.assert_index_equal(result, Index(Index([('foo', 'one'), ('foo', 'two'), ('bar', 'one'), ('baz', 'two'), + ('qux', 'one'), ('qux', 'two')], dtype='object'), + names=['A', 'B'])) + def test_numeric_compat(self): idx = self.create_index() @@ -3043,7 +3068,7 @@ def test_identical(self): i = self.index.copy(dtype=object) i = i.rename('foo') same_values = Index(i, dtype=object) - self.assertTrue(same_values.identical(self.index.copy(dtype=object))) + self.assertTrue(same_values.identical(i)) self.assertFalse(i.identical(self.index)) self.assertTrue(Index(same_values, name='foo', dtype=object