Skip to content

ENH: Add public start, stop, and step attributes to RangeIndex #25720

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/source/whatsnew/v0.25.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Other Enhancements
- :meth:`DataFrame.set_index` now works for instances of ``abc.Iterator``, provided their output is of the same length as the calling frame (:issue:`22484`, :issue:`24984`)
- :meth:`DatetimeIndex.union` now supports the ``sort`` argument. The behaviour of the sort parameter matches that of :meth:`Index.union` (:issue:`24994`)
- :meth:`DataFrame.rename` now supports the ``errors`` argument to raise errors when attempting to rename nonexistent keys (:issue:`13473`)
- :class:`RangeIndex` has gained :attr:`~RangeIndex.start`, :attr:`~RangeIndex.stop`, and :attr:`~RangeIndex.step` attributes (:issue:`25710`)

.. _whatsnew_0250.api_breaking:

Expand Down
27 changes: 26 additions & 1 deletion pandas/core/indexes/range.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ class RangeIndex(Int64Index):

Attributes
----------
None
start
stop
step

Methods
-------
Expand Down Expand Up @@ -209,6 +211,29 @@ def _format_data(self, name=None):
return None

# --------------------------------------------------------------------
@property
def start(self):
"""
The value of the `start` parameter (or ``0`` if this was not supplied)
"""
# GH 25710
return self._start

@property
def stop(self):
"""
The value of the `stop` parameter
"""
# GH 25710
return self._stop

@property
def step(self):
"""
The value of the `step` parameter (or ``1`` if this was not supplied)
"""
# GH 25710
return self._step

@cache_readonly
def nbytes(self):
Expand Down
77 changes: 36 additions & 41 deletions pandas/tests/indexes/test_range.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,47 +35,25 @@ def test_too_many_names(self):
with pytest.raises(ValueError, match="^Length"):
self.index.names = ["roger", "harold"]

def test_constructor(self):
index = RangeIndex(5)
expected = np.arange(5, dtype=np.int64)
assert isinstance(index, RangeIndex)
assert index._start == 0
assert index._stop == 5
assert index._step == 1
assert index.name is None
tm.assert_index_equal(Index(expected), index)

index = RangeIndex(1, 5)
expected = np.arange(1, 5, dtype=np.int64)
assert isinstance(index, RangeIndex)
assert index._start == 1
tm.assert_index_equal(Index(expected), index)

index = RangeIndex(1, 5, 2)
expected = np.arange(1, 5, 2, dtype=np.int64)
assert isinstance(index, RangeIndex)
assert index._step == 2
tm.assert_index_equal(Index(expected), index)

for index in [RangeIndex(0), RangeIndex(start=0), RangeIndex(stop=0),
RangeIndex(0, 0)]:
expected = np.empty(0, dtype=np.int64)
assert isinstance(index, RangeIndex)
assert index._start == 0
assert index._stop == 0
assert index._step == 1
tm.assert_index_equal(Index(expected), index)

for index in [RangeIndex(0, name='Foo'),
RangeIndex(start=0, name='Foo'),
RangeIndex(stop=0, name='Foo'),
RangeIndex(0, 0, name='Foo')]:
assert isinstance(index, RangeIndex)
assert index.name == 'Foo'

# we don't allow on a bare Index
with pytest.raises(TypeError):
Index(0, 1000)
@pytest.mark.parametrize('name', [None, 'foo'])
@pytest.mark.parametrize('args, kwargs, start, stop, step', [
((5,), dict(), 0, 5, 1),
((1, 5), dict(), 1, 5, 1),
((1, 5, 2), dict(), 1, 5, 2),
((0,), dict(), 0, 0, 1),
((0, 0), dict(), 0, 0, 1),
(tuple(), dict(start=0), 0, 0, 1),
(tuple(), dict(stop=0), 0, 0, 1)])
def test_constructor(self, args, kwargs, start, stop, step, name):
result = RangeIndex(*args, name=name, **kwargs)
expected = Index(np.arange(start, stop, step, dtype=np.int64),
name=name)
assert isinstance(result, RangeIndex)
assert result._start == start
assert result._stop == stop
assert result._step == step
assert result.name is name
tm.assert_index_equal(result, expected)

def test_constructor_invalid_args(self):
msg = "RangeIndex\\(\\.\\.\\.\\) must be called with integers"
Expand All @@ -92,6 +70,12 @@ def test_constructor_invalid_args(self):
with pytest.raises(TypeError):
RangeIndex(i)

# we don't allow on a bare Index
msg = (r'Index\(\.\.\.\) must be called with a collection of some '
r'kind, 0 was passed')
with pytest.raises(TypeError, match=msg):
Index(0, 1000)

def test_constructor_same(self):

# pass thru w and w/o copy
Expand Down Expand Up @@ -172,6 +156,17 @@ def test_constructor_corner(self):
with pytest.raises(TypeError):
RangeIndex(1, 5, dtype='float64')

@pytest.mark.parametrize('index, start, stop, step', [
(RangeIndex(5), 0, 5, 1),
(RangeIndex(0, 5), 0, 5, 1),
(RangeIndex(5, step=2), 0, 5, 2),
(RangeIndex(1, 5, 2), 1, 5, 2)])
def test_start_stop_step_attrs(self, index, start, stop, step):
# GH 25710
assert index.start == start
assert index.stop == stop
assert index.step == step

def test_copy(self):
i = RangeIndex(5, name='Foo')
i_copy = i.copy()
Expand Down