|
2 | 2 |
|
3 | 3 | import pytest
|
4 | 4 | import numpy as np
|
5 |
| -import datetime |
| 5 | +from datetime import timedelta |
6 | 6 | from pandas import (Interval, IntervalIndex, Index, isna,
|
7 | 7 | interval_range, Timestamp, Timedelta,
|
8 |
| - compat, date_range, DateOffset) |
| 8 | + compat, date_range, timedelta_range, DateOffset) |
| 9 | +from pandas.tseries.offsets import Day |
9 | 10 | from pandas._libs.interval import IntervalTree
|
10 | 11 | from pandas.tests.indexes.common import Base
|
11 | 12 | import pandas.util.testing as tm
|
@@ -763,8 +764,8 @@ def test_construction_from_numeric(self, closed):
|
763 | 764 | def test_construction_from_timestamp(self, closed):
|
764 | 765 | # combinations of start/end/periods without freq
|
765 | 766 | start, end = Timestamp('2017-01-01'), Timestamp('2017-01-06')
|
766 |
| - expected = IntervalIndex.from_breaks(date_range(start=start, end=end), |
767 |
| - name='foo', closed=closed) |
| 767 | + breaks = date_range(start=start, end=end) |
| 768 | + expected = IntervalIndex.from_breaks(breaks, name='foo', closed=closed) |
768 | 769 |
|
769 | 770 | result = interval_range(start=start, end=end, name='foo',
|
770 | 771 | closed=closed)
|
@@ -826,37 +827,90 @@ def test_construction_from_timestamp(self, closed):
|
826 | 827 | closed=closed)
|
827 | 828 | tm.assert_index_equal(result, expected)
|
828 | 829 |
|
| 830 | + @pytest.mark.parametrize('closed', ['left', 'right', 'neither', 'both']) |
| 831 | + def test_construction_from_timedelta(self, closed): |
| 832 | + # combinations of start/end/periods without freq |
| 833 | + start, end = Timedelta('1 day'), Timedelta('6 days') |
| 834 | + breaks = timedelta_range(start=start, end=end) |
| 835 | + expected = IntervalIndex.from_breaks(breaks, name='foo', closed=closed) |
| 836 | + |
| 837 | + result = interval_range(start=start, end=end, name='foo', |
| 838 | + closed=closed) |
| 839 | + tm.assert_index_equal(result, expected) |
| 840 | + |
| 841 | + result = interval_range(start=start, periods=5, name='foo', |
| 842 | + closed=closed) |
| 843 | + tm.assert_index_equal(result, expected) |
| 844 | + |
| 845 | + result = interval_range(end=end, periods=5, name='foo', |
| 846 | + closed=closed) |
| 847 | + tm.assert_index_equal(result, expected) |
| 848 | + |
| 849 | + # combinations of start/end/periods with fixed freq |
| 850 | + freq = '2D' |
| 851 | + start, end = Timedelta('1 day'), Timedelta('7 days') |
| 852 | + breaks = timedelta_range(start=start, end=end, freq=freq) |
| 853 | + expected = IntervalIndex.from_breaks(breaks, name='foo', closed=closed) |
| 854 | + |
| 855 | + result = interval_range(start=start, end=end, freq=freq, name='foo', |
| 856 | + closed=closed) |
| 857 | + tm.assert_index_equal(result, expected) |
| 858 | + |
| 859 | + result = interval_range(start=start, periods=3, freq=freq, name='foo', |
| 860 | + closed=closed) |
| 861 | + tm.assert_index_equal(result, expected) |
| 862 | + |
| 863 | + result = interval_range(end=end, periods=3, freq=freq, name='foo', |
| 864 | + closed=closed) |
| 865 | + tm.assert_index_equal(result, expected) |
| 866 | + |
| 867 | + # output truncates early if freq causes end to be skipped. |
| 868 | + end = Timedelta('7 days 1 hour') |
| 869 | + result = interval_range(start=start, end=end, freq=freq, name='foo', |
| 870 | + closed=closed) |
| 871 | + tm.assert_index_equal(result, expected) |
| 872 | + |
829 | 873 | def test_constructor_coverage(self):
|
830 | 874 | # float value for periods
|
831 | 875 | expected = pd.interval_range(start=0, periods=10)
|
832 | 876 | result = pd.interval_range(start=0, periods=10.5)
|
833 | 877 | tm.assert_index_equal(result, expected)
|
834 | 878 |
|
835 |
| - # equivalent datetime-like start/end |
| 879 | + # equivalent timestamp-like start/end |
836 | 880 | start, end = Timestamp('2017-01-01'), Timestamp('2017-01-15')
|
837 | 881 | expected = pd.interval_range(start=start, end=end)
|
838 | 882 |
|
839 | 883 | result = pd.interval_range(start=start.to_pydatetime(),
|
840 | 884 | end=end.to_pydatetime())
|
841 | 885 | tm.assert_index_equal(result, expected)
|
842 | 886 |
|
843 |
| - result = pd.interval_range(start=start.date(), end=end.date()) |
| 887 | + result = pd.interval_range(start=start.tz_localize('UTC'), |
| 888 | + end=end.tz_localize('UTC')) |
844 | 889 | tm.assert_index_equal(result, expected)
|
845 | 890 |
|
846 |
| - result = pd.interval_range(start=str(start), end=str(end)) |
| 891 | + result = pd.interval_range(start=start.asm8, end=end.asm8) |
847 | 892 | tm.assert_index_equal(result, expected)
|
848 | 893 |
|
849 |
| - result = pd.interval_range(start=start.strftime('%Y-%m-%d'), |
850 |
| - end=end.strftime('%Y-%m-%d')) |
| 894 | + # equivalent freq with timestamp |
| 895 | + equiv_freq = ['D', Day(), Timedelta(days=1), timedelta(days=1), |
| 896 | + DateOffset(days=1)] |
| 897 | + for freq in equiv_freq: |
| 898 | + result = pd.interval_range(start=start, end=end, freq=freq) |
| 899 | + tm.assert_index_equal(result, expected) |
| 900 | + |
| 901 | + # equivalent timedelta-like start/end |
| 902 | + start, end = Timedelta(days=1), Timedelta(days=10) |
| 903 | + expected = pd.interval_range(start=start, end=end) |
| 904 | + |
| 905 | + result = pd.interval_range(start=start.to_pytimedelta(), |
| 906 | + end=end.to_pytimedelta()) |
851 | 907 | tm.assert_index_equal(result, expected)
|
852 | 908 |
|
853 |
| - result = pd.interval_range(start=start.strftime('%m/%d/%y'), |
854 |
| - end=end.strftime('%m/%d/%y')) |
| 909 | + result = pd.interval_range(start=start.asm8, end=end.asm8) |
855 | 910 | tm.assert_index_equal(result, expected)
|
856 | 911 |
|
857 |
| - # equivalent freq |
858 |
| - equiv_freq = ['D', DateOffset(days=1), Timedelta(days=1), |
859 |
| - datetime.timedelta(days=1)] |
| 912 | + # equivalent freq with timedelta |
| 913 | + equiv_freq = ['D', Day(), Timedelta(days=1), timedelta(days=1)] |
860 | 914 | for freq in equiv_freq:
|
861 | 915 | result = pd.interval_range(start=start, end=end, freq=freq)
|
862 | 916 | tm.assert_index_equal(result, expected)
|
@@ -885,37 +939,61 @@ def test_errors(self):
|
885 | 939 | # mixed units
|
886 | 940 | msg = 'start, end, freq need to be type compatible'
|
887 | 941 | with tm.assert_raises_regex(TypeError, msg):
|
888 |
| - interval_range(start=Timestamp('20130101'), end=10, freq=2) |
| 942 | + interval_range(start=0, end=Timestamp('20130101'), freq=2) |
| 943 | + |
| 944 | + with tm.assert_raises_regex(TypeError, msg): |
| 945 | + interval_range(start=0, end=Timedelta('1 day'), freq=2) |
889 | 946 |
|
890 | 947 | with tm.assert_raises_regex(TypeError, msg):
|
891 |
| - interval_range(start=0, end=Timestamp('20130101'), freq=2) |
| 948 | + interval_range(start=0, end=10, freq='D') |
| 949 | + |
| 950 | + with tm.assert_raises_regex(TypeError, msg): |
| 951 | + interval_range(start=Timestamp('20130101'), end=10, freq='D') |
| 952 | + |
| 953 | + with tm.assert_raises_regex(TypeError, msg): |
| 954 | + interval_range(start=Timestamp('20130101'), |
| 955 | + end=Timedelta('1 day'), freq='D') |
892 | 956 |
|
893 | 957 | with tm.assert_raises_regex(TypeError, msg):
|
894 |
| - interval_range(start=0, end=10, freq=Timedelta('1day')) |
| 958 | + interval_range(start=Timestamp('20130101'), |
| 959 | + end=Timestamp('20130110'), freq=2) |
| 960 | + |
| 961 | + with tm.assert_raises_regex(TypeError, msg): |
| 962 | + interval_range(start=Timedelta('1 day'), end=10, freq='D') |
| 963 | + |
| 964 | + with tm.assert_raises_regex(TypeError, msg): |
| 965 | + interval_range(start=Timedelta('1 day'), |
| 966 | + end=Timestamp('20130110'), freq='D') |
| 967 | + |
| 968 | + with tm.assert_raises_regex(TypeError, msg): |
| 969 | + interval_range(start=Timedelta('1 day'), |
| 970 | + end=Timedelta('10 days'), freq=2) |
895 | 971 |
|
896 | 972 | # invalid periods
|
897 | 973 | msg = 'periods must be a number, got foo'
|
898 | 974 | with tm.assert_raises_regex(TypeError, msg):
|
899 | 975 | interval_range(start=0, periods='foo')
|
900 | 976 |
|
901 | 977 | # invalid start
|
902 |
| - msg = 'start must be numeric or datetime-like' |
| 978 | + msg = 'start must be numeric or datetime-like, got foo' |
903 | 979 | with tm.assert_raises_regex(ValueError, msg):
|
904 | 980 | interval_range(start='foo', periods=10)
|
905 | 981 |
|
906 | 982 | # invalid end
|
907 |
| - msg = 'end must be numeric or datetime-like' |
| 983 | + msg = 'end must be numeric or datetime-like, got \(0, 1\]' |
908 | 984 | with tm.assert_raises_regex(ValueError, msg):
|
909 | 985 | interval_range(end=Interval(0, 1), periods=10)
|
910 | 986 |
|
911 | 987 | # invalid freq for datetime-like
|
912 |
| - msg = ('freq must be convertible to DateOffset when start/end are ' |
913 |
| - 'datetime-like') |
| 988 | + msg = 'freq must be numeric or convertible to DateOffset, got foo' |
| 989 | + with tm.assert_raises_regex(ValueError, msg): |
| 990 | + interval_range(start=0, end=10, freq='foo') |
| 991 | + |
914 | 992 | with tm.assert_raises_regex(ValueError, msg):
|
915 | 993 | interval_range(start=Timestamp('20130101'), periods=10, freq='foo')
|
916 | 994 |
|
917 | 995 | with tm.assert_raises_regex(ValueError, msg):
|
918 |
| - interval_range(end=Timestamp('20130101'), periods=10, freq='foo') |
| 996 | + interval_range(end=Timedelta('1 day'), periods=10, freq='foo') |
919 | 997 |
|
920 | 998 |
|
921 | 999 | class TestIntervalTree(object):
|
|
0 commit comments