From cad58c1f8c27197cd073a36daca9b5c201f78613 Mon Sep 17 00:00:00 2001 From: Warren Weckesser Date: Thu, 27 Jun 2024 20:36:03 -0400 Subject: [PATCH] Revert "MAINT: Minimal changes to get working with numpy 2.0" This reverts commit 64c597a5c67806bc93aec57c750cc7dc6f8ff8d5. --- .github/workflows/tests.yml | 68 +++++++++++----------- README.md | 39 +++++++++++-- pyproject.toml | 2 +- src/peaktopeak/peaktopeak_gufunc.c.src | 21 ++----- src/searchsorted/searchsorted_gufunc.c.src | 2 +- ufunclab/tests/test_peaktopeak.py | 19 +++--- 6 files changed, 83 insertions(+), 68 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7b1eedf..6f5ad1e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,7 +7,7 @@ jobs: strategy: matrix: python-version: ['3.12', '3.11', '3.10', '3.9'] - numpy-version: ['1.20.3', '1.21.6', '1.22.4', '1.23.5', '1.24.4', '1.25.2', '1.26.4', '2.0.0'] + numpy-version: ['1.20.3', '1.21.6', '1.22.4', '1.23.5', '1.24.4', '1.25.2', '1.26.4'] exclude: - python-version: '3.10' numpy-version: '1.20.3' @@ -59,7 +59,7 @@ jobs: strategy: matrix: python-version: ['3.12', '3.11', '3.10', '3.9'] - numpy-version: ['1.20.3', '1.21.6', '1.22.4', '1.23.5', '1.24.4', '1.25.2', '1.26.4', '2.0.0'] + numpy-version: ['1.20.3', '1.21.6', '1.22.4', '1.23.5', '1.24.4', '1.25.2', '1.26.4'] exclude: - python-version: '3.10' numpy-version: '1.20.3' @@ -107,38 +107,38 @@ jobs: run: | pytest --pyargs ufunclab - # main-numpy: - # strategy: - # matrix: - # python-version: ['3.10', '3.11', '3.12'] - # os: [ubuntu-latest] - - # runs-on: ${{ matrix.os }} - - # steps: - # - uses: actions/checkout@v4 - # - name: Set up Python - # uses: actions/setup-python@v4 - # with: - # python-version: ${{ matrix.python-version }} - # - name: Install dependencies - # run: | - # sudo apt-get install libopenblas-dev - # python -m pip install --upgrade pip wheel - # python -m pip install --upgrade setuptools==59.2.0 - # python -m pip install ninja meson-python toml pytest - # pushd . - # cd .. - # git clone --shallow-submodules --recurse-submodules https://github.com/numpy/numpy.git - # cd numpy - # python -m pip install . - # popd - # - name: Install ufunclab - # run: | - # python -m pip install --no-build-isolation . - # - name: Test with pytest - # run: | - # pytest --pyargs ufunclab + main-numpy: + strategy: + matrix: + python-version: ['3.10', '3.11', '3.12'] + os: [ubuntu-latest] + + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + sudo apt-get install libopenblas-dev + python -m pip install --upgrade pip wheel + python -m pip install --upgrade setuptools==59.2.0 + python -m pip install ninja meson-python toml pytest + pushd . + cd .. + git clone --shallow-submodules --recurse-submodules https://github.com/numpy/numpy.git + cd numpy + python -m pip install . + popd + - name: Install ufunclab + run: | + python -m pip install --no-build-isolation . + - name: Test with pytest + run: | + pytest --pyargs ufunclab windows-msvc: diff --git a/README.md b/README.md index dc54137..533310d 100644 --- a/README.md +++ b/README.md @@ -993,11 +993,11 @@ of a NumPy array, but when the input is signed integers, the output is an unsigned integer with the same bit width. The function handles the standard integer and floating point types, -and object arrays. The function does not accept complex arrays. Also, -the function does not implement any special handling of `nan`, so the -behavior of this function with arrays containing `nan` is undefined -(i.e. it might not do what you want, and the behavior might change in -the next update of the software). +`datetime64`, `timedelta64`, and object arrays. The function does not +accept complex arrays. Also, the function does not implement any special +handling of `nan`, so the behavior of this function with arrays containing +`nan` is undefined (i.e. it might not do what you want, and the behavior +might change in the next update of the software). ``` >>> x = np.array([85, 125, 0, -75, -50], dtype=np.int8) @@ -1033,6 +1033,35 @@ array([Fraction(59, 21), Fraction(8, 9)], dtype=object) ``` +`dates` is an array of `datetime64`. + +``` +>>> dates = np.array([np.datetime64('2015-11-02T12:34:50'), +... np.datetime64('2016-03-01T16:00:00'), +... np.datetime64('2015-07-02T21:20:19'), +... np.datetime64('2016-05-01T19:25:00')]) + +>>> dates +array(['2015-11-02T12:34:50', '2016-03-01T16:00:00', + '2015-07-02T21:20:19', '2016-05-01T19:25:00'], + dtype='datetime64[s]') +>>> timespan = peaktopeak(dates) +>>> timespan +numpy.timedelta64(26258681,'s') +>>> timespan / np.timedelta64(1, 'D') # Convert to number of days. +303.9199189814815 +``` + +Casting works when the `out` argument is an array with dtype `timedelta64`. +For example, + +``` +>>> out = np.empty((), dtype='timedelta64[D]') +>>> peaktopeak(dates, out=out) +array(303, dtype='timedelta64[D]') + +``` + #### `all_same` diff --git a/pyproject.toml b/pyproject.toml index 92684cf..ec18253 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ requires = [ [project] name = 'ufunclab' -version = '0.0.8.dev10' +version = '0.0.8.dev9' description = 'NumPy ufuncs and utilities.' readme = 'README.md' requires-python = '>=3.9' diff --git a/src/peaktopeak/peaktopeak_gufunc.c.src b/src/peaktopeak/peaktopeak_gufunc.c.src index a6d8031..7b80732 100644 --- a/src/peaktopeak/peaktopeak_gufunc.c.src +++ b/src/peaktopeak/peaktopeak_gufunc.c.src @@ -132,11 +132,6 @@ peaktopeak_@typename@_loop(char **args, const npy_intp *dimensions, // typical use-cases for these calculations do not encounter this situation. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -#ifdef UNDEFINED - -Handling of datetime64 and timedelta64 is disabled. This code needs to -be updated for NumPy 2.0 - static void peaktopeak_int64_signed_loop(char **args, const npy_intp *dimensions, const npy_intp* steps, void* data) { @@ -176,8 +171,6 @@ static void peaktopeak_int64_signed_loop(char **args, const npy_intp *dimensions } } -#endif - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // ufunc inner loop for object arrays. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -259,8 +252,8 @@ static char peaktopeak_typecodes[] = { NPY_FLOAT, NPY_FLOAT, NPY_DOUBLE, NPY_DOUBLE, NPY_LONGDOUBLE, NPY_LONGDOUBLE, - // NPY_DATETIME, NPY_TIMEDELTA, - // NPY_TIMEDELTA, NPY_TIMEDELTA, + NPY_DATETIME, NPY_TIMEDELTA, + NPY_TIMEDELTA, NPY_TIMEDELTA, NPY_OBJECT, NPY_OBJECT }; @@ -276,16 +269,14 @@ static PyUFuncGenericFunction peaktopeak_funcs[] = { (PyUFuncGenericFunction) &peaktopeak_float_loop, (PyUFuncGenericFunction) &peaktopeak_double_loop, (PyUFuncGenericFunction) &peaktopeak_longdouble_loop, - // (PyUFuncGenericFunction) &peaktopeak_int64_signed_loop, - // (PyUFuncGenericFunction) &peaktopeak_int64_signed_loop, + (PyUFuncGenericFunction) &peaktopeak_int64_signed_loop, + (PyUFuncGenericFunction) &peaktopeak_int64_signed_loop, (PyUFuncGenericFunction) &peaktopeak_object_loop }; #define PEAKTOPEAK_NTYPES (sizeof(peaktopeak_funcs)/sizeof(peaktopeak_funcs[0])) static void *peaktopeak_data[PEAKTOPEAK_NTYPES]; -#ifdef UNDEFINED - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // peaktopeak type resolver // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -419,8 +410,6 @@ PeakToPeakTypeResolver(PyUFuncObject *ufunc, return 0; } -#endif - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Python extension module definitions. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -477,7 +466,7 @@ PyMODINIT_FUNC PyInit__peaktopeak(void) Py_DECREF(module); return NULL; } - // peaktopeak_gufunc->type_resolver = PeakToPeakTypeResolver; + peaktopeak_gufunc->type_resolver = PeakToPeakTypeResolver; status = PyModule_AddObject(module, "peaktopeak", (PyObject *) peaktopeak_gufunc); if (status == -1) { diff --git a/src/searchsorted/searchsorted_gufunc.c.src b/src/searchsorted/searchsorted_gufunc.c.src index f7bc78f..09f6f4d 100644 --- a/src/searchsorted/searchsorted_gufunc.c.src +++ b/src/searchsorted/searchsorted_gufunc.c.src @@ -90,7 +90,7 @@ SearchSortedTypeResolver(PyUFuncObject *ufunc, */ type_num1 = PyArray_DESCR(operands[0])->type_num; type_num2 = PyArray_DESCR(operands[1])->type_num; - if (type_num1 >= NPY_NTYPES_LEGACY || type_num2 >= NPY_NTYPES_LEGACY || + if (type_num1 >= NPY_NTYPES || type_num2 >= NPY_NTYPES || type_num1 == NPY_OBJECT || type_num2 == NPY_OBJECT) { return PyUFunc_DefaultTypeResolver(ufunc, casting, operands, type_tup, out_dtypes); diff --git a/ufunclab/tests/test_peaktopeak.py b/ufunclab/tests/test_peaktopeak.py index a168944..e6e7d9b 100644 --- a/ufunclab/tests/test_peaktopeak.py +++ b/ufunclab/tests/test_peaktopeak.py @@ -64,14 +64,11 @@ def test_fractions_2d(): assert_array_equal(p1, [Fraction(23, 9), Fraction(0)]) -# Removed until datetime64 and timedelta64 handling is restored -# in ufunclab.peaktopeak. -# -# def test_dates(): -# dates = np.array([np.datetime64('2015-11-02T12:34:50'), -# np.datetime64('2015-11-02T10:00:00'), -# np.datetime64('2015-11-02T21:20:19'), -# np.datetime64('2015-11-02T19:25:00')]) -# timespan = peaktopeak(dates) -# assert_equal(timespan.dtype, np.dtype('m8[s]')) -# assert_equal(timespan, np.timedelta64(40819, 's')) +def test_dates(): + dates = np.array([np.datetime64('2015-11-02T12:34:50'), + np.datetime64('2015-11-02T10:00:00'), + np.datetime64('2015-11-02T21:20:19'), + np.datetime64('2015-11-02T19:25:00')]) + timespan = peaktopeak(dates) + assert_equal(timespan.dtype, np.dtype('m8[s]')) + assert_equal(timespan, np.timedelta64(40819, 's'))