diff --git a/doc/source/whatsnew/v0.19.0.txt b/doc/source/whatsnew/v0.19.0.txt index 375bbd79fd29b..0822bb23cbc3f 100644 --- a/doc/source/whatsnew/v0.19.0.txt +++ b/doc/source/whatsnew/v0.19.0.txt @@ -766,6 +766,7 @@ Bug Fixes - Bug in ``DatetimeIndex`` with nanosecond frequency does not include timestamp specified with ``end`` (:issue:`13672`) - Bug in ``Index`` raises ``OutOfBoundsDatetime`` if ``datetime`` exceeds ``datetime64[ns]`` bounds, rather than coercing to ``object`` dtype (:issue:`13663`) +- Bug in ``RangeIndex`` can be created without no arguments rather than raises ``TypeError`` (:issue:`13793`) - Bug in ``.value_counts`` raises ``OutOfBoundsDatetime`` if data exceeds ``datetime64[ns]`` bounds (:issue:`13663`) - Bug in ``DatetimeIndex`` may raise ``OutOfBoundsDatetime`` if input ``np.datetime64`` has other unit than ``ns`` (:issue:`9114`) diff --git a/pandas/indexes/range.py b/pandas/indexes/range.py index a561cab30b472..7094f8d589036 100644 --- a/pandas/indexes/range.py +++ b/pandas/indexes/range.py @@ -70,7 +70,10 @@ def _ensure_int(value, field): return new_value - if start is None: + if start is None and stop is None and step is None: + msg = "RangeIndex(...) must be called with integers" + raise TypeError(msg) + elif start is None: start = 0 else: start = _ensure_int(start, 'start') @@ -122,8 +125,13 @@ def _simple_new(cls, start, stop=None, step=None, name=None, result = object.__new__(cls) # handle passed None, non-integers + if start is None and stop is None: + # empty + start, stop, step = 0, 0, 1 + if start is None or not is_integer(start): try: + return RangeIndex(start, stop, step, name=name, **kwargs) except TypeError: return Index(start, stop, step, name=name, **kwargs) diff --git a/pandas/tests/indexes/test_range.py b/pandas/tests/indexes/test_range.py index 329ffa9b7cc77..8a036def0be1b 100644 --- a/pandas/tests/indexes/test_range.py +++ b/pandas/tests/indexes/test_range.py @@ -74,17 +74,28 @@ def test_constructor(self): self.assertEqual(index._step, 2) tm.assert_index_equal(Index(expected), index) - index = RangeIndex() - expected = np.empty(0, dtype=np.int64) - self.assertIsInstance(index, RangeIndex) - self.assertEqual(index._start, 0) - self.assertEqual(index._stop, 0) - self.assertEqual(index._step, 1) - tm.assert_index_equal(Index(expected), index) - - index = RangeIndex(name='Foo') - self.assertIsInstance(index, RangeIndex) - self.assertEqual(index.name, 'Foo') + msg = "RangeIndex\\(\\.\\.\\.\\) must be called with integers" + with tm.assertRaisesRegexp(TypeError, msg): + RangeIndex() + + for index in [RangeIndex(0), RangeIndex(start=0), RangeIndex(stop=0), + RangeIndex(0, 0)]: + expected = np.empty(0, dtype=np.int64) + self.assertIsInstance(index, RangeIndex) + self.assertEqual(index._start, 0) + self.assertEqual(index._stop, 0) + self.assertEqual(index._step, 1) + tm.assert_index_equal(Index(expected), index) + + with tm.assertRaisesRegexp(TypeError, msg): + RangeIndex(name='Foo') + + for index in [RangeIndex(0, name='Foo'), + RangeIndex(start=0, name='Foo'), + RangeIndex(stop=0, name='Foo'), + RangeIndex(0, 0, name='Foo')]: + self.assertIsInstance(index, RangeIndex) + self.assertEqual(index.name, 'Foo') # we don't allow on a bare Index self.assertRaises(TypeError, lambda: Index(0, 1000)) @@ -210,10 +221,10 @@ def test_numeric_compat2(self): RangeIndex(0, 1000, 1)._int64index // 2), (RangeIndex(0, 100, 1), 2.0, RangeIndex(0, 100, 1)._int64index // 2.0), - (RangeIndex(), 50, RangeIndex()), + (RangeIndex(0), 50, RangeIndex(0)), (RangeIndex(2, 4, 2), 3, RangeIndex(0, 1, 1)), (RangeIndex(-5, -10, -6), 4, RangeIndex(-2, -1, 1)), - (RangeIndex(-100, -200, 3), 2, RangeIndex())] + (RangeIndex(-100, -200, 3), 2, RangeIndex(0))] for idx, div, expected in cases_exact: tm.assert_index_equal(idx // div, expected, exact=True) @@ -288,7 +299,7 @@ def test_delete(self): def test_view(self): super(TestRangeIndex, self).test_view() - i = RangeIndex(name='Foo') + i = RangeIndex(0, name='Foo') i_view = i.view() self.assertEqual(i_view.name, 'Foo') @@ -612,8 +623,8 @@ def test_union(self): (RI(0, 100, 5), RI(0, 100, 20), RI(0, 100, 5)), (RI(0, -100, -5), RI(5, -100, -20), RI(-95, 10, 5)), (RI(0, -11, -1), RI(1, -12, -4), RI(-11, 2, 1)), - (RI(), RI(), RI()), - (RI(0, -10, -2), RI(), RI(0, -10, -2)), + (RI(0), RI(0), RI(0)), + (RI(0, -10, -2), RI(0), RI(0, -10, -2)), (RI(0, 100, 2), RI(100, 150, 200), RI(0, 102, 2)), (RI(0, -100, -2), RI(-100, 50, 102), RI(-100, 4, 2)), (RI(0, -100, -1), RI(0, -50, -3), RI(-99, 1, 1)), @@ -621,7 +632,7 @@ def test_union(self): (RI(0, 10, 5), RI(-5, -6, -20), RI(-5, 10, 5)), (RI(0, 3, 1), RI(4, 5, 1), I64([0, 1, 2, 4])), (RI(0, 10, 1), I64([]), RI(0, 10, 1)), - (RI(), I64([1, 5, 6]), I64([1, 5, 6]))] + (RI(0), I64([1, 5, 6]), I64([1, 5, 6]))] for idx1, idx2, expected in cases: res1 = idx1.union(idx2) res2 = idx2.union(idx1)