From 2ee25f0de316a7292dce88369dcba6f942066f0a Mon Sep 17 00:00:00 2001 From: Brock Date: Mon, 2 Nov 2020 13:07:32 -0800 Subject: [PATCH 1/6] TST/REF: share to_period tests --- pandas/conftest.py | 10 +++ pandas/core/frame.py | 14 ++- pandas/tests/frame/methods/test_to_period.py | 77 +++++++++++++--- .../tests/frame/methods/test_to_timestamp.py | 89 +++++++++++++++---- pandas/tests/series/methods/test_to_period.py | 56 ------------ .../tests/series/methods/test_to_timestamp.py | 64 ------------- 6 files changed, 157 insertions(+), 153 deletions(-) delete mode 100644 pandas/tests/series/methods/test_to_period.py delete mode 100644 pandas/tests/series/methods/test_to_timestamp.py diff --git a/pandas/conftest.py b/pandas/conftest.py index 515d20e8c5781..dfca95c1f9efe 100644 --- a/pandas/conftest.py +++ b/pandas/conftest.py @@ -290,6 +290,16 @@ def unique_nulls_fixture(request): # ---------------------------------------------------------------- # Classes # ---------------------------------------------------------------- + + +@pytest.fixture(params=[pd.DataFrame, pd.Series]) +def frame_or_series(request): + """ + Fixture to parametrize over DataFrame and Series. + """ + return request.param + + @pytest.fixture( params=[pd.Index, pd.Series], ids=["index", "series"] # type: ignore[list-item] ) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 5134529d9c21f..24b89085ac121 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -131,7 +131,13 @@ from pandas.core.construction import extract_array from pandas.core.generic import NDFrame, _shared_docs from pandas.core.indexes import base as ibase -from pandas.core.indexes.api import Index, ensure_index, ensure_index_from_sequences +from pandas.core.indexes.api import ( + DatetimeIndex, + Index, + PeriodIndex, + ensure_index, + ensure_index_from_sequences, +) from pandas.core.indexes.multi import MultiIndex, maybe_droplevels from pandas.core.indexing import check_bool_indexer, convert_to_index_sliceable from pandas.core.internals import BlockManager @@ -9253,6 +9259,9 @@ def to_timestamp( axis_name = self._get_axis_name(axis) old_ax = getattr(self, axis_name) + if not isinstance(old_ax, PeriodIndex): + raise TypeError(f"unsupported Type {type(old_ax).__name__}") + new_ax = old_ax.to_timestamp(freq=freq, how=how) setattr(new_obj, axis_name, new_ax) @@ -9282,6 +9291,9 @@ def to_period(self, freq=None, axis: Axis = 0, copy: bool = True) -> DataFrame: axis_name = self._get_axis_name(axis) old_ax = getattr(self, axis_name) + if not isinstance(old_ax, DatetimeIndex): + raise TypeError(f"unsupported Type {type(old_ax).__name__}") + new_ax = old_ax.to_period(freq=freq) setattr(new_obj, axis_name, new_ax) diff --git a/pandas/tests/frame/methods/test_to_period.py b/pandas/tests/frame/methods/test_to_period.py index 051461b6c554d..e3f3fe9f697a9 100644 --- a/pandas/tests/frame/methods/test_to_period.py +++ b/pandas/tests/frame/methods/test_to_period.py @@ -1,36 +1,87 @@ import numpy as np import pytest -from pandas import DataFrame, date_range, period_range +from pandas import ( + DataFrame, + DatetimeIndex, + PeriodIndex, + Series, + date_range, + period_range, +) import pandas._testing as tm class TestToPeriod: - def test_frame_to_period(self): + def test_to_period(self, frame_or_series): K = 5 - dr = date_range("1/1/2000", "1/1/2001") - pr = period_range("1/1/2000", "1/1/2001") - df = DataFrame(np.random.randn(len(dr), K), index=dr) - df["mix"] = "a" + dr = date_range("1/1/2000", "1/1/2001", freq="D") + obj = DataFrame( + np.random.randn(len(dr), K), index=dr, columns=["A", "B", "C", "D", "E"] + ) + obj["mix"] = "a" + if frame_or_series is Series: + obj = obj["A"] - pts = df.to_period() - exp = df.copy() - exp.index = pr - tm.assert_frame_equal(pts, exp) + pts = obj.to_period() + exp = obj.copy() + exp.index = period_range("1/1/2000", "1/1/2001") + tm.assert_equal(pts, exp) - pts = df.to_period("M") - tm.assert_index_equal(pts.index, exp.index.asfreq("M")) + pts = obj.to_period("M") + exp.index = exp.index.asfreq("M") + tm.assert_equal(pts, exp) + + def test_to_period_without_freq(self, frame_or_series): + # GH#7606 without freq + idx = DatetimeIndex(["2011-01-01", "2011-01-02", "2011-01-03", "2011-01-04"]) + exp_idx = PeriodIndex( + ["2011-01-01", "2011-01-02", "2011-01-03", "2011-01-04"], freq="D" + ) + + obj = DataFrame(np.random.randn(4, 4), index=idx, columns=idx) + if frame_or_series is Series: + obj = obj[idx[0]] + expected = obj.copy() + expected.index = exp_idx + tm.assert_equal(obj.to_period(), expected) + + if frame_or_series is DataFrame: + expected = obj.copy() + expected.columns = exp_idx + tm.assert_frame_equal(obj.to_period(axis=1), expected) + + def test_to_period_columns(self): + dr = date_range("1/1/2000", "1/1/2001") + df = DataFrame(np.random.randn(len(dr), 5), index=dr) + df["mix"] = "a" df = df.T pts = df.to_period(axis=1) exp = df.copy() - exp.columns = pr + exp.columns = period_range("1/1/2000", "1/1/2001") tm.assert_frame_equal(pts, exp) pts = df.to_period("M", axis=1) tm.assert_index_equal(pts.columns, exp.columns.asfreq("M")) + def test_to_period_invalid_axis(self): + dr = date_range("1/1/2000", "1/1/2001") + df = DataFrame(np.random.randn(len(dr), 5), index=dr) + df["mix"] = "a" + msg = "No axis named 2 for object type DataFrame" with pytest.raises(ValueError, match=msg): df.to_period(axis=2) + + def test_to_period_raises(self, index, frame_or_series): + # https://github.com/pandas-dev/pandas/issues/33327 + obj = Series(index=index, dtype=object) + if frame_or_series is DataFrame: + obj = obj.to_frame() + + if not isinstance(index, DatetimeIndex): + msg = f"unsupported Type {type(index).__name__}" + with pytest.raises(TypeError, match=msg): + obj.to_period() diff --git a/pandas/tests/frame/methods/test_to_timestamp.py b/pandas/tests/frame/methods/test_to_timestamp.py index ae7d2827e05a6..e23d12b691b4a 100644 --- a/pandas/tests/frame/methods/test_to_timestamp.py +++ b/pandas/tests/frame/methods/test_to_timestamp.py @@ -6,6 +6,8 @@ from pandas import ( DataFrame, DatetimeIndex, + PeriodIndex, + Series, Timedelta, date_range, period_range, @@ -14,48 +16,70 @@ import pandas._testing as tm +def _get_with_delta(delta, freq="A-DEC"): + return date_range( + to_datetime("1/1/2001") + delta, + to_datetime("12/31/2009") + delta, + freq=freq, + ) + + class TestToTimestamp: - def test_frame_to_time_stamp(self): + def test_to_timestamp(self, frame_or_series): K = 5 index = period_range(freq="A", start="1/1/2001", end="12/1/2009") - df = DataFrame(np.random.randn(len(index), K), index=index) - df["mix"] = "a" + obj = DataFrame( + np.random.randn(len(index), K), + index=index, + columns=["A", "B", "C", "D", "E"], + ) + obj["mix"] = "a" + if frame_or_series is Series: + obj = obj["A"] exp_index = date_range("1/1/2001", end="12/31/2009", freq="A-DEC") exp_index = exp_index + Timedelta(1, "D") - Timedelta(1, "ns") - result = df.to_timestamp("D", "end") + result = obj.to_timestamp("D", "end") tm.assert_index_equal(result.index, exp_index) - tm.assert_numpy_array_equal(result.values, df.values) + tm.assert_numpy_array_equal(result.values, obj.values) + if frame_or_series is Series: + assert result.name == "A" exp_index = date_range("1/1/2001", end="1/1/2009", freq="AS-JAN") - result = df.to_timestamp("D", "start") + result = obj.to_timestamp("D", "start") tm.assert_index_equal(result.index, exp_index) - def _get_with_delta(delta, freq="A-DEC"): - return date_range( - to_datetime("1/1/2001") + delta, - to_datetime("12/31/2009") + delta, - freq=freq, - ) + result = obj.to_timestamp(how="start") + tm.assert_index_equal(result.index, exp_index) delta = timedelta(hours=23) - result = df.to_timestamp("H", "end") + result = obj.to_timestamp("H", "end") exp_index = _get_with_delta(delta) exp_index = exp_index + Timedelta(1, "h") - Timedelta(1, "ns") tm.assert_index_equal(result.index, exp_index) delta = timedelta(hours=23, minutes=59) - result = df.to_timestamp("T", "end") + result = obj.to_timestamp("T", "end") exp_index = _get_with_delta(delta) exp_index = exp_index + Timedelta(1, "m") - Timedelta(1, "ns") tm.assert_index_equal(result.index, exp_index) - result = df.to_timestamp("S", "end") + result = obj.to_timestamp("S", "end") delta = timedelta(hours=23, minutes=59, seconds=59) exp_index = _get_with_delta(delta) exp_index = exp_index + Timedelta(1, "s") - Timedelta(1, "ns") tm.assert_index_equal(result.index, exp_index) + def test_to_timestamp_columns(self): + K = 5 + index = period_range(freq="A", start="1/1/2001", end="12/1/2009") + df = DataFrame( + np.random.randn(len(index), K), + index=index, + columns=["A", "B", "C", "D", "E"], + ) + df["mix"] = "a" + # columns df = df.T @@ -87,10 +111,6 @@ def _get_with_delta(delta, freq="A-DEC"): exp_index = exp_index + Timedelta(1, "s") - Timedelta(1, "ns") tm.assert_index_equal(result.columns, exp_index) - # invalid axis - with pytest.raises(ValueError, match="axis"): - df.to_timestamp(axis=2) - result1 = df.to_timestamp("5t", axis=1) result2 = df.to_timestamp("t", axis=1) expected = date_range("2001-01-01", "2009-01-01", freq="AS") @@ -101,3 +121,34 @@ def _get_with_delta(delta, freq="A-DEC"): # PeriodIndex.to_timestamp always use 'infer' assert result1.columns.freqstr == "AS-JAN" assert result2.columns.freqstr == "AS-JAN" + + def to_timestamp_invalid_axis(self): + index = period_range(freq="A", start="1/1/2001", end="12/1/2009") + obj = DataFrame(np.random.randn(len(index), 5), index=index) + + # invalid axis + with pytest.raises(ValueError, match="axis"): + obj.to_timestamp(axis=2) + + def test_to_timestamp_hourly(self, frame_or_series): + + index = period_range(freq="H", start="1/1/2001", end="1/2/2001") + obj = Series(1, index=index, name="foo") + if frame_or_series is not Series: + obj = obj.to_frame() + + exp_index = date_range("1/1/2001 00:59:59", end="1/2/2001 00:59:59", freq="H") + result = obj.to_timestamp(how="end") + exp_index = exp_index + Timedelta(1, "s") - Timedelta(1, "ns") + tm.assert_index_equal(result.index, exp_index) + if frame_or_series is Series: + assert result.name == "foo" + + def test_to_timestamp_raises(self, index, frame_or_series): + # GH#33327 + obj = frame_or_series(index=index, dtype=object) + + if not isinstance(index, PeriodIndex): + msg = f"unsupported Type {type(index).__name__}" + with pytest.raises(TypeError, match=msg): + obj.to_timestamp() diff --git a/pandas/tests/series/methods/test_to_period.py b/pandas/tests/series/methods/test_to_period.py deleted file mode 100644 index b40fc81931e20..0000000000000 --- a/pandas/tests/series/methods/test_to_period.py +++ /dev/null @@ -1,56 +0,0 @@ -import numpy as np -import pytest - -from pandas import ( - DataFrame, - DatetimeIndex, - PeriodIndex, - Series, - date_range, - period_range, -) -import pandas._testing as tm - - -class TestToPeriod: - def test_to_period(self): - rng = date_range("1/1/2000", "1/1/2001", freq="D") - ts = Series(np.random.randn(len(rng)), index=rng) - - pts = ts.to_period() - exp = ts.copy() - exp.index = period_range("1/1/2000", "1/1/2001") - tm.assert_series_equal(pts, exp) - - pts = ts.to_period("M") - exp.index = exp.index.asfreq("M") - tm.assert_index_equal(pts.index, exp.index.asfreq("M")) - tm.assert_series_equal(pts, exp) - - # GH#7606 without freq - idx = DatetimeIndex(["2011-01-01", "2011-01-02", "2011-01-03", "2011-01-04"]) - exp_idx = PeriodIndex( - ["2011-01-01", "2011-01-02", "2011-01-03", "2011-01-04"], freq="D" - ) - - s = Series(np.random.randn(4), index=idx) - expected = s.copy() - expected.index = exp_idx - tm.assert_series_equal(s.to_period(), expected) - - df = DataFrame(np.random.randn(4, 4), index=idx, columns=idx) - expected = df.copy() - expected.index = exp_idx - tm.assert_frame_equal(df.to_period(), expected) - - expected = df.copy() - expected.columns = exp_idx - tm.assert_frame_equal(df.to_period(axis=1), expected) - - def test_to_period_raises(self, index): - # https://github.com/pandas-dev/pandas/issues/33327 - ser = Series(index=index, dtype=object) - if not isinstance(index, DatetimeIndex): - msg = f"unsupported Type {type(index).__name__}" - with pytest.raises(TypeError, match=msg): - ser.to_period() diff --git a/pandas/tests/series/methods/test_to_timestamp.py b/pandas/tests/series/methods/test_to_timestamp.py deleted file mode 100644 index 13a2042a2f639..0000000000000 --- a/pandas/tests/series/methods/test_to_timestamp.py +++ /dev/null @@ -1,64 +0,0 @@ -from datetime import timedelta - -import pytest - -from pandas import PeriodIndex, Series, Timedelta, date_range, period_range, to_datetime -import pandas._testing as tm - - -class TestToTimestamp: - def test_to_timestamp(self): - index = period_range(freq="A", start="1/1/2001", end="12/1/2009") - series = Series(1, index=index, name="foo") - - exp_index = date_range("1/1/2001", end="12/31/2009", freq="A-DEC") - result = series.to_timestamp(how="end") - exp_index = exp_index + Timedelta(1, "D") - Timedelta(1, "ns") - tm.assert_index_equal(result.index, exp_index) - assert result.name == "foo" - - exp_index = date_range("1/1/2001", end="1/1/2009", freq="AS-JAN") - result = series.to_timestamp(how="start") - tm.assert_index_equal(result.index, exp_index) - - def _get_with_delta(delta, freq="A-DEC"): - return date_range( - to_datetime("1/1/2001") + delta, - to_datetime("12/31/2009") + delta, - freq=freq, - ) - - delta = timedelta(hours=23) - result = series.to_timestamp("H", "end") - exp_index = _get_with_delta(delta) - exp_index = exp_index + Timedelta(1, "h") - Timedelta(1, "ns") - tm.assert_index_equal(result.index, exp_index) - - delta = timedelta(hours=23, minutes=59) - result = series.to_timestamp("T", "end") - exp_index = _get_with_delta(delta) - exp_index = exp_index + Timedelta(1, "m") - Timedelta(1, "ns") - tm.assert_index_equal(result.index, exp_index) - - result = series.to_timestamp("S", "end") - delta = timedelta(hours=23, minutes=59, seconds=59) - exp_index = _get_with_delta(delta) - exp_index = exp_index + Timedelta(1, "s") - Timedelta(1, "ns") - tm.assert_index_equal(result.index, exp_index) - - index = period_range(freq="H", start="1/1/2001", end="1/2/2001") - series = Series(1, index=index, name="foo") - - exp_index = date_range("1/1/2001 00:59:59", end="1/2/2001 00:59:59", freq="H") - result = series.to_timestamp(how="end") - exp_index = exp_index + Timedelta(1, "s") - Timedelta(1, "ns") - tm.assert_index_equal(result.index, exp_index) - assert result.name == "foo" - - def test_to_timestamp_raises(self, index): - # https://github.com/pandas-dev/pandas/issues/33327 - ser = Series(index=index, dtype=object) - if not isinstance(index, PeriodIndex): - msg = f"unsupported Type {type(index).__name__}" - with pytest.raises(TypeError, match=msg): - ser.to_timestamp() From 3f0451eb5206c66a74508f9a25fdb6979ab21469 Mon Sep 17 00:00:00 2001 From: Brock Date: Mon, 2 Nov 2020 14:03:20 -0800 Subject: [PATCH 2/6] share between_time tests --- .../tests/frame/methods/test_between_time.py | 18 +++-- .../tests/series/methods/test_between_time.py | 68 ------------------- 2 files changed, 13 insertions(+), 73 deletions(-) diff --git a/pandas/tests/frame/methods/test_between_time.py b/pandas/tests/frame/methods/test_between_time.py index 19e802d0fa663..73cc82a9bc851 100644 --- a/pandas/tests/frame/methods/test_between_time.py +++ b/pandas/tests/frame/methods/test_between_time.py @@ -8,9 +8,12 @@ class TestBetweenTime: - def test_between_time(self, close_open_fixture): + def test_between_time(self, close_open_fixture, frame_or_series): rng = date_range("1/1/2000", "1/5/2000", freq="5min") ts = DataFrame(np.random.randn(len(rng), 2), index=rng) + if frame_or_series is not DataFrame: + ts = ts[0] + stime = time(0, 0) etime = time(1, 0) inc_start, inc_end = close_open_fixture @@ -37,11 +40,13 @@ def test_between_time(self, close_open_fixture): result = ts.between_time("00:00", "01:00") expected = ts.between_time(stime, etime) - tm.assert_frame_equal(result, expected) + tm.assert_equal(result, expected) # across midnight rng = date_range("1/1/2000", "1/5/2000", freq="5min") ts = DataFrame(np.random.randn(len(rng), 2), index=rng) + if frame_or_series is not DataFrame: + ts = ts[0] stime = time(22, 0) etime = time(9, 0) @@ -65,12 +70,15 @@ def test_between_time(self, close_open_fixture): else: assert (t < etime) or (t >= stime) - def test_between_time_raises(self): + def test_between_time_raises(self, frame_or_series): # GH#20725 - df = DataFrame([[1, 2, 3], [4, 5, 6]]) + obj = DataFrame([[1, 2, 3], [4, 5, 6]]) + if frame_or_series is not DataFrame: + obj = obj[0] + msg = "Index must be DatetimeIndex" with pytest.raises(TypeError, match=msg): # index is not a DatetimeIndex - df.between_time(start_time="00:00", end_time="12:00") + obj.between_time(start_time="00:00", end_time="12:00") def test_between_time_axis(self, axis): # GH#8839 diff --git a/pandas/tests/series/methods/test_between_time.py b/pandas/tests/series/methods/test_between_time.py index e9d2f8e6f1637..e7255b90fc06b 100644 --- a/pandas/tests/series/methods/test_between_time.py +++ b/pandas/tests/series/methods/test_between_time.py @@ -1,5 +1,4 @@ from datetime import datetime, time -from itertools import product import numpy as np import pytest @@ -27,73 +26,6 @@ def test_localized_between_time(self, tzstr): tm.assert_series_equal(result, expected) assert timezones.tz_compare(result.index.tz, tz) - def test_between_time(self): - rng = date_range("1/1/2000", "1/5/2000", freq="5min") - ts = Series(np.random.randn(len(rng)), index=rng) - stime = time(0, 0) - etime = time(1, 0) - - close_open = product([True, False], [True, False]) - for inc_start, inc_end in close_open: - filtered = ts.between_time(stime, etime, inc_start, inc_end) - exp_len = 13 * 4 + 1 - if not inc_start: - exp_len -= 5 - if not inc_end: - exp_len -= 4 - - assert len(filtered) == exp_len - for rs in filtered.index: - t = rs.time() - if inc_start: - assert t >= stime - else: - assert t > stime - - if inc_end: - assert t <= etime - else: - assert t < etime - - result = ts.between_time("00:00", "01:00") - expected = ts.between_time(stime, etime) - tm.assert_series_equal(result, expected) - - # across midnight - rng = date_range("1/1/2000", "1/5/2000", freq="5min") - ts = Series(np.random.randn(len(rng)), index=rng) - stime = time(22, 0) - etime = time(9, 0) - - close_open = product([True, False], [True, False]) - for inc_start, inc_end in close_open: - filtered = ts.between_time(stime, etime, inc_start, inc_end) - exp_len = (12 * 11 + 1) * 4 + 1 - if not inc_start: - exp_len -= 4 - if not inc_end: - exp_len -= 4 - - assert len(filtered) == exp_len - for rs in filtered.index: - t = rs.time() - if inc_start: - assert (t >= stime) or (t <= etime) - else: - assert (t > stime) or (t <= etime) - - if inc_end: - assert (t <= etime) or (t >= stime) - else: - assert (t < etime) or (t >= stime) - - def test_between_time_raises(self): - # GH20725 - ser = Series("a b c".split()) - msg = "Index must be DatetimeIndex" - with pytest.raises(TypeError, match=msg): - ser.between_time(start_time="00:00", end_time="12:00") - def test_between_time_types(self): # GH11818 rng = date_range("1/1/2000", "1/5/2000", freq="5min") From 1b0dc6969bbe57c6a1e65376b9b25b96fcb7fffd Mon Sep 17 00:00:00 2001 From: Brock Date: Mon, 2 Nov 2020 14:10:12 -0800 Subject: [PATCH 3/6] TST: share between_time tests --- .../tests/frame/methods/test_between_time.py | 34 +++++++++++++++++-- .../tests/indexes/datetimes/test_indexing.py | 9 +++++ .../tests/series/methods/test_between_time.py | 34 ------------------- 3 files changed, 41 insertions(+), 36 deletions(-) diff --git a/pandas/tests/frame/methods/test_between_time.py b/pandas/tests/frame/methods/test_between_time.py index 73cc82a9bc851..03e31d40cb361 100644 --- a/pandas/tests/frame/methods/test_between_time.py +++ b/pandas/tests/frame/methods/test_between_time.py @@ -1,13 +1,43 @@ -from datetime import time +from datetime import datetime, time import numpy as np import pytest -from pandas import DataFrame, date_range +from pandas._libs.tslibs import timezones + +from pandas import DataFrame, Series, date_range import pandas._testing as tm class TestBetweenTime: + @pytest.mark.parametrize("tzstr", ["US/Eastern", "dateutil/US/Eastern"]) + def test_localized_between_time(self, tzstr, frame_or_series): + tz = timezones.maybe_get_tz(tzstr) + + rng = date_range("4/16/2012", "5/1/2012", freq="H") + ts = Series(np.random.randn(len(rng)), index=rng) + if frame_or_series is DataFrame: + ts = ts.to_frame() + + ts_local = ts.tz_localize(tzstr) + + t1, t2 = time(10, 0), time(11, 0) + result = ts_local.between_time(t1, t2) + expected = ts.between_time(t1, t2).tz_localize(tzstr) + tm.assert_equal(result, expected) + assert timezones.tz_compare(result.index.tz, tz) + + def test_between_time_types(self, frame_or_series): + # GH11818 + rng = date_range("1/1/2000", "1/5/2000", freq="5min") + obj = DataFrame({"A": 0}, index=rng) + if frame_or_series is Series: + obj = obj["A"] + + msg = r"Cannot convert arg \[datetime\.datetime\(2010, 1, 2, 1, 0\)\] to a time" + with pytest.raises(ValueError, match=msg): + obj.between_time(datetime(2010, 1, 2, 1), datetime(2010, 1, 2, 5)) + def test_between_time(self, close_open_fixture, frame_or_series): rng = date_range("1/1/2000", "1/5/2000", freq="5min") ts = DataFrame(np.random.randn(len(rng), 2), index=rng) diff --git a/pandas/tests/indexes/datetimes/test_indexing.py b/pandas/tests/indexes/datetimes/test_indexing.py index 4e46eb126894b..330092b08c1b2 100644 --- a/pandas/tests/indexes/datetimes/test_indexing.py +++ b/pandas/tests/indexes/datetimes/test_indexing.py @@ -719,3 +719,12 @@ def test_slice_datetime_locs(self, box, kind, tz_aware_fixture): result = index.slice_locs(key, box(2010, 1, 2)) expected = (0, 1) assert result == expected + + +class TestIndexerBetweenTime: + def test_indexer_between_time(self): + # GH#11818 + rng = date_range("1/1/2000", "1/5/2000", freq="5min") + msg = r"Cannot convert arg \[datetime\.datetime\(2010, 1, 2, 1, 0\)\] to a time" + with pytest.raises(ValueError, match=msg): + rng.indexer_between_time(datetime(2010, 1, 2, 1), datetime(2010, 1, 2, 5)) diff --git a/pandas/tests/series/methods/test_between_time.py b/pandas/tests/series/methods/test_between_time.py index e7255b90fc06b..97eef6885afdf 100644 --- a/pandas/tests/series/methods/test_between_time.py +++ b/pandas/tests/series/methods/test_between_time.py @@ -1,46 +1,12 @@ -from datetime import datetime, time - import numpy as np import pytest -from pandas._libs.tslibs import timezones import pandas.util._test_decorators as td from pandas import DataFrame, Series, date_range -import pandas._testing as tm class TestBetweenTime: - @pytest.mark.parametrize("tzstr", ["US/Eastern", "dateutil/US/Eastern"]) - def test_localized_between_time(self, tzstr): - tz = timezones.maybe_get_tz(tzstr) - - rng = date_range("4/16/2012", "5/1/2012", freq="H") - ts = Series(np.random.randn(len(rng)), index=rng) - - ts_local = ts.tz_localize(tzstr) - - t1, t2 = time(10, 0), time(11, 0) - result = ts_local.between_time(t1, t2) - expected = ts.between_time(t1, t2).tz_localize(tzstr) - tm.assert_series_equal(result, expected) - assert timezones.tz_compare(result.index.tz, tz) - - def test_between_time_types(self): - # GH11818 - rng = date_range("1/1/2000", "1/5/2000", freq="5min") - msg = r"Cannot convert arg \[datetime\.datetime\(2010, 1, 2, 1, 0\)\] to a time" - with pytest.raises(ValueError, match=msg): - rng.indexer_between_time(datetime(2010, 1, 2, 1), datetime(2010, 1, 2, 5)) - - frame = DataFrame({"A": 0}, index=rng) - with pytest.raises(ValueError, match=msg): - frame.between_time(datetime(2010, 1, 2, 1), datetime(2010, 1, 2, 5)) - - series = Series(0, index=rng) - with pytest.raises(ValueError, match=msg): - series.between_time(datetime(2010, 1, 2, 1), datetime(2010, 1, 2, 5)) - @td.skip_if_has_locale def test_between_time_formats(self): # GH11818 From f7db2684da44eda2c121ba621a6588544969ee2c Mon Sep 17 00:00:00 2001 From: Brock Date: Mon, 2 Nov 2020 14:13:41 -0800 Subject: [PATCH 4/6] share the rest of between_time tests --- .../tests/frame/methods/test_between_time.py | 42 ++++++++++++++++++- .../tests/series/methods/test_between_time.py | 42 ------------------- 2 files changed, 41 insertions(+), 43 deletions(-) delete mode 100644 pandas/tests/series/methods/test_between_time.py diff --git a/pandas/tests/frame/methods/test_between_time.py b/pandas/tests/frame/methods/test_between_time.py index 03e31d40cb361..73722f36a0b86 100644 --- a/pandas/tests/frame/methods/test_between_time.py +++ b/pandas/tests/frame/methods/test_between_time.py @@ -4,12 +4,36 @@ import pytest from pandas._libs.tslibs import timezones +import pandas.util._test_decorators as td from pandas import DataFrame, Series, date_range import pandas._testing as tm class TestBetweenTime: + @td.skip_if_has_locale + def test_between_time_formats(self, frame_or_series): + # GH#11818 + rng = date_range("1/1/2000", "1/5/2000", freq="5min") + ts = DataFrame(np.random.randn(len(rng), 2), index=rng) + if frame_or_series is Series: + ts = ts[0] + + strings = [ + ("2:00", "2:30"), + ("0200", "0230"), + ("2:00am", "2:30am"), + ("0200am", "0230am"), + ("2:00:00", "2:30:00"), + ("020000", "023000"), + ("2:00:00am", "2:30:00am"), + ("020000am", "023000am"), + ] + expected_length = 28 + + for time_string in strings: + assert len(ts.between_time(*time_string)) == expected_length + @pytest.mark.parametrize("tzstr", ["US/Eastern", "dateutil/US/Eastern"]) def test_localized_between_time(self, tzstr, frame_or_series): tz = timezones.maybe_get_tz(tzstr) @@ -110,7 +134,23 @@ def test_between_time_raises(self, frame_or_series): with pytest.raises(TypeError, match=msg): # index is not a DatetimeIndex obj.between_time(start_time="00:00", end_time="12:00") - def test_between_time_axis(self, axis): + def test_between_time_axis(self, frame_or_series): + # GH#8839 + rng = date_range("1/1/2000", periods=100, freq="10min") + ts = Series(np.random.randn(len(rng)), index=rng) + if frame_or_series is DataFrame: + ts = ts.to_frame() + + stime, etime = ("08:00:00", "09:00:00") + expected_length = 7 + + assert len(ts.between_time(stime, etime)) == expected_length + assert len(ts.between_time(stime, etime, axis=0)) == expected_length + msg = f"No axis named {ts.ndim} for object type {type(ts).__name__}" + with pytest.raises(ValueError, match=msg): + ts.between_time(stime, etime, axis=ts.ndim) + + def test_between_time_axis_aliases(self, axis): # GH#8839 rng = date_range("1/1/2000", periods=100, freq="10min") ts = DataFrame(np.random.randn(len(rng), len(rng))) diff --git a/pandas/tests/series/methods/test_between_time.py b/pandas/tests/series/methods/test_between_time.py deleted file mode 100644 index 97eef6885afdf..0000000000000 --- a/pandas/tests/series/methods/test_between_time.py +++ /dev/null @@ -1,42 +0,0 @@ -import numpy as np -import pytest - -import pandas.util._test_decorators as td - -from pandas import DataFrame, Series, date_range - - -class TestBetweenTime: - @td.skip_if_has_locale - def test_between_time_formats(self): - # GH11818 - rng = date_range("1/1/2000", "1/5/2000", freq="5min") - ts = DataFrame(np.random.randn(len(rng), 2), index=rng) - - strings = [ - ("2:00", "2:30"), - ("0200", "0230"), - ("2:00am", "2:30am"), - ("0200am", "0230am"), - ("2:00:00", "2:30:00"), - ("020000", "023000"), - ("2:00:00am", "2:30:00am"), - ("020000am", "023000am"), - ] - expected_length = 28 - - for time_string in strings: - assert len(ts.between_time(*time_string)) == expected_length - - def test_between_time_axis(self): - # issue 8839 - rng = date_range("1/1/2000", periods=100, freq="10min") - ts = Series(np.random.randn(len(rng)), index=rng) - stime, etime = ("08:00:00", "09:00:00") - expected_length = 7 - - assert len(ts.between_time(stime, etime)) == expected_length - assert len(ts.between_time(stime, etime, axis=0)) == expected_length - msg = "No axis named 1 for object type Series" - with pytest.raises(ValueError, match=msg): - ts.between_time(stime, etime, axis=1) From 8c4e4105559f9e731282bab39a2136ba02192f0e Mon Sep 17 00:00:00 2001 From: Brock Date: Mon, 2 Nov 2020 14:30:39 -0800 Subject: [PATCH 5/6] TST: share at_time tessts --- pandas/tests/frame/methods/test_at_time.py | 44 ++++++++--- pandas/tests/indexing/test_loc.py | 22 ++++++ pandas/tests/series/indexing/test_getitem.py | 12 ++- pandas/tests/series/methods/test_at_time.py | 77 -------------------- 4 files changed, 68 insertions(+), 87 deletions(-) delete mode 100644 pandas/tests/series/methods/test_at_time.py diff --git a/pandas/tests/frame/methods/test_at_time.py b/pandas/tests/frame/methods/test_at_time.py index ac98d632c5dcd..859b90950ec53 100644 --- a/pandas/tests/frame/methods/test_at_time.py +++ b/pandas/tests/frame/methods/test_at_time.py @@ -4,14 +4,32 @@ import pytest import pytz +from pandas._libs.tslibs import timezones + from pandas import DataFrame, date_range import pandas._testing as tm class TestAtTime: - def test_at_time(self): + @pytest.mark.parametrize("tzstr", ["US/Eastern", "dateutil/US/Eastern"]) + def test_localized_at_time(self, tzstr, frame_or_series): + tz = timezones.maybe_get_tz(tzstr) + + rng = date_range("4/16/2012", "5/1/2012", freq="H") + ts = frame_or_series(np.random.randn(len(rng)), index=rng) + + ts_local = ts.tz_localize(tzstr) + + result = ts_local.at_time(time(10, 0)) + expected = ts.at_time(time(10, 0)).tz_localize(tzstr) + tm.assert_equal(result, expected) + assert timezones.tz_compare(result.index.tz, tz) + + def test_at_time(self, frame_or_series): rng = date_range("1/1/2000", "1/5/2000", freq="5min") ts = DataFrame(np.random.randn(len(rng), 2), index=rng) + if frame_or_series is not DataFrame: + ts = ts[0] rs = ts.at_time(rng[1]) assert (rs.index.hour == rng[1].hour).all() assert (rs.index.minute == rng[1].minute).all() @@ -19,23 +37,29 @@ def test_at_time(self): result = ts.at_time("9:30") expected = ts.at_time(time(9, 30)) - tm.assert_frame_equal(result, expected) + tm.assert_equal(result, expected) + # TODO: this is testing loc, not at_time result = ts.loc[time(9, 30)] expected = ts.loc[(rng.hour == 9) & (rng.minute == 30)] + tm.assert_equal(result, expected) - tm.assert_frame_equal(result, expected) - + def test_at_time_midnight(self, frame_or_series): # midnight, everything rng = date_range("1/1/2000", "1/31/2000") ts = DataFrame(np.random.randn(len(rng), 3), index=rng) + if frame_or_series is not DataFrame: + ts = ts[0] result = ts.at_time(time(0, 0)) - tm.assert_frame_equal(result, ts) + tm.assert_equal(result, ts) + def test_at_time_nonexistent(self, frame_or_series): # time doesn't exist rng = date_range("1/1/2012", freq="23Min", periods=384) - ts = DataFrame(np.random.randn(len(rng), 2), rng) + ts = DataFrame(np.random.randn(len(rng)), rng) + if frame_or_series is not DataFrame: + ts = ts[0] rs = ts.at_time("16:00") assert len(rs) == 0 @@ -62,12 +86,14 @@ def test_at_time_tz(self): expected = df.iloc[1:2] tm.assert_frame_equal(result, expected) - def test_at_time_raises(self): + def test_at_time_raises(self, frame_or_series): # GH#20725 - df = DataFrame([[1, 2, 3], [4, 5, 6]]) + obj = DataFrame([[1, 2, 3], [4, 5, 6]]) + if frame_or_series is not DataFrame: + obj = obj[0] msg = "Index must be DatetimeIndex" with pytest.raises(TypeError, match=msg): # index is not a DatetimeIndex - df.at_time("00:00") + obj.at_time("00:00") @pytest.mark.parametrize("axis", ["index", "columns", 0, 1]) def test_at_time_axis(self, axis): diff --git a/pandas/tests/indexing/test_loc.py b/pandas/tests/indexing/test_loc.py index d1dcae5997b9d..f64305eb2c74d 100644 --- a/pandas/tests/indexing/test_loc.py +++ b/pandas/tests/indexing/test_loc.py @@ -1,4 +1,5 @@ """ test label based indexing with loc """ +from datetime import time from io import StringIO import re @@ -992,6 +993,27 @@ def test_loc_setitem_str_to_small_float_conversion_type(self): expected = DataFrame(col_data, columns=["A"], dtype=float) tm.assert_frame_equal(result, expected) + def test_loc_getitem_time_object(self, frame_or_series): + rng = date_range("1/1/2000", "1/5/2000", freq="5min") + mask = (rng.hour == 9) & (rng.minute == 30) + + df = DataFrame(np.random.randn(len(rng), 3), index=rng) + if frame_or_series is Series: + df = df[0] + + result_df = df.loc[time(9, 30)] + exp_df = df.loc[mask] + tm.assert_equal(result_df, exp_df) + + chunk = df.loc["1/4/2000":] + result = chunk.loc[time(9, 30)] + expected = result_df[-1:] + + # Without resetting the freqs, these are 5 min and 1440 min, respectively + result.index = result.index._with_freq(None) + expected.index = expected.index._with_freq(None) + tm.assert_equal(result, expected) + class TestLocWithMultiIndex: @pytest.mark.parametrize( diff --git a/pandas/tests/series/indexing/test_getitem.py b/pandas/tests/series/indexing/test_getitem.py index f8517c3b91fc1..080e1a4724c8c 100644 --- a/pandas/tests/series/indexing/test_getitem.py +++ b/pandas/tests/series/indexing/test_getitem.py @@ -1,7 +1,7 @@ """ Series.__getitem__ test classes are organized by the type of key passed. """ -from datetime import datetime +from datetime import datetime, time import numpy as np import pytest @@ -83,6 +83,16 @@ def test_string_index_alias_tz_aware(self, tz): result = ser["1/3/2000"] tm.assert_almost_equal(result, ser[2]) + def test_getitem_time_object(self): + rng = date_range("1/1/2000", "1/5/2000", freq="5min") + ts = Series(np.random.randn(len(rng)), index=rng) + + mask = (rng.hour == 9) & (rng.minute == 30) + result = ts[time(9, 30)] + expected = ts[mask] + result.index = result.index._with_freq(None) + tm.assert_series_equal(result, expected) + class TestSeriesGetitemSlices: def test_getitem_slice_2d(self, datetime_series): diff --git a/pandas/tests/series/methods/test_at_time.py b/pandas/tests/series/methods/test_at_time.py deleted file mode 100644 index 810e4c1446708..0000000000000 --- a/pandas/tests/series/methods/test_at_time.py +++ /dev/null @@ -1,77 +0,0 @@ -from datetime import time - -import numpy as np -import pytest - -from pandas._libs.tslibs import timezones - -from pandas import DataFrame, Series, date_range -import pandas._testing as tm - - -class TestAtTime: - @pytest.mark.parametrize("tzstr", ["US/Eastern", "dateutil/US/Eastern"]) - def test_localized_at_time(self, tzstr): - tz = timezones.maybe_get_tz(tzstr) - - rng = date_range("4/16/2012", "5/1/2012", freq="H") - ts = Series(np.random.randn(len(rng)), index=rng) - - ts_local = ts.tz_localize(tzstr) - - result = ts_local.at_time(time(10, 0)) - expected = ts.at_time(time(10, 0)).tz_localize(tzstr) - tm.assert_series_equal(result, expected) - assert timezones.tz_compare(result.index.tz, tz) - - def test_at_time(self): - rng = date_range("1/1/2000", "1/5/2000", freq="5min") - ts = Series(np.random.randn(len(rng)), index=rng) - rs = ts.at_time(rng[1]) - assert (rs.index.hour == rng[1].hour).all() - assert (rs.index.minute == rng[1].minute).all() - assert (rs.index.second == rng[1].second).all() - - result = ts.at_time("9:30") - expected = ts.at_time(time(9, 30)) - tm.assert_series_equal(result, expected) - - df = DataFrame(np.random.randn(len(rng), 3), index=rng) - - result = ts[time(9, 30)] - result_df = df.loc[time(9, 30)] - expected = ts[(rng.hour == 9) & (rng.minute == 30)] - exp_df = df[(rng.hour == 9) & (rng.minute == 30)] - - result.index = result.index._with_freq(None) - tm.assert_series_equal(result, expected) - tm.assert_frame_equal(result_df, exp_df) - - chunk = df.loc["1/4/2000":] - result = chunk.loc[time(9, 30)] - expected = result_df[-1:] - - # Without resetting the freqs, these are 5 min and 1440 min, respectively - result.index = result.index._with_freq(None) - expected.index = expected.index._with_freq(None) - tm.assert_frame_equal(result, expected) - - # midnight, everything - rng = date_range("1/1/2000", "1/31/2000") - ts = Series(np.random.randn(len(rng)), index=rng) - - result = ts.at_time(time(0, 0)) - tm.assert_series_equal(result, ts) - - # time doesn't exist - rng = date_range("1/1/2012", freq="23Min", periods=384) - ts = Series(np.random.randn(len(rng)), rng) - rs = ts.at_time("16:00") - assert len(rs) == 0 - - def test_at_time_raises(self): - # GH20725 - ser = Series("a b c".split()) - msg = "Index must be DatetimeIndex" - with pytest.raises(TypeError, match=msg): - ser.at_time("00:00") From 980022898d49e065461f737c527fd6f8ecd015c9 Mon Sep 17 00:00:00 2001 From: Brock Date: Mon, 2 Nov 2020 14:32:56 -0800 Subject: [PATCH 6/6] indexing test --- pandas/tests/frame/methods/test_at_time.py | 5 ----- pandas/tests/indexing/test_loc.py | 14 +++++++------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/pandas/tests/frame/methods/test_at_time.py b/pandas/tests/frame/methods/test_at_time.py index 859b90950ec53..7ac3868e8ddf4 100644 --- a/pandas/tests/frame/methods/test_at_time.py +++ b/pandas/tests/frame/methods/test_at_time.py @@ -39,11 +39,6 @@ def test_at_time(self, frame_or_series): expected = ts.at_time(time(9, 30)) tm.assert_equal(result, expected) - # TODO: this is testing loc, not at_time - result = ts.loc[time(9, 30)] - expected = ts.loc[(rng.hour == 9) & (rng.minute == 30)] - tm.assert_equal(result, expected) - def test_at_time_midnight(self, frame_or_series): # midnight, everything rng = date_range("1/1/2000", "1/31/2000") diff --git a/pandas/tests/indexing/test_loc.py b/pandas/tests/indexing/test_loc.py index f64305eb2c74d..c1a5db992d3df 100644 --- a/pandas/tests/indexing/test_loc.py +++ b/pandas/tests/indexing/test_loc.py @@ -997,17 +997,17 @@ def test_loc_getitem_time_object(self, frame_or_series): rng = date_range("1/1/2000", "1/5/2000", freq="5min") mask = (rng.hour == 9) & (rng.minute == 30) - df = DataFrame(np.random.randn(len(rng), 3), index=rng) + obj = DataFrame(np.random.randn(len(rng), 3), index=rng) if frame_or_series is Series: - df = df[0] + obj = obj[0] - result_df = df.loc[time(9, 30)] - exp_df = df.loc[mask] - tm.assert_equal(result_df, exp_df) + result = obj.loc[time(9, 30)] + exp = obj.loc[mask] + tm.assert_equal(result, exp) - chunk = df.loc["1/4/2000":] + chunk = obj.loc["1/4/2000":] result = chunk.loc[time(9, 30)] - expected = result_df[-1:] + expected = result[-1:] # Without resetting the freqs, these are 5 min and 1440 min, respectively result.index = result.index._with_freq(None)