Skip to content

Commit a82bdde

Browse files
committed
BUG: Common NumericIndex.__new__, fixed name handling in indices
closes #12309
1 parent 23810e5 commit a82bdde

File tree

10 files changed

+68
-76
lines changed

10 files changed

+68
-76
lines changed

pandas/indexes/category.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ def __new__(cls, data=None, categories=None, ordered=None, dtype=None,
4545
if fastpath:
4646
return cls._simple_new(data, name=name)
4747

48+
if name is None and hasattr(data, 'name'):
49+
name = data.name
50+
4851
if isinstance(data, com.ABCCategorical):
4952
data = cls._create_categorical(cls, data, categories, ordered)
5053
elif isinstance(data, CategoricalIndex):

pandas/indexes/multi.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,10 @@ def __new__(cls, levels=None, labels=None, sortorder=None, names=None,
6666
name=None, **kwargs):
6767

6868
# compat with Index
69-
if name is not None:
70-
names = name
69+
if name is None and hasattr(levels, 'name'):
70+
name = levels.name
71+
if isinstance(levels, MultiIndex):
72+
return levels.copy(name=name, names=names, deep=copy)
7173
if levels is None or labels is None:
7274
raise TypeError("Must pass both levels and labels")
7375
if len(levels) != len(labels):
@@ -77,8 +79,6 @@ def __new__(cls, levels=None, labels=None, sortorder=None, names=None,
7779
if len(levels) == 1:
7880
if names:
7981
name = names[0]
80-
else:
81-
name = None
8282
return Index(levels[0], name=name, copy=True).take(labels[0])
8383

8484
result = object.__new__(MultiIndex)
@@ -333,7 +333,7 @@ def set_labels(self, labels, level=None, inplace=False,
333333
labels = property(fget=_get_labels, fset=__set_labels)
334334

335335
def copy(self, names=None, dtype=None, levels=None, labels=None,
336-
deep=False, _set_identity=False):
336+
deep=False, name=None, _set_identity=False):
337337
"""
338338
Make a copy of this object. Names, dtype, levels and labels can be
339339
passed and will be set on new copy.
@@ -344,6 +344,7 @@ def copy(self, names=None, dtype=None, levels=None, labels=None,
344344
dtype : numpy dtype or pandas type, optional
345345
levels : sequence, optional
346346
labels : sequence, optional
347+
name : object, optional
347348
348349
Returns
349350
-------
@@ -366,7 +367,7 @@ def copy(self, names=None, dtype=None, levels=None, labels=None,
366367
names = self.names
367368
return MultiIndex(levels=levels, labels=labels, names=names,
368369
sortorder=self.sortorder, verify_integrity=False,
369-
_set_identity=_set_identity)
370+
name=name, _set_identity=_set_identity)
370371

371372
def __array__(self, dtype=None):
372373
""" the array interface, return my values """

pandas/indexes/numeric.py

Lines changed: 28 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,32 @@ class NumericIndex(Index):
1919
"""
2020
_is_numeric_dtype = True
2121

22+
def __new__(cls, data=None, dtype=None, copy=False, name=None,
23+
fastpath=False, **kwargs):
24+
25+
if fastpath:
26+
return cls._simple_new(data, name=name)
27+
28+
# isscalar, generators handled in coerce_to_ndarray
29+
data = cls._coerce_to_ndarray(data)
30+
31+
if issubclass(data.dtype.type, compat.string_types):
32+
cls._string_data_error(data)
33+
34+
if copy or data.dtype != cls._default_dtype:
35+
try:
36+
subarr = np.array(data, dtype=cls._default_dtype, copy=copy)
37+
assert((subarr == data) | np.isnan(subarr)).all()
38+
except:
39+
raise TypeError('Unsafe NumPy casting, you must '
40+
'explicitly cast')
41+
else:
42+
subarr = data
43+
44+
if name is None and hasattr(data, 'name'):
45+
name = data.name
46+
return cls._simple_new(subarr, name=name)
47+
2248
def _maybe_cast_slice_bound(self, label, side, kind):
2349
"""
2450
This function should be overloaded in subclasses that allow non-trivial
@@ -94,35 +120,7 @@ class Int64Index(NumericIndex):
94120
_can_hold_na = False
95121

96122
_engine_type = _index.Int64Engine
97-
98-
def __new__(cls, data=None, dtype=None, copy=False, name=None,
99-
fastpath=False, **kwargs):
100-
101-
if fastpath:
102-
return cls._simple_new(data, name=name)
103-
104-
# isscalar, generators handled in coerce_to_ndarray
105-
data = cls._coerce_to_ndarray(data)
106-
107-
if issubclass(data.dtype.type, compat.string_types):
108-
cls._string_data_error(data)
109-
110-
elif issubclass(data.dtype.type, np.integer):
111-
# don't force the upcast as we may be dealing
112-
# with a platform int
113-
if (dtype is None or
114-
not issubclass(np.dtype(dtype).type, np.integer)):
115-
dtype = np.int64
116-
117-
subarr = np.array(data, dtype=dtype, copy=copy)
118-
else:
119-
subarr = np.array(data, dtype=np.int64, copy=copy)
120-
if len(data) > 0:
121-
if (subarr != data).any():
122-
raise TypeError('Unsafe NumPy casting to integer, you must'
123-
' explicitly cast')
124-
125-
return cls._simple_new(subarr, name=name)
123+
_default_dtype = np.int64
126124

127125
@property
128126
def inferred_type(self):
@@ -192,42 +190,7 @@ class Float64Index(NumericIndex):
192190
_inner_indexer = _algos.inner_join_indexer_float64
193191
_outer_indexer = _algos.outer_join_indexer_float64
194192

195-
def __new__(cls, data=None, dtype=None, copy=False, name=None,
196-
fastpath=False, **kwargs):
197-
198-
if fastpath:
199-
return cls._simple_new(data, name)
200-
201-
data = cls._coerce_to_ndarray(data)
202-
203-
if issubclass(data.dtype.type, compat.string_types):
204-
cls._string_data_error(data)
205-
206-
if dtype is None:
207-
dtype = np.float64
208-
dtype = np.dtype(dtype)
209-
210-
# allow integer / object dtypes to be passed, but coerce to float64
211-
if dtype.kind in ['i', 'O']:
212-
dtype = np.float64
213-
214-
elif dtype.kind in ['f']:
215-
pass
216-
217-
else:
218-
raise TypeError("cannot support {0} dtype in "
219-
"Float64Index".format(dtype))
220-
221-
try:
222-
subarr = np.array(data, dtype=dtype, copy=copy)
223-
except:
224-
raise TypeError('Unsafe NumPy casting, you must explicitly cast')
225-
226-
# coerce to float64 for storage
227-
if subarr.dtype != np.float64:
228-
subarr = subarr.astype(np.float64)
229-
230-
return cls._simple_new(subarr, name)
193+
_default_dtype = np.float64
231194

232195
@property
233196
def inferred_type(self):

pandas/tests/frame/test_block_internals.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,11 +372,13 @@ def test_consolidate_datetime64(self):
372372
ser_starting.index = ser_starting.values
373373
ser_starting = ser_starting.tz_localize('US/Eastern')
374374
ser_starting = ser_starting.tz_convert('UTC')
375+
ser_starting.index.name = 'starting'
375376

376377
ser_ending = df.ending
377378
ser_ending.index = ser_ending.values
378379
ser_ending = ser_ending.tz_localize('US/Eastern')
379380
ser_ending = ser_ending.tz_convert('UTC')
381+
ser_ending.index.name = 'ending'
380382

381383
df.starting = ser_starting.index
382384
df.ending = ser_ending.index

pandas/tests/indexes/common.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,3 +654,19 @@ def test_fillna(self):
654654
expected[1] = True
655655
self.assert_numpy_array_equal(idx._isnan, expected)
656656
self.assertTrue(idx.hasnans)
657+
658+
def test_copy(self):
659+
# GH12309
660+
for name, index in compat.iteritems(self.indices):
661+
first = index.__class__(index, copy=True, name='mario')
662+
second = first.__class__(first, copy=False)
663+
self.assertTrue(index.equals(first))
664+
# Even though "copy=False", we want a new object:
665+
self.assertTrue(id(first) != id(second))
666+
667+
if isinstance(index, MultiIndex) and len(index.levels) > 1:
668+
# No unique "name" attribute (each level has its own)
669+
continue
670+
671+
self.assertEqual(first.name, 'mario')
672+
self.assertEqual(second.name, 'mario')

pandas/tests/test_common.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -725,9 +725,9 @@ def test_ensure_platform_int():
725725
pi = com._ensure_platform_int(x)
726726
assert (pi.dtype == np.int_)
727727

728-
# int32
728+
# int32 - "dtype" argument is irrelevant
729729
x = Int64Index([1, 2, 3], dtype='int32')
730-
assert (x.dtype == np.int32)
730+
assert (x.dtype == np.int64)
731731

732732
pi = com._ensure_platform_int(x)
733733
assert (pi.dtype == np.int_)

pandas/tseries/index.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,9 @@ def __new__(cls, data=None,
218218
verify_integrity=True, normalize=False,
219219
closed=None, ambiguous='raise', dtype=None, **kwargs):
220220

221+
if name is None and hasattr(data, 'name'):
222+
name = data.name
223+
221224
dayfirst = kwargs.pop('dayfirst', None)
222225
yearfirst = kwargs.pop('yearfirst', None)
223226

pandas/tseries/period.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,9 @@ def __new__(cls, data=None, ordinal=None, freq=None, start=None, end=None,
179179
raise ValueError('Periods must be a number, got %s' %
180180
str(periods))
181181

182+
if name is None and hasattr(data, 'name'):
183+
name = data.name
184+
182185
if data is None:
183186
if ordinal is not None:
184187
data = np.asarray(ordinal, dtype=np.int64)

pandas/tseries/tdi.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,9 @@ def __new__(cls, data=None, unit=None,
133133

134134
if isinstance(data, TimedeltaIndex) and freq is None and name is None:
135135
if copy:
136-
data = data.copy()
137-
return data
136+
return data.copy()
137+
else:
138+
return data._shallow_copy()
138139

139140
freq_infer = False
140141
if not isinstance(freq, DateOffset):

pandas/tseries/tests/test_timedeltas.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1649,7 +1649,7 @@ def test_join_self(self):
16491649
kinds = 'outer', 'inner', 'left', 'right'
16501650
for kind in kinds:
16511651
joined = index.join(index, how=kind)
1652-
self.assertIs(index, joined)
1652+
tm.assert_index_equal(index, joined)
16531653

16541654
def test_factorize(self):
16551655
idx1 = TimedeltaIndex(['1 day', '1 day', '2 day', '2 day', '3 day',

0 commit comments

Comments
 (0)