Skip to content

Commit 9e27f12

Browse files
makbigcjschendel
authored andcommitted
[BUG] Construction of Interval restricted to numeric/ Timestamp/ Timedelta (pandas-dev#23013) (pandas-dev#25768)
1 parent 0d3e0e6 commit 9e27f12

File tree

4 files changed

+30
-9
lines changed

4 files changed

+30
-9
lines changed

doc/source/whatsnew/v0.25.0.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ Strings
245245
Interval
246246
^^^^^^^^
247247

248-
-
248+
- Construction of :class:`Interval` is restricted to numeric, :class:`Timestamp` and :class:`Timedelta` endpoints (:issue:`23013`)
249249
-
250250
-
251251

pandas/_libs/interval.pyx

+14
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@ cnp.import_array()
2020
cimport pandas._libs.util as util
2121

2222
from pandas._libs.hashtable cimport Int64Vector, Int64VectorData
23+
from pandas._libs.tslibs.util cimport is_integer_object, is_float_object
2324

2425
from pandas._libs.tslibs import Timestamp
26+
from pandas._libs.tslibs.timedeltas import Timedelta
2527
from pandas._libs.tslibs.timezones cimport tz_compare
2628

2729

@@ -250,6 +252,10 @@ cdef class Interval(IntervalMixin):
250252
def __init__(self, left, right, str closed='right'):
251253
# note: it is faster to just do these checks than to use a special
252254
# constructor (__cinit__/__new__) to avoid them
255+
256+
self._validate_endpoint(left)
257+
self._validate_endpoint(right)
258+
253259
if closed not in _VALID_CLOSED:
254260
msg = "invalid option for 'closed': {closed}".format(closed=closed)
255261
raise ValueError(msg)
@@ -266,6 +272,14 @@ cdef class Interval(IntervalMixin):
266272
self.right = right
267273
self.closed = closed
268274

275+
def _validate_endpoint(self, endpoint):
276+
# GH 23013
277+
if not (is_integer_object(endpoint) or is_float_object(endpoint) or
278+
isinstance(endpoint, (Timestamp, Timedelta))):
279+
msg = ("Only numeric, Timestamp and Timedelta endpoints "
280+
"are allowed when constructing an Interval.")
281+
raise ValueError(msg)
282+
269283
def __hash__(self):
270284
return hash((self.left, self.right, self.closed))
271285

pandas/tests/indexes/interval/test_construction.py

+6
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,12 @@ def test_generic_errors(self, constructor):
315315
"""
316316
pass
317317

318+
def test_constructor_string(self):
319+
# GH23013
320+
# When forming the interval from breaks,
321+
# the interval of strings is already forbidden.
322+
pass
323+
318324
def test_constructor_errors(self, constructor):
319325
# mismatched closed within intervals with no constructor override
320326
ivs = [Interval(0, 1, closed='right'), Interval(2, 3, closed='left')]

pandas/tests/scalar/interval/test_interval.py

+9-8
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import numpy as np
44
import pytest
55

6-
from pandas import Interval, Timedelta, Timestamp
6+
from pandas import Interval, Period, Timedelta, Timestamp
77
import pandas.core.common as com
88

99

@@ -100,13 +100,14 @@ def test_length_timestamp(self, tz, left, right, expected):
100100
('a', 'z'),
101101
(('a', 'b'), ('c', 'd')),
102102
(list('AB'), list('ab')),
103-
(Interval(0, 1), Interval(1, 2))])
104-
def test_length_errors(self, left, right):
105-
# GH 18789
106-
iv = Interval(left, right)
107-
msg = 'cannot compute length between .* and .*'
108-
with pytest.raises(TypeError, match=msg):
109-
iv.length
103+
(Interval(0, 1), Interval(1, 2)),
104+
(Period('2018Q1', freq='Q'), Period('2018Q1', freq='Q'))
105+
])
106+
def test_construct_errors(self, left, right):
107+
# GH 23013
108+
msg = "Only numeric, Timestamp and Timedelta endpoints are allowed"
109+
with pytest.raises(ValueError, match=msg):
110+
Interval(left, right)
110111

111112
def test_math_add(self, closed):
112113
interval = Interval(0, 1, closed=closed)

0 commit comments

Comments
 (0)