From 6dfaea564dee5a5eb87580ba49462ac45609b96e Mon Sep 17 00:00:00 2001 From: Charles Harris Date: Sat, 8 Jul 2023 16:42:54 -0600 Subject: [PATCH 01/35] MAINT: prepare 1.25.x for further development --- doc/source/release.rst | 1 + doc/source/release/1.25.2-notes.rst | 14 ++++++++++++++ pavement.py | 2 +- 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 doc/source/release/1.25.2-notes.rst diff --git a/doc/source/release.rst b/doc/source/release.rst index 6615f0024ee2..ef1d35a74d2b 100644 --- a/doc/source/release.rst +++ b/doc/source/release.rst @@ -5,6 +5,7 @@ Release notes .. toctree:: :maxdepth: 3 + 1.25.2 1.25.1 1.25.0 1.24.3 diff --git a/doc/source/release/1.25.2-notes.rst b/doc/source/release/1.25.2-notes.rst new file mode 100644 index 000000000000..8bc62b0eb9c4 --- /dev/null +++ b/doc/source/release/1.25.2-notes.rst @@ -0,0 +1,14 @@ +.. currentmodule:: numpy + +========================== +NumPy 1.25.2 Release Notes +========================== +NumPy 1.25.2 is a maintenance release that fixes bugs and regressions discovered after the +1.25.1 release. The Python versions supported by this release are 3.9-3.11. + +Contributors +============ + +Pull requests merged +==================== + diff --git a/pavement.py b/pavement.py index 4f3b20b6b2af..9704b9ce067c 100644 --- a/pavement.py +++ b/pavement.py @@ -38,7 +38,7 @@ #----------------------------------- # Path to the release notes -RELEASE_NOTES = 'doc/source/release/1.25.1-notes.rst' +RELEASE_NOTES = 'doc/source/release/1.25.2-notes.rst' #------------------------------------------------------- From 3e78dd2339da73bd8828a60cd7b10c005389d851 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 11 Jul 2023 15:24:13 +0100 Subject: [PATCH 02/35] ENH: Improve clang-cl compliance Avoid unnecessary MSVC path when using clang-cl --- numpy/core/src/multiarray/_multiarray_tests.c.src | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpy/core/src/multiarray/_multiarray_tests.c.src b/numpy/core/src/multiarray/_multiarray_tests.c.src index 1fd28e72192a..0f25e31dbf10 100644 --- a/numpy/core/src/multiarray/_multiarray_tests.c.src +++ b/numpy/core/src/multiarray/_multiarray_tests.c.src @@ -2054,7 +2054,7 @@ get_fpu_mode(PyObject *NPY_UNUSED(self), PyObject *args) return NULL; } -#if defined(_MSC_VER) +#if defined(_MSC_VER) && !defined(__clang__) { unsigned int result = 0; result = _controlfp(0, 0); From f0a7c932e28b0905e4c3b9b889ad303a0a96f50b Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 11 Jul 2023 16:48:10 +0100 Subject: [PATCH 03/35] ENH: Enable FPU Mode return for clang-cl --- numpy/core/src/multiarray/_multiarray_tests.c.src | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpy/core/src/multiarray/_multiarray_tests.c.src b/numpy/core/src/multiarray/_multiarray_tests.c.src index 0f25e31dbf10..482596f97654 100644 --- a/numpy/core/src/multiarray/_multiarray_tests.c.src +++ b/numpy/core/src/multiarray/_multiarray_tests.c.src @@ -2060,7 +2060,7 @@ get_fpu_mode(PyObject *NPY_UNUSED(self), PyObject *args) result = _controlfp(0, 0); return PyLong_FromLongLong(result); } -#elif defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)) +#elif (defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__))) || (defined(_MSC_VER) && defined(__clang__)) { unsigned short cw = 0; __asm__("fstcw %w0" : "=m" (cw)); From 84b0a78c48bcfcc45df654b8c5e96f4c53784bc1 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 11 Jul 2023 17:45:28 +0100 Subject: [PATCH 04/35] TST: Add clang-cl run --- .github/workflows/windows_clangcl.yml | 91 +++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 .github/workflows/windows_clangcl.yml diff --git a/.github/workflows/windows_clangcl.yml b/.github/workflows/windows_clangcl.yml new file mode 100644 index 000000000000..e3ee856fd001 --- /dev/null +++ b/.github/workflows/windows_clangcl.yml @@ -0,0 +1,91 @@ +name: Test Clang-CL Build (Windows) + +on: + pull_request: + branches: + - main + - maintenance/** + +env: + PYTHON_VERSION: 3.11 + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read # to fetch code (actions/checkout) + +jobs: + meson: + name: Meson windows build/test + runs-on: windows-2019 + # if: "github.repository == 'numpy/numpy'" + steps: + - name: Checkout + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + with: + submodules: recursive + fetch-depth: 0 + - name: Setup Python + uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + with: + python-version: ${{ env.PYTHON_VERSION }} + + - name: Install dependencies + run: | + pip install -r build_requirements.txt + - name: openblas-libs + run: | + # Download and install pre-built OpenBLAS library + # with 32-bit interfaces + # Unpack it in the pkg-config hardcoded path + choco install unzip -y + choco install wget -y + # Install llvm, which contains clang-cl + choco install llvm -y --version=16.0.6 + choco install -y --checksum 6004DF17818F5A6DBF19CB335CC92702 pkgconfiglite + wget https://anaconda.org/multibuild-wheels-staging/openblas-libs/v0.3.21/download/openblas-v0.3.21-win_amd64-gcc_10_3_0.zip + unzip -d c:\opt openblas-v0.3.21-win_amd64-gcc_10_3_0.zip + echo "PKG_CONFIG_PATH=c:\opt\64\lib\pkgconfig;" >> $env:GITHUB_ENV + - name: meson-configure + run: | + "[binaries]","c = 'clang-cl'","cpp = 'clang-cl'","ar = 'llvm-lib'","c_ld = 'lld-link'","cpp_ld = 'lld-link'" | Out-File $PWD/clang-cl-build.ini -Encoding ascii + meson setup build --prefix=$PWD\build-install --native-file=$PWD/clang-cl-build.ini -Ddebug=false --optimization 2 --vsenv + - name: meson-build + run: | + meson compile -C build -v + + - name: meson-install + run: | + cd build + meson install --no-rebuild + - name: build-path + run: | + echo "installed_path=$PWD\build-install\Lib\site-packages" >> $env:GITHUB_ENV + - name: post-install + run: | + $numpy_path = "${env:installed_path}\numpy" + $libs_path = "${numpy_path}\.libs" + mkdir ${libs_path} + $ob_path = "C:/opt/64/bin/" + cp $ob_path/*.dll $libs_path + # Write _distributor_init.py to load .libs DLLs. + python -c "from tools import openblas_support; openblas_support.make_init(r'${numpy_path}')" + + - name: prep-test + run: | + echo "PYTHONPATH=${env:installed_path}" >> $env:GITHUB_ENV + python -m pip install -r test_requirements.txt + python -m pip install threadpoolctl + + - name: test + run: | + mkdir tmp + cd tmp + echo "============================================" + python -c "import numpy; print(numpy.show_runtime())" + echo "============================================" + echo "LASTEXITCODE is '$LASTEXITCODE'" + python -c "import numpy, sys; sys.exit(numpy.test(verbose=3) is False)" + echo "LASTEXITCODE is '$LASTEXITCODE'" From 4576cc3903670897a77ca90765446aec208bbaee Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 12 Jul 2023 00:21:24 +0100 Subject: [PATCH 05/35] TST: Xfail tests when using clang-cl --- numpy/core/tests/test_einsum.py | 20 ++++++++++++++++++++ numpy/core/tests/test_scalarmath.py | 14 +++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/numpy/core/tests/test_einsum.py b/numpy/core/tests/test_einsum.py index 3a06d119fe0e..a61098922b46 100644 --- a/numpy/core/tests/test_einsum.py +++ b/numpy/core/tests/test_einsum.py @@ -8,6 +8,12 @@ assert_raises, suppress_warnings, assert_raises_regex, assert_allclose ) +try: + COMPILERS = np.show_config(mode="dicts")["Compilers"] + USING_CLANG_CL = COMPILERS["c"]["name"] == "clang-cl" +except TypeError: + USING_CLANG_CL = False + # Setup for optimize einsum chars = 'abcdefghij' sizes = np.array([2, 3, 4, 5, 4, 3, 2, 6, 5, 4, 3]) @@ -609,9 +615,23 @@ def check_einsum_sums(self, dtype, do_opt=False): [2.]) # contig_stride0_outstride0_two def test_einsum_sums_int8(self): + if ( + (sys.platform == 'darwin' and platform.machine() == 'x86_64') + or + USING_CLANG_CL + ): + pytest.xfail('Fails on macOS x86-64 and when using clang-cl ' + 'with Meson, see gh-23838') self.check_einsum_sums('i1') def test_einsum_sums_uint8(self): + if ( + (sys.platform == 'darwin' and platform.machine() == 'x86_64') + or + USING_CLANG_CL + ): + pytest.xfail('Fails on macOS x86-64 and when using clang-cl ' + 'with Meson, see gh-23838') self.check_einsum_sums('u1') def test_einsum_sums_int16(self): diff --git a/numpy/core/tests/test_scalarmath.py b/numpy/core/tests/test_scalarmath.py index c737099c1b55..9977c8b1163b 100644 --- a/numpy/core/tests/test_scalarmath.py +++ b/numpy/core/tests/test_scalarmath.py @@ -17,6 +17,12 @@ assert_warns, _SUPPORTS_SVE, ) +try: + COMPILERS = np.show_config(mode="dicts")["Compilers"] + USING_CLANG_CL = COMPILERS["c"]["name"] == "clang-cl" +except TypeError: + USING_CLANG_CL = False + types = [np.bool_, np.byte, np.ubyte, np.short, np.ushort, np.intc, np.uintc, np.int_, np.uint, np.longlong, np.ulonglong, np.single, np.double, np.longdouble, np.csingle, @@ -798,7 +804,13 @@ class TestBitShifts: @pytest.mark.parametrize('op', [operator.rshift, operator.lshift], ids=['>>', '<<']) def test_shift_all_bits(self, type_code, op): - """ Shifts where the shift amount is the width of the type or wider """ + """Shifts where the shift amount is the width of the type or wider """ + if ( + USING_CLANG_CL and + type_code in ("l", "L") and + op is operator.lshift + ): + pytest.xfail("Failing on clang-cl builds") # gh-2449 dt = np.dtype(type_code) nbits = dt.itemsize * 8 From c9f2e05714aa32cb92763b92585916ecd941cb6f Mon Sep 17 00:00:00 2001 From: Charles Harris Date: Thu, 13 Jul 2023 13:28:50 -0600 Subject: [PATCH 06/35] MAINT: Update test_einsum from main. --- numpy/core/tests/test_einsum.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/numpy/core/tests/test_einsum.py b/numpy/core/tests/test_einsum.py index a61098922b46..702be2486515 100644 --- a/numpy/core/tests/test_einsum.py +++ b/numpy/core/tests/test_einsum.py @@ -1,4 +1,6 @@ import itertools +import sys +import platform import pytest @@ -108,7 +110,7 @@ def test_einsum_errors(self): def test_einsum_object_errors(self): # Exceptions created by object arithmetic should - # successfully propogate + # successfully propagate class CustomException(Exception): pass From 56c918d71f039b98f1fe686cf482015e6e6fcbaf Mon Sep 17 00:00:00 2001 From: Charles Harris Date: Thu, 13 Jul 2023 16:04:57 -0600 Subject: [PATCH 07/35] MAINT: Update test_requirements.txt from main. --- test_requirements.txt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/test_requirements.txt b/test_requirements.txt index 16f448eb8066..295be18d5bf6 100644 --- a/test_requirements.txt +++ b/test_requirements.txt @@ -1,10 +1,12 @@ cython>=0.29.34,<3.0 wheel==0.38.1 -setuptools==59.2.0 -hypothesis==6.24.1 -pytest==6.2.5 -pytz==2021.3 -pytest-cov==3.0.0 +setuptools==59.2.0 ; python_version < '3.12' +setuptools ; python_version >= '3.12' +hypothesis==6.81.1 +pytest==7.4.0 +pytz==2023.3 +pytest-cov==4.1.0 +pytest-xdist # for numpy.random.test.test_extending cffi; python_version < '3.10' # For testing types. Notes on the restrictions: From d8fa9a13aac8bb4ab053ebb6847ec619fea52065 Mon Sep 17 00:00:00 2001 From: Charles Harris Date: Thu, 13 Jul 2023 17:22:32 -0600 Subject: [PATCH 08/35] MAINT: Update {doc|test}_requirements.txt --- build_requirements.txt | 2 +- doc_requirements.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/build_requirements.txt b/build_requirements.txt index de57da2793bb..a936715b9ac2 100644 --- a/build_requirements.txt +++ b/build_requirements.txt @@ -2,4 +2,4 @@ meson-python>=0.10.0 Cython>=0.29.34,<3.0 wheel==0.38.1 ninja -spin==0.3 +spin==0.4 diff --git a/doc_requirements.txt b/doc_requirements.txt index b8a82aff7540..9811ef746ab7 100644 --- a/doc_requirements.txt +++ b/doc_requirements.txt @@ -11,3 +11,4 @@ breathe>4.33.0 # needed to build release notes towncrier +toml \ No newline at end of file From a102a82e2610bcd1e8e37ffb5ed613ed7a306f73 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Jul 2023 17:42:39 +0000 Subject: [PATCH 09/35] MAINT: Bump larsoner/circleci-artifacts-redirector-action Bumps [larsoner/circleci-artifacts-redirector-action](https://github.com/larsoner/circleci-artifacts-redirector-action) from 0a7552bf8cf99cbd40a8928fa48e858e205b98c8 to 443f056c4757600f1452146a7ce1627d1c034029. - [Release notes](https://github.com/larsoner/circleci-artifacts-redirector-action/releases) - [Commits](https://github.com/larsoner/circleci-artifacts-redirector-action/compare/0a7552bf8cf99cbd40a8928fa48e858e205b98c8...443f056c4757600f1452146a7ce1627d1c034029) --- updated-dependencies: - dependency-name: larsoner/circleci-artifacts-redirector-action dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .github/workflows/circleci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/circleci.yml b/.github/workflows/circleci.yml index 75638f6b65c6..89e472d2a76e 100644 --- a/.github/workflows/circleci.yml +++ b/.github/workflows/circleci.yml @@ -17,7 +17,7 @@ jobs: statuses: write steps: - name: GitHub Action step - uses: larsoner/circleci-artifacts-redirector-action@0a7552bf8cf99cbd40a8928fa48e858e205b98c8 # master + uses: larsoner/circleci-artifacts-redirector-action@443f056c4757600f1452146a7ce1627d1c034029 # master with: repo-token: ${{ secrets.GITHUB_TOKEN }} api-token: ${{ secrets.CIRCLE_TOKEN }} From d09aacb03bcea807664a6347ba6350f3ab12992e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Jul 2023 17:42:45 +0000 Subject: [PATCH 10/35] MAINT: Bump pypa/cibuildwheel from 2.13.1 to 2.14.0 Bumps [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel) from 2.13.1 to 2.14.0. - [Release notes](https://github.com/pypa/cibuildwheel/releases) - [Changelog](https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md) - [Commits](https://github.com/pypa/cibuildwheel/compare/0ecddd92b62987d7a2ae8911f4bb8ec9e2e4496a...66b46d086804a9e9782354100d96a3a445431bca) --- updated-dependencies: - dependency-name: pypa/cibuildwheel dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 504bc28f4351..23b7d75839db 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -118,7 +118,7 @@ jobs: if: ${{ matrix.buildplat[1] == 'win32' }} - name: Build wheels - uses: pypa/cibuildwheel@0ecddd92b62987d7a2ae8911f4bb8ec9e2e4496a # v2.13.1 + uses: pypa/cibuildwheel@66b46d086804a9e9782354100d96a3a445431bca # v2.14.0 env: CIBW_BUILD: ${{ matrix.python }}-${{ matrix.buildplat[1] }} From 31f937e968ed43b4959694979bda48713cd0a364 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jul 2023 17:13:34 +0000 Subject: [PATCH 11/35] MAINT: Bump actions/setup-python from 4.6.1 to 4.7.0 Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4.6.1 to 4.7.0. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/bd6b4b6205c4dbad673328db7b31b7fab9e241c0...61a6322f88396a6271a6ee3565807d608ecaddd1) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/build_test.yml | 34 ++++++++++++++--------------- .github/workflows/emscripten.yml | 2 +- .github/workflows/linux_meson.yml | 2 +- .github/workflows/wheels.yml | 4 ++-- .github/workflows/windows_meson.yml | 2 +- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index 6d6fb00b5ad2..c6a592bd00f0 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -35,7 +35,7 @@ jobs: with: submodules: recursive fetch-depth: 0 - - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Install linter requirements @@ -55,7 +55,7 @@ jobs: with: submodules: recursive fetch-depth: 0 - - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: python-version: ${{ env.PYTHON_VERSION }} - uses: ./.github/actions @@ -74,7 +74,7 @@ jobs: with: submodules: recursive fetch-depth: 0 - - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: python-version: ${{ matrix.python-version }} - uses: ./.github/actions @@ -128,7 +128,7 @@ jobs: with: submodules: recursive fetch-depth: 0 - - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: python-version: ${{ env.PYTHON_VERSION }} - uses: ./.github/actions @@ -144,7 +144,7 @@ jobs: with: submodules: recursive fetch-depth: 0 - - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: python-version: ${{ env.PYTHON_VERSION }} - uses: ./.github/actions @@ -160,7 +160,7 @@ jobs: with: submodules: recursive fetch-depth: 0 - - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: python-version: ${{ env.PYTHON_VERSION }} - uses: ./.github/actions @@ -176,7 +176,7 @@ jobs: with: submodules: recursive fetch-depth: 0 - - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: python-version: ${{ env.PYTHON_VERSION }} - uses: ./.github/actions @@ -192,7 +192,7 @@ jobs: with: submodules: recursive fetch-depth: 0 - - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: python-version: ${{ env.PYTHON_VERSION }} - uses: ./.github/actions @@ -208,7 +208,7 @@ jobs: with: submodules: recursive fetch-depth: 0 - - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: python-version: ${{ env.PYTHON_VERSION }} - uses: ./.github/actions @@ -226,7 +226,7 @@ jobs: with: submodules: recursive fetch-depth: 0 - - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: python-version: ${{ env.PYTHON_VERSION }} - uses: ./.github/actions @@ -248,7 +248,7 @@ jobs: with: submodules: recursive fetch-depth: 0 - - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: python-version: ${{ env.PYTHON_VERSION }} - uses: ./.github/actions @@ -266,7 +266,7 @@ jobs: with: submodules: recursive fetch-depth: 0 - - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: python-version: ${{ env.PYTHON_VERSION }} - uses: ./.github/actions @@ -282,7 +282,7 @@ jobs: with: submodules: recursive fetch-depth: 0 - - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: python-version: ${{ env.PYTHON_VERSION }} - uses: ./.github/actions @@ -321,7 +321,7 @@ jobs: with: submodules: recursive fetch-depth: 0 - - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: python-version: ${{ env.PYTHON_VERSION }} - uses: ./.github/actions @@ -337,7 +337,7 @@ jobs: with: submodules: recursive fetch-depth: 0 - - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: python-version: ${{ env.PYTHON_VERSION }} - uses: ./.github/actions @@ -409,7 +409,7 @@ jobs: with: submodules: recursive fetch-depth: 0 - - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Install Intel SDE @@ -438,7 +438,7 @@ jobs: with: submodules: recursive fetch-depth: 0 - - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Install Intel SDE diff --git a/.github/workflows/emscripten.yml b/.github/workflows/emscripten.yml index abedc623ff28..b33872d025eb 100644 --- a/.github/workflows/emscripten.yml +++ b/.github/workflows/emscripten.yml @@ -42,7 +42,7 @@ jobs: - name: set up python id: setup-python - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: python-version: ${{ env.PYTHON_VERSION }} diff --git a/.github/workflows/linux_meson.yml b/.github/workflows/linux_meson.yml index 208caa38a417..c66a8572c1b2 100644 --- a/.github/workflows/linux_meson.yml +++ b/.github/workflows/linux_meson.yml @@ -29,7 +29,7 @@ jobs: with: submodules: recursive fetch-depth: 0 - - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Install dependencies diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 23b7d75839db..f4337244a795 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -102,7 +102,7 @@ jobs: fetch-depth: 0 # Used to push the built wheels - - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: python-version: "3.x" @@ -186,7 +186,7 @@ jobs: # https://github.com/actions/checkout/issues/338 fetch-depth: 0 # Used to push the built wheels - - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: # Build sdist on lowest supported Python python-version: "3.9" diff --git a/.github/workflows/windows_meson.yml b/.github/workflows/windows_meson.yml index 32c4b9854cfe..eac0f7e640be 100644 --- a/.github/workflows/windows_meson.yml +++ b/.github/workflows/windows_meson.yml @@ -28,7 +28,7 @@ jobs: submodules: recursive fetch-depth: 0 - name: Setup Python - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: python-version: ${{ env.PYTHON_VERSION }} From ed3f9636151a89b69acaae9b0910b5203a895916 Mon Sep 17 00:00:00 2001 From: Charles Harris Date: Thu, 13 Jul 2023 18:35:24 -0600 Subject: [PATCH 12/35] MAINT: Update cibuildwheel to 2.14.0 --- tools/ci/cirrus_wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci/cirrus_wheels.yml b/tools/ci/cirrus_wheels.yml index 90d15d1db434..e3bc2c680832 100644 --- a/tools/ci/cirrus_wheels.yml +++ b/tools/ci/cirrus_wheels.yml @@ -1,6 +1,6 @@ build_and_store_wheels: &BUILD_AND_STORE_WHEELS install_cibuildwheel_script: - - python -m pip install cibuildwheel==2.13.1 + - python -m pip install cibuildwheel==2.14.0 cibuildwheel_script: - cibuildwheel wheels_artifacts: From 621390f62e57c4e33808bb0426061ffe062bde57 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Tue, 27 Jun 2023 12:03:59 +0200 Subject: [PATCH 13/35] BLD: use `-ftrapping-math` with Clang on macOS The distutils build also uses this flag, and it avoids some problems with `floor_divide` and similar functions (xref gh-19479). For older macOS arm64 Clang versions, the flag does get accepted, but then gets overridden because it's not actually supported - which yields these warnings: ``` warning: overriding currently unsupported use of floating point exceptions on this target [-Wunsupported-floating-point-opt] ``` Since they're a little annoying to suppress and will go away when updating to the latest XCode version, we'll ignore these warnings. --- meson.build | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/meson.build b/meson.build index be0f2985c03d..8366250a7919 100644 --- a/meson.build +++ b/meson.build @@ -52,6 +52,15 @@ endif add_project_arguments( cc.get_supported_arguments( '-fno-strict-aliasing'), language : 'c' ) +# +# Clang defaults to a non-strict floating error point model, but we need strict +# behavior. `-ftrapping-math` is equivalent to `-ffp-exception-behavior=strict`. +# Note that this is only supported on macOS arm64 as of XCode 14.3 +if cc.get_id() == 'clang' + add_project_arguments( + cc.get_supported_arguments('-ftrapping-math'), language: ['c', 'cpp'], + ) +endif # Generate version number. Note that this will not (yet) update the version # number seen by pip or reflected in wheel filenames. See From 11ea00aff73a378de37601baaccd5d8c24d2f6d9 Mon Sep 17 00:00:00 2001 From: mattip Date: Sun, 9 Jul 2023 10:10:09 +0300 Subject: [PATCH 14/35] BUG: properly handle negative indexes in ufunc_at fast path --- numpy/core/src/umath/ufunc_object.c | 11 ++++++++--- numpy/core/tests/test_ufunc.py | 8 ++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c index 94cd73ef6c14..d992dd9602a6 100644 --- a/numpy/core/src/umath/ufunc_object.c +++ b/numpy/core/src/umath/ufunc_object.c @@ -5955,14 +5955,19 @@ trivial_at_loop(PyArrayMethodObject *ufuncimpl, NPY_ARRAYMETHOD_FLAGS flags, } } - npy_intp *inner_size = NpyIter_GetInnerLoopSizePtr(iter->outer); - if (!(flags & NPY_METH_NO_FLOATINGPOINT_ERRORS)) { npy_clear_floatstatus_barrier((char *)context); } do { - args[1] = (char *) iter->outer_ptrs[0]; + npy_intp *inner_size = NpyIter_GetInnerLoopSizePtr(iter->outer); + npy_intp * indxP = (npy_intp *)iter->outer_ptrs[0]; + for (npy_intp i=0; i < *inner_size; i++) { + if (indxP[i] < 0) { + indxP[i] += iter->fancy_dims[0]; + } + } + args[1] = (char *)indxP; steps[1] = iter->outer_strides[0]; res = ufuncimpl->contiguous_indexed_loop( diff --git a/numpy/core/tests/test_ufunc.py b/numpy/core/tests/test_ufunc.py index 2ce6b4b69ea6..d6aa3e1056bf 100644 --- a/numpy/core/tests/test_ufunc.py +++ b/numpy/core/tests/test_ufunc.py @@ -2215,6 +2215,14 @@ def test_ufunc_at_advanced(self): np.maximum.at(a, [0], 0) assert_equal(a, np.array([1, 2, 3])) + def test_at_negative_indexes(self): + a = np.arange(10) + indxs = np.array([-1, 1, -1, 2]) + np.add.at(a, indxs, 1) + assert a[-1] == 11 # issue 24147 + assert a[1] == 2 + assert a[2] == 3 + def test_at_not_none_signature(self): # Test ufuncs with non-trivial signature raise a TypeError a = np.ones((2, 2, 2)) From 33380387c9ed1be753cb269bf6b970c3b86a9681 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Thu, 13 Jul 2023 15:42:29 -0600 Subject: [PATCH 15/35] BUG: PyObject_IsTrue and PyObject_Not error handling in setflags --- numpy/core/src/multiarray/methods.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/numpy/core/src/multiarray/methods.c b/numpy/core/src/multiarray/methods.c index 37bf94d5ee4b..d97c6f87d05d 100644 --- a/numpy/core/src/multiarray/methods.c +++ b/numpy/core/src/multiarray/methods.c @@ -2713,7 +2713,11 @@ array_setflags(PyArrayObject *self, PyObject *args, PyObject *kwds) return NULL; if (align_flag != Py_None) { - if (PyObject_Not(align_flag)) { + int isnot = PyObject_Not(align_flag); + if (isnot == -1) { + return NULL; + } + if (isnot) { PyArray_CLEARFLAGS(self, NPY_ARRAY_ALIGNED); } else if (IsAligned(self)) { @@ -2728,7 +2732,11 @@ array_setflags(PyArrayObject *self, PyObject *args, PyObject *kwds) } if (uic != Py_None) { - if (PyObject_IsTrue(uic)) { + int istrue = PyObject_IsTrue(uic); + if (istrue == -1) { + return NULL; + } + if (istrue) { fa->flags = flagback; PyErr_SetString(PyExc_ValueError, "cannot set WRITEBACKIFCOPY " @@ -2743,7 +2751,11 @@ array_setflags(PyArrayObject *self, PyObject *args, PyObject *kwds) } if (write_flag != Py_None) { - if (PyObject_IsTrue(write_flag)) { + int istrue = PyObject_IsTrue(write_flag); + if (istrue == -1) { + return NULL; + } + else if (istrue == 1) { if (_IsWriteable(self)) { /* * _IsWritable (and PyArray_UpdateFlags) allows flipping this, From 78137bafef59abb9ebef1aaf67a7301bc32672c2 Mon Sep 17 00:00:00 2001 From: Tyler Reddy Date: Mon, 10 Jul 2023 14:12:48 -0600 Subject: [PATCH 16/35] BUG: histogram small range robust * Fixes #23110 * the histogram `norm` variable is used to determine the bin index of input values, and `norm` is calculated in some cases by dividing `n_equal_bins` by the range of the data; when the range of the data is extraordinarily small, the `norm` can become floating point infinity * in this patch, we delay calculating `norm` to increase resistance to the generation of infinite values--for example, a really small input value divided by a really small range is more resistant to generating infinity, so we effectively just change the order of operations a bit * however, I haven't considered whether this is broadly superior for resisting floating point non-finite values for other `histogram` input/extreme value permutations--one might speculate that this is just patching one extreme case that happened to show up in the wild, but may increase likelihood of some other extreme case that isn't in our testsuite yet * the main logic for this patch is that it fixes an issue that occurred in the wild and adds a test for it--if another extreme value case eventually pops up, at least this case will have a regression guard to keep guiding us in the right direction --- numpy/lib/histograms.py | 6 ++++-- numpy/lib/tests/test_histograms.py | 7 +++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/numpy/lib/histograms.py b/numpy/lib/histograms.py index 35745e6dd929..6ac65b726928 100644 --- a/numpy/lib/histograms.py +++ b/numpy/lib/histograms.py @@ -807,7 +807,8 @@ def histogram(a, bins=10, range=None, density=None, weights=None): n = np.zeros(n_equal_bins, ntype) # Pre-compute histogram scaling factor - norm = n_equal_bins / _unsigned_subtract(last_edge, first_edge) + norm_numerator = n_equal_bins + norm_denom = _unsigned_subtract(last_edge, first_edge) # We iterate over blocks here for two reasons: the first is that for # large arrays, it is actually faster (for example for a 10^8 array it @@ -835,7 +836,8 @@ def histogram(a, bins=10, range=None, density=None, weights=None): # Compute the bin indices, and for values that lie exactly on # last_edge we need to subtract one - f_indices = _unsigned_subtract(tmp_a, first_edge) * norm + f_indices = ((_unsigned_subtract(tmp_a, first_edge) / norm_denom) + * norm_numerator) indices = f_indices.astype(np.intp) indices[indices == n_equal_bins] -= 1 diff --git a/numpy/lib/tests/test_histograms.py b/numpy/lib/tests/test_histograms.py index 87e6e1d41c4a..38b3d3dcbf3f 100644 --- a/numpy/lib/tests/test_histograms.py +++ b/numpy/lib/tests/test_histograms.py @@ -408,6 +408,13 @@ def test_big_arrays(self): hist = np.histogramdd(sample=sample, bins=(xbins, ybins, zbins)) assert_equal(type(hist), type((1, 2))) + def test_gh_23110(self): + hist, e = np.histogram(np.array([-0.9e-308], dtype='>f8'), + bins=2, + range=(-1e-308, -2e-313)) + expected_hist = np.array([1, 0]) + assert_array_equal(hist, expected_hist) + class TestHistogramOptimBinNums: """ From 1dd9398d17289b9a4a86c054452854cbe09a44a4 Mon Sep 17 00:00:00 2001 From: Charles Harris Date: Fri, 14 Jul 2023 18:40:52 -0600 Subject: [PATCH 17/35] MAINT: Update meson.build files from main branch In addition to the meson.build files in numpy, the submodules `numpy/core/src/npysort/x86-simd-sort` and `numpy/core/src/umath/svml` have also been updated to get the meson build changes in them. The include files have not been updated, as the main change seems to be removal of some of them in line with the changes in 2.0.0. Likewise the ABI and API numbers in `numpy/core/meson.build` have been kept in line with 1.25.x, but the dependencies there should be checked by someone more familiar with the new build infrastructure. --- meson.build | 2 +- numpy/core/meson.build | 12 ++- numpy/core/src/npysort/x86-simd-sort | 2 +- numpy/core/src/umath/svml | 2 +- numpy/linalg/meson.build | 2 +- numpy/meson.build | 107 ++++++++++++++++++---- numpy/random/_examples/cython/meson.build | 45 +++++++++ numpy/random/meson.build | 4 +- 8 files changed, 151 insertions(+), 25 deletions(-) create mode 100644 numpy/random/_examples/cython/meson.build diff --git a/meson.build b/meson.build index 8366250a7919..8bfe987715d1 100644 --- a/meson.build +++ b/meson.build @@ -4,7 +4,7 @@ project( # Note that the git commit hash cannot be added dynamically here # It is dynamically added upon import by versioneer # See `numpy/__init__.py` - version: '1.24.0.dev0', + version: '1.26.0.dev0', license: 'BSD-3', meson_version: '>= 1.1.0', default_options: [ diff --git a/numpy/core/meson.build b/numpy/core/meson.build index 754005c8306a..2f02de2695ba 100644 --- a/numpy/core/meson.build +++ b/numpy/core/meson.build @@ -45,11 +45,16 @@ C_ABI_VERSION = '0x01000009' # 0x00000010 - 1.23.x # 0x00000010 - 1.24.x # 0x00000011 - 1.25.x +# 0x00000011 - 1.26.x C_API_VERSION = '0x00000011' # Check whether we have a mismatch between the set C API VERSION and the # actual C API VERSION. Will raise a MismatchCAPIError if so. -run_command('code_generators/verify_c_api_version.py', '--api-version', C_API_VERSION, check: true) +r = run_command('code_generators/verify_c_api_version.py', '--api-version', C_API_VERSION) + +if r.returncode() != 0 + error('verify_c_api_version.py failed with output:\n' + r.stderr().strip()) +endif # Generate config.h and _numpyconfig.h @@ -533,6 +538,8 @@ npymath_lib = static_library('npymath', dependencies: py_dep, install: true, install_dir: np_dir / 'core/lib', + name_prefix: name_prefix_staticlib, + name_suffix: name_suffix_staticlib, ) dir_separator = '/' @@ -923,7 +930,7 @@ py.extension_module('_multiarray_umath', 'src/npymath', 'src/umath', ], - dependencies: blas, + dependencies: blas_dep, link_with: npymath_lib, install: true, subdir: 'numpy/core', @@ -994,7 +1001,6 @@ python_sources = [ 'shape_base.py', 'shape_base.pyi', 'umath.py', - 'umath_tests.py', ] py.install_sources( diff --git a/numpy/core/src/npysort/x86-simd-sort b/numpy/core/src/npysort/x86-simd-sort index 6283f2491ceb..85fbe7d1abca 160000 --- a/numpy/core/src/npysort/x86-simd-sort +++ b/numpy/core/src/npysort/x86-simd-sort @@ -1 +1 @@ -Subproject commit 6283f2491cebe2332795943e30e31828178e5efd +Subproject commit 85fbe7d1abca3b9a224ba1c62d52afe9a180f8ef diff --git a/numpy/core/src/umath/svml b/numpy/core/src/umath/svml index 1c5260a61e7d..1b21e453f6b1 160000 --- a/numpy/core/src/umath/svml +++ b/numpy/core/src/umath/svml @@ -1 +1 @@ -Subproject commit 1c5260a61e7dce6be48073dfa96291edb0a11d79 +Subproject commit 1b21e453f6b1ba6a6aca392b1d810d9d41576123 diff --git a/numpy/linalg/meson.build b/numpy/linalg/meson.build index 083692913c7c..d290e5b3932d 100644 --- a/numpy/linalg/meson.build +++ b/numpy/linalg/meson.build @@ -20,7 +20,7 @@ endif py.extension_module('lapack_lite', lapack_lite_module_src, - dependencies: [np_core_dep, lapack], + dependencies: [np_core_dep, blas_dep, lapack_dep], install: true, subdir: 'numpy/linalg', ) diff --git a/numpy/meson.build b/numpy/meson.build index 7b85d8e92f5b..c9a4970a8a51 100644 --- a/numpy/meson.build +++ b/numpy/meson.build @@ -22,6 +22,18 @@ if is_mingw add_project_arguments('-D__USE_MINGW_ANSI_STDIO=1', language: ['c', 'cpp']) endif +# We install libnpymath and libnpyrandom; ensure they're using a `.lib` rather +# than a `.a` file extension in order not to break including them in a +# distutils-based build (see gh-23981 and +# https://mesonbuild.com/FAQ.html#why-does-building-my-project-with-msvc-output-static-libraries-called-libfooa) +if is_windows and cc.get_id() == 'msvc' + name_prefix_staticlib = '' + name_suffix_staticlib = 'lib' +else + name_prefix_staticlib = [] + name_suffix_staticlib = [] +endif + # Enable UNIX large file support on 32-bit systems (64 bit off_t, # lseek -> lseek64, etc.) cflags_large_file_support = [] @@ -55,36 +67,84 @@ else blas = dependency(blas_name, required: false) endif have_blas = blas.found() -if have_blas and blas_name == 'blas' +cblas = [] +if have_blas # Netlib BLAS has a separate `libcblas.so` which we use directly in the g77 - # ABI wrappers, so detect it and error out if we cannot find it. + # ABI wrappers, so detect it and error out if we cannot find it. OpenBLAS can + # be built without CBLAS too (see gh-23909, done by Arch Linux until + # recently) # In the future, this should be done automatically for: # `dependency('blas', modules: cblas)` # see https://github.com/mesonbuild/meson/pull/10921. - cblas = dependency('cblas') -else - cblas = [] + have_cblas = false + if cc.links(''' + #include + int main(int argc, const char *argv[]) + { + double a[4] = {1,2,3,4}; + double b[4] = {5,6,7,8}; + return cblas_ddot(4, a, 1, b, 1) > 10; + } + ''', + dependencies: blas, + name: 'CBLAS', + ) + have_cblas = true + else + cblas = dependency('cblas', required: false) + if cblas.found() + have_cblas = true + endif + endif endif if lapack_name == 'openblas' lapack_name = ['openblas', 'OpenBLAS'] endif -lapack = dependency(lapack_name, required: false) -have_lapack = lapack.found() +lapack_dep = dependency(lapack_name, required: false) +have_lapack = lapack_dep.found() dependency_map = { 'BLAS': blas, - 'LAPACK': lapack, + 'LAPACK': lapack_dep, } +use_ilp64 = get_option('use-ilp64') +if not use_ilp64 + # For now, keep supporting this environment variable too (same as in setup.py) + # `false is the default for the CLI flag, so check if env var was set + use_ilp64 = run_command(py, + [ + '-c', + 'import os; print(1) if os.environ.get("NPY_USE_BLAS_ILP64", "0") != "0" else print(0)' + ], + check: true + ).stdout().strip() == '1' +endif + # BLAS and LAPACK are optional dependencies for NumPy. We can only use a BLAS # which provides a CBLAS interface. # TODO: add ILP64 support if have_blas - # TODO: this is a shortcut - it needs to be checked rather than used - # unconditionally, and then added to the extension modules that need the - # macro, rather than as a project argument. - add_project_arguments('-DHAVE_CBLAS', language: ['c', 'cpp']) + c_args_blas = [] # note: used for C and C++ via `blas_dep` below + if have_cblas + c_args_blas += ['-DHAVE_CBLAS'] + endif + if use_ilp64 + c_args_blas += ['-DHAVE_BLAS_ILP64'] + endif + # This is currently injected directly into CFLAGS/CXXFLAGS for wheel builds + # (see cibuildwheel settings in pyproject.toml) + blas_symbol_suffix = get_option('blas-symbol-suffix') + if blas_symbol_suffix != '' + c_args_blas += ['-DBLAS_SYMBOL_SUFFIX=' + blas_symbol_suffix] + endif + blas_dep = declare_dependency( + dependencies: [blas, cblas], + compile_args: c_args_blas, + ) +else + blas_dep = [] endif # Copy the main __init__.py|pxd files to the build dir (needed for Cython) @@ -138,7 +198,6 @@ pure_subdirs = [ '_utils', 'array_api', 'compat', - 'distutils', 'doc', 'f2py', 'lib', @@ -149,6 +208,9 @@ pure_subdirs = [ 'tests', 'typing', ] +if py.version().version_compare('<3.12') + pure_subdirs += 'distutils' +endif np_dir = py.get_install_dir() / 'numpy' @@ -175,6 +237,14 @@ foreach name, compiler : compilers conf_data.set(name + '_COMP_LINKER_ID', compiler.get_linker_id()) conf_data.set(name + '_COMP_VERSION', compiler.version()) conf_data.set(name + '_COMP_CMD_ARRAY', ', '.join(compiler.cmd_array())) + conf_data.set(name + '_COMP_ARGS', ', '.join( + get_option(name.to_lower() + '_args') + ) + ) + conf_data.set(name + '_COMP_LINK_ARGS', ', '.join( + get_option(name.to_lower() + '_link_args') + ) + ) endforeach # Machines CPU and system information @@ -198,10 +268,13 @@ foreach name, dep : dependency_map if dep.found() conf_data.set(name + '_VERSION', dep.version()) conf_data.set(name + '_TYPE_NAME', dep.type_name()) - conf_data.set(name + '_INCLUDEDIR', dep.get_variable('includedir')) - conf_data.set(name + '_LIBDIR', dep.get_variable('libdir')) - conf_data.set(name + '_OPENBLAS_CONFIG', dep.get_variable('openblas_config')) - conf_data.set(name + '_PCFILEDIR', dep.get_variable('pcfiledir')) + if dep.type_name() == 'pkgconfig' + # CMake detection yields less info, so we need to leave it blank there + conf_data.set(name + '_INCLUDEDIR', dep.get_variable('includedir')) + conf_data.set(name + '_LIBDIR', dep.get_variable('libdir')) + conf_data.set(name + '_OPENBLAS_CONFIG', dep.get_variable('openblas_config')) + conf_data.set(name + '_PCFILEDIR', dep.get_variable('pcfiledir')) + endif endif endforeach diff --git a/numpy/random/_examples/cython/meson.build b/numpy/random/_examples/cython/meson.build new file mode 100644 index 000000000000..c00837d49d97 --- /dev/null +++ b/numpy/random/_examples/cython/meson.build @@ -0,0 +1,45 @@ +project('random-build-examples', 'c', 'cpp', 'cython') + +py_mod = import('python') +py3 = py_mod.find_installation(pure: false) + +cc = meson.get_compiler('c') +cy = meson.get_compiler('cython') + +if not cy.version().version_compare('>=0.29.35') + error('tests requires Cython >= 0.29.35') +endif + +_numpy_abs = run_command(py3, ['-c', + 'import os; os.chdir(".."); import numpy; print(os.path.abspath(numpy.get_include() + "../../.."))'], + check: true).stdout().strip() + +npymath_path = _numpy_abs / 'core' / 'lib' +npy_include_path = _numpy_abs / 'core' / 'include' +npyrandom_path = _numpy_abs / 'random' / 'lib' +npymath_lib = cc.find_library('npymath', dirs: npymath_path) +npyrandom_lib = cc.find_library('npyrandom', dirs: npyrandom_path) + +py3.extension_module( + 'extending_distributions', + 'extending_distributions.pyx', + install: false, + include_directories: [npy_include_path], + dependencies: [npyrandom_lib, npymath_lib], +) +py3.extension_module( + 'extending', + 'extending.pyx', + install: false, + include_directories: [npy_include_path], + dependencies: [npyrandom_lib, npymath_lib], +) +py3.extension_module( + 'extending_cpp', + 'extending_distributions.pyx', + install: false, + override_options : ['cython_language=cpp'], + cython_args: ['--module-name', 'extending_cpp'], + include_directories: [npy_include_path], + dependencies: [npyrandom_lib, npymath_lib], +) diff --git a/numpy/random/meson.build b/numpy/random/meson.build index 036cd81b9a2e..4980a80ba2c8 100644 --- a/numpy/random/meson.build +++ b/numpy/random/meson.build @@ -15,6 +15,8 @@ npyrandom_lib = static_library('npyrandom', dependencies: [py_dep, np_core_dep], install: true, install_dir: np_dir / 'random/lib', + name_prefix: name_prefix_staticlib, + name_suffix: name_suffix_staticlib, ) # Build Cython extensions for numpy.random @@ -150,7 +152,7 @@ py.install_sources( [ '_examples/cython/extending.pyx', '_examples/cython/extending_distributions.pyx', - '_examples/cython/setup.py', + '_examples/cython/meson.build', ], subdir: 'numpy/random/_examples/cython' ) From d7e21759ec3648f2d31a9571a31cb41c19bc3799 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Sun, 16 Jul 2023 12:19:46 +0200 Subject: [PATCH 18/35] BLD: also backport additions to `meson_options.txt` --- meson_options.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/meson_options.txt b/meson_options.txt index 0b506385a8ba..f18d1c0942ac 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -2,6 +2,10 @@ option('blas', type: 'string', value: 'openblas', description: 'option for BLAS library switching') option('lapack', type: 'string', value: 'openblas', description: 'option for LAPACK library switching') +option('use-ilp64', type: 'boolean', value: false, + description: 'Use ILP64 (64-bit integer) BLAS and LAPACK interfaces') +option('blas-symbol-suffix', type: 'string', value: '', + description: 'BLAS and LAPACK symbol suffix to use, if any (often `64_` for ILP64)') option('disable-svml', type: 'boolean', value: false, description: 'Disable building against SVML') option('disable-threading', type: 'boolean', value: false, From 55a343a6a2fea7eabb1da7d14fd6c8d35b979e76 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Sun, 16 Jul 2023 12:24:34 +0200 Subject: [PATCH 19/35] BLD: put back install of two files still needed for tests --- numpy/core/meson.build | 1 + numpy/random/meson.build | 1 + 2 files changed, 2 insertions(+) diff --git a/numpy/core/meson.build b/numpy/core/meson.build index 2f02de2695ba..ab773c56d735 100644 --- a/numpy/core/meson.build +++ b/numpy/core/meson.build @@ -1001,6 +1001,7 @@ python_sources = [ 'shape_base.py', 'shape_base.pyi', 'umath.py', + 'umath_tests.py', ] py.install_sources( diff --git a/numpy/random/meson.build b/numpy/random/meson.build index 4980a80ba2c8..c582428f9629 100644 --- a/numpy/random/meson.build +++ b/numpy/random/meson.build @@ -153,6 +153,7 @@ py.install_sources( '_examples/cython/extending.pyx', '_examples/cython/extending_distributions.pyx', '_examples/cython/meson.build', + '_examples/cython/setup.py', ], subdir: 'numpy/random/_examples/cython' ) From 5b62e958f4fc4e843cf1179f0aeb77c7470e5436 Mon Sep 17 00:00:00 2001 From: Charles Harris Date: Mon, 17 Jul 2023 14:29:48 -0600 Subject: [PATCH 20/35] MAINT: Ignore 16 bit avx512 for old versions of binutils. Update numpy/core/setup.py to avoid the use of instructions that are unrecognized in binutils < 2.38. This should fix CI failures on gcc-7. --- numpy/core/setup.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/numpy/core/setup.py b/numpy/core/setup.py index 8ef012f70f73..571320ceb253 100644 --- a/numpy/core/setup.py +++ b/numpy/core/setup.py @@ -79,6 +79,13 @@ def can_link_svml(): and "linux" in platform and sys.maxsize > 2**31) +def can_link_svml_fp16(): + """SVML FP16 requires binutils >= 2.38 for an updated assembler + """ + if can_link_svml(): + binutils_ver = os.popen("ld -v").readlines()[0].strip()[-4:] + return float(binutils_ver) >= 2.38 + def check_git_submodules(): out = os.popen("git submodule status") modules = out.readlines() @@ -1009,6 +1016,8 @@ def generate_umath_doc_header(ext, build_dir): # The ordering of names returned by glob is undefined, so we sort # to make builds reproducible. svml_objs.sort() + if not can_link_svml_fp16(): + svml_objs = [o for o in svml_objs if not o.endswith('_h_la.s')] config.add_extension('_multiarray_umath', sources=multiarray_src + umath_src + From 394a9f8b9dee06703ee7b98c8d6d8ae6732e401e Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Sat, 22 Jul 2023 17:12:12 +0200 Subject: [PATCH 21/35] MAINT: exclude min, max and round from `np.__all__` This is a workaround for breakage in downstream packages that do `from numpy import *`, see gh-24229. Note that there are other builtins that are contained in `__all__`: ``` >>> for s in dir(builtins): ... if s in np.__all__: ... print(s) ... all any divmod sum ``` Those were already there before the change in 1.25.0, and can stay. The downstream code should be fixed before the numpy 2.0 release. Closes gh-24229 --- numpy/__init__.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/numpy/__init__.py b/numpy/__init__.py index ae86313874eb..b4b33320b9f9 100644 --- a/numpy/__init__.py +++ b/numpy/__init__.py @@ -235,6 +235,12 @@ __all__.extend(lib.__all__) __all__.extend(['linalg', 'fft', 'random', 'ctypeslib', 'ma']) + # Remove min and max from __all__ to avoid `from numpy import *` override + # the builtins min/max. Temporary fix for 1.25.x/1.26.x, see gh-24229. + __all__.remove('min') + __all__.remove('max') + __all__.remove('round') + # Remove one of the two occurrences of `issubdtype`, which is exposed as # both `numpy.core.issubdtype` and `numpy.lib.issubdtype`. __all__.remove('issubdtype') From b547355c513070ecb472e7dc1ad75333f65c874d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Jul 2023 17:58:22 +0000 Subject: [PATCH 22/35] MAINT: Bump pypa/cibuildwheel from 2.14.0 to 2.14.1 Bumps [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel) from 2.14.0 to 2.14.1. - [Release notes](https://github.com/pypa/cibuildwheel/releases) - [Changelog](https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md) - [Commits](https://github.com/pypa/cibuildwheel/compare/66b46d086804a9e9782354100d96a3a445431bca...f21bb8376a051ffb6cb5604b28ccaef7b90e8ab7) --- updated-dependencies: - dependency-name: pypa/cibuildwheel dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index f4337244a795..f5b4fb03d61f 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -118,7 +118,7 @@ jobs: if: ${{ matrix.buildplat[1] == 'win32' }} - name: Build wheels - uses: pypa/cibuildwheel@66b46d086804a9e9782354100d96a3a445431bca # v2.14.0 + uses: pypa/cibuildwheel@f21bb8376a051ffb6cb5604b28ccaef7b90e8ab7 # v2.14.1 env: CIBW_BUILD: ${{ matrix.python }}-${{ matrix.buildplat[1] }} From 2c2ff2869d64722b401dacfc2a8b6baccf0f28de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Jul 2023 17:59:32 +0000 Subject: [PATCH 23/35] MAINT: Bump larsoner/circleci-artifacts-redirector-action Bumps [larsoner/circleci-artifacts-redirector-action](https://github.com/larsoner/circleci-artifacts-redirector-action) from 443f056c4757600f1452146a7ce1627d1c034029 to 7e80b26b4c58b5d3272effc05491c18296b1ad6e. - [Release notes](https://github.com/larsoner/circleci-artifacts-redirector-action/releases) - [Commits](https://github.com/larsoner/circleci-artifacts-redirector-action/compare/443f056c4757600f1452146a7ce1627d1c034029...7e80b26b4c58b5d3272effc05491c18296b1ad6e) --- updated-dependencies: - dependency-name: larsoner/circleci-artifacts-redirector-action dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .github/workflows/circleci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/circleci.yml b/.github/workflows/circleci.yml index 89e472d2a76e..c3d1c0ccf1b0 100644 --- a/.github/workflows/circleci.yml +++ b/.github/workflows/circleci.yml @@ -17,7 +17,7 @@ jobs: statuses: write steps: - name: GitHub Action step - uses: larsoner/circleci-artifacts-redirector-action@443f056c4757600f1452146a7ce1627d1c034029 # master + uses: larsoner/circleci-artifacts-redirector-action@7e80b26b4c58b5d3272effc05491c18296b1ad6e # master with: repo-token: ${{ secrets.GITHUB_TOKEN }} api-token: ${{ secrets.CIRCLE_TOKEN }} From 2fff42469539c12fd175ab3190a1dc27fe786427 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Sat, 15 Jul 2023 10:29:36 -0500 Subject: [PATCH 24/35] BUG: Fix the signature for np.array_api.take The array_api take() doesn't flatten the array by default, so the axis argument must be provided for multidimensional arrays. However, it should be optional when the input array is 1-D, which the signature previously did not allow. c.f. https://github.com/data-apis/array-api/pull/644 --- numpy/array_api/_indexing_functions.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/numpy/array_api/_indexing_functions.py b/numpy/array_api/_indexing_functions.py index ba56bcd6f004..baf23f7f0b69 100644 --- a/numpy/array_api/_indexing_functions.py +++ b/numpy/array_api/_indexing_functions.py @@ -5,14 +5,16 @@ import numpy as np -def take(x: Array, indices: Array, /, *, axis: int) -> Array: +def take(x: Array, indices: Array, /, *, axis: Optional[int] = None) -> Array: """ Array API compatible wrapper for :py:func:`np.take `. See its docstring for more information. - """ + """ + if axis is None and x.ndim != 1: + raise ValueError("axis must be specified when ndim > 1") if indices.dtype not in _integer_dtypes: raise TypeError("Only integer dtypes are allowed in indexing") - if indices.ndim != 1: + if indices.ndim != 1: raise ValueError("Only 1-dim indices array is supported") return Array._new(np.take(x._array, indices._array, axis=axis)) From 729d1f6d4f8bfc05915b62f95b7b352914cb6349 Mon Sep 17 00:00:00 2001 From: mattip Date: Mon, 17 Jul 2023 16:12:15 +0300 Subject: [PATCH 25/35] BLD: update OpenBLAS to an intermeidate commit --- tools/openblas_support.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/openblas_support.py b/tools/openblas_support.py index fd8c6a97a34e..47159d0fa3ed 100644 --- a/tools/openblas_support.py +++ b/tools/openblas_support.py @@ -13,8 +13,8 @@ from urllib.request import urlopen, Request from urllib.error import HTTPError -OPENBLAS_V = '0.3.23' -OPENBLAS_LONG = 'v0.3.23' +OPENBLAS_V = '0.3.23.dev' +OPENBLAS_LONG = 'v0.3.23-246-g3d31191b' BASE_LOC = 'https://anaconda.org/multibuild-wheels-staging/openblas-libs' BASEURL = f'{BASE_LOC}/{OPENBLAS_LONG}/download' SUPPORTED_PLATFORMS = [ From 31f516c17303a5d367a305125fa9f09538570d61 Mon Sep 17 00:00:00 2001 From: Peter Hawkins Date: Tue, 18 Jul 2023 21:02:27 +0000 Subject: [PATCH 26/35] Fix reference count leak in str(scalar). PyArray_DescrFromTypeObject() returns a fresh reference to the descriptor object, which must be freed. This leak was introduced in https://github.com/numpy/numpy/commit/670842b38005febf64259f268332e46d86233ef0 --- numpy/core/src/multiarray/scalartypes.c.src | 1 + 1 file changed, 1 insertion(+) diff --git a/numpy/core/src/multiarray/scalartypes.c.src b/numpy/core/src/multiarray/scalartypes.c.src index ff30737b5fb5..4243a583fc1d 100644 --- a/numpy/core/src/multiarray/scalartypes.c.src +++ b/numpy/core/src/multiarray/scalartypes.c.src @@ -316,6 +316,7 @@ genint_type_str(PyObject *self) item = gentype_generic_method(self, NULL, NULL, "item"); break; } + Py_DECREF(descr); if (item == NULL) { return NULL; } From cd687c7c7e0b5d5505e883e8cbfd4cd4827595c6 Mon Sep 17 00:00:00 2001 From: Randy Eckenrode Date: Mon, 17 Jul 2023 11:20:20 -0600 Subject: [PATCH 27/35] BUG: fix invalid function pointer conversion error `f2py_init_func` is defined in `fortranobject.h` as: typedef void (*f2py_init_func)(int *, npy_intp *, f2py_set_data_func, int *); `f90mod_rules.py` attempts to assign functions with the following prototype to `func` of `struct FortranDataDef`: void(*)(int*, int*, void(*)(char*, int*), int*) This causes the `test_module_doc.py` test to fail when `npy_intp` is `long` and clang 16 is used as the compiler because the assignment is identified as an invalid function pointer conversion, which clang 16 treats as an error by default. Using `npy_intp` instead of `int` fixes the error. --- numpy/f2py/f90mod_rules.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/numpy/f2py/f90mod_rules.py b/numpy/f2py/f90mod_rules.py index a3bb6a212a65..1c47bee02b91 100644 --- a/numpy/f2py/f90mod_rules.py +++ b/numpy/f2py/f90mod_rules.py @@ -161,8 +161,8 @@ def iadd(line, s=ihooks): fargs.append('f2py_%s_getdims_%s' % (m['name'], n)) efargs.append(fargs[-1]) sargs.append( - 'void (*%s)(int*,int*,void(*)(char*,int*),int*)' % (n)) - sargsp.append('void (*)(int*,int*,void(*)(char*,int*),int*)') + 'void (*%s)(int*,npy_intp*,void(*)(char*,npy_intp*),int*)' % (n)) + sargsp.append('void (*)(int*,npy_intp*,void(*)(char*,npy_intp*),int*)') iadd('\tf2py_%s_def[i_f2py++].func = %s;' % (m['name'], n)) fadd('subroutine %s(r,s,f2pysetdata,flag)' % (fargs[-1])) fadd('use %s, only: d => %s\n' % From 0745bda91b75e5df229318b1333804c136edf465 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Mon, 24 Jul 2023 10:09:29 +0200 Subject: [PATCH 28/35] BUG: Factor out slow `getenv` call used for memory policy warning Using `getenv` regularly is probably not great anyway, but it seems very slow on windows which leads to a large overhead for every array deallocation here. Refactor it out to only check on first import and add helper because the tests are set up slightly differently. (Manually checked that the startup works, tests run with policy set to 1, not modifying it and passing.) --- doc/source/reference/global_state.rst | 3 ++ numpy/core/src/multiarray/arrayobject.c | 8 ++++-- numpy/core/src/multiarray/arrayobject.h | 2 ++ numpy/core/src/multiarray/multiarraymodule.c | 29 ++++++++++++++++++++ numpy/core/tests/test_mem_policy.py | 20 +++++++------- 5 files changed, 49 insertions(+), 13 deletions(-) diff --git a/doc/source/reference/global_state.rst b/doc/source/reference/global_state.rst index a898450afa20..d29f23ec67bd 100644 --- a/doc/source/reference/global_state.rst +++ b/doc/source/reference/global_state.rst @@ -96,3 +96,6 @@ release (NumPy 2.0) by setting an environment before importing NumPy: By default this will also activate the :ref:`NEP 50 ` related setting ``NPY_PROMOTION_STATE`` (please see the NEP for details on this). + +.. versionchanged:: 1.25.2 + This variable is only checked on the first import. diff --git a/numpy/core/src/multiarray/arrayobject.c b/numpy/core/src/multiarray/arrayobject.c index 46c4d90c9e00..4298ca38343e 100644 --- a/numpy/core/src/multiarray/arrayobject.c +++ b/numpy/core/src/multiarray/arrayobject.c @@ -62,6 +62,9 @@ maintainer email: oliphant.travis@ieee.org #include "binop_override.h" #include "array_coercion.h" + +NPY_NO_EXPORT npy_bool numpy_warn_if_no_mem_policy = 0; + /*NUMPY_API Compute the size of an array (in number of items) */ @@ -460,9 +463,8 @@ array_dealloc(PyArrayObject *self) } } if (fa->mem_handler == NULL) { - char *env = getenv("NUMPY_WARN_IF_NO_MEM_POLICY"); - if ((env != NULL) && (strncmp(env, "1", 1) == 0)) { - char const * msg = "Trying to dealloc data, but a memory policy " + if (numpy_warn_if_no_mem_policy) { + char const *msg = "Trying to dealloc data, but a memory policy " "is not set. If you take ownership of the data, you must " "set a base owning the data (e.g. a PyCapsule)."; WARN_IN_DEALLOC(PyExc_RuntimeWarning, msg); diff --git a/numpy/core/src/multiarray/arrayobject.h b/numpy/core/src/multiarray/arrayobject.h index a6b3a32bd73e..b71354a5e4dd 100644 --- a/numpy/core/src/multiarray/arrayobject.h +++ b/numpy/core/src/multiarray/arrayobject.h @@ -5,6 +5,8 @@ #ifndef NUMPY_CORE_SRC_MULTIARRAY_ARRAYOBJECT_H_ #define NUMPY_CORE_SRC_MULTIARRAY_ARRAYOBJECT_H_ +extern NPY_NO_EXPORT npy_bool numpy_warn_if_no_mem_policy; + NPY_NO_EXPORT PyObject * _strings_richcompare(PyArrayObject *self, PyArrayObject *other, int cmp_op, int rstrip); diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c index b04af8cbee65..3e7e35e45365 100644 --- a/numpy/core/src/multiarray/multiarraymodule.c +++ b/numpy/core/src/multiarray/multiarraymodule.c @@ -4475,6 +4475,24 @@ normalize_axis_index(PyObject *NPY_UNUSED(self), } +static PyObject * +_set_numpy_warn_if_no_mem_policy(PyObject *NPY_UNUSED(self), PyObject *arg) +{ + int res = PyObject_IsTrue(arg); + if (res < 0) { + return NULL; + } + int old_value = numpy_warn_if_no_mem_policy; + numpy_warn_if_no_mem_policy = res; + if (old_value) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + + static PyObject * _reload_guard(PyObject *NPY_UNUSED(self), PyObject *NPY_UNUSED(args)) { static int initialized = 0; @@ -4733,6 +4751,9 @@ static struct PyMethodDef array_module_methods[] = { METH_O, "Set the NEP 50 promotion state. This is not thread-safe.\n" "The optional warnings can be safely silenced using the \n" "`np._no_nep50_warning()` context manager."}, + {"_set_numpy_warn_if_no_mem_policy", + (PyCFunction)_set_numpy_warn_if_no_mem_policy, + METH_O, "Change the warn if no mem policy flag for testing."}, {"_add_newdoc_ufunc", (PyCFunction)add_newdoc_ufunc, METH_VARARGS, NULL}, {"_get_sfloat_dtype", @@ -5029,6 +5050,14 @@ initialize_static_globals(void) npy_numpy2_behavior = NPY_TRUE; } + char *env = getenv("NUMPY_WARN_IF_NO_MEM_POLICY"); + if ((env != NULL) && (strncmp(env, "1", 1) == 0)) { + numpy_warn_if_no_mem_policy = 1; + } + else { + numpy_warn_if_no_mem_policy = 0; + } + return 0; } diff --git a/numpy/core/tests/test_mem_policy.py b/numpy/core/tests/test_mem_policy.py index 479f702ea12f..60cdaa8faa2a 100644 --- a/numpy/core/tests/test_mem_policy.py +++ b/numpy/core/tests/test_mem_policy.py @@ -395,16 +395,19 @@ def test_switch_owner(get_module, policy): a = get_module.get_array() assert np.core.multiarray.get_handler_name(a) is None get_module.set_own(a) - oldval = os.environ.get('NUMPY_WARN_IF_NO_MEM_POLICY', None) + if policy is None: - if 'NUMPY_WARN_IF_NO_MEM_POLICY' in os.environ: - os.environ.pop('NUMPY_WARN_IF_NO_MEM_POLICY') + # See what we expect to be set based on the env variable + policy = os.getenv("NUMPY_WARN_IF_NO_MEM_POLICY", "0") == "1" + oldval = None else: - os.environ['NUMPY_WARN_IF_NO_MEM_POLICY'] = policy + policy = policy == "1" + oldval = np.core._multiarray_umath._set_numpy_warn_if_no_mem_policy( + policy) try: # The policy should be NULL, so we have to assume we can call # "free". A warning is given if the policy == "1" - if policy == "1": + if policy: with assert_warns(RuntimeWarning) as w: del a gc.collect() @@ -413,11 +416,8 @@ def test_switch_owner(get_module, policy): gc.collect() finally: - if oldval is None: - if 'NUMPY_WARN_IF_NO_MEM_POLICY' in os.environ: - os.environ.pop('NUMPY_WARN_IF_NO_MEM_POLICY') - else: - os.environ['NUMPY_WARN_IF_NO_MEM_POLICY'] = oldval + if oldval is not None: + np.core._multiarray_umath._set_numpy_warn_if_no_mem_policy(oldval) def test_owner_is_base(get_module): a = get_module.get_array_with_base() From 7ca0270a3c889b61955ab83ff0c1816b6f0a75a2 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Tue, 25 Jul 2023 08:15:21 +0200 Subject: [PATCH 29/35] MAINT: Fix naming conflict in backport of moving getenv mempolicy warning --- numpy/core/src/multiarray/multiarraymodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c index 3e7e35e45365..66305722d14c 100644 --- a/numpy/core/src/multiarray/multiarraymodule.c +++ b/numpy/core/src/multiarray/multiarraymodule.c @@ -5050,7 +5050,7 @@ initialize_static_globals(void) npy_numpy2_behavior = NPY_TRUE; } - char *env = getenv("NUMPY_WARN_IF_NO_MEM_POLICY"); + env = getenv("NUMPY_WARN_IF_NO_MEM_POLICY"); if ((env != NULL) && (strncmp(env, "1", 1) == 0)) { numpy_warn_if_no_mem_policy = 1; } From e3882da4b71a03838386d0b4e3650ebebc8857f8 Mon Sep 17 00:00:00 2001 From: Andrew Nelson Date: Sat, 29 Jul 2023 10:15:13 +1000 Subject: [PATCH 30/35] CI: correct URL in cirrus.star [skip cirrus] --- .cirrus.star | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cirrus.star b/.cirrus.star index 25c7b7dfd863..6b2203872394 100644 --- a/.cirrus.star +++ b/.cirrus.star @@ -24,7 +24,7 @@ def main(ctx): # only contains the actual commit message on a non-PR trigger event. # For a PR event it contains the PR title and description. SHA = env.get("CIRRUS_CHANGE_IN_REPO") - url = "https://api.github.com/repos/scipy/scipy/git/commits/" + SHA + url = "https://api.github.com/repos/numpy/numpy/git/commits/" + SHA dct = http.get(url).json() # if "[wheel build]" in dct["message"]: # return fs.read("ci/cirrus_wheels.yml") From 8a731a5f254ff71255c1455525045321b6dbe0b6 Mon Sep 17 00:00:00 2001 From: Sam James Date: Sun, 23 Jul 2023 21:31:08 +0100 Subject: [PATCH 31/35] BUG: Fix C types in scalartypes https://github.com/numpy/numpy/pull/23746 introduced a fast path for scalar int conversions, but the map between Python types and C types was subtly wrong. This fixes tests on at least ppc32 (big-endian). Many thanks to Sebastian Berg for debugging this with me and pointing out what needed to be fixed. Closes #24239. Fixes: 81caed6e3c34c4bf4b22b4f6167e816ba2a3f73c --- numpy/core/src/multiarray/scalartypes.c.src | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/numpy/core/src/multiarray/scalartypes.c.src b/numpy/core/src/multiarray/scalartypes.c.src index 4243a583fc1d..f3382e511422 100644 --- a/numpy/core/src/multiarray/scalartypes.c.src +++ b/numpy/core/src/multiarray/scalartypes.c.src @@ -283,34 +283,34 @@ genint_type_str(PyObject *self) void *val = scalar_value(self, descr); switch (descr->type_num) { case NPY_BYTE: - item = PyLong_FromLong(*(int8_t *)val); + item = PyLong_FromLong(*(npy_byte *)val); break; case NPY_UBYTE: - item = PyLong_FromUnsignedLong(*(uint8_t *)val); + item = PyLong_FromUnsignedLong(*(npy_ubyte *)val); break; case NPY_SHORT: - item = PyLong_FromLong(*(int16_t *)val); + item = PyLong_FromLong(*(npy_short *)val); break; case NPY_USHORT: - item = PyLong_FromUnsignedLong(*(uint16_t *)val); + item = PyLong_FromUnsignedLong(*(npy_ushort *)val); break; case NPY_INT: - item = PyLong_FromLong(*(int32_t *)val); + item = PyLong_FromLong(*(npy_int *)val); break; case NPY_UINT: - item = PyLong_FromUnsignedLong(*(uint32_t *)val); + item = PyLong_FromUnsignedLong(*(npy_uint *)val); break; case NPY_LONG: - item = PyLong_FromLong(*(int64_t *)val); + item = PyLong_FromLong(*(npy_long *)val); break; case NPY_ULONG: - item = PyLong_FromUnsignedLong(*(uint64_t *)val); + item = PyLong_FromUnsignedLong(*(npy_ulong *)val); break; case NPY_LONGLONG: - item = PyLong_FromLongLong(*(long long *)val); + item = PyLong_FromLongLong(*(npy_longlong *)val); break; case NPY_ULONGLONG: - item = PyLong_FromUnsignedLongLong(*(unsigned long long *)val); + item = PyLong_FromUnsignedLongLong(*(npy_ulonglong *)val); break; default: item = gentype_generic_method(self, NULL, NULL, "item"); From 5c964bb4b1e2be9fba288f00a0b70025f48e0d7b Mon Sep 17 00:00:00 2001 From: Matti Picus Date: Thu, 27 Jul 2023 15:04:19 +0300 Subject: [PATCH 32/35] TST: add failing test --- numpy/core/tests/test_ufunc.py | 1 + 1 file changed, 1 insertion(+) diff --git a/numpy/core/tests/test_ufunc.py b/numpy/core/tests/test_ufunc.py index d6aa3e1056bf..03eeff285600 100644 --- a/numpy/core/tests/test_ufunc.py +++ b/numpy/core/tests/test_ufunc.py @@ -2222,6 +2222,7 @@ def test_at_negative_indexes(self): assert a[-1] == 11 # issue 24147 assert a[1] == 2 assert a[2] == 3 + assert np.all(indxs == [-1, 1, -1, 2]) def test_at_not_none_signature(self): # Test ufuncs with non-trivial signature raise a TypeError From fa3a023a98da1d3f8fbeac0f961e9885fa93b8c3 Mon Sep 17 00:00:00 2001 From: Matti Picus Date: Thu, 27 Jul 2023 15:05:58 +0300 Subject: [PATCH 33/35] BUG: fix for modifying the index arg in ufunc_at --- numpy/core/src/umath/loops.c.src | 99 +++++++++++++++++++++-------- numpy/core/src/umath/ufunc_object.c | 13 ++-- 2 files changed, 79 insertions(+), 33 deletions(-) diff --git a/numpy/core/src/umath/loops.c.src b/numpy/core/src/umath/loops.c.src index 97a74b4257aa..e69a27a9ea70 100644 --- a/numpy/core/src/umath/loops.c.src +++ b/numpy/core/src/umath/loops.c.src @@ -450,14 +450,19 @@ NPY_NO_EXPORT NPY_GCC_OPT_3 int void *NPY_UNUSED(func)) { char *ip1 = args[0]; - char *indx = args[1]; + char *indxp = args[1]; char *value = args[2]; npy_intp is1 = steps[0], isindex = steps[1], isb = steps[2]; + npy_intp shape = steps[3]; npy_intp n = dimensions[0]; npy_intp i; @type@ *indexed; - for(i = 0; i < n; i++, indx += isindex, value += isb) { - indexed = (@type@ *)(ip1 + is1 * *(npy_intp *)indx); + for(i = 0; i < n; i++, indxp += isindex, value += isb) { + npy_intp indx = *(npy_intp *)indxp; + if (indx < 0) { + indx += shape; + } + indexed = (@type@ *)(ip1 + is1 * indx); *indexed = *indexed @OP@ *(@type@ *)value; } return 0; @@ -1241,14 +1246,19 @@ NPY_NO_EXPORT int void *NPY_UNUSED(func)) { char *ip1 = args[0]; - char *indx = args[1]; + char *indxp = args[1]; char *value = args[2]; npy_intp is1 = steps[0], isindex = steps[1], isb = steps[2]; + npy_intp shape = steps[3]; npy_intp n = dimensions[0]; npy_intp i; @type@ *indexed; - for(i = 0; i < n; i++, indx += isindex, value += isb) { - indexed = (@type@ *)(ip1 + is1 * *(npy_intp *)indx); + for(i = 0; i < n; i++, indxp += isindex, value += isb) { + npy_intp indx = *(npy_intp *)indxp; + if (indx < 0) { + indx += shape; + } + indexed = (@type@ *)(ip1 + is1 * indx); *indexed = npy_floor_divide@c@(*indexed, *(@type@ *)value); } return 0; @@ -1395,14 +1405,19 @@ LONGDOUBLE_@kind@_indexed(PyArrayMethod_Context *NPY_UNUSED(context), void *NPY_UNUSED(func)) { char *ip1 = args[0]; - char *indx = args[1]; + char *indxp = args[1]; char *value = args[2]; npy_intp is1 = steps[0], isindex = steps[1], isb = steps[2]; + npy_intp shape = steps[3]; npy_intp n = dimensions[0]; npy_intp i; npy_longdouble *indexed; - for(i = 0; i < n; i++, indx += isindex, value += isb) { - indexed = (npy_longdouble *)(ip1 + is1 * *(npy_intp *)indx); + for(i = 0; i < n; i++, indxp += isindex, value += isb) { + npy_intp indx = *(npy_intp *)indxp; + if (indx < 0) { + indx += shape; + } + indexed = (npy_longdouble *)(ip1 + is1 * indx); *indexed = *indexed @OP@ *(npy_longdouble *)value; } return 0; @@ -1520,14 +1535,19 @@ HALF_@kind@_indexed(void *NPY_UNUSED(context), void *NPY_UNUSED(func)) { char *ip1 = args[0]; - char *indx = args[1]; + char *indxp = args[1]; char *value = args[2]; npy_intp is1 = steps[0], isindex = steps[1], isb = steps[2]; + npy_intp shape = steps[3]; npy_intp n = dimensions[0]; npy_intp i; npy_half *indexed; - for(i = 0; i < n; i++, indx += isindex, value += isb) { - indexed = (npy_half *)(ip1 + is1 * *(npy_intp *)indx); + for(i = 0; i < n; i++, indxp += isindex, value += isb) { + npy_intp indx = *(npy_intp *)indxp; + if (indx < 0) { + indx += shape; + } + indexed = (npy_half *)(ip1 + is1 * indx); const float v = npy_half_to_float(*(npy_half *)value); *indexed = npy_float_to_half(npy_half_to_float(*indexed) @OP@ v); } @@ -1641,14 +1661,19 @@ HALF_@kind@_indexed(PyArrayMethod_Context *NPY_UNUSED(context), void *NPY_UNUSED(func)) { char *ip1 = args[0]; - char *indx = args[1]; + char *indxp = args[1]; char *value = args[2]; npy_intp is1 = steps[0], isindex = steps[1], isb = steps[2]; + npy_intp shape = steps[3]; npy_intp n = dimensions[0]; npy_intp i; npy_half *indexed; - for(i = 0; i < n; i++, indx += isindex, value += isb) { - indexed = (npy_half *)(ip1 + is1 * *(npy_intp *)indx); + for(i = 0; i < n; i++, indxp += isindex, value += isb) { + npy_intp indx = *(npy_intp *)indxp; + if (indx < 0) { + indx += shape; + } + indexed = (npy_half *)(ip1 + is1 * indx); npy_half v = *(npy_half *)value; *indexed = (@OP@(*indexed, v) || npy_half_isnan(*indexed)) ? *indexed : v; } @@ -1679,14 +1704,19 @@ HALF_@kind@_indexed(PyArrayMethod_Context *NPY_UNUSED(context), void *NPY_UNUSED(func)) { char *ip1 = args[0]; - char *indx = args[1]; + char *indxp = args[1]; char *value = args[2]; npy_intp is1 = steps[0], isindex = steps[1], isb = steps[2]; + npy_intp shape = steps[3]; npy_intp n = dimensions[0]; npy_intp i; npy_half *indexed; - for (i = 0; i < n; i++, indx += isindex, value += isb) { - indexed = (npy_half *)(ip1 + is1 * *(npy_intp *)indx); + for (i = 0; i < n; i++, indxp += isindex, value += isb) { + npy_intp indx = *(npy_intp *)indxp; + if (indx < 0) { + indx += shape; + } + indexed = (npy_half *)(ip1 + is1 * indx); npy_half v = *(npy_half *)value; *indexed = (@OP@(*indexed, v) || npy_half_isnan(v)) ? *indexed: v; } @@ -1717,14 +1747,19 @@ HALF_floor_divide_indexed(PyArrayMethod_Context *NPY_UNUSED(context), void *NPY_UNUSED(func)) { char *ip1 = args[0]; - char *indx = args[1]; + char *indxp = args[1]; char *value = args[2]; npy_intp is1 = steps[0], isindex = steps[1], isb = steps[2]; + npy_intp shape = steps[3]; npy_intp n = dimensions[0]; npy_intp i; npy_half *indexed; - for(i = 0; i < n; i++, indx += isindex, value += isb) { - indexed = (npy_half *)(ip1 + is1 * *(npy_intp *)indx); + for(i = 0; i < n; i++, indxp += isindex, value += isb) { + npy_intp indx = *(npy_intp *)indxp; + if (indx < 0) { + indx += shape; + } + indexed = (npy_half *)(ip1 + is1 * indx); float v = npy_half_to_float(*(npy_half *)value); float div = npy_floor_dividef(npy_half_to_float(*indexed), v); *indexed = npy_float_to_half(div); @@ -1947,14 +1982,19 @@ NPY_NO_EXPORT int @TYPE@_@kind@_indexed (PyArrayMethod_Context *NPY_UNUSED(context), char * const*args, npy_intp const *dimensions, npy_intp const *steps, NpyAuxData *NPY_UNUSED(func)) { char *ip1 = args[0]; - char *indx = args[1]; + char *indxp = args[1]; char *value = args[2]; npy_intp is1 = steps[0], isindex = steps[1], isb = steps[2]; + npy_intp shape = steps[3]; npy_intp n = dimensions[0]; npy_intp i; @ftype@ *indexed; - for(i = 0; i < n; i++, indx += isindex, value += isb) { - indexed = (@ftype@ *)(ip1 + is1 * *(npy_intp *)indx); + for(i = 0; i < n; i++, indxp += isindex, value += isb) { + npy_intp indx = *(npy_intp *)indxp; + if (indx < 0) { + indx += shape; + } + indexed = (@ftype@ *)(ip1 + is1 * indx); const @ftype@ b_r = ((@ftype@ *)value)[0]; const @ftype@ b_i = ((@ftype@ *)value)[1]; indexed[0] @OP@= b_r; @@ -1981,14 +2021,19 @@ NPY_NO_EXPORT int @TYPE@_multiply_indexed (PyArrayMethod_Context *NPY_UNUSED(context), char * const*args, npy_intp const *dimensions, npy_intp const *steps, NpyAuxData *NPY_UNUSED(func)) { char *ip1 = args[0]; - char *indx = args[1]; + char *indxp = args[1]; char *value = args[2]; npy_intp is1 = steps[0], isindex = steps[1], isb = steps[2]; + npy_intp shape = steps[3]; npy_intp n = dimensions[0]; npy_intp i; @ftype@ *indexed; - for(i = 0; i < n; i++, indx += isindex, value += isb) { - indexed = (@ftype@ *)(ip1 + is1 * *(npy_intp *)indx); + for(i = 0; i < n; i++, indxp += isindex, value += isb) { + npy_intp indx = *(npy_intp *)indxp; + if (indx < 0) { + indx += shape; + } + indexed = (@ftype@ *)(ip1 + is1 * indx); const @ftype@ a_r = indexed[0]; const @ftype@ a_i = indexed[1]; const @ftype@ b_r = ((@ftype@ *)value)[0]; diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c index d992dd9602a6..ef12f43c5c14 100644 --- a/numpy/core/src/umath/ufunc_object.c +++ b/numpy/core/src/umath/ufunc_object.c @@ -5939,7 +5939,7 @@ trivial_at_loop(PyArrayMethodObject *ufuncimpl, NPY_ARRAYMETHOD_FLAGS flags, int buffersize=0, errormask = 0; int res; char *args[3]; - npy_intp steps[3]; + npy_intp steps[4]; args[0] = (char *) iter->baseoffset; steps[0] = iter->fancy_strides[0]; if (ufuncimpl->nin == 1) { @@ -5962,16 +5962,17 @@ trivial_at_loop(PyArrayMethodObject *ufuncimpl, NPY_ARRAYMETHOD_FLAGS flags, do { npy_intp *inner_size = NpyIter_GetInnerLoopSizePtr(iter->outer); npy_intp * indxP = (npy_intp *)iter->outer_ptrs[0]; - for (npy_intp i=0; i < *inner_size; i++) { - if (indxP[i] < 0) { - indxP[i] += iter->fancy_dims[0]; - } - } args[1] = (char *)indxP; steps[1] = iter->outer_strides[0]; + /* + * The value of iter->fancy_dims[0] is added to negative indexes + * inside the inner loop + */ + steps[3] = iter->fancy_dims[0]; res = ufuncimpl->contiguous_indexed_loop( context, args, inner_size, steps, NULL); + if (args[2] != NULL) { args[2] += (*inner_size) * steps[2]; } From 7b5e51a1acadb8730a102f1d867a268afe518297 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Fri, 28 Jul 2023 21:25:42 +0200 Subject: [PATCH 34/35] BUG: Further fixes to indexing loop and added tests This is a follow-up to gh-24272 which missed a few files. --- numpy/core/src/umath/_umath_tests.c.src | 11 +++++++--- .../src/umath/loops_arithm_fp.dispatch.c.src | 22 ++++++++++++++----- .../src/umath/loops_arithmetic.dispatch.c.src | 22 ++++++++++++++----- .../src/umath/loops_minmax.dispatch.c.src | 11 +++++++--- numpy/core/tests/test_ufunc.py | 22 +++++++++++++------ 5 files changed, 63 insertions(+), 25 deletions(-) diff --git a/numpy/core/src/umath/_umath_tests.c.src b/numpy/core/src/umath/_umath_tests.c.src index b427991e5463..b9e192706d00 100644 --- a/numpy/core/src/umath/_umath_tests.c.src +++ b/numpy/core/src/umath/_umath_tests.c.src @@ -375,13 +375,18 @@ INT32_negative_indexed(PyArrayMethod_Context *NPY_UNUSED(context), npy_intp const *steps, NpyAuxData *NPY_UNUSED(func)) { char *ip1 = args[0]; - char *indx = args[1]; + char *indxp = args[1]; npy_intp is1 = steps[0], isindex = steps[1]; npy_intp n = dimensions[0]; + npy_intp shape = steps[3]; npy_intp i; int32_t *indexed; - for(i = 0; i < n; i++, indx += isindex) { - indexed = (int32_t *)(ip1 + is1 * *(npy_intp *)indx); + for(i = 0; i < n; i++, indxp += isindex) { + npy_intp indx = *(npy_intp *)indxp; + if (indx < 0) { + indx += shape; + } + indexed = (int32_t *)(ip1 + is1 * indx); if (i == 3) { *indexed = -200; } else { diff --git a/numpy/core/src/umath/loops_arithm_fp.dispatch.c.src b/numpy/core/src/umath/loops_arithm_fp.dispatch.c.src index b72db5846f70..7ba3981e8119 100644 --- a/numpy/core/src/umath/loops_arithm_fp.dispatch.c.src +++ b/numpy/core/src/umath/loops_arithm_fp.dispatch.c.src @@ -258,14 +258,19 @@ NPY_NO_EXPORT int NPY_CPU_DISPATCH_CURFX(@TYPE@_@kind@_indexed) (PyArrayMethod_Context *NPY_UNUSED(context), char * const*args, npy_intp const *dimensions, npy_intp const *steps, NpyAuxData *NPY_UNUSED(func)) { char *ip1 = args[0]; - char *indx = args[1]; + char *indxp = args[1]; char *value = args[2]; npy_intp is1 = steps[0], isindex = steps[1], isb = steps[2]; + npy_intp shape = steps[3]; npy_intp n = dimensions[0]; npy_intp i; @type@ *indexed; - for(i = 0; i < n; i++, indx += isindex, value += isb) { - indexed = (@type@ *)(ip1 + is1 * *(npy_intp *)indx); + for(i = 0; i < n; i++, indxp += isindex, value += isb) { + npy_intp indx = *(npy_intp *)indxp; + if (indx < 0) { + indx += shape; + } + indexed = (@type@ *)(ip1 + is1 * indx); *indexed = *indexed @OP@ *(@type@ *)value; } return 0; @@ -650,14 +655,19 @@ NPY_NO_EXPORT int NPY_CPU_DISPATCH_CURFX(@TYPE@_@kind@_indexed) (PyArrayMethod_Context *NPY_UNUSED(context), char * const*args, npy_intp const *dimensions, npy_intp const *steps, NpyAuxData *NPY_UNUSED(func)) { char *ip1 = args[0]; - char *indx = args[1]; + char *indxp = args[1]; char *value = args[2]; npy_intp is1 = steps[0], isindex = steps[1], isb = steps[2]; + npy_intp shape = steps[3]; npy_intp n = dimensions[0]; npy_intp i; @ftype@ *indexed; - for(i = 0; i < n; i++, indx += isindex, value += isb) { - indexed = (@ftype@ *)(ip1 + is1 * *(npy_intp *)indx); + for(i = 0; i < n; i++, indxp += isindex, value += isb) { + npy_intp indx = *(npy_intp *)indxp; + if (indx < 0) { + indx += shape; + } + indexed = (@ftype@ *)(ip1 + is1 * indx); const @ftype@ b_r = ((@ftype@ *)value)[0]; const @ftype@ b_i = ((@ftype@ *)value)[1]; #if @is_mul@ diff --git a/numpy/core/src/umath/loops_arithmetic.dispatch.c.src b/numpy/core/src/umath/loops_arithmetic.dispatch.c.src index b6f12629807b..e07bb79808af 100644 --- a/numpy/core/src/umath/loops_arithmetic.dispatch.c.src +++ b/numpy/core/src/umath/loops_arithmetic.dispatch.c.src @@ -400,14 +400,19 @@ NPY_NO_EXPORT int NPY_CPU_DISPATCH_CURFX(@TYPE@_divide_indexed) (PyArrayMethod_Context *NPY_UNUSED(context), char * const*args, npy_intp const *dimensions, npy_intp const *steps, NpyAuxData *NPY_UNUSED(func)) { char *ip1 = args[0]; - char *indx = args[1]; + char *indxp = args[1]; char *value = args[2]; npy_intp is1 = steps[0], isindex = steps[1], isb = steps[2]; + npy_intp shape = steps[3]; npy_intp n = dimensions[0]; npy_intp i; @type@ *indexed; - for(i = 0; i < n; i++, indx += isindex, value += isb) { - indexed = (@type@ *)(ip1 + is1 * *(npy_intp *)indx); + for(i = 0; i < n; i++, indxp += isindex, value += isb) { + npy_intp indx = *(npy_intp *)indxp; + if (indx < 0) { + indx += shape; + } + indexed = (@type@ *)(ip1 + is1 * indx); *indexed = floor_div_@TYPE@(*indexed, *(@type@ *)value); } return 0; @@ -486,14 +491,19 @@ NPY_NO_EXPORT int NPY_CPU_DISPATCH_CURFX(@TYPE@_divide_indexed) (PyArrayMethod_Context *NPY_UNUSED(context), char * const*args, npy_intp const *dimensions, npy_intp const *steps, NpyAuxData *NPY_UNUSED(func)) { char *ip1 = args[0]; - char *indx = args[1]; + char *indxp = args[1]; char *value = args[2]; npy_intp is1 = steps[0], isindex = steps[1], isb = steps[2]; + npy_intp shape = steps[3]; npy_intp n = dimensions[0]; npy_intp i; @type@ *indexed; - for(i = 0; i < n; i++, indx += isindex, value += isb) { - indexed = (@type@ *)(ip1 + is1 * *(npy_intp *)indx); + for(i = 0; i < n; i++, indxp += isindex, value += isb) { + npy_intp indx = *(npy_intp *)indxp; + if (indx < 0) { + indx += shape; + } + indexed = (@type@ *)(ip1 + is1 * indx); @type@ in2 = *(@type@ *)value; if (NPY_UNLIKELY(in2 == 0)) { npy_set_floatstatus_divbyzero(); diff --git a/numpy/core/src/umath/loops_minmax.dispatch.c.src b/numpy/core/src/umath/loops_minmax.dispatch.c.src index 9d8667d3830a..236e2e2eb760 100644 --- a/numpy/core/src/umath/loops_minmax.dispatch.c.src +++ b/numpy/core/src/umath/loops_minmax.dispatch.c.src @@ -456,14 +456,19 @@ NPY_NO_EXPORT int NPY_CPU_DISPATCH_CURFX(@TYPE@_@kind@_indexed) (PyArrayMethod_Context *NPY_UNUSED(context), char *const *args, npy_intp const *dimensions, npy_intp const *steps, NpyAuxData *NPY_UNUSED(func)) { char *ip1 = args[0]; - char *indx = args[1]; + char *indxp = args[1]; char *value = args[2]; npy_intp is1 = steps[0], isindex = steps[1], isb = steps[2]; npy_intp n = dimensions[0]; + npy_intp shape = steps[3]; npy_intp i; @type@ *indexed; - for(i = 0; i < n; i++, indx += isindex, value += isb) { - indexed = (@type@ *)(ip1 + is1 * *(npy_intp *)indx); + for(i = 0; i < n; i++, indxp += isindex, value += isb) { + npy_intp indx = *(npy_intp *)indxp; + if (indx < 0) { + indx += shape; + } + indexed = (@type@ *)(ip1 + is1 * indx); *indexed = SCALAR_OP(*indexed, *(@type@ *)value); } return 0; diff --git a/numpy/core/tests/test_ufunc.py b/numpy/core/tests/test_ufunc.py index 03eeff285600..02c437021fe9 100644 --- a/numpy/core/tests/test_ufunc.py +++ b/numpy/core/tests/test_ufunc.py @@ -2215,13 +2215,21 @@ def test_ufunc_at_advanced(self): np.maximum.at(a, [0], 0) assert_equal(a, np.array([1, 2, 3])) - def test_at_negative_indexes(self): - a = np.arange(10) - indxs = np.array([-1, 1, -1, 2]) - np.add.at(a, indxs, 1) - assert a[-1] == 11 # issue 24147 - assert a[1] == 2 - assert a[2] == 3 + @pytest.mark.parametrize("dtype", + np.typecodes['AllInteger'] + np.typecodes['Float']) + @pytest.mark.parametrize("ufunc", + [np.add, np.subtract, np.divide, np.minimum, np.maximum]) + def test_at_negative_indexes(self, dtype, ufunc): + a = np.arange(0, 10).astype(dtype) + indxs = np.array([-1, 1, -1, 2]).astype(np.intp) + vals = np.array([1, 5, 2, 10], dtype=a.dtype) + + expected = a.copy() + for i, v in zip(indxs, vals): + expected[i] = ufunc(expected[i], v) + + ufunc.at(a, indxs, vals) + assert_array_equal(a, expected) assert np.all(indxs == [-1, 1, -1, 2]) def test_at_not_none_signature(self): From 47793ab7b7ab8a73bb4a54d4abd7f266664dfd6d Mon Sep 17 00:00:00 2001 From: Charles Harris Date: Sun, 30 Jul 2023 13:06:14 -0600 Subject: [PATCH 35/35] REL: Prepare for the NumPy 1.25.2 release. - Create 1.25.2-changelog.rst - Update 1.25.2-notes.rst --- doc/changelog/1.25.2-changelog.rst | 45 ++++++++++++++++++++++++++++ doc/source/release/1.25.2-notes.rst | 46 +++++++++++++++++++++++++++-- numpy/core/setup.py | 9 ++++-- 3 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 doc/changelog/1.25.2-changelog.rst diff --git a/doc/changelog/1.25.2-changelog.rst b/doc/changelog/1.25.2-changelog.rst new file mode 100644 index 000000000000..cd5b7f2e83e2 --- /dev/null +++ b/doc/changelog/1.25.2-changelog.rst @@ -0,0 +1,45 @@ + +Contributors +============ + +A total of 13 people contributed to this release. People with a "+" by their +names contributed a patch for the first time. + +* Aaron Meurer +* Andrew Nelson +* Charles Harris +* Kevin Sheppard +* Matti Picus +* Nathan Goldbaum +* Peter Hawkins +* Ralf Gommers +* Randy Eckenrode + +* Sam James + +* Sebastian Berg +* Tyler Reddy +* dependabot[bot] + +Pull requests merged +==================== + +A total of 19 pull requests were merged for this release. + +* `#24148 `__: MAINT: prepare 1.25.x for further development +* `#24174 `__: ENH: Improve clang-cl compliance +* `#24179 `__: MAINT: Upgrade various build dependencies. +* `#24182 `__: BLD: use ``-ftrapping-math`` with Clang on macOS +* `#24183 `__: BUG: properly handle negative indexes in ufunc_at fast path +* `#24184 `__: BUG: PyObject_IsTrue and PyObject_Not error handling in setflags +* `#24185 `__: BUG: histogram small range robust +* `#24186 `__: MAINT: Update meson.build files from main branch +* `#24234 `__: MAINT: exclude min, max and round from ``np.__all__`` +* `#24241 `__: MAINT: Dependabot updates +* `#24242 `__: BUG: Fix the signature for np.array_api.take +* `#24243 `__: BLD: update OpenBLAS to an intermeidate commit +* `#24244 `__: BUG: Fix reference count leak in str(scalar). +* `#24245 `__: BUG: fix invalid function pointer conversion error +* `#24255 `__: BUG: Factor out slow ``getenv`` call used for memory policy warning +* `#24292 `__: CI: correct URL in cirrus.star [skip cirrus] +* `#24293 `__: BUG: Fix C types in scalartypes +* `#24294 `__: BUG: do not modify the input to ufunc_at +* `#24295 `__: BUG: Further fixes to indexing loop and added tests diff --git a/doc/source/release/1.25.2-notes.rst b/doc/source/release/1.25.2-notes.rst index 8bc62b0eb9c4..f4f2606b710d 100644 --- a/doc/source/release/1.25.2-notes.rst +++ b/doc/source/release/1.25.2-notes.rst @@ -3,12 +3,54 @@ ========================== NumPy 1.25.2 Release Notes ========================== -NumPy 1.25.2 is a maintenance release that fixes bugs and regressions discovered after the -1.25.1 release. The Python versions supported by this release are 3.9-3.11. +NumPy 1.25.2 is a maintenance release that fixes bugs and regressions +discovered after the 1.25.1 release. This is the last planned release in the +1.25.x series, the next release will be 1.26.0, which will use the meson build +system and support Python 3.12. The Python versions supported by this release +are 3.9-3.11. Contributors ============ +A total of 13 people contributed to this release. People with a "+" by their +names contributed a patch for the first time. + +* Aaron Meurer +* Andrew Nelson +* Charles Harris +* Kevin Sheppard +* Matti Picus +* Nathan Goldbaum +* Peter Hawkins +* Ralf Gommers +* Randy Eckenrode + +* Sam James + +* Sebastian Berg +* Tyler Reddy +* dependabot[bot] + Pull requests merged ==================== +A total of 19 pull requests were merged for this release. + +* `#24148 `__: MAINT: prepare 1.25.x for further development +* `#24174 `__: ENH: Improve clang-cl compliance +* `#24179 `__: MAINT: Upgrade various build dependencies. +* `#24182 `__: BLD: use ``-ftrapping-math`` with Clang on macOS +* `#24183 `__: BUG: properly handle negative indexes in ufunc_at fast path +* `#24184 `__: BUG: PyObject_IsTrue and PyObject_Not error handling in setflags +* `#24185 `__: BUG: histogram small range robust +* `#24186 `__: MAINT: Update meson.build files from main branch +* `#24234 `__: MAINT: exclude min, max and round from ``np.__all__`` +* `#24241 `__: MAINT: Dependabot updates +* `#24242 `__: BUG: Fix the signature for np.array_api.take +* `#24243 `__: BLD: update OpenBLAS to an intermeidate commit +* `#24244 `__: BUG: Fix reference count leak in str(scalar). +* `#24245 `__: BUG: fix invalid function pointer conversion error +* `#24255 `__: BUG: Factor out slow ``getenv`` call used for memory policy warning +* `#24292 `__: CI: correct URL in cirrus.star [skip cirrus] +* `#24293 `__: BUG: Fix C types in scalartypes +* `#24294 `__: BUG: do not modify the input to ufunc_at +* `#24295 `__: BUG: Further fixes to indexing loop and added tests + diff --git a/numpy/core/setup.py b/numpy/core/setup.py index 571320ceb253..c6cdd4025966 100644 --- a/numpy/core/setup.py +++ b/numpy/core/setup.py @@ -83,8 +83,13 @@ def can_link_svml_fp16(): """SVML FP16 requires binutils >= 2.38 for an updated assembler """ if can_link_svml(): - binutils_ver = os.popen("ld -v").readlines()[0].strip()[-4:] - return float(binutils_ver) >= 2.38 + import re + binutils_ver = os.popen("ld -v").readlines()[0].strip() + binutils_ver = re.search(r"\d\.\d\d", binutils_ver) + if binutils_ver is not None: + return float(binutils_ver.group()) >= 2.38 + else: + return False def check_git_submodules(): out = os.popen("git submodule status")