@@ -42,24 +42,37 @@ def create_index_with_nan(self, closed='right'):
4242 np .where (mask , np .arange (10 ), np .nan ),
4343 np .where (mask , np .arange (1 , 11 ), np .nan ), closed = closed )
4444
45- def test_constructors (self , closed , name ):
46- left , right = Index ([0 , 1 , 2 , 3 ]), Index ([1 , 2 , 3 , 4 ])
45+ @pytest .mark .parametrize ('data' , [
46+ Index ([0 , 1 , 2 , 3 , 4 ]),
47+ Index (list ('abcde' )),
48+ date_range ('2017-01-01' , periods = 5 ),
49+ date_range ('2017-01-01' , periods = 5 , tz = 'US/Eastern' ),
50+ timedelta_range ('1 day' , periods = 5 )])
51+ def test_constructors (self , data , closed , name ):
52+ left , right = data [:- 1 ], data [1 :]
4753 ivs = [Interval (l , r , closed = closed ) for l , r in lzip (left , right )]
4854 expected = IntervalIndex ._simple_new (
4955 left = left , right = right , closed = closed , name = name )
5056
57+ # validate expected
58+ assert expected .closed == closed
59+ assert expected .name == name
60+ assert expected .dtype .subtype == data .dtype
61+ tm .assert_index_equal (expected .left , data [:- 1 ])
62+ tm .assert_index_equal (expected .right , data [1 :])
63+
64+ # validated constructors
5165 result = IntervalIndex (ivs , name = name )
5266 tm .assert_index_equal (result , expected )
5367
5468 result = IntervalIndex .from_intervals (ivs , name = name )
5569 tm .assert_index_equal (result , expected )
5670
57- result = IntervalIndex .from_breaks (
58- np .arange (5 ), closed = closed , name = name )
71+ result = IntervalIndex .from_breaks (data , closed = closed , name = name )
5972 tm .assert_index_equal (result , expected )
6073
6174 result = IntervalIndex .from_arrays (
62- left . values , right . values , closed = closed , name = name )
75+ left , right , closed = closed , name = name )
6376 tm .assert_index_equal (result , expected )
6477
6578 result = IntervalIndex .from_tuples (
@@ -186,6 +199,9 @@ def test_constructors_errors(self):
186199 IntervalIndex .from_intervals ([Interval (0 , 1 ),
187200 Interval (1 , 2 , closed = 'left' )])
188201
202+ with tm .assert_raises_regex (ValueError , msg ):
203+ IntervalIndex ([Interval (0 , 1 ), Interval (2 , 3 , closed = 'left' )])
204+
189205 with tm .assert_raises_regex (ValueError , msg ):
190206 Index ([Interval (0 , 1 ), Interval (2 , 3 , closed = 'left' )])
191207
@@ -209,26 +225,24 @@ def test_constructors_errors(self):
209225 with tm .assert_raises_regex (ValueError , msg ):
210226 IntervalIndex .from_arrays (range (10 , - 1 , - 1 ), range (9 , - 2 , - 1 ))
211227
212- def test_constructors_datetimelike (self , closed ):
228+ @pytest .mark .parametrize ('tz_left, tz_right' , [
229+ (None , 'UTC' ), ('UTC' , None ), ('UTC' , 'US/Eastern' )])
230+ def test_constructors_errors_tz (self , tz_left , tz_right ):
231+ # GH 18537
232+ left = date_range ('2017-01-01' , periods = 4 , tz = tz_left )
233+ right = date_range ('2017-01-02' , periods = 4 , tz = tz_right )
213234
214- # DTI / TDI
215- for idx in [pd .date_range ('20130101' , periods = 5 ),
216- pd .timedelta_range ('1 day' , periods = 5 )]:
217- result = IntervalIndex .from_breaks (idx , closed = closed )
218- expected = IntervalIndex .from_breaks (idx .values , closed = closed )
219- tm .assert_index_equal (result , expected )
220-
221- expected_scalar_type = type (idx [0 ])
222- i = result [0 ]
223- assert isinstance (i .left , expected_scalar_type )
224- assert isinstance (i .right , expected_scalar_type )
235+ # don't need to check IntervalIndex(...) or from_intervals, since
236+ # mixed tz are disallowed at the Interval level
237+ with pytest .raises (ValueError ):
238+ IntervalIndex .from_arrays (left , right )
225239
226- def test_constructors_error (self ):
240+ with pytest .raises (ValueError ):
241+ IntervalIndex .from_tuples (lzip (left , right ))
227242
228- # non-intervals
229- def f ():
230- IntervalIndex .from_intervals ([0.997 , 4.0 ])
231- pytest .raises (TypeError , f )
243+ with pytest .raises (ValueError ):
244+ breaks = left .tolist () + [right [- 1 ]]
245+ IntervalIndex .from_breaks (breaks )
232246
233247 def test_properties (self , closed ):
234248 index = self .create_index (closed = closed )
@@ -964,23 +978,46 @@ def test_sort_values(self, closed):
964978 expected = IntervalIndex ([np .nan , Interval (1 , 2 ), Interval (0 , 1 )])
965979 tm .assert_index_equal (result , expected )
966980
967- def test_datetime (self ):
968- dates = date_range ('2000' , periods = 3 )
969- idx = IntervalIndex .from_breaks (dates )
970-
971- tm .assert_index_equal (idx .left , dates [:2 ])
972- tm .assert_index_equal (idx .right , dates [- 2 :])
973-
974- expected = date_range ('2000-01-01T12:00' , periods = 2 )
975- tm .assert_index_equal (idx .mid , expected )
976-
977- assert Timestamp ('2000-01-01T12' ) not in idx
978- assert Timestamp ('2000-01-01T12' ) not in idx
979-
980- target = date_range ('1999-12-31T12:00' , periods = 7 , freq = '12H' )
981- actual = idx .get_indexer (target )
981+ @pytest .mark .parametrize ('tz' , [None , 'US/Eastern' ])
982+ def test_datetime (self , tz ):
983+ start = Timestamp ('2000-01-01' , tz = tz )
984+ dates = date_range (start = start , periods = 10 )
985+ index = IntervalIndex .from_breaks (dates )
986+
987+ # test mid
988+ start = Timestamp ('2000-01-01T12:00' , tz = tz )
989+ expected = date_range (start = start , periods = 9 )
990+ tm .assert_index_equal (index .mid , expected )
991+
992+ # __contains__ doesn't check individual points
993+ assert Timestamp ('2000-01-01' , tz = tz ) not in index
994+ assert Timestamp ('2000-01-01T12' , tz = tz ) not in index
995+ assert Timestamp ('2000-01-02' , tz = tz ) not in index
996+ iv_true = Interval (Timestamp ('2000-01-01T08' , tz = tz ),
997+ Timestamp ('2000-01-01T18' , tz = tz ))
998+ iv_false = Interval (Timestamp ('1999-12-31' , tz = tz ),
999+ Timestamp ('2000-01-01' , tz = tz ))
1000+ assert iv_true in index
1001+ assert iv_false not in index
1002+
1003+ # .contains does check individual points
1004+ assert not index .contains (Timestamp ('2000-01-01' , tz = tz ))
1005+ assert index .contains (Timestamp ('2000-01-01T12' , tz = tz ))
1006+ assert index .contains (Timestamp ('2000-01-02' , tz = tz ))
1007+ assert index .contains (iv_true )
1008+ assert not index .contains (iv_false )
1009+
1010+ # test get_indexer
1011+ start = Timestamp ('1999-12-31T12:00' , tz = tz )
1012+ target = date_range (start = start , periods = 7 , freq = '12H' )
1013+ actual = index .get_indexer (target )
1014+ expected = np .array ([- 1 , - 1 , 0 , 0 , 1 , 1 , 2 ], dtype = 'intp' )
1015+ tm .assert_numpy_array_equal (actual , expected )
9821016
983- expected = np .array ([- 1 , - 1 , 0 , 0 , 1 , 1 , - 1 ], dtype = 'intp' )
1017+ start = Timestamp ('2000-01-08T18:00' , tz = tz )
1018+ target = date_range (start = start , periods = 7 , freq = '6H' )
1019+ actual = index .get_indexer (target )
1020+ expected = np .array ([7 , 7 , 8 , 8 , 8 , 8 , - 1 ], dtype = 'intp' )
9841021 tm .assert_numpy_array_equal (actual , expected )
9851022
9861023 def test_append (self , closed ):
@@ -1079,9 +1116,11 @@ def test_construction_from_numeric(self, closed, name):
10791116 closed = closed )
10801117 tm .assert_index_equal (result , expected )
10811118
1082- def test_construction_from_timestamp (self , closed , name ):
1119+ @pytest .mark .parametrize ('tz' , [None , 'US/Eastern' ])
1120+ def test_construction_from_timestamp (self , closed , name , tz ):
10831121 # combinations of start/end/periods without freq
1084- start , end = Timestamp ('2017-01-01' ), Timestamp ('2017-01-06' )
1122+ start = Timestamp ('2017-01-01' , tz = tz )
1123+ end = Timestamp ('2017-01-06' , tz = tz )
10851124 breaks = date_range (start = start , end = end )
10861125 expected = IntervalIndex .from_breaks (breaks , name = name , closed = closed )
10871126
@@ -1099,7 +1138,8 @@ def test_construction_from_timestamp(self, closed, name):
10991138
11001139 # combinations of start/end/periods with fixed freq
11011140 freq = '2D'
1102- start , end = Timestamp ('2017-01-01' ), Timestamp ('2017-01-07' )
1141+ start = Timestamp ('2017-01-01' , tz = tz )
1142+ end = Timestamp ('2017-01-07' , tz = tz )
11031143 breaks = date_range (start = start , end = end , freq = freq )
11041144 expected = IntervalIndex .from_breaks (breaks , name = name , closed = closed )
11051145
@@ -1116,14 +1156,15 @@ def test_construction_from_timestamp(self, closed, name):
11161156 tm .assert_index_equal (result , expected )
11171157
11181158 # output truncates early if freq causes end to be skipped.
1119- end = Timestamp ('2017-01-08' )
1159+ end = Timestamp ('2017-01-08' , tz = tz )
11201160 result = interval_range (start = start , end = end , freq = freq , name = name ,
11211161 closed = closed )
11221162 tm .assert_index_equal (result , expected )
11231163
11241164 # combinations of start/end/periods with non-fixed freq
11251165 freq = 'M'
1126- start , end = Timestamp ('2017-01-01' ), Timestamp ('2017-12-31' )
1166+ start = Timestamp ('2017-01-01' , tz = tz )
1167+ end = Timestamp ('2017-12-31' , tz = tz )
11271168 breaks = date_range (start = start , end = end , freq = freq )
11281169 expected = IntervalIndex .from_breaks (breaks , name = name , closed = closed )
11291170
@@ -1140,7 +1181,7 @@ def test_construction_from_timestamp(self, closed, name):
11401181 tm .assert_index_equal (result , expected )
11411182
11421183 # output truncates early if freq causes end to be skipped.
1143- end = Timestamp ('2018-01-15' )
1184+ end = Timestamp ('2018-01-15' , tz = tz )
11441185 result = interval_range (start = start , end = end , freq = freq , name = name ,
11451186 closed = closed )
11461187 tm .assert_index_equal (result , expected )
@@ -1308,6 +1349,13 @@ def test_errors(self):
13081349 with tm .assert_raises_regex (ValueError , msg ):
13091350 interval_range (end = Timedelta ('1 day' ), periods = 10 , freq = 'foo' )
13101351
1352+ # mixed tz
1353+ start = Timestamp ('2017-01-01' , tz = 'US/Eastern' )
1354+ end = Timestamp ('2017-01-07' , tz = 'US/Pacific' )
1355+ msg = 'Start and end cannot both be tz-aware with different timezones'
1356+ with tm .assert_raises_regex (TypeError , msg ):
1357+ interval_range (start = start , end = end )
1358+
13111359
13121360class TestIntervalTree (object ):
13131361 def setup_method (self , method ):
0 commit comments