Skip to content

Commit ee78449

Browse files
committed
Address invalid lengths
1 parent 3cc5b28 commit ee78449

File tree

4 files changed

+38
-2
lines changed

4 files changed

+38
-2
lines changed

pandas/_libs/interval.pyx

+6-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,12 @@ cdef class IntervalMixin(object):
5959
@property
6060
def length(self):
6161
"""Return the length of the Interval"""
62-
return self.right - self.left
62+
try:
63+
return self.right - self.left
64+
except TypeError:
65+
# length not defined for some types, e.g. string
66+
msg = 'cannot compute length between {left} and {right}'
67+
raise TypeError(msg.format(left=self.left, right=self.right))
6368

6469

6570
cdef _interval_like(other):

pandas/core/indexes/interval.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,13 @@ def length(self):
605605
Return an Index with entries denoting the length of each Interval in
606606
the IntervalIndex
607607
"""
608-
return self.right - self.left
608+
try:
609+
return self.right - self.left
610+
except TypeError:
611+
# length not defined for some types, e.g. string
612+
msg = ('IntervalIndex contains Intervals without defined length, '
613+
'e.g. Intervals with string endpoints')
614+
raise TypeError(msg)
609615

610616
def __len__(self):
611617
return len(self.left)

pandas/tests/indexes/test_interval.py

+13
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ def test_properties(self, closed):
289289
pd.to_datetime(['20170101', '20170202', '20170303', '20170404']),
290290
pd.to_timedelta(['1ns', '2ms', '3s', '4M', '5H', '6D'])])
291291
def test_length(self, closed, breaks):
292+
# GH 18789
292293
index = IntervalIndex.from_breaks(breaks, closed=closed)
293294
result = index.length
294295
expected = Index(iv.length for iv in index)
@@ -300,6 +301,18 @@ def test_length(self, closed, breaks):
300301
expected = Index(iv.length if notna(iv) else iv for iv in index)
301302
tm.assert_index_equal(result, expected)
302303

304+
@pytest.mark.parametrize('breaks', [
305+
list('abcdefgh'),
306+
lzip(range(10), range(1, 11)),
307+
[['A', 'B'], ['a', 'b'], ['c', 'd'], ['e', 'f']],
308+
[Interval(0, 1), Interval(1, 2), Interval(3, 4), Interval(4, 5)]])
309+
def test_length_errors(self, closed, breaks):
310+
# GH 18789
311+
index = IntervalIndex.from_breaks(breaks)
312+
msg = 'IntervalIndex contains Intervals without defined length'
313+
with tm.assert_raises_regex(TypeError, msg):
314+
index.length
315+
303316
def test_with_nans(self, closed):
304317
index = self.create_index(closed=closed)
305318
assert not index.hasnans

pandas/tests/scalar/test_interval.py

+12
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,18 @@ def test_length_timestamp(self, tz, left, right, expected):
9797
expected = Timedelta(expected)
9898
assert result == expected
9999

100+
@pytest.mark.parametrize('left, right', [
101+
('a', 'z'),
102+
(('a', 'b'), ('c', 'd')),
103+
(list('AB'), list('ab')),
104+
(Interval(0, 1), Interval(1, 2))])
105+
def test_length_errors(self, left, right):
106+
# GH 18789
107+
iv = Interval(left, right)
108+
msg = 'cannot compute length between .* and .*'
109+
with tm.assert_raises_regex(TypeError, msg):
110+
iv.length
111+
100112
def test_math_add(self, interval):
101113
expected = Interval(1, 2)
102114
actual = interval + 1

0 commit comments

Comments
 (0)