Skip to content

Commit e2c1f3a

Browse files
committed
REF: Refactor signature of RangeIndex._simple_new
1 parent 3ff4f38 commit e2c1f3a

File tree

4 files changed

+38
-39
lines changed

4 files changed

+38
-39
lines changed

doc/source/whatsnew/v0.25.0.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ Other Enhancements
8282
- :meth:`DataFrame.query` and :meth:`DataFrame.eval` now supports quoting column names with backticks to refer to names with spaces (:issue:`6508`)
8383
- :func:`merge_asof` now gives a more clear error message when merge keys are categoricals that are not equal (:issue:`26136`)
8484
- :meth:`pandas.core.window.Rolling` supports exponential (or Poisson) window type (:issue:`21303`)
85-
-
85+
- :class:`RangeIndex` can now be constructed using python ``range`` instances (:issue:`xxxxx`)
86+
8687

8788
.. _whatsnew_0250.api_breaking:
8889

pandas/core/indexes/base.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -270,11 +270,8 @@ def __new__(cls, data=None, dtype=None, copy=False, name=None,
270270
data = data.to_numpy()
271271

272272
# range
273-
if isinstance(data, RangeIndex):
273+
if isinstance(data, (RangeIndex, range)):
274274
return RangeIndex(start=data, copy=copy, dtype=dtype, name=name)
275-
elif isinstance(data, range):
276-
return RangeIndex.from_range(data, copy=copy, dtype=dtype,
277-
name=name)
278275

279276
# categorical
280277
elif is_categorical_dtype(data) or is_categorical_dtype(dtype):

pandas/core/indexes/range.py

+29-32
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class RangeIndex(Int64Index):
4040
4141
Parameters
4242
----------
43-
start : int (default: 0), or other RangeIndex instance
43+
start : int (default: 0), range or RangeIndex instance
4444
If int and "stop" is not given, interpreted as "stop" instead.
4545
stop : int (default: 0)
4646
step : int (default: 1)
@@ -82,16 +82,14 @@ def __new__(cls, start=None, stop=None, step=None,
8282
"removed in a future version.",
8383
FutureWarning, stacklevel=2)
8484
if fastpath:
85-
return cls._simple_new(start, stop, step, name=name)
85+
return cls._simple_new(range(start, stop, step), name=name)
8686

87-
cls._validate_dtype(dtype)
88-
89-
# RangeIndex
90-
if isinstance(start, RangeIndex):
91-
if name is None:
92-
name = start.name
93-
return cls._simple_new(name=name,
94-
**dict(start._get_data_as_items()))
87+
# RangeIndex, range
88+
if isinstance(start, (RangeIndex, range)):
89+
if isinstance(start, RangeIndex):
90+
name = start.name if name is None else name
91+
start = start._range
92+
return cls._simple_new(start, dtype=dtype, name=name)
9593

9694
# validate the arguments
9795
if com._all_none(start, stop, step):
@@ -108,10 +106,11 @@ def __new__(cls, start=None, stop=None, step=None,
108106
if step == 0:
109107
raise ValueError("Step must not be zero")
110108

111-
return cls._simple_new(start, stop, step, name)
109+
rng = range(start, stop, step)
110+
return cls._simple_new(rng, dtype=dtype, name=name)
112111

113112
@classmethod
114-
def from_range(cls, data, name=None, dtype=None, **kwargs):
113+
def from_range(cls, data, name=None, dtype=None):
115114
"""
116115
Create RangeIndex from a range object.
117116
@@ -123,27 +122,22 @@ def from_range(cls, data, name=None, dtype=None, **kwargs):
123122
raise TypeError(
124123
'{0}(...) must be called with object coercible to a '
125124
'range, {1} was passed'.format(cls.__name__, repr(data)))
126-
127-
start, stop, step = data.start, data.stop, data.step
128-
return cls(start, stop, step, dtype=dtype, name=name, **kwargs)
125+
return cls._simple_new(data, dtype=dtype, name=name)
129126

130127
@classmethod
131-
def _simple_new(cls, start, stop=None, step=None, name=None,
132-
dtype=None, **kwargs):
128+
def _simple_new(cls, values, name=None, dtype=None, **kwargs):
133129
result = object.__new__(cls)
134130

131+
cls._validate_dtype(dtype)
132+
135133
# handle passed None, non-integers
136-
if start is None and stop is None:
134+
if values is None:
137135
# empty
138-
start, stop, step = 0, 0, 1
139-
140-
if start is None or not is_integer(start):
141-
try:
142-
return cls(start, stop, step, name=name, **kwargs)
143-
except TypeError:
144-
return Index(start, stop, step, name=name, **kwargs)
136+
values = range(0, 0, 1)
137+
elif not isinstance(values, range):
138+
return Index(values, dtype=dtype, name=name, **kwargs)
145139

146-
result._range = range(start, stop or 0, step or 1)
140+
result._range = values
147141

148142
result.name = name
149143
for k, v in kwargs.items():
@@ -360,8 +354,7 @@ def tolist(self):
360354
def _shallow_copy(self, values=None, **kwargs):
361355
if values is None:
362356
name = kwargs.get("name", self.name)
363-
return self._simple_new(
364-
name=name, **dict(self._get_data_as_items()))
357+
return self._simple_new(self._range, name=name)
365358
else:
366359
kwargs.setdefault('name', self.name)
367360
return self._int64index._shallow_copy(values, **kwargs)
@@ -480,11 +473,13 @@ def intersection(self, other, sort=False):
480473
tmp_start = first.start + (second.start - first.start) * \
481474
first.step // gcd * s
482475
new_step = first.step * second.step // gcd
483-
new_index = self._simple_new(tmp_start, int_high, new_step)
476+
new_range = range(tmp_start, int_high, new_step)
477+
new_index = self._simple_new(new_range)
484478

485479
# adjust index to limiting interval
486480
new_start = new_index._min_fitting_element(int_low)
487-
new_index = self._simple_new(new_start, new_index.stop, new_index.step)
481+
new_range = range(new_start, new_index.stop, new_index.step)
482+
new_index = self._simple_new(new_range)
488483

489484
if (self.step < 0 and other.step < 0) is not (new_index.step < 0):
490485
new_index = new_index[::-1]
@@ -640,10 +635,12 @@ def __floordiv__(self, other):
640635
start = self.start // other
641636
step = self.step // other
642637
stop = start + len(self) * step
643-
return self._simple_new(start, stop, step, name=self.name)
638+
new_range = range(start, stop, step or 1)
639+
return self._simple_new(new_range, name=self.name)
644640
if len(self) == 1:
645641
start = self.start // other
646-
return self._simple_new(start, start + 1, 1, name=self.name)
642+
new_range = range(start, start + 1, 1)
643+
return self._simple_new(new_range, name=self.name)
647644
return self._int64index // other
648645

649646
def all(self) -> bool:

pandas/tests/indexes/test_range.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,9 @@ def test_constructor_same(self):
9494

9595
def test_constructor_range(self):
9696

97-
with pytest.raises(TypeError):
98-
RangeIndex(range(1, 5, 2))
97+
result = RangeIndex(range(1, 5, 2))
98+
expected = RangeIndex(1, 5, 2)
99+
tm.assert_index_equal(result, expected, exact=True)
99100

100101
result = RangeIndex.from_range(range(1, 5, 2))
101102
expected = RangeIndex(1, 5, 2)
@@ -120,6 +121,9 @@ def test_constructor_range(self):
120121

121122
with pytest.raises(TypeError):
122123
Index(range(1, 5, 2), dtype='float64')
124+
msg = '^from_range\(\) got an unexpected keyword argument'
125+
with pytest.raises(TypeError, match=msg):
126+
pd.RangeIndex.from_range(range(10), copy=True)
123127

124128
def test_constructor_name(self):
125129
# GH12288

0 commit comments

Comments
 (0)