66from pandas import (Interval , IntervalIndex , Index , isna ,
77 interval_range , Timestamp , Timedelta ,
88 compat , date_range , timedelta_range , DateOffset )
9- from pandas .compat import zip
9+ from pandas .compat import lzip
1010from pandas .tseries .offsets import Day
1111from pandas ._libs .interval import IntervalTree
1212from pandas .tests .indexes .common import Base
@@ -38,7 +38,7 @@ def create_index_with_nan(self, closed='right'):
3838 @pytest .mark .parametrize ('name' , [None , 'foo' ])
3939 def test_constructors (self , closed , name ):
4040 left , right = Index ([0 , 1 , 2 , 3 ]), Index ([1 , 2 , 3 , 4 ])
41- ivs = [Interval (l , r , closed = closed ) for l , r in zip (left , right )]
41+ ivs = [Interval (l , r , closed = closed ) for l , r in lzip (left , right )]
4242 expected = IntervalIndex ._simple_new (
4343 left = left , right = right , closed = closed , name = name )
4444
@@ -57,7 +57,7 @@ def test_constructors(self, closed, name):
5757 tm .assert_index_equal (result , expected )
5858
5959 result = IntervalIndex .from_tuples (
60- zip (left , right ), closed = closed , name = name )
60+ lzip (left , right ), closed = closed , name = name )
6161 tm .assert_index_equal (result , expected )
6262
6363 result = Index (ivs , name = name )
@@ -68,6 +68,9 @@ def test_constructors(self, closed, name):
6868 tm .assert_index_equal (Index (expected ), expected )
6969 tm .assert_index_equal (IntervalIndex (expected ), expected )
7070
71+ result = IntervalIndex .from_intervals (expected )
72+ tm .assert_index_equal (result , expected )
73+
7174 result = IntervalIndex .from_intervals (
7275 expected .values , name = expected .name )
7376 tm .assert_index_equal (result , expected )
@@ -86,63 +89,117 @@ def test_constructors(self, closed, name):
8689 breaks , closed = expected .closed , name = expected .name )
8790 tm .assert_index_equal (result , expected )
8891
89- def test_constructors_other (self ):
90-
91- # all-nan
92- result = IntervalIndex .from_intervals ([np .nan ])
93- expected = np .array ([np .nan ], dtype = object )
94- tm .assert_numpy_array_equal (result .values , expected )
95-
96- # empty
97- result = IntervalIndex .from_intervals ([])
98- expected = np .array ([], dtype = object )
99- tm .assert_numpy_array_equal (result .values , expected )
92+ @pytest .mark .parametrize ('data' , [[np .nan ], [np .nan ] * 2 , [np .nan ] * 50 ])
93+ def test_constructors_nan (self , closed , data ):
94+ # GH 18421
95+ expected_values = np .array (data , dtype = object )
96+ expected_idx = IntervalIndex (data , closed = closed )
97+
98+ # validate the expected index
99+ assert expected_idx .closed == closed
100+ tm .assert_numpy_array_equal (expected_idx .values , expected_values )
101+
102+ result = IntervalIndex .from_tuples (data , closed = closed )
103+ tm .assert_index_equal (result , expected_idx )
104+ tm .assert_numpy_array_equal (result .values , expected_values )
105+
106+ result = IntervalIndex .from_breaks ([np .nan ] + data , closed = closed )
107+ tm .assert_index_equal (result , expected_idx )
108+ tm .assert_numpy_array_equal (result .values , expected_values )
109+
110+ result = IntervalIndex .from_arrays (data , data , closed = closed )
111+ tm .assert_index_equal (result , expected_idx )
112+ tm .assert_numpy_array_equal (result .values , expected_values )
113+
114+ if closed == 'right' :
115+ # Can't specify closed for IntervalIndex.from_intervals
116+ result = IntervalIndex .from_intervals (data )
117+ tm .assert_index_equal (result , expected_idx )
118+ tm .assert_numpy_array_equal (result .values , expected_values )
119+
120+ @pytest .mark .parametrize ('data' , [
121+ [],
122+ np .array ([], dtype = 'int64' ),
123+ np .array ([], dtype = 'float64' ),
124+ np .array ([], dtype = object )])
125+ def test_constructors_empty (self , data , closed ):
126+ # GH 18421
127+ expected_dtype = getattr (data , 'dtype' , None ) or object
128+ expected_values = np .array (data , dtype = object )
129+ expected_index = IntervalIndex (data , closed = closed )
130+
131+ # validate the expected index
132+ assert expected_index .empty
133+ assert expected_index .closed == closed
134+ assert expected_index .dtype .subtype == expected_dtype
135+ tm .assert_numpy_array_equal (expected_index .values , expected_values )
136+
137+ result = IntervalIndex .from_tuples (data , closed = closed )
138+ tm .assert_index_equal (result , expected_index )
139+ tm .assert_numpy_array_equal (result .values , expected_values )
140+
141+ result = IntervalIndex .from_breaks (data , closed = closed )
142+ tm .assert_index_equal (result , expected_index )
143+ tm .assert_numpy_array_equal (result .values , expected_values )
144+
145+ result = IntervalIndex .from_arrays (data , data , closed = closed )
146+ tm .assert_index_equal (result , expected_index )
147+ tm .assert_numpy_array_equal (result .values , expected_values )
148+
149+ if closed == 'right' :
150+ # Can't specify closed for IntervalIndex.from_intervals
151+ result = IntervalIndex .from_intervals (data )
152+ tm .assert_index_equal (result , expected_index )
153+ tm .assert_numpy_array_equal (result .values , expected_values )
100154
101155 def test_constructors_errors (self ):
102156
103157 # scalar
104- msg = ('IntervalIndex(...) must be called with a collection of '
158+ msg = ('IntervalIndex\ (...\ ) must be called with a collection of '
105159 'some kind, 5 was passed' )
106- with pytest . raises (TypeError , message = msg ):
160+ with tm . assert_raises_regex (TypeError , msg ):
107161 IntervalIndex (5 )
108162
109163 # not an interval
110- msg = "type <class 'numpy.int32 '> with value 0 is not an interval"
111- with pytest . raises (TypeError , message = msg ):
164+ msg = "type <class 'numpy.int64 '> with value 0 is not an interval"
165+ with tm . assert_raises_regex (TypeError , msg ):
112166 IntervalIndex ([0 , 1 ])
113167
114- with pytest . raises (TypeError , message = msg ):
168+ with tm . assert_raises_regex (TypeError , msg ):
115169 IntervalIndex .from_intervals ([0 , 1 ])
116170
117171 # invalid closed
118172 msg = "invalid options for 'closed': invalid"
119- with pytest . raises (ValueError , message = msg ):
173+ with tm . assert_raises_regex (ValueError , msg ):
120174 IntervalIndex .from_arrays ([0 , 1 ], [1 , 2 ], closed = 'invalid' )
121175
122- # mismatched closed
176+ # mismatched closed within intervals
123177 msg = 'intervals must all be closed on the same side'
124- with pytest . raises (ValueError , message = msg ):
178+ with tm . assert_raises_regex (ValueError , msg ):
125179 IntervalIndex .from_intervals ([Interval (0 , 1 ),
126180 Interval (1 , 2 , closed = 'left' )])
127181
128- with pytest .raises (ValueError , message = msg ):
129- IntervalIndex .from_arrays ([0 , 10 ], [3 , 5 ])
130-
131- with pytest .raises (ValueError , message = msg ):
182+ with tm .assert_raises_regex (ValueError , msg ):
132183 Index ([Interval (0 , 1 ), Interval (2 , 3 , closed = 'left' )])
133184
185+ # mismatched closed inferred from intervals vs constructor.
186+ msg = 'conflicting values for closed'
187+ with tm .assert_raises_regex (ValueError , msg ):
188+ iv = [Interval (0 , 1 , closed = 'both' ), Interval (1 , 2 , closed = 'both' )]
189+ IntervalIndex (iv , closed = 'neither' )
190+
134191 # no point in nesting periods in an IntervalIndex
135192 msg = 'Period dtypes are not supported, use a PeriodIndex instead'
136- with pytest . raises (ValueError , message = msg ):
193+ with tm . assert_raises_regex (ValueError , msg ):
137194 IntervalIndex .from_breaks (
138195 pd .period_range ('2000-01-01' , periods = 3 ))
139196
140197 # decreasing breaks/arrays
141198 msg = 'left side of interval must be <= right side'
142- with pytest . raises (ValueError , message = msg ):
199+ with tm . assert_raises_regex (ValueError , msg ):
143200 IntervalIndex .from_breaks (range (10 , - 1 , - 1 ))
144201
145- with pytest . raises (ValueError , message = msg ):
202+ with tm . assert_raises_regex (ValueError , msg ):
146203 IntervalIndex .from_arrays (range (10 , - 1 , - 1 ), range (9 , - 2 , - 1 ))
147204
148205 def test_constructors_datetimelike (self , closed ):
@@ -865,23 +922,23 @@ def test_is_non_overlapping_monotonic(self, closed):
865922 idx = IntervalIndex .from_tuples (tpls , closed = closed )
866923 assert idx .is_non_overlapping_monotonic is True
867924
868- idx = IntervalIndex .from_tuples (reversed ( tpls ) , closed = closed )
925+ idx = IntervalIndex .from_tuples (tpls [:: - 1 ] , closed = closed )
869926 assert idx .is_non_overlapping_monotonic is True
870927
871928 # Should be False in all cases (overlapping)
872929 tpls = [(0 , 2 ), (1 , 3 ), (4 , 5 ), (6 , 7 )]
873930 idx = IntervalIndex .from_tuples (tpls , closed = closed )
874931 assert idx .is_non_overlapping_monotonic is False
875932
876- idx = IntervalIndex .from_tuples (reversed ( tpls ) , closed = closed )
933+ idx = IntervalIndex .from_tuples (tpls [:: - 1 ] , closed = closed )
877934 assert idx .is_non_overlapping_monotonic is False
878935
879936 # Should be False in all cases (non-monotonic)
880937 tpls = [(0 , 1 ), (2 , 3 ), (6 , 7 ), (4 , 5 )]
881938 idx = IntervalIndex .from_tuples (tpls , closed = closed )
882939 assert idx .is_non_overlapping_monotonic is False
883940
884- idx = IntervalIndex .from_tuples (reversed ( tpls ) , closed = closed )
941+ idx = IntervalIndex .from_tuples (tpls [:: - 1 ] , closed = closed )
885942 assert idx .is_non_overlapping_monotonic is False
886943
887944 # Should be False for closed='both', overwise True (GH16560)
@@ -1054,10 +1111,6 @@ def test_constructor_coverage(self):
10541111 end = end .to_pydatetime ())
10551112 tm .assert_index_equal (result , expected )
10561113
1057- result = pd .interval_range (start = start .tz_localize ('UTC' ),
1058- end = end .tz_localize ('UTC' ))
1059- tm .assert_index_equal (result , expected )
1060-
10611114 result = pd .interval_range (start = start .asm8 , end = end .asm8 )
10621115 tm .assert_index_equal (result , expected )
10631116
0 commit comments