From c1e0abe08e518f68c41cbd4bbb8631f3d7affea1 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Wed, 20 Mar 2024 11:06:54 +0000 Subject: [PATCH 1/2] - initial attempt --- pandas/_libs/tslibs/offsets.pyx | 16 +++++++++++ pandas/tests/tseries/offsets/common.py | 40 ++++++++++++++++++++++++++ test_fast.sh | 2 +- 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index d799770a57be2..0c6cfd89cc165 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -689,6 +689,22 @@ cdef class BaseOffset: "does not have a vectorized implementation" ) + def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): + import traceback, sys + traceback.print_stack(file=sys.stdout) + print(ufunc, method, type(inputs[0]), type(inputs[1])) + a, b = inputs + if isinstance(a, ndarray) and isinstance(b, BaseOffset): + array = a + offset = b + elif isinstance(b, ndarray) and isinstance(a, BaseOffset): + array = b + offset = a + else: + return NotImplemented + + return offset._apply_array(a).astype('M8[ns]') + def rollback(self, dt) -> datetime: """ Roll provided date backward to next offset only if not on offset. diff --git a/pandas/tests/tseries/offsets/common.py b/pandas/tests/tseries/offsets/common.py index c12130544e6b2..afcc5ded5cac2 100644 --- a/pandas/tests/tseries/offsets/common.py +++ b/pandas/tests/tseries/offsets/common.py @@ -24,6 +24,8 @@ WeekOfMonth, ) from pandas.compat import IS64 +from pandas import Series, Timedelta, Timestamp +from numpy.testing import assert_allclose def assert_offset_equal(offset, base, expected): @@ -205,3 +207,41 @@ def test_compare_str(self): assert off != "foo" # Note: inequalities are only implemented for Tick subclasses; # tests for this are in test_ticks + + test_dates_sr = Series([Timestamp(2021, 1, 1) + Timedelta(days=d) for d in range(1000)]) + + def test_np_array_add(self): + if self._offset is None or not hasattr(self, "offset2"): + # i.e. skip for TestCommon and YQM subclasses that do not have + # offset2 attr + return + a, b = self.offset2, self.test_dates_sr.to_numpy() + #breakpoint() + c = a + b + assert_allclose((self.offset2 + self.test_dates_sr).to_numpy(), + c) + + def test_np_array_radd(self): + if self._offset is None or not hasattr(self, "offset2"): + # i.e. skip for TestCommon and YQM subclasses that do not have + # offset2 attr + return + a, b = self.test_dates_sr.to_numpy(), self.offset2 + #breakpoint() + c = a + b + assert_allclose((self.test_dates_sr + self.offset2).to_numpy(), + c) + + def test_np_array_sub(self): + if self._offset is None or not hasattr(self, "offset2"): + # i.e. skip for TestCommon and YQM subclasses that do not have + # offset2 attr + return + assert (self.offset2 - self.test_dates_sr).to_numpy() == self.offset2 - self.test_dates_sr.to_numpy() + + def test_np_array_rsub(self): + if self._offset is None or not hasattr(self, "offset2"): + # i.e. skip for TestCommon and YQM subclasses that do not have + # offset2 attr + return + assert (self.test_dates_sr - self.offset2).to_numpy() == self.test_dates_sr.to_numpy() - self.offset2 \ No newline at end of file diff --git a/test_fast.sh b/test_fast.sh index 0120c712e3df8..141c56dc53355 100755 --- a/test_fast.sh +++ b/test_fast.sh @@ -5,4 +5,4 @@ # https://github.com/pytest-dev/pytest/issues/1075 export PYTHONHASHSEED=$(python -c 'import random; print(random.randint(1, 4294967295))') -pytest pandas --skip-slow --skip-network --skip-db -m "not single_cpu" -n 4 -r sxX "$@" +pytest pandas/tests/tseries/offsets --skip-slow --skip-network --skip-db -m "not single_cpu" -n 4 -r sxX "$@" From 7582696f59963471d7d00d471ce055b0d2735fcf Mon Sep 17 00:00:00 2001 From: hottwaj Date: Wed, 27 Mar 2024 13:06:31 +0000 Subject: [PATCH 2/2] Update pandas/_libs/tslibs/offsets.pyx Co-authored-by: Matthew Roeschke <10647082+mroeschke@users.noreply.github.com> --- pandas/_libs/tslibs/offsets.pyx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 71ec8e24a0356..52d935a70ee45 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -457,10 +457,9 @@ cdef class BaseOffset: def __add__(self, other): if util.is_array(other): - from pandas.api.types import is_datetime64_any_dtype if other.dtype == object: return np.array([self + x for x in other]) - elif is_datetime64_any_dtype(other): + elif other.dtype.kind == "M": return self._apply_array(other).astype(other.dtype) try: