From 33212f6e59c65fc5c5afc7b75baa823bd5a182ec Mon Sep 17 00:00:00 2001 From: Charles Harris Date: Sat, 16 Sep 2023 15:19:30 -0600 Subject: [PATCH 01/38] MAINT: prepare 1.26.x for further development --- doc/source/release.rst | 1 + doc/source/release/1.26.1-notes.rst | 8 ++++++++ pavement.py | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 doc/source/release/1.26.1-notes.rst diff --git a/doc/source/release.rst b/doc/source/release.rst index cef3a6d0510c..2c2947ee6685 100644 --- a/doc/source/release.rst +++ b/doc/source/release.rst @@ -5,6 +5,7 @@ Release notes .. toctree:: :maxdepth: 3 + 1.26.1 1.26.0 1.25.2 1.25.1 diff --git a/doc/source/release/1.26.1-notes.rst b/doc/source/release/1.26.1-notes.rst new file mode 100644 index 000000000000..9d415a463f84 --- /dev/null +++ b/doc/source/release/1.26.1-notes.rst @@ -0,0 +1,8 @@ +.. currentmodule:: numpy + +========================== +NumPy 1.26.1 Release Notes +========================== +NumPy 1.26.1 is a maintenance release that fixes bugs and regressions +discovered after the 1.26.0 release. This is the last planned release in the +The Python versions supported by this release are 3.9-3.12. diff --git a/pavement.py b/pavement.py index 585194f39647..70a5e7657dde 100644 --- a/pavement.py +++ b/pavement.py @@ -38,7 +38,7 @@ #----------------------------------- # Path to the release notes -RELEASE_NOTES = 'doc/source/release/1.26.0-notes.rst' +RELEASE_NOTES = 'doc/source/release/1.26.1-notes.rst' #------------------------------------------------------- From ad497730d9e37240184036bb64d8e87de299e2bd Mon Sep 17 00:00:00 2001 From: Charles Harris Date: Mon, 18 Sep 2023 13:23:49 -0600 Subject: [PATCH 02/38] MAINT: Update cibuildwheel-version - Update to cibuildwheel@2.16.0 in .github/workflows/wheels.yml - Unpin the pip installed version in tools/ci/cirrus_wheels.yml The unpinning allows cirrus_wheels to always use the latest. --- .github/workflows/wheels.yml | 2 +- tools/ci/cirrus_wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index d83bddafdcfc..329623ce6bf4 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -118,7 +118,7 @@ jobs: python-version: "3.x" - name: Build wheels - uses: pypa/cibuildwheel@39a63b5912f086dd459cf6fcb13dcdd3fe3bc24d # v2.15.0 + uses: pypa/cibuildwheel@a873dd9cbf9e3c4c73a1fd11ac31cf835f6eb502 # v2.16.0 env: CIBW_PRERELEASE_PYTHONS: True CIBW_BUILD: ${{ matrix.python }}-${{ matrix.buildplat[1] }} diff --git a/tools/ci/cirrus_wheels.yml b/tools/ci/cirrus_wheels.yml index 8cb566bc5a33..fc383d51e54d 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.15.0 + - python -m pip install cibuildwheel cibuildwheel_script: - cibuildwheel wheels_artifacts: From 7947ae56950ad49fea020e2f9a0fe634e45ddf4c Mon Sep 17 00:00:00 2001 From: Chongyun Lee <45286352+licy183@users.noreply.github.com> Date: Wed, 20 Sep 2023 03:03:21 +0800 Subject: [PATCH 03/38] MAINT: fix version string in wheels built with setup.py Since numpy 1.26.0, when building with setup.py, the building system generates a weird verion string 1.26.1.26.0. Commit a880c68752c47a63577e55689275b5fb9d6595a3 has a logical error when doing some code clean-up. This generates the abnormal version string 1.26.01.26.0, and then setuptools normalized this string as 1.26.1.26.0. --- numpy/distutils/core.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/numpy/distutils/core.py b/numpy/distutils/core.py index c4a14e59901f..1cdc739731bf 100644 --- a/numpy/distutils/core.py +++ b/numpy/distutils/core.py @@ -65,7 +65,8 @@ def _dict_append(d, **kws): elif isinstance(dv, dict): _dict_append(dv, **v) elif is_string(dv): - d[k] = dv + v + assert is_string(v) + d[k] = v else: raise TypeError(repr(type(dv))) From c534d134fe256e14acc468a21d5b4471bbda6284 Mon Sep 17 00:00:00 2001 From: Sayed Adel Date: Mon, 18 Sep 2023 10:12:35 +0400 Subject: [PATCH 04/38] BLD, BUG: Fix build failure for host flags e.g. `-march=native` on unsupported architectures --- meson_cpu/meson.build | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/meson_cpu/meson.build b/meson_cpu/meson.build index 97b33c461b95..ed2313bc6a62 100644 --- a/meson_cpu/meson.build +++ b/meson_cpu/meson.build @@ -98,7 +98,7 @@ if host_machine.endian() == 'little' and cpu_family == 'ppc64' min_features = [VSX2] endif -# Used by build option 'max' +# Used by build option 'max/native/detect' max_features_dict = { 'x86': X86_FEATURES, 'x86_64': X86_FEATURES, @@ -111,6 +111,11 @@ max_features = [] foreach fet_name, fet_obj : max_features_dict max_features += [fet_obj] endforeach +if max_features.length() == 0 + message('Disabling CPU feature detection due to unsupported architecture: "' + cpu_family + '"') + CPU_CONF_BASELINE = 'none' + CPU_CONF_DISPATCH = 'none' +endif parse_options = { 'cpu-baseline': CPU_CONF_BASELINE, From a17c6b9ed720a39d98c565e569ef8d1b2d4af96b Mon Sep 17 00:00:00 2001 From: munira-alduraibi Date: Wed, 13 Sep 2023 20:29:54 +0300 Subject: [PATCH 05/38] DOC: Updated the meson page to reflect the new meson defaults related to #24550 --- doc/source/f2py/buildtools/meson.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/doc/source/f2py/buildtools/meson.rst b/doc/source/f2py/buildtools/meson.rst index 23b454ee5857..e8bfe0ea8e41 100644 --- a/doc/source/f2py/buildtools/meson.rst +++ b/doc/source/f2py/buildtools/meson.rst @@ -110,9 +110,6 @@ Salient points It is worth keeping in mind the following: -* ``meson`` will default to passing ``-fimplicit-none`` under ``gfortran`` by - default, which differs from that of the standard ``np.distutils`` behaviour - * It is not possible to use SCREAMCASE in this context, so either the contents of the ``.f`` file or the generated wrapper ``.c`` needs to be lowered to regular letters; which can be facilitated by the ``--lower`` option of From 8f8a4a4a54d63ce7d9ed8aca024561e6820d8970 Mon Sep 17 00:00:00 2001 From: Sayed Adel Date: Fri, 22 Sep 2023 11:30:49 +0400 Subject: [PATCH 06/38] BUG: Fix SIMD f32 trunc test on s390x when baseline is none --- numpy/core/tests/test_simd_module.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/numpy/core/tests/test_simd_module.py b/numpy/core/tests/test_simd_module.py index 44dc58dac098..4fbaa9f3008b 100644 --- a/numpy/core/tests/test_simd_module.py +++ b/numpy/core/tests/test_simd_module.py @@ -86,6 +86,8 @@ def test_signed_overflow(self, sfx): assert lanes == [0] * nlanes def test_truncate_f32(self): + if not npyv.simd_f32: + pytest.skip("F32 isn't support by the SIMD extension") f32 = npyv.setall_f32(0.1)[0] assert f32 != 0.1 assert round(f32, 1) == 0.1 From e6a9786323b5d05ddff2f6c0d675153985369e16 Mon Sep 17 00:00:00 2001 From: Matti Picus Date: Thu, 21 Sep 2023 14:07:17 +0300 Subject: [PATCH 07/38] BLD: add libquadmath to licences and other tweaks (#24753) Other improvements: - use SPDX short specifiers, fixes from review - only use `openblas_support.make_init()` in CI, fix paths - fix license concatenation for wheels we distribute Closes gh-24764 --- .../{windows_meson.yml => windows.yml} | 30 +++-- .github/workflows/windows_clangcl.yml | 82 ------------ azure-steps-windows.yml | 6 +- tools/ci/cirrus_wheels.yml | 2 +- tools/openblas_support.py | 12 +- tools/wheels/LICENSE_linux.txt | 40 ++++-- tools/wheels/LICENSE_osx.txt | 118 +++++++++++++++++- tools/wheels/LICENSE_win32.txt | 102 +++++---------- tools/wheels/cibw_before_build.sh | 2 +- 9 files changed, 213 insertions(+), 181 deletions(-) rename .github/workflows/{windows_meson.yml => windows.yml} (80%) delete mode 100644 .github/workflows/windows_clangcl.yml diff --git a/.github/workflows/windows_meson.yml b/.github/workflows/windows.yml similarity index 80% rename from .github/workflows/windows_meson.yml rename to .github/workflows/windows.yml index 851284a20fb0..fbde86092b92 100644 --- a/.github/workflows/windows_meson.yml +++ b/.github/workflows/windows.yml @@ -1,4 +1,4 @@ -name: Test Meson build (Windows) +name: Windows tests on: pull_request: @@ -6,9 +6,6 @@ on: - main - maintenance/** -env: - PYTHON_VERSION: 3.11 - concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true @@ -17,10 +14,13 @@ permissions: contents: read # to fetch code (actions/checkout) jobs: - msvc_64bit_python_openblas: - name: MSVC, x86-64, LP64 OpenBLAS + python64bit_openblas: + name: x86-64, LP64 OpenBLAS runs-on: windows-2019 if: "github.repository == 'numpy/numpy'" + strategy: + matrix: + compiler: ["MSVC", "Clang-cl"] steps: - name: Checkout uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 @@ -31,7 +31,7 @@ jobs: - name: Setup Python uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: - python-version: ${{ env.PYTHON_VERSION }} + python-version: '3.11' - name: Install build dependencies from PyPI run: | @@ -48,16 +48,28 @@ jobs: 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: Install NumPy + - name: Install Clang-cl + if: matrix.compiler == 'Clang-cl' + run: | + choco install llvm -y --version=16.0.6 + + - name: Install NumPy (MSVC) + if: matrix.compiler == 'MSVC' run: | spin build -j2 -- --vsenv + - name: Install NumPy (Clang-cl) + if: matrix.compiler == 'Clang-cl' + 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 + spin build -j2 -- --vsenv --native-file=$PWD/clang-cl-build.ini + - name: Copy OpenBLAS DLL, write _distributor_init.py run: | # Getting the OpenBLAS DLL to the right place so it loads $installed_path = "$PWD\build-install\usr\Lib\site-packages" $numpy_path = "${installed_path}\numpy" - $libs_path = "${numpy_path}\.libs" + $libs_path = "${installed_path}\numpy.libs" mkdir ${libs_path} $ob_path = "C:/opt/64/bin/" cp $ob_path/*.dll $libs_path diff --git a/.github/workflows/windows_clangcl.yml b/.github/workflows/windows_clangcl.yml deleted file mode 100644 index 3f3201df587b..000000000000 --- a/.github/workflows/windows_clangcl.yml +++ /dev/null @@ -1,82 +0,0 @@ -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@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 - with: - submodules: recursive - fetch-depth: 0 - - name: Setup Python - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 - with: - python-version: ${{ env.PYTHON_VERSION }} - - - name: Install build dependencies from PyPI - run: | - pip install spin Cython - - - name: Install OpenBLAS and Clang-cl - 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: Write native file for Clang-cl binaries - run: | - # TODO: this job is identical to the one in `windows_meson.yml` aside - # from installing Clang-cl and usage of this .ini file. So merge the - # two and use a matrix'ed CI job 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 - - - name: Install NumPy - run: | - spin build -j2 -- --vsenv --native-file=$PWD/clang-cl-build.ini - - - name: Copy OpenBLAS DLL, write _distributor_init.py - run: | - # Getting the OpenBLAS DLL to the right place so it loads - $installed_path = "$PWD\build-install\usr\Lib\site-packages" - $numpy_path = "${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: Install test dependencies - run: | - python -m pip install -r test_requirements.txt - python -m pip install threadpoolctl - - - name: Run test suite - run: | - spin test diff --git a/azure-steps-windows.yml b/azure-steps-windows.yml index e09663cd7fbc..3fa6b18dc108 100644 --- a/azure-steps-windows.yml +++ b/azure-steps-windows.yml @@ -49,11 +49,11 @@ steps: displayName: 'Build NumPy' - powershell: | - # copy from c:/opt/openblas/openblas_dll to numpy/.libs to ensure it can + # copy from c:/opt/openblas/openblas_dll to numpy/../numpy.libs to ensure it can # get loaded when numpy is imported (no RPATH on Windows) $target = $(python -c "import sysconfig; print(sysconfig.get_path('platlib'))") - mkdir $target/numpy/.libs - copy C:/opt/openblas/openblas_dll/*.dll $target/numpy/.libs + mkdir $target/numpy.libs + copy C:/opt/openblas/openblas_dll/*.dll $target/numpy.libs displayName: 'Copy OpenBLAS DLL to site-packages' - script: | diff --git a/tools/ci/cirrus_wheels.yml b/tools/ci/cirrus_wheels.yml index fc383d51e54d..9feef6025f78 100644 --- a/tools/ci/cirrus_wheels.yml +++ b/tools/ci/cirrus_wheels.yml @@ -41,7 +41,7 @@ linux_aarch64_task: apt update apt install -y python3-venv python-is-python3 gfortran libatlas-base-dev libgfortran5 eatmydata git fetch origin - ./tools/travis-before-install.sh + bash ./tools/wheels/cibw_before_build.sh ${PWD} which python echo $CIRRUS_CHANGE_MESSAGE <<: *BUILD_AND_STORE_WHEELS diff --git a/tools/openblas_support.py b/tools/openblas_support.py index 5fe0d662cdcd..170c1948d3be 100644 --- a/tools/openblas_support.py +++ b/tools/openblas_support.py @@ -238,6 +238,9 @@ def get_members(): def make_init(dirname): ''' Create a _distributor_init.py file for OpenBlas + + Obsoleted by the use of delvewheel in wheel building, which + adds an equivalent snippet to numpy/__init__.py, but still useful in CI ''' with open(os.path.join(dirname, '_distributor_init.py'), 'w') as fid: fid.write(textwrap.dedent(""" @@ -246,19 +249,20 @@ def make_init(dirname): Once a DLL is preloaded, its namespace is made available to any subsequent DLL. This file originated in the numpy-wheels repo, and is created as part of the scripts that build the wheel. + ''' import os import glob if os.name == 'nt': - # convention for storing / loading the DLL from - # numpy/.libs/, if present + # load any DLL from numpy/../numpy.libs/, if present try: from ctypes import WinDLL - basedir = os.path.dirname(__file__) except: pass else: - libs_dir = os.path.abspath(os.path.join(basedir, '.libs')) + basedir = os.path.dirname(__file__) + libs_dir = os.path.join(basedir, os.pardir, 'numpy.libs') + libs_dir = os.path.abspath(libs_dir) DLL_filenames = [] if os.path.isdir(libs_dir): for filename in glob.glob(os.path.join(libs_dir, diff --git a/tools/wheels/LICENSE_linux.txt b/tools/wheels/LICENSE_linux.txt index 9ea808afce50..97596fe61f28 100644 --- a/tools/wheels/LICENSE_linux.txt +++ b/tools/wheels/LICENSE_linux.txt @@ -5,10 +5,10 @@ This binary distribution of NumPy also bundles the following software: Name: OpenBLAS -Files: .libs/libopenb*.so +Files: numpy.libs/libopenblas*.so Description: bundled as a dynamically linked library -Availability: https://github.com/xianyi/OpenBLAS/ -License: 3-clause BSD +Availability: https://github.com/OpenMathLib/OpenBLAS/ +License: BSD-3-Clause-Attribution Copyright (c) 2011-2014, The OpenBLAS Project All rights reserved. @@ -41,10 +41,10 @@ License: 3-clause BSD Name: LAPACK -Files: .libs/libopenb*.so +Files: numpy.libs/libopenblas*.so Description: bundled in OpenBLAS -Availability: https://github.com/xianyi/OpenBLAS/ -License 3-clause BSD +Availability: https://github.com/OpenMathLib/OpenBLAS/ +License: BSD-3-Clause-Attribution Copyright (c) 1992-2013 The University of Tennessee and The University of Tennessee Research Foundation. All rights reserved. @@ -96,10 +96,10 @@ License 3-clause BSD Name: GCC runtime library -Files: .libs/libgfortran*.so +Files: numpy.libs/libgfortran*.so Description: dynamically linked to files compiled with gcc -Availability: https://gcc.gnu.org/viewcvs/gcc/ -License: GPLv3 + runtime exception +Availability: https://gcc.gnu.org/git/?p=gcc.git;a=tree;f=libgfortran +License: GPL-3.0-with-GCC-exception Copyright (C) 2002-2017 Free Software Foundation, Inc. Libgfortran is free software; you can redistribute it and/or modify @@ -878,3 +878,25 @@ may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . + +Name: libquadmath +Files: numpy.libs/libquadmath*.so +Description: dynamically linked to files compiled with gcc +Availability: https://gcc.gnu.org/git/?p=gcc.git;a=tree;f=libquadmath +License: LGPL-2.1-or-later + + GCC Quad-Precision Math Library + Copyright (C) 2010-2019 Free Software Foundation, Inc. + Written by Francois-Xavier Coudert + + This file is part of the libquadmath library. + Libquadmath is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + Libquadmath is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html diff --git a/tools/wheels/LICENSE_osx.txt b/tools/wheels/LICENSE_osx.txt index 9a687c3b6b05..dd221a34d49f 100644 --- a/tools/wheels/LICENSE_osx.txt +++ b/tools/wheels/LICENSE_osx.txt @@ -3,12 +3,102 @@ This binary distribution of NumPy also bundles the following software: +Name: OpenBLAS +Files: numpy/.dylibs/libopenblas*.so +Description: bundled as a dynamically linked library +Availability: https://github.com/OpenMathLib/OpenBLAS/ +License: BSD-3-Clause-Attribution + Copyright (c) 2011-2014, The OpenBLAS Project + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. Neither the name of the OpenBLAS project nor the names of + its contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Name: LAPACK +Files: numpy/.dylibs/libopenblas*.so +Description: bundled in OpenBLAS +Availability: https://github.com/OpenMathLib/OpenBLAS/ +License: BSD-3-Clause-Attribution + Copyright (c) 1992-2013 The University of Tennessee and The University + of Tennessee Research Foundation. All rights + reserved. + Copyright (c) 2000-2013 The University of California Berkeley. All + rights reserved. + Copyright (c) 2006-2013 The University of Colorado Denver. All rights + reserved. + + $COPYRIGHT$ + + Additional copyrights may follow + + $HEADER$ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer listed + in this license in the documentation and/or other materials + provided with the distribution. + + - Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + The copyright holders provide no reassurances that the source code + provided does not infringe any patent, copyright, or any other + intellectual property rights of third parties. The copyright holders + disclaim any liability to any recipient for claims brought against + recipient by any third party for infringement of that parties + intellectual property rights. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + Name: GCC runtime library -Files: .dylibs/* +Files: numpy/.dylibs/libgfortran*, numpy/.dylibs/libgcc* Description: dynamically linked to files compiled with gcc -Availability: https://gcc.gnu.org/viewcvs/gcc/ -License: GPLv3 + runtime exception +Availability: https://gcc.gnu.org/git/?p=gcc.git;a=tree;f=libgfortran +License: GPL-3.0-with-GCC-exception Copyright (C) 2002-2017 Free Software Foundation, Inc. Libgfortran is free software; you can redistribute it and/or modify @@ -787,3 +877,25 @@ may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . + +Name: libquadmath +Files: numpy/.dylibs/libquadmath*.so +Description: dynamically linked to files compiled with gcc +Availability: https://gcc.gnu.org/git/?p=gcc.git;a=tree;f=libquadmath +License: LGPL-2.1-or-later + + GCC Quad-Precision Math Library + Copyright (C) 2010-2019 Free Software Foundation, Inc. + Written by Francois-Xavier Coudert + + This file is part of the libquadmath library. + Libquadmath is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + Libquadmath is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html diff --git a/tools/wheels/LICENSE_win32.txt b/tools/wheels/LICENSE_win32.txt index 1014d77cd3ed..dd368ad49f30 100644 --- a/tools/wheels/LICENSE_win32.txt +++ b/tools/wheels/LICENSE_win32.txt @@ -5,10 +5,10 @@ This binary distribution of NumPy also bundles the following software: Name: OpenBLAS -Files: extra-dll\libopenb*.dll +Files: numpy\.libs\libopenblas*.dll Description: bundled as a dynamically linked library -Availability: https://github.com/xianyi/OpenBLAS/ -License: 3-clause BSD +Availability: https://github.com/OpenMathLib/OpenBLAS/ +License: BSD-3-Clause-Attribution Copyright (c) 2011-2014, The OpenBLAS Project All rights reserved. @@ -41,10 +41,10 @@ License: 3-clause BSD Name: LAPACK -Files: extra-dll\libopenb*.dll +Files: numpy\.libs\libopenblas*.dll Description: bundled in OpenBLAS -Availability: https://github.com/xianyi/OpenBLAS/ -License 3-clause BSD +Availability: https://github.com/OpenMathLib/OpenBLAS/ +License: BSD-3-Clause-Attribution Copyright (c) 1992-2013 The University of Tennessee and The University of Tennessee Research Foundation. All rights reserved. @@ -96,10 +96,10 @@ License 3-clause BSD Name: GCC runtime library -Files: extra-dll\*.dll -Description: statically linked, in DLL files compiled with gfortran only -Availability: https://gcc.gnu.org/viewcvs/gcc/ -License: GPLv3 + runtime exception +Files: numpy\.libs\libopenblas*.dll +Description: statically linked to files compiled with gcc +Availability: https://gcc.gnu.org/git/?p=gcc.git;a=tree;f=libgfortran +License: GPL-3.0-with-GCC-exception Copyright (C) 2002-2017 Free Software Foundation, Inc. Libgfortran is free software; you can redistribute it and/or modify @@ -121,64 +121,6 @@ License: GPLv3 + runtime exception see the files COPYING3 and COPYING.RUNTIME respectively. If not, see . - -Name: Microsoft Visual C++ Runtime Files -Files: extra-dll\msvcp140.dll -License: MSVC - https://www.visualstudio.com/license-terms/distributable-code-microsoft-visual-studio-2015-rc-microsoft-visual-studio-2015-sdk-rc-includes-utilities-buildserver-files/#visual-c-runtime - - Subject to the License Terms for the software, you may copy and - distribute with your program any of the files within the followng - folder and its subfolders except as noted below. You may not modify - these files. - - C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist - - You may not distribute the contents of the following folders: - - C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\debug_nonredist - C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\onecore\debug_nonredist - - Subject to the License Terms for the software, you may copy and - distribute the following files with your program in your program’s - application local folder or by deploying them into the Global - Assembly Cache (GAC): - - VC\atlmfc\lib\mfcmifc80.dll - VC\atlmfc\lib\amd64\mfcmifc80.dll - - -Name: Microsoft Visual C++ Runtime Files -Files: extra-dll\msvc*90.dll, extra-dll\Microsoft.VC90.CRT.manifest -License: MSVC - For your convenience, we have provided the following folders for - use when redistributing VC++ runtime files. Subject to the license - terms for the software, you may redistribute the folder - (unmodified) in the application local folder as a sub-folder with - no change to the folder name. You may also redistribute all the - files (*.dll and *.manifest) within a folder, listed below the - folder for your convenience, as an entire set. - - \VC\redist\x86\Microsoft.VC90.ATL\ - atl90.dll - Microsoft.VC90.ATL.manifest - \VC\redist\ia64\Microsoft.VC90.ATL\ - atl90.dll - Microsoft.VC90.ATL.manifest - \VC\redist\amd64\Microsoft.VC90.ATL\ - atl90.dll - Microsoft.VC90.ATL.manifest - \VC\redist\x86\Microsoft.VC90.CRT\ - msvcm90.dll - msvcp90.dll - msvcr90.dll - Microsoft.VC90.CRT.manifest - \VC\redist\ia64\Microsoft.VC90.CRT\ - msvcm90.dll - msvcp90.dll - msvcr90.dll - Microsoft.VC90.CRT.manifest - ---- Full text of license texts referred to above follows (that they are @@ -935,4 +877,26 @@ into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read -. \ No newline at end of file +. + +Name: libquadmath +Files: numpy\.libs\libopenb*.dll +Description: statically linked to files compiled with gcc +Availability: https://gcc.gnu.org/git/?p=gcc.git;a=tree;f=libquadmath +License: LGPL-2.1-or-later + + GCC Quad-Precision Math Library + Copyright (C) 2010-2019 Free Software Foundation, Inc. + Written by Francois-Xavier Coudert + + This file is part of the libquadmath library. + Libquadmath is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + Libquadmath is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html diff --git a/tools/wheels/cibw_before_build.sh b/tools/wheels/cibw_before_build.sh index 372b25af09b8..23471a43285e 100644 --- a/tools/wheels/cibw_before_build.sh +++ b/tools/wheels/cibw_before_build.sh @@ -4,6 +4,7 @@ PROJECT_DIR="$1" PLATFORM=$(PYTHONPATH=tools python -c "import openblas_support; print(openblas_support.get_plat())") # Update license +cat $PROJECT_DIR/LICENSES_bundled.txt >> $PROJECT_DIR/LICENSE.txt if [[ $RUNNER_OS == "Linux" ]] ; then cat $PROJECT_DIR/tools/wheels/LICENSE_linux.txt >> $PROJECT_DIR/LICENSE.txt elif [[ $RUNNER_OS == "macOS" ]]; then @@ -36,7 +37,6 @@ elif [[ $RUNNER_OS == "Windows" ]]; then # this location you need to alter that script. mkdir -p /c/opt/openblas/openblas_dll - PYTHONPATH=tools python -c "import openblas_support; openblas_support.make_init('numpy')" mkdir -p /c/opt/32/lib/pkgconfig mkdir -p /c/opt/64/lib/pkgconfig target=$(python -c "import tools.openblas_support as obs; plat=obs.get_plat(); ilp64=obs.get_ilp64(); target=f'openblas_{plat}.zip'; obs.download_openblas(target, plat, ilp64);print(target)") From bcf318be8256fbe63bda050941b3b9fe6e9fe17c Mon Sep 17 00:00:00 2001 From: Charles Harris Date: Sat, 23 Sep 2023 20:08:20 -0600 Subject: [PATCH 08/38] MAINT: Activate ``use-compute-credits`` for Cirrus. This pays for testing/wheel builds using Cirrus when the free credits run out. [skip azp] [skip actions] --- tools/ci/cirrus_arm.yml | 2 ++ tools/ci/cirrus_wheels.yml | 3 +++ 2 files changed, 5 insertions(+) diff --git a/tools/ci/cirrus_arm.yml b/tools/ci/cirrus_arm.yml index e4e127d2af4e..c3daf953d751 100644 --- a/tools/ci/cirrus_arm.yml +++ b/tools/ci/cirrus_arm.yml @@ -22,6 +22,7 @@ modified_clone: &MODIFIED_CLONE linux_aarch64_test_task: + use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' compute_engine_instance: image_project: cirrus-images image: family/docker-builder-arm64 @@ -66,6 +67,7 @@ linux_aarch64_test_task: macos_arm64_test_task: + use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' depends_on: - linux_aarch64_test macos_instance: diff --git a/tools/ci/cirrus_wheels.yml b/tools/ci/cirrus_wheels.yml index 9feef6025f78..ea290a8b23c8 100644 --- a/tools/ci/cirrus_wheels.yml +++ b/tools/ci/cirrus_wheels.yml @@ -11,6 +11,7 @@ build_and_store_wheels: &BUILD_AND_STORE_WHEELS ###################################################################### linux_aarch64_task: + use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' compute_engine_instance: image_project: cirrus-images image: family/docker-builder-arm64 @@ -52,6 +53,7 @@ linux_aarch64_task: ###################################################################### macosx_arm64_task: + use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' macos_instance: image: ghcr.io/cirruslabs/macos-monterey-xcode:14 matrix: @@ -101,6 +103,7 @@ macosx_arm64_task: ###################################################################### wheels_upload_task: + use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' # Artifacts don't seem to be persistent from task to task. # Rather than upload wheels at the end of each cibuildwheel run we do a # final upload here. This is because a run may be on different OS for From 4fa5fddc4c5480e1a09778323aaafbb8346667fc Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Mon, 25 Sep 2023 22:48:30 +0200 Subject: [PATCH 09/38] BLD: updated vendored-meson/meson for mips64 fix See https://github.com/numpy/meson/pull/1 for details --- vendored-meson/meson | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendored-meson/meson b/vendored-meson/meson index 82d41db3d4b5..b7dc7abc4102 160000 --- a/vendored-meson/meson +++ b/vendored-meson/meson @@ -1 +1 @@ -Subproject commit 82d41db3d4b51124c5f138078c079b8eb62ecdeb +Subproject commit b7dc7abc4102ec3db4bb9066cb5e674e7a4b08f4 From dab0e4b31783870a0325f9a3173a47cb6b83a648 Mon Sep 17 00:00:00 2001 From: Andrew Nelson Date: Mon, 25 Sep 2023 20:41:45 +1000 Subject: [PATCH 10/38] MAINT: fix licence path win --- tools/wheels/LICENSE_win32.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/wheels/LICENSE_win32.txt b/tools/wheels/LICENSE_win32.txt index dd368ad49f30..ef954a6ea781 100644 --- a/tools/wheels/LICENSE_win32.txt +++ b/tools/wheels/LICENSE_win32.txt @@ -5,7 +5,7 @@ This binary distribution of NumPy also bundles the following software: Name: OpenBLAS -Files: numpy\.libs\libopenblas*.dll +Files: numpy.libs\libopenblas*.dll Description: bundled as a dynamically linked library Availability: https://github.com/OpenMathLib/OpenBLAS/ License: BSD-3-Clause-Attribution @@ -41,7 +41,7 @@ License: BSD-3-Clause-Attribution Name: LAPACK -Files: numpy\.libs\libopenblas*.dll +Files: numpy.libs\libopenblas*.dll Description: bundled in OpenBLAS Availability: https://github.com/OpenMathLib/OpenBLAS/ License: BSD-3-Clause-Attribution @@ -96,7 +96,7 @@ License: BSD-3-Clause-Attribution Name: GCC runtime library -Files: numpy\.libs\libopenblas*.dll +Files: numpy.libs\libopenblas*.dll Description: statically linked to files compiled with gcc Availability: https://gcc.gnu.org/git/?p=gcc.git;a=tree;f=libgfortran License: GPL-3.0-with-GCC-exception @@ -880,7 +880,7 @@ Public License instead of this License. But first, please read . Name: libquadmath -Files: numpy\.libs\libopenb*.dll +Files: numpy.libs\libopenb*.dll Description: statically linked to files compiled with gcc Availability: https://gcc.gnu.org/git/?p=gcc.git;a=tree;f=libquadmath License: LGPL-2.1-or-later From 0a171690e3990792d99406fe3ce376417f5af0b8 Mon Sep 17 00:00:00 2001 From: Mahder Gebremedhin Date: Sat, 23 Sep 2023 23:36:37 +0200 Subject: [PATCH 11/38] BUG: Fix order of Windows OS detection macros. (#24762) * BUG: Fix order of Windows OS detection macros. - The order should be `__MINGW32__/__MINGW64__`, then `_WIN64`, and then `_WIN32`. 64 bit MinGW compilers define `_MINGW32__`, `__MINGW64__`, `_WIN32`, and `_WIN64`. 32 bit MinGW compilers define `__MINGW32__`, and `_WIN32`. 64 bit MSVC compilation defines `_WIN32` and `_WIN64`. 32 bit MSVC compilation defines `_WIN32`. - Fixes #24761. * Adjust the structure slightly and add comments. - This is better than just relying on the order of evaluation in the whole chain. Once Windows is detected (`_WIN32`), handle the possible known Windows environments separately. * Remove check for non-standard macros. - `WIN32`, `__WIN32__`, `WIN64`, `__WIN64__` are not standard macros defined by Window compilers. It should be enough to check for `_WIN32` and `_WIN64` alone. --- numpy/core/include/numpy/npy_os.h | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/numpy/core/include/numpy/npy_os.h b/numpy/core/include/numpy/npy_os.h index 6d8317d0667c..0ce5d78b42c0 100644 --- a/numpy/core/include/numpy/npy_os.h +++ b/numpy/core/include/numpy/npy_os.h @@ -19,12 +19,18 @@ #define NPY_OS_SOLARIS #elif defined(__CYGWIN__) #define NPY_OS_CYGWIN -#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) - #define NPY_OS_WIN32 -#elif defined(_WIN64) || defined(__WIN64__) || defined(WIN64) - #define NPY_OS_WIN64 -#elif defined(__MINGW32__) || defined(__MINGW64__) +/* We are on Windows.*/ +#elif defined(_WIN32) + /* We are using MinGW (64-bit or 32-bit)*/ + #if defined(__MINGW32__) || defined(__MINGW64__) #define NPY_OS_MINGW + /* Otherwise, if _WIN64 is defined, we are targeting 64-bit Windows*/ + #elif defined(_WIN64) + #define NPY_OS_WIN64 + /* Otherwise assume we are targeting 32-bit Windows*/ + #else + #define NPY_OS_WIN32 + #endif #elif defined(__APPLE__) #define NPY_OS_DARWIN #elif defined(__HAIKU__) From 6f0534bc053fef70f7096968465e59e65cfeb787 Mon Sep 17 00:00:00 2001 From: Jake Lishman Date: Thu, 28 Sep 2023 20:42:29 +0100 Subject: [PATCH 12/38] BUG, SIMD: use scalar cmul on bad Apple clang x86_64 (#24828) * BUG, SIMD: use scalar cmul on bad Apple clang x86_64 Apple clang 14.0.0 outputs code with non-deterministic behaviour for the AVX2-accelerated `multiply` ufunc on `complex64` and `complex128` for x86_64 on macOS with AVX2 enabled. This bug is fixed by Apple clang 14.0.3, but 14.0.0 is still commonly the available toolchain on CI images. In order to not output unsound code, this simply skips the SIMD version of the ufunc when using an affected compiler. * MAINT: Formatting cleanup. --------- Co-authored-by: Charles Harris --- numpy/core/src/umath/loops_arithm_fp.dispatch.c.src | 10 ++++++++++ 1 file changed, 10 insertions(+) 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 c8bcedb6bbdc..30111258d646 100644 --- a/numpy/core/src/umath/loops_arithm_fp.dispatch.c.src +++ b/numpy/core/src/umath/loops_arithm_fp.dispatch.c.src @@ -367,6 +367,16 @@ NPY_NO_EXPORT void NPY_CPU_DISPATCH_CURFX(@TYPE@_@kind@) } #endif #if @VECTOR@ + // Certain versions of Apple clang (commonly used in CI images) produce + // non-deterministic output in the mul path with AVX2 enabled on x86_64. + // Work around by scalarising. + #if @is_mul@ \ + && defined(NPY_CPU_AMD64) && defined(__clang__) \ + && defined(__apple_build_version__) \ + && __apple_build_version__ >= 14000000 \ + && __apple_build_version__ < 14030000 + goto loop_scalar; + #endif // end affected Apple clang. if (is_mem_overlap(b_src0, b_ssrc0, b_dst, b_sdst, len) || is_mem_overlap(b_src1, b_ssrc1, b_dst, b_sdst, len) || b_sdst % sizeof(@ftype@) != 0 || b_sdst == 0 || From 56c68f275975f6410a4c060b2026acae918f54d6 Mon Sep 17 00:00:00 2001 From: Rohit Goswami Date: Thu, 21 Sep 2023 11:57:40 +0000 Subject: [PATCH 13/38] TMP: Hide in a try except --- numpy/f2py/crackfortran.py | 59 +++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/numpy/f2py/crackfortran.py b/numpy/f2py/crackfortran.py index cc041ec56e6e..ba1f89ff53d6 100755 --- a/numpy/f2py/crackfortran.py +++ b/numpy/f2py/crackfortran.py @@ -1449,26 +1449,51 @@ def analyzeline(m, case, line): # wrapping. continue fc = 0 - vtype = vars[v].get('typespec') - vdim = getdimension(vars[v]) + try: + vtype = vars[v].get('typespec') # can fail + vdim = getdimension(vars[v]) - if (vtype == 'complex'): - cmplxpat = r"\(.*?\)" - matches = re.findall(cmplxpat, l[1]) - else: - matches = l[1].split(',') + if (vtype == 'complex'): + cmplxpat = r"\(.*?\)" + matches = re.findall(cmplxpat, l[1]) + else: + matches = l[1].split(',') - if v not in vars: - vars[v] = {} - if '=' in vars[v] and not vars[v]['='] == matches[idx]: - outmess('analyzeline: changing init expression of "%s" ("%s") to "%s"\n' % ( - v, vars[v]['='], matches[idx])) + if v not in vars: + vars[v] = {} + if '=' in vars[v] and not vars[v]['='] == matches[idx]: + outmess('analyzeline: changing init expression of "%s" ("%s") to "%s"\n' % ( + v, vars[v]['='], matches[idx])) - if vdim is not None: - # Need to assign multiple values to one variable - vars[v]['='] = "(/{}/)".format(", ".join(matches)) - else: - vars[v]['='] = matches[idx] + if vdim is not None: + # Need to assign multiple values to one variable + vars[v]['='] = "(/{}/)".format(", ".join(matches)) + else: + vars[v]['='] = matches[idx] + except: + i = 0 + j = 0 + for v in rmbadname([x.strip() for x in markoutercomma(l[0]).split('@,@')]): + if v[0] == '(': + outmess( + 'analyzeline: implied-DO list "%s" is not supported. Skipping.\n' % v) + # XXX: subsequent init expressions may get wrong values. + # Ignoring since data statements are irrelevant for + # wrapping. + continue + fc = 0 + while (i < llen) and (fc or not l[1][i] == ','): + if l[1][i] == "'": + fc = not fc + i = i + 1 + i = i + 1 + if v not in vars: + vars[v] = {} + if '=' in vars[v] and not vars[v]['='] == l[1][j:i - 1]: + outmess('analyzeline: changing init expression of "%s" ("%s") to "%s"\n' % ( + v, vars[v]['='], l[1][j:i - 1])) + vars[v]['='] = l[1][j:i - 1] + j = i last_name = v groupcache[groupcounter]['vars'] = vars if last_name is not None: From e3f82136ecd0a0b29677f00e12086ae80e5c80b3 Mon Sep 17 00:00:00 2001 From: Rohit Goswami Date: Fri, 22 Sep 2023 15:34:18 +0000 Subject: [PATCH 14/38] TST: Add examples for gh-24746 --- numpy/f2py/tests/src/crackfortran/data_common.f | 8 ++++++++ numpy/f2py/tests/src/crackfortran/data_stmts.f90 | 2 ++ numpy/f2py/tests/test_data.py | 14 ++++++++++++++ 3 files changed, 24 insertions(+) create mode 100644 numpy/f2py/tests/src/crackfortran/data_common.f diff --git a/numpy/f2py/tests/src/crackfortran/data_common.f b/numpy/f2py/tests/src/crackfortran/data_common.f new file mode 100644 index 000000000000..5ffd865c8379 --- /dev/null +++ b/numpy/f2py/tests/src/crackfortran/data_common.f @@ -0,0 +1,8 @@ + BLOCK DATA PARAM_INI + COMMON /MYCOM/ MYDATA + DATA MYDATA /0/ + END + SUBROUTINE SUB1 + COMMON /MYCOM/ MYDATA + MYDATA = MYDATA + 1 + END diff --git a/numpy/f2py/tests/src/crackfortran/data_stmts.f90 b/numpy/f2py/tests/src/crackfortran/data_stmts.f90 index 0eb97a563899..576c5e485baf 100644 --- a/numpy/f2py/tests/src/crackfortran/data_stmts.f90 +++ b/numpy/f2py/tests/src/crackfortran/data_stmts.f90 @@ -4,6 +4,7 @@ module cmplxdat integer :: i, j real :: x, y real, dimension(2) :: z + real(kind=8) :: pi complex(kind=8), target :: medium_ref_index complex(kind=8), target :: ref_index_one, ref_index_two complex(kind=8), dimension(2) :: my_array @@ -15,4 +16,5 @@ module cmplxdat data medium_ref_index / (1.d0, 0.d0) / data ref_index_one, ref_index_two / (13.0d0, 21.0d0), (-30.0d0, 43.0d0) / data my_array / (1.0d0, 2.0d0), (-3.0d0, 4.0d0) / + data pi / 3.1415926535897932384626433832795028841971693993751058209749445923078164062d0 / end module cmplxdat diff --git a/numpy/f2py/tests/test_data.py b/numpy/f2py/tests/test_data.py index 3b8ca544ec74..497d8f975edc 100644 --- a/numpy/f2py/tests/test_data.py +++ b/numpy/f2py/tests/test_data.py @@ -15,6 +15,7 @@ def test_data_stmts(self): assert self.module.cmplxdat.j == 3 assert self.module.cmplxdat.x == 1.5 assert self.module.cmplxdat.y == 2.0 + assert self.module.cmplxdat.pi == 3.1415926535897932384626433832795028841971693993751058209749445923078164062 assert self.module.cmplxdat.medium_ref_index == np.array(1.+0.j) assert np.all(self.module.cmplxdat.z == np.array([3.5, 7.0])) assert np.all(self.module.cmplxdat.my_array == np.array([ 1.+2.j, -3.+4.j])) @@ -26,8 +27,21 @@ def test_crackedlines(self): mod = crackfortran(self.sources) assert mod[0]['vars']['x']['='] == '1.5' assert mod[0]['vars']['y']['='] == '2.0' + assert mod[0]['vars']['pi']['='] == '3.1415926535897932384626433832795028841971693993751058209749445923078164062d0' assert mod[0]['vars']['my_real_array']['='] == '(/1.0d0, 2.0d0, 3.0d0/)' assert mod[0]['vars']['ref_index_one']['='] == '(13.0d0, 21.0d0)' assert mod[0]['vars']['ref_index_two']['='] == '(-30.0d0, 43.0d0)' assert mod[0]['vars']['my_array']['='] == '(/(1.0d0, 2.0d0), (-3.0d0, 4.0d0)/)' assert mod[0]['vars']['z']['='] == '(/3.5, 7.0/)' + +class TestDataF77(util.F2PyTest): + sources = [util.getpath("tests", "src", "crackfortran", "data_common.f")] + + # For gh-23276 + def test_data_stmts(self): + assert self.module.mycom.mydata == 0 + + def test_crackedlines(self): + mod = crackfortran(str(self.sources[0])) + print(mod[0]['vars']) + assert mod[0]['vars']['mydata']['='] == '0' From 8415cf09c54abbb35ea83060cbe30359532d20b8 Mon Sep 17 00:00:00 2001 From: Rohit Goswami Date: Fri, 22 Sep 2023 16:01:34 +0000 Subject: [PATCH 15/38] BUG,MAINT: Fallback to old behavior on F77 --- numpy/f2py/crackfortran.py | 59 +++++++++++--------------------------- 1 file changed, 16 insertions(+), 43 deletions(-) diff --git a/numpy/f2py/crackfortran.py b/numpy/f2py/crackfortran.py index ba1f89ff53d6..d2bc7e972384 100755 --- a/numpy/f2py/crackfortran.py +++ b/numpy/f2py/crackfortran.py @@ -1425,9 +1425,7 @@ def analyzeline(m, case, line): if dl.startswith(','): dl = dl[1:].strip() ll.append([dl, il]) - vars = {} - if 'vars' in groupcache[groupcounter]: - vars = groupcache[groupcounter]['vars'] + vars = groupcache[groupcounter].get('vars', {}) last_name = None for l in ll: l = [x.strip() for x in l] @@ -1452,48 +1450,23 @@ def analyzeline(m, case, line): try: vtype = vars[v].get('typespec') # can fail vdim = getdimension(vars[v]) - - if (vtype == 'complex'): - cmplxpat = r"\(.*?\)" - matches = re.findall(cmplxpat, l[1]) - else: - matches = l[1].split(',') - - if v not in vars: - vars[v] = {} - if '=' in vars[v] and not vars[v]['='] == matches[idx]: - outmess('analyzeline: changing init expression of "%s" ("%s") to "%s"\n' % ( - v, vars[v]['='], matches[idx])) - - if vdim is not None: - # Need to assign multiple values to one variable - vars[v]['='] = "(/{}/)".format(", ".join(matches)) - else: - vars[v]['='] = matches[idx] + matches = re.findall(r"\(.*?\)", l[1]) if vtype == 'complex' else l[1].split(',') + vars.setdefault(v, {}) + if '=' in vars[v] and vars[v]['='] != matches[idx]: + outmess('analyzeline: changing init expression of "%s" ("%s") to "%s"\n' % (v, vars[v]['='], matches[idx])) + vars[v]['='] = "(/{}/)".format(", ".join(matches)) if vdim is not None else matches[idx] except: - i = 0 - j = 0 - for v in rmbadname([x.strip() for x in markoutercomma(l[0]).split('@,@')]): - if v[0] == '(': - outmess( - 'analyzeline: implied-DO list "%s" is not supported. Skipping.\n' % v) - # XXX: subsequent init expressions may get wrong values. - # Ignoring since data statements are irrelevant for - # wrapping. - continue - fc = 0 - while (i < llen) and (fc or not l[1][i] == ','): - if l[1][i] == "'": + idy, jdx, fc = 0, 0, 0 + while idy < llen and (fc or l[1][idy] != ','): + if l[1][idy] == "'": fc = not fc - i = i + 1 - i = i + 1 - if v not in vars: - vars[v] = {} - if '=' in vars[v] and not vars[v]['='] == l[1][j:i - 1]: - outmess('analyzeline: changing init expression of "%s" ("%s") to "%s"\n' % ( - v, vars[v]['='], l[1][j:i - 1])) - vars[v]['='] = l[1][j:i - 1] - j = i + idy += 1 + idy += 1 + vars.setdefault(v, {}) + if '=' in vars[v] and vars[v]['='] != l[1][jdx:idy - 1]: + outmess('analyzeline: changing init expression of "%s" ("%s") to "%s"\n' % (v, vars[v]['='], l[1][jdx:idy - 1])) + vars[v]['='] = l[1][jdx:idy - 1] + jdx = idy last_name = v groupcache[groupcounter]['vars'] = vars if last_name is not None: From b63422de0acf56b284cb6981a88eae176e662b07 Mon Sep 17 00:00:00 2001 From: Rohit Goswami Date: Fri, 22 Sep 2023 16:09:27 +0000 Subject: [PATCH 16/38] MAINT: Minor cleanup --- numpy/f2py/crackfortran.py | 45 ++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/numpy/f2py/crackfortran.py b/numpy/f2py/crackfortran.py index d2bc7e972384..1a38dae4dbc4 100755 --- a/numpy/f2py/crackfortran.py +++ b/numpy/f2py/crackfortran.py @@ -1428,48 +1428,45 @@ def analyzeline(m, case, line): vars = groupcache[groupcounter].get('vars', {}) last_name = None for l in ll: - l = [x.strip() for x in l] - if l[0][0] == ',': + l[0], l[1] = l[0].strip(), l[1].strip() + if l[0].startswith(','): l[0] = l[0][1:] - if l[0][0] == '(': - outmess( - 'analyzeline: implied-DO list "%s" is not supported. Skipping.\n' % l[0]) + if l[0].startswith('('): + outmess('analyzeline: implied-DO list "%s" is not supported. Skipping.\n' % l[0]) continue - llen = len(l[1]) - for idx, v in enumerate(rmbadname( - [x.strip() for x in markoutercomma(l[0]).split('@,@')]) - ): - if v[0] == '(': - outmess( - 'analyzeline: implied-DO list "%s" is not supported. Skipping.\n' % v) + for idx, v in enumerate(rmbadname([x.strip() for x in markoutercomma(l[0]).split('@,@')])): + if v.startswith('('): + outmess('analyzeline: implied-DO list "%s" is not supported. Skipping.\n' % v) # XXX: subsequent init expressions may get wrong values. # Ignoring since data statements are irrelevant for # wrapping. continue - fc = 0 try: - vtype = vars[v].get('typespec') # can fail + vtype = vars[v].get('typespec') vdim = getdimension(vars[v]) matches = re.findall(r"\(.*?\)", l[1]) if vtype == 'complex' else l[1].split(',') vars.setdefault(v, {}) - if '=' in vars[v] and vars[v]['='] != matches[idx]: - outmess('analyzeline: changing init expression of "%s" ("%s") to "%s"\n' % (v, vars[v]['='], matches[idx])) - vars[v]['='] = "(/{}/)".format(", ".join(matches)) if vdim is not None else matches[idx] + current_val = vars[v].get('=') + new_val = "(/{}/)".format(", ".join(matches)) if vdim else matches[idx] + if current_val and current_val != new_val: + outmess('analyzeline: changing init expression of "%s" ("%s") to "%s"\n' % (v, current_val, new_val)) + vars[v]['='] = new_val except: idy, jdx, fc = 0, 0, 0 - while idy < llen and (fc or l[1][idy] != ','): + while idy < len(l[1]) and (fc or l[1][idy] != ','): if l[1][idy] == "'": fc = not fc idy += 1 - idy += 1 vars.setdefault(v, {}) - if '=' in vars[v] and vars[v]['='] != l[1][jdx:idy - 1]: - outmess('analyzeline: changing init expression of "%s" ("%s") to "%s"\n' % (v, vars[v]['='], l[1][jdx:idy - 1])) - vars[v]['='] = l[1][jdx:idy - 1] - jdx = idy + current_val = vars[v].get('=') + new_val = l[1][jdx:idy] + if current_val and current_val != new_val: + outmess('analyzeline: changing init expression of "%s" ("%s") to "%s"\n' % (v, current_val, new_val)) + vars[v]['='] = new_val + jdx = idy + 1 last_name = v groupcache[groupcounter]['vars'] = vars - if last_name is not None: + if last_name: previous_context = ('variable', last_name, groupcounter) elif case == 'common': line = m.group('after').strip() From 112730c205fa654ce5ae7bdba7219052ddc310c3 Mon Sep 17 00:00:00 2001 From: Rohit Goswami Date: Fri, 22 Sep 2023 16:09:44 +0000 Subject: [PATCH 17/38] MAINT: Refactor changes to be clearer --- numpy/f2py/crackfortran.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/numpy/f2py/crackfortran.py b/numpy/f2py/crackfortran.py index 1a38dae4dbc4..e7d26c18a255 100755 --- a/numpy/f2py/crackfortran.py +++ b/numpy/f2py/crackfortran.py @@ -1445,25 +1445,20 @@ def analyzeline(m, case, line): vtype = vars[v].get('typespec') vdim = getdimension(vars[v]) matches = re.findall(r"\(.*?\)", l[1]) if vtype == 'complex' else l[1].split(',') - vars.setdefault(v, {}) - current_val = vars[v].get('=') new_val = "(/{}/)".format(", ".join(matches)) if vdim else matches[idx] - if current_val and current_val != new_val: - outmess('analyzeline: changing init expression of "%s" ("%s") to "%s"\n' % (v, current_val, new_val)) - vars[v]['='] = new_val - except: + except: # gh-24746 idy, jdx, fc = 0, 0, 0 while idy < len(l[1]) and (fc or l[1][idy] != ','): if l[1][idy] == "'": fc = not fc idy += 1 - vars.setdefault(v, {}) - current_val = vars[v].get('=') new_val = l[1][jdx:idy] - if current_val and current_val != new_val: - outmess('analyzeline: changing init expression of "%s" ("%s") to "%s"\n' % (v, current_val, new_val)) - vars[v]['='] = new_val jdx = idy + 1 + vars.setdefault(v, {}) + current_val = vars[v].get('=') + if current_val and current_val != new_val: + outmess('analyzeline: changing init expression of "%s" ("%s") to "%s"\n' % (v, current_val, new_val)) + vars[v]['='] = new_val last_name = v groupcache[groupcounter]['vars'] = vars if last_name: From 138b5e19e55061149cbfb161e793a69e50193617 Mon Sep 17 00:00:00 2001 From: Rohit Goswami Date: Sun, 24 Sep 2023 13:28:41 +0000 Subject: [PATCH 18/38] TST: More tests for gh-24746 --- .../f2py/tests/src/crackfortran/data_with_comments.f | 8 ++++++++ numpy/f2py/tests/test_data.py | 11 +++++++++++ 2 files changed, 19 insertions(+) create mode 100644 numpy/f2py/tests/src/crackfortran/data_with_comments.f diff --git a/numpy/f2py/tests/src/crackfortran/data_with_comments.f b/numpy/f2py/tests/src/crackfortran/data_with_comments.f new file mode 100644 index 000000000000..4128f004e840 --- /dev/null +++ b/numpy/f2py/tests/src/crackfortran/data_with_comments.f @@ -0,0 +1,8 @@ + BLOCK DATA PARAM_INI + COMMON /MYCOM/ MYTAB + INTEGER MYTAB(3) + DATA MYTAB/ + * 0, ! 1 and more commenty stuff + * 4, ! 2 + * 0 / + END diff --git a/numpy/f2py/tests/test_data.py b/numpy/f2py/tests/test_data.py index 497d8f975edc..fc8baae6585b 100644 --- a/numpy/f2py/tests/test_data.py +++ b/numpy/f2py/tests/test_data.py @@ -45,3 +45,14 @@ def test_crackedlines(self): mod = crackfortran(str(self.sources[0])) print(mod[0]['vars']) assert mod[0]['vars']['mydata']['='] == '0' + + +class TestDataWithCommentsF77(util.F2PyTest): + sources = [util.getpath("tests", "src", "crackfortran", "data_with_comments.f")] + + # For gh-23276 + def test_data_stmts(self): + assert len(self.module.mycom.mytab) == 3 + assert self.module.mycom.mytab[0] == 0 + assert self.module.mycom.mytab[1] == 4 + assert self.module.mycom.mytab[2] == 0 From 5614044d14c2ef2eab8531fe4ccbf6cd3ec115cf Mon Sep 17 00:00:00 2001 From: Rohit Goswami Date: Sun, 24 Sep 2023 13:29:04 +0000 Subject: [PATCH 19/38] BUG: Fix handling of data statements --- numpy/f2py/crackfortran.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/numpy/f2py/crackfortran.py b/numpy/f2py/crackfortran.py index e7d26c18a255..d004f808db58 100755 --- a/numpy/f2py/crackfortran.py +++ b/numpy/f2py/crackfortran.py @@ -1441,6 +1441,15 @@ def analyzeline(m, case, line): # Ignoring since data statements are irrelevant for # wrapping. continue + if '!' in l[1]: + # Fixes gh-24746 pyf generation + # XXX: This essentially ignores the value for generating the pyf which is fine: + # integer dimension(3) :: mytab + # common /mycom/ mytab + # Since in any case it is initialized in the Fortran code + outmess('Comment line in declaration "%s" is not supported. Skipping.\n' % l[1]) + new_val = 0 + continue try: vtype = vars[v].get('typespec') vdim = getdimension(vars[v]) From 093a07cef0169f84a163c47b92a551d3cf90f552 Mon Sep 17 00:00:00 2001 From: Rohit Goswami Date: Tue, 26 Sep 2023 14:24:45 +0000 Subject: [PATCH 20/38] MAINT: Cleanup as per review Co-authored-by: jncots --- numpy/f2py/crackfortran.py | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/numpy/f2py/crackfortran.py b/numpy/f2py/crackfortran.py index d004f808db58..0cb6dbf087d5 100755 --- a/numpy/f2py/crackfortran.py +++ b/numpy/f2py/crackfortran.py @@ -1448,24 +1448,14 @@ def analyzeline(m, case, line): # common /mycom/ mytab # Since in any case it is initialized in the Fortran code outmess('Comment line in declaration "%s" is not supported. Skipping.\n' % l[1]) - new_val = 0 continue - try: - vtype = vars[v].get('typespec') - vdim = getdimension(vars[v]) - matches = re.findall(r"\(.*?\)", l[1]) if vtype == 'complex' else l[1].split(',') - new_val = "(/{}/)".format(", ".join(matches)) if vdim else matches[idx] - except: # gh-24746 - idy, jdx, fc = 0, 0, 0 - while idy < len(l[1]) and (fc or l[1][idy] != ','): - if l[1][idy] == "'": - fc = not fc - idy += 1 - new_val = l[1][jdx:idy] - jdx = idy + 1 vars.setdefault(v, {}) + vtype = vars[v].get('typespec') + vdim = getdimension(vars[v]) + matches = re.findall(r"\(.*?\)", l[1]) if vtype == 'complex' else l[1].split(',') + new_val = "(/{}/)".format(", ".join(matches)) if vdim else matches[idx] current_val = vars[v].get('=') - if current_val and current_val != new_val: + if current_val and (current_val != new_val): outmess('analyzeline: changing init expression of "%s" ("%s") to "%s"\n' % (v, current_val, new_val)) vars[v]['='] = new_val last_name = v From 390be3a1dff1b196622dfd16db1448f4927fed97 Mon Sep 17 00:00:00 2001 From: Rohit Goswami Date: Wed, 27 Sep 2023 11:13:58 +0000 Subject: [PATCH 21/38] ENH: Fix DATA with * statements Co-authored-by: jncots --- numpy/f2py/crackfortran.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/numpy/f2py/crackfortran.py b/numpy/f2py/crackfortran.py index 0cb6dbf087d5..261ff81af2c4 100755 --- a/numpy/f2py/crackfortran.py +++ b/numpy/f2py/crackfortran.py @@ -1453,7 +1453,26 @@ def analyzeline(m, case, line): vtype = vars[v].get('typespec') vdim = getdimension(vars[v]) matches = re.findall(r"\(.*?\)", l[1]) if vtype == 'complex' else l[1].split(',') - new_val = "(/{}/)".format(", ".join(matches)) if vdim else matches[idx] + try: + new_val = "(/{}/)".format(", ".join(matches)) if vdim else matches[idx] + except IndexError: + # gh-24746 + # Runs only if above code fails. Fixes the line + # DATA IVAR1, IVAR2, IVAR3, IVAR4, EVAR5 /4*0,0.0D0/ + # by exanding to ['0', '0', '0', '0', '0.0d0'] + if any("*" in m for m in matches): + expanded_list = [] + for match in matches: + if "*" in match: + try: + multiplier, value = match.split("*") + expanded_list.extend([value.strip()] * int(multiplier)) + except ValueError: # if int(multiplier) fails + expanded_list.append(match.strip()) + else: + expanded_list.append(match.strip()) + matches = expanded_list + new_val = "(/{}/)".format(", ".join(matches)) if vdim else matches[idx] current_val = vars[v].get('=') if current_val and (current_val != new_val): outmess('analyzeline: changing init expression of "%s" ("%s") to "%s"\n' % (v, current_val, new_val)) From b7bf593903790d8ea443a1e12e170c9a03ff4c09 Mon Sep 17 00:00:00 2001 From: Rohit Goswami Date: Wed, 27 Sep 2023 11:28:53 +0000 Subject: [PATCH 22/38] TST: Add check for multipliers in data [f2py] Co-authored-by: jncots --- numpy/f2py/crackfortran.py | 2 +- numpy/f2py/tests/src/crackfortran/data_multiplier.f | 5 +++++ numpy/f2py/tests/test_data.py | 12 ++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 numpy/f2py/tests/src/crackfortran/data_multiplier.f diff --git a/numpy/f2py/crackfortran.py b/numpy/f2py/crackfortran.py index 261ff81af2c4..d39acb039073 100755 --- a/numpy/f2py/crackfortran.py +++ b/numpy/f2py/crackfortran.py @@ -1459,7 +1459,7 @@ def analyzeline(m, case, line): # gh-24746 # Runs only if above code fails. Fixes the line # DATA IVAR1, IVAR2, IVAR3, IVAR4, EVAR5 /4*0,0.0D0/ - # by exanding to ['0', '0', '0', '0', '0.0d0'] + # by expanding to ['0', '0', '0', '0', '0.0d0'] if any("*" in m for m in matches): expanded_list = [] for match in matches: diff --git a/numpy/f2py/tests/src/crackfortran/data_multiplier.f b/numpy/f2py/tests/src/crackfortran/data_multiplier.f new file mode 100644 index 000000000000..19ff8a83e97b --- /dev/null +++ b/numpy/f2py/tests/src/crackfortran/data_multiplier.f @@ -0,0 +1,5 @@ + BLOCK DATA MYBLK + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + COMMON /MYCOM/ IVAR1, IVAR2, IVAR3, IVAR4, EVAR5 + DATA IVAR1, IVAR2, IVAR3, IVAR4, EVAR5 /2*3,2*2,0.0D0/ + END diff --git a/numpy/f2py/tests/test_data.py b/numpy/f2py/tests/test_data.py index fc8baae6585b..4e5604c006b1 100644 --- a/numpy/f2py/tests/test_data.py +++ b/numpy/f2py/tests/test_data.py @@ -47,6 +47,18 @@ def test_crackedlines(self): assert mod[0]['vars']['mydata']['='] == '0' +class TestDataMultiplierF77(util.F2PyTest): + sources = [util.getpath("tests", "src", "crackfortran", "data_multiplier.f")] + + # For gh-23276 + def test_data_stmts(self): + assert self.module.mycom.ivar1 == 3 + assert self.module.mycom.ivar2 == 3 + assert self.module.mycom.ivar3 == 2 + assert self.module.mycom.ivar4 == 2 + assert self.module.mycom.evar5 == 0 + + class TestDataWithCommentsF77(util.F2PyTest): sources = [util.getpath("tests", "src", "crackfortran", "data_with_comments.f")] From 57730a4cec89c9074e9ad38d4b34eaa2f647678a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Sok=C3=B3=C5=82?= Date: Fri, 6 Oct 2023 10:43:44 +0200 Subject: [PATCH 23/38] Add NumpyUnpickler --- .../upcoming_changes/24870.new_feature.rst | 6 ++++++ doc/source/reference/routines.io.rst | 1 + doc/source/user/how-to-io.rst | 5 +++++ numpy/lib/format.py | 16 ++++++++++++++-- numpy/lib/format.pyi | 3 +++ numpy/lib/npyio.py | 2 +- 6 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 doc/release/upcoming_changes/24870.new_feature.rst diff --git a/doc/release/upcoming_changes/24870.new_feature.rst b/doc/release/upcoming_changes/24870.new_feature.rst new file mode 100644 index 000000000000..82d4015ff05f --- /dev/null +++ b/doc/release/upcoming_changes/24870.new_feature.rst @@ -0,0 +1,6 @@ +`numpy.lib.format.NumpyUnpickler` +--------------------------------- + +`numpy.lib.format.NumpyUnpickler` class was added +that provides a stable way for loading pickled arrays, +created with NumPy 2.0, with Numpy 1.26. diff --git a/doc/source/reference/routines.io.rst b/doc/source/reference/routines.io.rst index 1ec2ccb5eea4..93a2da9495d0 100644 --- a/doc/source/reference/routines.io.rst +++ b/doc/source/reference/routines.io.rst @@ -14,6 +14,7 @@ NumPy binary files (NPY, NPZ) save savez savez_compressed + lib.format.NumpyUnpickler The format of these binary file types is documented in :py:mod:`numpy.lib.format` diff --git a/doc/source/user/how-to-io.rst b/doc/source/user/how-to-io.rst index 6a4127e8f00a..55070ff5e727 100644 --- a/doc/source/user/how-to-io.rst +++ b/doc/source/user/how-to-io.rst @@ -319,6 +319,11 @@ Use :func:`numpy.save` and :func:`numpy.load`. Set ``allow_pickle=False``, unless the array dtype includes Python objects, in which case pickling is required. +:func:`numpy.load` also supports unpickling files created with NumPy 2.0. +If you try to unpickle a 2.0 pickled array directly, you will get +an exception. Use :class:`numpy.lib.format.NumpyUnpickler` for +unpickling these files. + Convert from a pandas DataFrame to a NumPy array ================================================ diff --git a/numpy/lib/format.py b/numpy/lib/format.py index d5b3fbac23ab..05c51fe5635f 100644 --- a/numpy/lib/format.py +++ b/numpy/lib/format.py @@ -169,7 +169,7 @@ ) -__all__ = [] +__all__ = ["NumpyUnpickler"] EXPECTED_KEYS = {'descr', 'fortran_order', 'shape'} @@ -797,7 +797,7 @@ def read_array(fp, allow_pickle=False, pickle_kwargs=None, *, if pickle_kwargs is None: pickle_kwargs = {} try: - array = pickle.load(fp, **pickle_kwargs) + array = NumpyUnpickler(fp, **pickle_kwargs).load() except UnicodeError as err: # Friendlier error message raise UnicodeError("Unpickling a python object failed: %r\n" @@ -974,3 +974,15 @@ def _read_bytes(fp, size, error_template="ran out of data"): raise ValueError(msg % (error_template, size, len(data))) else: return data + + +class NumpyUnpickler(pickle.Unpickler): + """ + A thin wrapper for :py:class:`pickle.Unpickler` that + allows to load 2.0 array pickles with numpy 1.26. + """ + + def find_class(self, module: str, name: str) -> object: + if module.startswith("numpy._core"): + module = module.replace("_core", "core", 1) + return pickle.Unpickler.find_class(self, module, name) diff --git a/numpy/lib/format.pyi b/numpy/lib/format.pyi index a4468f52f464..a433309c2583 100644 --- a/numpy/lib/format.pyi +++ b/numpy/lib/format.pyi @@ -1,3 +1,4 @@ +import pickle from typing import Any, Literal, Final __all__: list[str] @@ -20,3 +21,5 @@ def read_array_header_2_0(fp): ... def write_array(fp, array, version=..., allow_pickle=..., pickle_kwargs=...): ... def read_array(fp, allow_pickle=..., pickle_kwargs=...): ... def open_memmap(filename, mode=..., dtype=..., shape=..., fortran_order=..., version=...): ... + +class NumpyUnpickler(pickle.Unpickler): ... diff --git a/numpy/lib/npyio.py b/numpy/lib/npyio.py index 339b1dc62113..73ef6dde900b 100644 --- a/numpy/lib/npyio.py +++ b/numpy/lib/npyio.py @@ -462,7 +462,7 @@ def load(file, mmap_mode=None, allow_pickle=False, fix_imports=True, raise ValueError("Cannot load file containing pickled data " "when allow_pickle=False") try: - return pickle.load(fid, **pickle_kwargs) + return format.NumpyUnpickler(fid, **pickle_kwargs).load() except Exception as e: raise pickle.UnpicklingError( f"Failed to interpret file {file!r} as a pickle") from e From 2fc605a4ad86a490c3d090a7b5fb8e0219354839 Mon Sep 17 00:00:00 2001 From: Charles Harris Date: Wed, 4 Oct 2023 17:19:23 -0600 Subject: [PATCH 24/38] MAINT: Xfail test failing on PyPy. Skip a test that fails on pypy3.9-v1.3.13 and pypy3.10-v1.3.13, released 9-29-2023. This may be a bit harsh, but it is hard to make it more specific. In reference to #24862. --- numpy/core/tests/test_multiarray.py | 1 + 1 file changed, 1 insertion(+) diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index b9021ccb24cf..a2ddc4f8341e 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -3726,6 +3726,7 @@ def test_inplace(self): # - defer if other has __array_ufunc__ and it is None # or other is not a subclass and has higher array priority # - else, call ufunc + @pytest.mark.xfail(IS_PYPY, reason="Bug in pypy3.{9, 10}-v7.3.13, #24862") def test_ufunc_binop_interaction(self): # Python method name (without underscores) # -> (numpy ufunc, has_in_place_version, preferred_dtype) From c7e073c2bb88a94fc2de5f843dc836f33820305b Mon Sep 17 00:00:00 2001 From: Charles Harris Date: Sat, 7 Oct 2023 15:06:28 -0600 Subject: [PATCH 25/38] BLD: fix math func feature checks, fix FreeBSD build, add CI job (#24876) (#24879) * BLD: fix incorrect feature checks for mandatory math functions Should fix the build on FreeBSD and other OSes that are not C99-compliant. Closes gh-24873 * CI: add a FreeBSD job on Cirrus CI * BUG: define `_npy_scaled_cexpl` when ccoshl/csinhl are missing This was a regression in the 1.24.x branch, after a lot of churn in this file. In 1.22.x/1.23.x, the conditional is the same as in this fix. * TST: avoid failures for FPE errors/warnings in `abs` on BSDs Co-authored-by: Ralf Gommers --- numpy/core/meson.build | 36 ++++++++++----- numpy/core/src/npymath/npy_math_complex.c.src | 4 +- numpy/core/tests/test_multiarray.py | 9 ++-- numpy/core/tests/test_numeric.py | 5 ++ numpy/core/tests/test_umath.py | 2 + numpy/core/tests/test_umath_complex.py | 2 +- tools/ci/cirrus_arm.yml | 46 ++++++++++++++++++- 7 files changed, 85 insertions(+), 19 deletions(-) diff --git a/numpy/core/meson.build b/numpy/core/meson.build index 473362f1b7e9..a1fc7e9d8a84 100644 --- a/numpy/core/meson.build +++ b/numpy/core/meson.build @@ -149,20 +149,32 @@ endif # Mandatory functions: if not found, fail the build # Some of these can still be blocklisted if the C99 implementation # is buggy, see numpy/core/src/common/npy_config.h -mandatory_funcs = [ +mandatory_math_funcs = [ 'sin', 'cos', 'tan', 'sinh', 'cosh', 'tanh', 'fabs', 'floor', 'ceil', 'sqrt', 'log10', 'log', 'exp', 'asin', 'acos', 'atan', 'fmod', 'modf', 'frexp', 'ldexp', 'expm1', 'log1p', 'acosh', 'asinh', 'atanh', - 'rint', 'trunc', 'exp2', - 'copysign', 'nextafter', 'strtoll', 'strtoull', 'cbrt', + 'rint', 'trunc', 'exp2', 'copysign', 'nextafter', 'cbrt', 'log2', 'pow', 'hypot', 'atan2', - 'csin', 'csinh', 'ccos', 'ccosh', 'ctan', 'ctanh', - 'creal', 'cimag', 'conj' ] -foreach func: mandatory_funcs - if not cc.has_function(func) - error('Function `{func}` not found') +foreach func: mandatory_math_funcs + if not cc.has_function(func, prefix: '#include ', dependencies: m_dep) + error(f'Function `@func@` not found') + endif +endforeach + +mandatory_complex_math_funcs = [ + 'csin', 'csinh', 'ccos', 'ccosh', 'ctan', 'ctanh', 'creal', 'cimag', 'conj' +] +foreach func: mandatory_complex_math_funcs + if not cc.has_function(func, prefix: '#include ', dependencies: m_dep) + error(f'Function `@func@` not found') + endif +endforeach + +foreach func: ['strtoll', 'strtoull'] + if not cc.has_function(func, prefix: '#include ') + error(f'Function `@func@` not found') endif endforeach @@ -177,13 +189,13 @@ c99_complex_funcs = [ foreach func: c99_complex_funcs func_single = func + 'f' func_longdouble = func + 'l' - if cc.has_function(func) + if cc.has_function(func, prefix: '#include ', dependencies: m_dep) cdata.set10('HAVE_' + func.to_upper(), true) endif - if cc.has_function(func_single) + if cc.has_function(func_single, prefix: '#include ', dependencies: m_dep) cdata.set10('HAVE_' + func_single.to_upper(), true) endif - if cc.has_function(func_longdouble) + if cc.has_function(func_longdouble, prefix: '#include ', dependencies: m_dep) cdata.set10('HAVE_' + func_longdouble.to_upper(), true) endif endforeach @@ -192,7 +204,7 @@ endforeach # libnpymath as a C99 compat layer, these may still be relevant. c99_macros = ['isfinite', 'isinf', 'isnan', 'signbit'] foreach macro: c99_macros - if cc.has_function(macro) + if cc.has_function(macro, prefix: '#include ', dependencies: m_dep) cdata.set10('NPY_HAVE_DECL_' + macro.to_upper(), true) if not cc.has_header_symbol('Python.h', macro, dependencies: py_dep) # Add in config.h as well, except if it will clash with Python's config.h content diff --git a/numpy/core/src/npymath/npy_math_complex.c.src b/numpy/core/src/npymath/npy_math_complex.c.src index eb9d810b7d82..8e1decbfd9d5 100644 --- a/numpy/core/src/npymath/npy_math_complex.c.src +++ b/numpy/core/src/npymath/npy_math_complex.c.src @@ -158,7 +158,9 @@ npy_carg@c@(@ctype@ z) #define SCALED_CEXP_LOWERL 11357.216553474703895L #define SCALED_CEXP_UPPERL 22756.021937783004509L -#if !defined(HAVE_CEXP@C@) +#if !defined(HAVE_CSINH@C@) || \ + !defined(HAVE_CCOSH@C@) || \ + !defined(HAVE_CEXP@C@) static @ctype@ diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index a2ddc4f8341e..ace40049fd83 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -9723,9 +9723,12 @@ def test_ragged_comparison_fails(op): def test_npymath_complex(fun, npfun, x, y, test_dtype): # Smoketest npymath functions z = test_dtype(complex(x, y)) - got = fun(z) - expected = npfun(z) - assert_allclose(got, expected) + with np.errstate(invalid='ignore'): + # Fallback implementations may emit a warning for +-inf (see gh-24876): + # RuntimeWarning: invalid value encountered in absolute + got = fun(z) + expected = npfun(z) + assert_allclose(got, expected) def test_npymath_real(): diff --git a/numpy/core/tests/test_numeric.py b/numpy/core/tests/test_numeric.py index 832a47c926cf..d2d041f71ef2 100644 --- a/numpy/core/tests/test_numeric.py +++ b/numpy/core/tests/test_numeric.py @@ -645,6 +645,11 @@ def assert_op_raises_fpe(self, fpeerr, flop, sc1, sc2): @pytest.mark.skipif(IS_WASM, reason="no wasm fp exception support") @pytest.mark.parametrize("typecode", np.typecodes["AllFloat"]) def test_floating_exceptions(self, typecode): + if 'bsd' in sys.platform and typecode in 'gG': + pytest.skip(reason="Fallback impl for (c)longdouble may not raise " + "FPE errors as expected on BSD OSes, " + "see gh-24876, gh-23379") + # Test basic arithmetic function errors with np.errstate(all='raise'): ftype = np.obj2sctype(typecode) diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py index 0e07a6cb937b..5567244d14a9 100644 --- a/numpy/core/tests/test_umath.py +++ b/numpy/core/tests/test_umath.py @@ -1646,6 +1646,8 @@ def test_sinh(self): np.array(1200.0, dtype='d')) @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm") + @pytest.mark.skipif('bsd' in sys.platform, + reason="fallback implementation may not raise, see gh-2487") def test_cosh(self): in_ = [np.nan, -np.nan, np.inf, -np.inf] out = [np.nan, np.nan, np.inf, np.inf] diff --git a/numpy/core/tests/test_umath_complex.py b/numpy/core/tests/test_umath_complex.py index 8aa9a28ff48d..e54300589094 100644 --- a/numpy/core/tests/test_umath_complex.py +++ b/numpy/core/tests/test_umath_complex.py @@ -576,8 +576,8 @@ def test_array(self, stride, astype): complex(0., 0.), complex(np.nan, np.nan), complex(np.nan, np.nan)], dtype=astype) - assert_equal(np.abs(arr[::stride]), abs_true[::stride]) with np.errstate(invalid='ignore'): + assert_equal(np.abs(arr[::stride]), abs_true[::stride]) assert_equal(np.square(arr[::stride]), sq_true[::stride]) class TestComplexAbsoluteAVX: diff --git a/tools/ci/cirrus_arm.yml b/tools/ci/cirrus_arm.yml index c3daf953d751..a28f182ae8ba 100644 --- a/tools/ci/cirrus_arm.yml +++ b/tools/ci/cirrus_arm.yml @@ -96,7 +96,7 @@ macos_arm64_test_task: RUNNER_OS="macOS" SDKROOT=/Applications/Xcode-14.0.0.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk - + # NOTE: OpenBLAS is not used in this job; if that's done in the future, ensure # PKG_CONFIG_PATH points to the directory containing the openblas.pc file # that's installed with the cibw_before_build.sh command. @@ -110,8 +110,50 @@ macos_arm64_test_task: pip install -r build_requirements.txt pip install pytest pytest-xdist hypothesis typing_extensions - + spin build -- -Dallow-noblas=true spin test -j auto ccache -s + + +freebsd_test_task: + use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' + compute_engine_instance: + image_project: freebsd-org-cloud-dev + image: family/freebsd-13-2 + platform: freebsd + cpu: 1 + memory: 4G + + install_devtools_script: | + pkg install -y git bash ninja ccache + + <<: *MODIFIED_CLONE + + ccache_cache: + folder: .ccache + populate_script: + - mkdir -p .ccache + fingerprint_key: ccache-freebsd + + prepare_env_script: | + # Create a venv (the `source` command needs bash, not the default sh shell) + chsh -s /usr/local/bin/bash + python -m venv .venv + source .venv/bin/activate + # Minimal build and test requirements + python -m pip install -U pip + python -m pip install meson-python Cython pytest hypothesis + + build_script: | + chsh -s /usr/local/bin/bash + source .venv/bin/activate + python -m pip install . --no-build-isolation -v -Csetup-args="-Dallow-noblas=true" + + test_script: | + chsh -s /usr/local/bin/bash + source .venv/bin/activate + cd tools + python -m pytest --pyargs numpy -m "not slow" + ccache -s From cbdc78534353939ec81c31a3138515860aac0b33 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Tue, 10 Oct 2023 00:27:02 +0200 Subject: [PATCH 26/38] ENH: meson: implement BLAS/LAPACK auto-detection and many CI jobs [wheel build] This reimplements the auto-detection and many of the switches that `numpy.distutils` offered. Beyond that, it implements several new features: - Auto-detect the symbol suffix for ILP64 OpenBLAS (can be none or `64_`) - MKL ILP64 support, threading control, and use of the layered library model for MKL >=2023.0 - FlexiBLAS support (LP64 and ILP64) - Support for the upcoming standard in Reference LAPACK for `_64` ILP64 symbol suffix convention. - A test suite for BLAS/LAPACK libraries, covering: - OpenBLAS: LP64, ILP64 detected via pkg-config and with a "system dependency" (i.e., custom code inside Meson) - MKL: LP64, ILP64 (layered) and LP64 (SDL) - Accelerate: LP64, ILP64 on macOS >=13.3 - FlexiBLAS: LP64, ILP64 on Fedora - ATLAS (LP64, via pkg-config only) - BLIS (LP64, via pkg-config only) - plain libblas/liblapack (Netlib, LP64 only) The list of libraries that is tried with the default 'auto' setting excludes a couple of libraries, because they're either no longer developed (ATLAS), not mature (libflame), or can't be tested and may be re-added later (ArmPL, ssl2). Those libraries can still be quite easily used via pkg-config. The new CI jobs are running by default right now. Once things settle down, the plan is to disable them by default and allow triggering them via a `[blas ci]` command in the commit message (just like for wheel builds). Docs will be included in a separate PR with the pending rewrite of all the build/install docs. For now, the CI jobs and the `meson_options.txt` file serve as guidance for how to use this. Note that the test suite contains a few hacks, because of packaging bugs for MKL on PyPI (broken .pc files) and BLIS (missing .pc file in Debian). --- .github/workflows/linux_meson.yml | 284 +++++++++++++++++++++++++++++- .github/workflows/linux_musl.yml | 14 +- .github/workflows/macos.yml | 19 +- azure-steps-windows.yml | 5 +- build_requirements.txt | 2 +- meson.build | 2 - meson_options.txt | 18 +- numpy/core/src/common/npy_cblas.h | 15 +- numpy/meson.build | 244 +++++++++++-------------- pyproject.toml | 12 +- tools/ci/_blis_debian.pc | 8 + vendored-meson/meson | 2 +- 12 files changed, 448 insertions(+), 177 deletions(-) create mode 100644 tools/ci/_blis_debian.pc diff --git a/.github/workflows/linux_meson.yml b/.github/workflows/linux_meson.yml index 7be5cb38bfc2..ebbd52997e42 100644 --- a/.github/workflows/linux_meson.yml +++ b/.github/workflows/linux_meson.yml @@ -1,4 +1,36 @@ -name: Test Meson build (Linux) +name: BLAS tests (Linux) + +# This file is meant for testing different BLAS/LAPACK flavors and build +# options on Linux. All other yml files for Linux will only test without BLAS +# (mostly because that's easier and faster to build) or with the same 64-bit +# OpenBLAS build that is used in the wheel jobs. +# +# Jobs and their purpose: +# +# - openblas32_stable_nightly: +# Uses the 32-bit OpenBLAS builds, both the latest stable release +# and a nightly build. +# - openblas_no_pkgconfig_fedora: +# Test OpenBLAS on Fedora. Fedora doesn't ship .pc files for OpenBLAS, +# hence this exercises the "system dependency" detection method. +# - flexiblas_fedora: +# Tests FlexiBLAS (the default on Fedora for its own packages), via +# pkg-config. FlexiBLAS allows runtime switching of BLAS/LAPACK +# libraries, which is a useful capability (not tested in this job). +# - openblas_cmake: +# Tests whether OpenBLAS LP64 is detected correctly when only CMake +# and not pkg-config is installed. +# - netlib: +# Installs vanilla blas/lapack, which is the last option tried in +# auto-detection. +# - mkl: +# Tests MKL installed from PyPI (because easiest/fastest, if broken) in +# 3 ways: both LP64 and ILP64 via pkg-config, and then using the +# Single Dynamic Library (SDL, or `libmkl_rt`). +# - blis: +# Simple test for LP64 via pkg-config +# - atlas: +# Simple test for LP64 via pkg-config on: pull_request: @@ -71,3 +103,253 @@ jobs: export NPY_RUN_MYPY_IN_TESTSUITE=1 pip install pytest pytest-xdist hypothesis typing_extensions spin test -j auto + + + openblas_no_pkgconfig_fedora: + if: "github.repository == 'numpy/numpy'" + runs-on: ubuntu-latest + container: fedora:39 + name: "OpenBLAS (Fedora, no pkg-config, LP64/ILP64)" + steps: + - name: Install system dependencies + run: | + dnf install git gcc-gfortran g++ python3-devel openblas-devel -y + + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + with: + submodules: recursive + fetch-depth: 0 + + - name: Install dependencies + run: | + pip install -r build_requirements.txt + pip install pytest hypothesis typing_extensions + + - name: Build (LP64) + run: spin build -- -Dblas=openblas -Dlapack=openblas -Ddisable-optimization=true + + - name: Test + run: spin test -- numpy/linalg + + - name: Build (ILP64) + run: | + rm -rf build + spin build -- -Duse-ilp64=true -Ddisable-optimization=true + + - name: Test + run: spin test -- numpy/linalg + + + flexiblas_fedora: + if: "github.repository == 'numpy/numpy'" + runs-on: ubuntu-latest + container: fedora:39 + name: "FlexiBLAS (LP64, ILP64 on Fedora)" + steps: + - name: Install system dependencies + run: | + dnf install git gcc-gfortran g++ python3-devel flexiblas-devel -y + + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + with: + submodules: recursive + fetch-depth: 0 + + - name: Install dependencies + run: | + pip install -r build_requirements.txt + pip install pytest hypothesis typing_extensions + + - name: Build + run: spin build -- -Ddisable-optimization=true + + - name: Test + run: spin test -- numpy/linalg + + - name: Build (ILP64) + run: | + rm -rf build + spin build -- -Ddisable-optimization=true -Duse-ilp64=true + + - name: Test (ILP64) + run: spin test -- numpy/linalg + + + openblas_cmake: + if: "github.repository == 'numpy/numpy'" + runs-on: ubuntu-latest + name: "OpenBLAS with CMake" + steps: + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + with: + submodules: recursive + fetch-depth: 0 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + pip install -r build_requirements.txt + pip install pytest pytest-xdist hypothesis typing_extensions + sudo apt-get install libopenblas-dev cmake + sudo apt-get remove pkg-config + + - name: Build + run: spin build -- -Ddisable-optimization=true + + - name: Test + run: spin test -j auto -- numpy/linalg + + + netlib: + if: "github.repository == 'numpy/numpy'" + runs-on: ubuntu-latest + name: "Netlib BLAS/LAPACK" + steps: + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + with: + submodules: recursive + fetch-depth: 0 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + pip install -r build_requirements.txt + sudo apt-get install liblapack-dev pkg-config + + - name: Build + run: | + spin build -- -Ddisable-optimization=true + + - name: Test + run: | + pip install pytest pytest-xdist hypothesis typing_extensions + spin test -j auto -- numpy/linalg + + + mkl: + if: "github.repository == 'numpy/numpy'" + runs-on: ubuntu-latest + name: "MKL (LP64, ILP64, SDL)" + steps: + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + with: + submodules: recursive + fetch-depth: 0 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + pip install -r build_requirements.txt + pip install pytest pytest-xdist hypothesis typing_extensions + pip install mkl mkl-devel + + - name: Repair MKL pkg-config files and symlinks + run: | + # MKL 2023.2 works when installed from conda-forge (except for `-iomp` + # and `-tbb` pkg-config files), Spack, or with the standalone Intel + # installer. The standalone installer is the worst option, since it's + # large and clumsy to install and requires running a setvars.sh script + # before things work. The PyPI MKL packages are broken and need the + # fixes in this step. For details, see + # https://github.com/conda-forge/intel_repack-feedstock/issues/34 + cd $Python3_ROOT_DIR/lib/pkgconfig + sed -i 's/\/intel64//g' mkl*.pc + # add the expected .so -> .so.2 symlinks to fix linking + cd .. + for i in $( ls libmkl*.so.2 ); do ln -s $i ${i%.*}; done + + - name: Build with defaults (LP64) + run: | + pkg-config --libs mkl-dynamic-lp64-seq # check link flags + spin build -- -Ddisable-optimization=true + + - name: Test + run: spin test -- numpy/linalg + + - name: Build with ILP64 + run: | + git clean -xdf > /dev/null + pkg-config --libs mkl-dynamic-ilp64-seq + spin build -- -Duse-ilp64=true -Ddisable-optimization=true + + - name: Test + run: spin test -- numpy/linalg + + - name: Build without pkg-config (default options, SDL) + run: | + git clean -xdf > /dev/null + pushd $Python3_ROOT_DIR/lib/pkgconfig + rm mkl*.pc + popd + export MKLROOT=$Python3_ROOT_DIR + spin build -- -Ddisable-optimization=true + + - name: Test + run: spin test -- numpy/linalg + + blis: + if: "github.repository == 'numpy/numpy'" + runs-on: ubuntu-latest + name: "BLIS" + steps: + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + with: + submodules: recursive + fetch-depth: 0 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + pip install -r build_requirements.txt + pip install pytest pytest-xdist hypothesis typing_extensions + sudo apt-get install libblis-dev libopenblas-dev pkg-config + + - name: Add BLIS pkg-config file + run: | + # Needed because blis.pc missing in Debian: + # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=989076 + # The alternative here would be to use another distro or Miniforge + sudo cp tools/ci/_blis_debian.pc /usr/lib/x86_64-linux-gnu/pkgconfig/blis.pc + # Check if the patch works: + pkg-config --libs blis + pkg-config --cflags blis + + - name: Build + run: spin build -- -Dblas=blis -Ddisable-optimization=true + + - name: Test + run: spin test -- numpy/linalg + + atlas: + if: "github.repository == 'numpy/numpy'" + runs-on: ubuntu-latest + name: "ATLAS" + steps: + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + with: + submodules: recursive + fetch-depth: 0 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + pip install -r build_requirements.txt + pip install pytest pytest-xdist hypothesis typing_extensions + sudo apt-get install libatlas-base-dev pkg-config + + - name: Build + run: spin build -- -Dblas=blas-atlas -Dlapack=lapack-atlas -Ddisable-optimization=true + + - name: Test + run: spin test -- numpy/linalg + diff --git a/.github/workflows/linux_musl.yml b/.github/workflows/linux_musl.yml index 593549485ba0..890a0b0e046d 100644 --- a/.github/workflows/linux_musl.yml +++ b/.github/workflows/linux_musl.yml @@ -33,12 +33,12 @@ jobs: # using git commands to clone because versioneer doesn't work when # actions/checkout is used for the clone step in a container - git config --global --add safe.directory $PWD - + git config --global --add safe.directory $PWD + if [ $GITHUB_EVENT_NAME != pull_request ]; then git clone --recursive --branch=$GITHUB_REF_NAME https://github.com/${GITHUB_REPOSITORY}.git $GITHUB_WORKSPACE git reset --hard $GITHUB_SHA - else + else git clone --recursive https://github.com/${GITHUB_REPOSITORY}.git $GITHUB_WORKSPACE git fetch origin $GITHUB_REF:my_ref_name git checkout $GITHUB_BASE_REF @@ -54,14 +54,14 @@ jobs: source test_env/bin/activate # required for figuring out the system tags in openblas_support - pip install packaging - + pip install packaging + # install openblas by co-opting the CIBW setup script RUNNER_OS=Linux sh tools/wheels/cibw_before_build.sh . pip install -r build_requirements.txt pip install pytest pytest-xdist hypothesis typing_extensions - # use meson to build and test - spin build + # use meson to build and test + spin build --with-scipy-openblas=64 -- -Duse-ilp64=true spin test -j auto diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 29f141b10f9d..b34c86bec901 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -100,7 +100,7 @@ jobs: ccache -s accelerate: - name: Accelerate ILP64 + name: Accelerate (LP64, ILP64) if: "github.repository == 'numpy/numpy'" runs-on: macos-13 steps: @@ -122,14 +122,15 @@ jobs: pip install -r build_requirements.txt pip install pytest pytest-xdist hypothesis - - name: Build NumPy against Accelerate (ILP64) - run: | - spin build -- -Dblas=accelerate -Dlapack=accelerate -Duse-ilp64=true + - name: Build against Accelerate (LP64) + run: spin build -- -Ddisable-optimization=true - - name: Show meson-log.txt - if: always() - run: 'cat build/meson-logs/meson-log.txt' + - name: Test (linalg only) + run: spin test -j2 -- numpy/linalg - - name: Test + - name: Build NumPy against Accelerate (ILP64) run: | - spin test -j2 + spin build -- -Duse-ilp64=true + + - name: Test (fast tests) + run: spin test -j2 diff --git a/azure-steps-windows.yml b/azure-steps-windows.yml index 3fa6b18dc108..1cae980b4368 100644 --- a/azure-steps-windows.yml +++ b/azure-steps-windows.yml @@ -42,7 +42,10 @@ steps: python -m pip install . -v -Csetup-args="--vsenv" -Csetup-args="-Dblas=none" -Csetup-args="-Dlapack=none" -Csetup-args="-Dallow-noblas=true" } elseif ( Test-Path env:NPY_USE_BLAS_ILP64 ) { - python -m pip install . -v -Csetup-args="--vsenv" -Csetup-args="-Duse-ilp64=true" -Csetup-args="-Dblas-symbol-suffix=64_" + python -m pip install scipy-openblas64 spin + spin config-openblas --with-scipy-openblas=64 + $env:PKG_CONFIG_PATH="$pwd/.openblas" + python -m pip install . -v -Csetup-args="--vsenv" -Csetup-args="-Duse-ilp64=true" } else { python -m pip install . -v -Csetup-args="--vsenv" } diff --git a/build_requirements.txt b/build_requirements.txt index 7f598f623252..b1cfe0e68f49 100644 --- a/build_requirements.txt +++ b/build_requirements.txt @@ -2,5 +2,5 @@ meson-python>=0.13.1 Cython>=3.0 wheel==0.38.1 ninja -spin==0.5 +spin==0.7 build diff --git a/meson.build b/meson.build index 9ba86f393d6d..264160d132eb 100644 --- a/meson.build +++ b/meson.build @@ -12,8 +12,6 @@ project( 'b_ndebug=if-release', 'c_std=c99', 'cpp_std=c++17', - 'blas=openblas', - 'lapack=openblas', 'pkgconfig.relocatable=true', ], ) diff --git a/meson_options.txt b/meson_options.txt index 8b1fad6c4041..05e9e733578e 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,13 +1,19 @@ -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('blas', type: 'string', value: 'auto', + description: 'Option for BLAS library selection. By default, try to find any in the order given by `blas-order`') +option('lapack', type: 'string', value: 'auto', + description: 'Option for LAPACK library selection. By default, try to find any in the order given by `lapack-order`') option('allow-noblas', type: 'boolean', value: false, description: 'If set to true, allow building with (slow!) internal fallback routines') +option('blas-order', type: 'array', + value: ['mkl', 'accelerate', 'openblas', 'flexiblas', 'blis', 'blas']) +option('lapack-order', type: 'array', + value: ['mkl', 'accelerate', 'openblas', 'flexiblas', 'lapack']) 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('blas-symbol-suffix', type: 'string', value: 'auto', + description: 'BLAS and LAPACK symbol suffix to use, if any') +option('mkl-threading', type: 'string', value: 'auto', + description: 'MKL threading method, one of: `seq`, `iomp`, `gomp`, `tbb`') option('disable-svml', type: 'boolean', value: false, description: 'Disable building against SVML') option('disable-threading', type: 'boolean', value: false, diff --git a/numpy/core/src/common/npy_cblas.h b/numpy/core/src/common/npy_cblas.h index dad9599f605e..596a7c68cedd 100644 --- a/numpy/core/src/common/npy_cblas.h +++ b/numpy/core/src/common/npy_cblas.h @@ -57,8 +57,21 @@ enum CBLAS_SIDE {CblasLeft=141, CblasRight=142}; #define BLAS_FUNC_CONCAT(name,prefix,suffix,suffix2) prefix ## name ## suffix ## suffix2 #define BLAS_FUNC_EXPAND(name,prefix,suffix,suffix2) BLAS_FUNC_CONCAT(name,prefix,suffix,suffix2) -#define CBLAS_FUNC(name) BLAS_FUNC_EXPAND(name,BLAS_SYMBOL_PREFIX,,BLAS_SYMBOL_SUFFIX) +/* + * Use either the OpenBLAS scheme with the `64_` suffix behind the Fortran + * compiler symbol mangling, or the MKL scheme (and upcoming + * reference-lapack#666) which does it the other way around and uses `_64`. + */ +#ifdef OPENBLAS_ILP64_NAMING_SCHEME #define BLAS_FUNC(name) BLAS_FUNC_EXPAND(name,BLAS_SYMBOL_PREFIX,BLAS_FORTRAN_SUFFIX,BLAS_SYMBOL_SUFFIX) +#else +#define BLAS_FUNC(name) BLAS_FUNC_EXPAND(name,BLAS_SYMBOL_PREFIX,BLAS_SYMBOL_SUFFIX,BLAS_FORTRAN_SUFFIX) +#endif +/* + * Note that CBLAS doesn't include Fortran compiler symbol mangling, so ends up + * being the same in both schemes + */ +#define CBLAS_FUNC(name) BLAS_FUNC_EXPAND(name,BLAS_SYMBOL_PREFIX,,BLAS_SYMBOL_SUFFIX) #ifdef HAVE_BLAS_ILP64 #define CBLAS_INT npy_int64 diff --git a/numpy/meson.build b/numpy/meson.build index 150257d5b8b3..afeae9c2cc11 100644 --- a/numpy/meson.build +++ b/numpy/meson.build @@ -48,23 +48,18 @@ else ] endif -macOS13_3_or_later = false -if host_machine.system() == 'darwin' - r = run_command('xcrun', '-sdk', 'macosx', '--show-sdk-version', check: true) - sdkVersion = r.stdout().strip() - - macOS13_3_or_later = sdkVersion.version_compare('>=13.3') -endif - +blas_name = get_option('blas') +lapack_name = get_option('lapack') +allow_noblas = get_option('allow-noblas') # This is currently injected directly into CFLAGS/CXXFLAGS for wheel builds # (see cibuildwheel settings in pyproject.toml), but used by CI jobs already blas_symbol_suffix = get_option('blas-symbol-suffix') use_ilp64 = get_option('use-ilp64') if not use_ilp64 + # TODO: clean this up # For now, keep supporting the `NPY_USE_BLAS_ILP64` environment variable too - # (same as in setup.py) `false is the default for the CLI flag, so check if - # env var was set + # `false` is the default for the CLI flag, so check if env var was set use_ilp64 = run_command(py, [ '-c', @@ -74,130 +69,97 @@ if not use_ilp64 ).stdout().strip() == '1' endif +if use_ilp64 + blas_interface = ['interface: ilp64'] +else + blas_interface = ['interface: lp64'] +endif -# TODO: 64-bit (ILP64) BLAS and LAPACK support (e.g., check for more .pc files -# so we detect `openblas64_.so` directly). Partially supported now, needs more -# auto-detection. -# -# Note that this works as long as BLAS and LAPACK are detected properly via -# pkg-config. By default we look for OpenBLAS, other libraries can be configured via -# `meson configure -Dblas=blas -Dlapack=lapack` (example to build with Netlib -# BLAS and LAPACK). -# For MKL and for auto-detecting one of multiple libs, we'll need a custom -# dependency in Meson (like is done for scalapack) - see -# https://github.com/mesonbuild/meson/issues/2835 -blas_name = get_option('blas') -lapack_name = get_option('lapack') +# MKL-specific options +_threading_opt = get_option('mkl-threading') +if _threading_opt == 'auto' + # Switch default to iomp once conda-forge missing openmp.pc issue is fixed + mkl_opts = ['threading: seq'] +else + mkl_opts = ['threading: ' + _threading_opt] +endif +blas_opts = {'mkl': mkl_opts} +mkl_version_req = '>=2023.0' # see gh-24824 +mkl_may_use_sdl = not use_ilp64 and _threading_opt in ['auto', 'iomp'] -# pkg-config uses a lower-case name while CMake uses a capitalized name, so try -# that too to make the fallback detection with CMake work -if blas_name == 'openblas' - if use_ilp64 - _openblas_names = ['openblas64', 'openblas', 'OpenBLAS'] - else - _openblas_names = ['openblas', 'OpenBLAS'] +# Note that we can only use a BLAS which provides a CBLAS interface. So disable +# BLAS completely if CBLAS is not found. + +# First try scipy-openblas, and if found don't look for cblas or lapack, we +# know what's inside the scipy-openblas wheels already. +if blas_name == 'openblas' or blas_name == 'auto' + blas = dependency('scipy-openblas', required: false) + if blas.found() + blas_name = 'scipy-openblas' endif - blas = dependency(_openblas_names, required: false) -elif blas_name.to_lower() == 'accelerate' - # macOS 13.3+ has updated interfaces aligned with BLAS/LAPACK 3.9.1. Use them if available. - if macOS13_3_or_later - accelerate_compile_args = ['-DACCELERATE_NEW_LAPACK'] - if(use_ilp64) - accelerate_compile_args += '-DACCELERATE_LAPACK_ILP64' +endif +if blas_name == 'auto' + foreach _name : get_option('blas-order') + if _name == 'mkl' + blas = dependency('mkl', + modules: ['cblas'] + blas_interface + mkl_opts, + required: false, # may be required, but we need to emit a custom error message + version: mkl_version_req, + ) + # Insert a second try with MKL, because we may be rejecting older versions + # or missing it because no pkg-config installed. If so, we need to retry + # with MKL SDL, and drop the version constraint (this always worked). + if not blas.found() and mkl_may_use_sdl + blas = dependency('mkl', modules: ['cblas', 'sdl: true'], required: false) + endif + else + if _name == 'flexiblas' and use_ilp64 + _name = 'flexiblas64' + endif + blas = dependency(_name, modules: ['cblas'] + blas_interface, required: false) endif - blas = declare_dependency( - compile_args: accelerate_compile_args, - dependencies: dependency('Accelerate') - ) - else - if(use_ilp64) - error('macOS SDK 13.3+ is required for ILP64 support.') + if blas.found() + break endif - blas = dependency('Accelerate') - endif + endforeach else - blas = dependency(blas_name, required: false) -endif -have_blas = blas.found() -cblas = [] -if have_blas - # As noted above, at this point the BLAS_SYMBOL_SUFFIX may be injected into - # the CFLAGS directly, so this requires care to use that when it happens: - if blas_symbol_suffix != '' - probe_args = ['-DBLAS_SYMBOL_SUFFIX=' + blas_symbol_suffix] - else - probe_args = [] - endif - - # 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. 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. - have_cblas = false - if blas_name.to_lower() == 'accelerate' - _cblas_header = '' - elif blas_name.to_lower().startswith('mkl') - _cblas_header = '' - else - _cblas_header = '' - endif - if cc.links(f''' - #ifndef BLAS_SYMBOL_SUFFIX - # define BLAS_SYMBOL_SUFFIX - #endif - #define EXPAND(suffix) cblas_ddot ## suffix - #define DDOT(suffix) EXPAND(suffix) - - #include @_cblas_header@ - - int main(int argc, const char *argv[]) - { - double a[4] = {1,2,3,4}; - double b[4] = {5,6,7,8}; - return DDOT(BLAS_SYMBOL_SUFFIX)(4, a, 1, b, 1) > 10; - } - ''', - dependencies: blas, - args: probe_args, - name: 'CBLAS', + if blas_name == 'mkl' + blas = dependency('mkl', + modules: ['cblas'] + blas_interface + mkl_opts, + required: false, + version: mkl_version_req, ) - have_cblas = true - else - cblas = dependency('cblas', required: false) - if cblas.found() - have_cblas = true + # Same deal as above - try again for MKL + if not blas.found() and mkl_may_use_sdl + blas = dependency('mkl', modules: ['cblas', 'sdl: true'], required: false) endif + else + blas = dependency(blas_name, modules: ['cblas'] + blas_interface, required: false) endif endif -# BLAS and LAPACK are dependencies for NumPy. Since NumPy 2.0, by default the -# build will fail if they are missing; the performance impact is large, so -# using fallback routines must be explicitly opted into by the user. xref -# gh-24200 for a discussion on this. -# -# Note that we can only use a BLAS which provides a CBLAS interface. So disable -# BLAS completely if CBLAS is not found. -allow_noblas = get_option('allow-noblas') +have_blas = blas.found() if have_blas - _args_blas = [] # note: used for C and C++ via `blas_dep` below - if have_cblas - _args_blas += ['-DHAVE_CBLAS'] - elif not allow_noblas - error('No CBLAS interface detected! Install a BLAS library with CBLAS ' + \ - 'support, or use the `allow-noblas` build option (note, this ' + \ - 'may be up to 100x slower for some linear algebra operations).') - endif + _args_blas = ['-DHAVE_CBLAS'] # note: used for C and C++ via `blas_dep` below if use_ilp64 _args_blas += ['-DHAVE_BLAS_ILP64'] + if 'openblas' in blas.name() + _args_blas += ['-DOPENBLAS_ILP64_NAMING_SCHEME'] + endif + endif + if blas_symbol_suffix == 'auto' + if blas_name == 'scipy-openblas' and use_ilp64 + blas_symbol_suffix = '64_' + else + blas_symbol_suffix = blas.get_variable('symbol_suffix', default_value: '') + endif + message(f'BLAS symbol suffix: @blas_symbol_suffix@') endif if blas_symbol_suffix != '' _args_blas += ['-DBLAS_SYMBOL_SUFFIX=' + blas_symbol_suffix] endif blas_dep = declare_dependency( - dependencies: [blas, cblas], + dependencies: [blas], compile_args: _args_blas, ) else @@ -210,35 +172,33 @@ else endif endif -if lapack_name == 'openblas' - lapack_dep = dependency(['openblas', 'OpenBLAS'], required: false) -elif lapack_name.to_lower() == 'accelerate' - # macOS 13.3+ has updated interfaces aligned with BLAS/LAPACK 3.9.1. Use them if available. - if macOS13_3_or_later - accelerate_compile_args = ['-DACCELERATE_NEW_LAPACK'] - if(use_ilp64) - accelerate_compile_args += '-DACCELERATE_LAPACK_ILP64' - endif - lapack_dep = declare_dependency( - compile_args: accelerate_compile_args, - dependencies: dependency('Accelerate') - ) +if 'mkl' in blas.name() or blas.name() == 'accelerate' or blas_name == 'scipy-openblas' + # For these libraries we know that they contain LAPACK, and it's desirable to + # use that - no need to run the full detection twice. + lapack = blas +else + if lapack_name == 'auto' + foreach _name : get_option('lapack-order') + lapack = dependency(_name, modules: ['lapack'] + blas_interface, required: false) + if lapack.found() + break + endif + endforeach else - if(use_ilp64) - error('macOS SDK 13.3+ is required for ILP64 support.') - endif - lapack_dep = dependency('Accelerate') + lapack = dependency(lapack_name, modules: ['lapack'] + blas_interface, required: false) endif -else - lapack_dep = dependency(lapack_name, required: false) endif -have_lapack = lapack_dep.found() + +have_lapack = lapack.found() if not have_lapack and not allow_noblas error('No LAPACK library detected! Install one, or use the ' + \ '`allow-noblas` build option (note, this may be up to 100x slower ' + \ 'for some linear algebra operations).') +else + lapack_dep = declare_dependency(dependencies: [lapack, blas_dep]) endif + # Copy the main __init__.py|pxd files to the build dir (needed for Cython) __init__py = fs.copyfile('__init__.py') __init__pxd = fs.copyfile('__init__.pxd') @@ -377,7 +337,7 @@ conf_data.set('PYTHON_VERSION', py.language_version()) dependency_map = { 'LAPACK': lapack_dep, } -if have_blas and have_cblas +if have_blas dependency_map += {'BLAS': blas} else conf_data.set('BLAS_NAME', blas_name) @@ -391,13 +351,11 @@ foreach name, dep : dependency_map if dep.found() conf_data.set(name + '_VERSION', dep.version()) conf_data.set(name + '_TYPE_NAME', dep.type_name()) - 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 + # get_variable() results may be missing for a variety of reasons + conf_data.set(name + '_INCLUDEDIR', dep.get_variable('includedir', default_value: 'unknown')) + conf_data.set(name + '_LIBDIR', dep.get_variable('libdir', default_value: 'unknown')) + conf_data.set(name + '_OPENBLAS_CONFIG', dep.get_variable('openblas_config', default_value: 'unknown')) + conf_data.set(name + '_PCFILEDIR', dep.get_variable('pcfiledir', default_value: 'unknown')) endif endforeach diff --git a/pyproject.toml b/pyproject.toml index c8620c90f4e7..4cbe74221c9e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -152,6 +152,7 @@ tracker = "https://github.com/numpy/numpy/issues" skip = "cp36-* cp37-* cp-38* pp37-* pp38-* *-manylinux_i686 *_ppc64le *_s390x *-musllinux_aarch64" build-verbosity = "3" before-build = "bash {project}/tools/wheels/cibw_before_build.sh {project}" +config-settings = "setup-args=-Duse-ilp64=true setup-args=-Dblas=openblas setup-args=-Dlapack=openblas setup-args=-Dblas-symbol-suffix=64_" # meson has a hard dependency on ninja, and we need meson to build # c-extensions in tests. There is a ninja PyPI package used in # build_requirements.txt for macOS, windows, linux but it cannot be in @@ -164,7 +165,7 @@ test-command = "bash {project}/tools/wheels/cibw_test_command.sh {project}" manylinux-x86_64-image = "manylinux2014" manylinux-aarch64-image = "manylinux2014" musllinux-x86_64-image = "musllinux_1_1" -environment = { CFLAGS="-fno-strict-aliasing -DBLAS_SYMBOL_SUFFIX=64_ -DHAVE_BLAS_ILP64", LDFLAGS="-Wl,--strip-debug", CXXFLAGS="-DBLAS_SYMBOL_SUFFIX=64_ -DHAVE_BLAS_ILP64", NPY_USE_BLAS_ILP64="1", RUNNER_OS="Linux"} +environment = {CFLAGS="-fno-strict-aliasing", LDFLAGS="-Wl,--strip-debug", NPY_USE_BLAS_ILP64="1", RUNNER_OS="Linux"} [tool.cibuildwheel.macos] # For universal2 wheels, we will need to fuse them manually @@ -174,12 +175,13 @@ environment = { CFLAGS="-fno-strict-aliasing -DBLAS_SYMBOL_SUFFIX=64_ -DHAVE_BLA # for more info archs = "x86_64 arm64" test-skip = "*_universal2:arm64" -# MACOS linker doesn't support stripping symbols -environment = {CFLAGS="-fno-strict-aliasing -DBLAS_SYMBOL_SUFFIX=64_ -DHAVE_BLAS_ILP64", CXXFLAGS="-DBLAS_SYMBOL_SUFFIX=64_ -DHAVE_BLAS_ILP64", NPY_USE_BLAS_ILP64="1", CC="clang", CXX = "clang++", RUNNER_OS="macOS"} +# MACOS linker doesn't support stripping symbols. +# Note that NPY_USE_BLAS_ILP64 is used in `tools/openblas_support.py`. +environment = {CFLAGS="-fno-strict-aliasing", CC="clang", CXX = "clang++", NPY_USE_BLAS_ILP64="1", RUNNER_OS="macOS"} [tool.cibuildwheel.windows] -environment = {NPY_USE_BLAS_ILP64="1", CFLAGS="-DBLAS_SYMBOL_SUFFIX=64_ -DHAVE_BLAS_ILP64", CXXFLAGS="-DBLAS_SYMBOL_SUFFIX=64_ -DHAVE_BLAS_ILP64", LDFLAGS="", PKG_CONFIG_PATH="C:/opt/64/lib/pkgconfig"} -config-settings = "setup-args=--vsenv" +environment = {NPY_USE_BLAS_ILP64="1", PKG_CONFIG_PATH="C:/opt/64/lib/pkgconfig"} +config-settings = "setup-args=--vsenv setup-args=-Duse-ilp64=true setup-args=-Dblas=openblas setup-args=-Dlapack=openblas" repair-wheel-command = "bash ./tools/wheels/repair_windows.sh {wheel} {dest_dir}" [[tool.cibuildwheel.overrides]] diff --git a/tools/ci/_blis_debian.pc b/tools/ci/_blis_debian.pc new file mode 100644 index 000000000000..b849b50f6b1f --- /dev/null +++ b/tools/ci/_blis_debian.pc @@ -0,0 +1,8 @@ +libdir=/usr/lib/x86_64-linux-gnu/blis-pthread/ +includedir=/usr/include/x86_64-linux-gnu/blis-pthread + +Name: BLIS +Description: BLAS-like Library Instantiation Software Framework - specific to NumPy CI job, needed until Debian ships blis.pc (see .github/workflows/linux_blas.yml) +Version: 0.9.0-numpy-ci +Libs: -L${libdir} -lblis +Cflags: -I${includedir} diff --git a/vendored-meson/meson b/vendored-meson/meson index b7dc7abc4102..66ba7dbbfe28 160000 --- a/vendored-meson/meson +++ b/vendored-meson/meson @@ -1 +1 @@ -Subproject commit b7dc7abc4102ec3db4bb9066cb5e674e7a4b08f4 +Subproject commit 66ba7dbbfe2838983f65ad8fe16da1535ebf5b9d From 34ea7a8b75f46b139a6afe46bba3a9ffd4ee5a68 Mon Sep 17 00:00:00 2001 From: Charles Harris Date: Tue, 10 Oct 2023 16:25:36 -0600 Subject: [PATCH 27/38] MAINT: Update ``spin/cmds.py`` from main. --- .spin/cmds.py | 157 ++++++++++++++++++++------------------------------ 1 file changed, 61 insertions(+), 96 deletions(-) diff --git a/.spin/cmds.py b/.spin/cmds.py index ea994c38311e..09556e67bbce 100644 --- a/.spin/cmds.py +++ b/.spin/cmds.py @@ -37,9 +37,14 @@ "-v", "--verbose", is_flag=True, help="Print all build output, even installation" ) +@click.option( + "--with-scipy-openblas", type=click.Choice(["32", "64"]), + default=None, + help="Build with pre-installed scipy-openblas32 or scipy-openblas64 wheel" +) @click.argument("meson_args", nargs=-1) @click.pass_context -def build(ctx, meson_args, jobs=None, clean=False, verbose=False): +def build(ctx, meson_args, with_scipy_openblas, jobs=None, clean=False, verbose=False, quiet=False): """🔧 Build package with Meson/ninja and install MESON_ARGS are passed through e.g.: @@ -53,6 +58,10 @@ def build(ctx, meson_args, jobs=None, clean=False, verbose=False): CFLAGS="-O0 -g" spin build """ + # XXX keep in sync with upstream build + if with_scipy_openblas: + _config_openblas(with_scipy_openblas) + ctx.params.pop("with_scipy_openblas", None) ctx.forward(meson.build) @@ -187,51 +196,6 @@ def test(ctx, pytest_args, markexpr, n_jobs, tests, verbose): ctx.forward(meson.test) -@click.command() -@click.option('--code', '-c', help='Python program passed in as a string') -@click.argument('gdb_args', nargs=-1) -def gdb(code, gdb_args): - """👾 Execute a Python snippet with GDB - - spin gdb -c 'import numpy as np; print(np.__version__)' - - Or pass arguments to gdb: - - spin gdb -c 'import numpy as np; print(np.__version__)' -- --fullname - - Or run another program, they way you normally would with gdb: - - \b - spin gdb ls - spin gdb -- --args ls -al - - You can also run Python programs: - - \b - spin gdb my_tests.py - spin gdb -- my_tests.py --mytest-flag - """ - meson._set_pythonpath() - gdb_args = list(gdb_args) - - if gdb_args and gdb_args[0].endswith('.py'): - gdb_args = ['--args', sys.executable] + gdb_args - - if sys.version_info[:2] >= (3, 11): - PYTHON_FLAGS = ['-P'] - code_prefix = '' - else: - PYTHON_FLAGS = [] - code_prefix = 'import sys; sys.path.pop(0); ' - - if code: - PYTHON_ARGS = ['-c', code_prefix + code] - gdb_args += ['--args', sys.executable] + PYTHON_FLAGS + PYTHON_ARGS - - gdb_cmd = ['gdb', '-ex', 'set detach-on-fork on'] + gdb_args - util.run(gdb_cmd, replace=True) - - # From scipy: benchmarks/benchmarks/common.py def _set_mem_rlimit(max_mem=None): """ @@ -297,19 +261,7 @@ def _run_asv(cmd): except (ImportError, RuntimeError): pass - try: - util.run(cmd, cwd='benchmarks', env=env, sys_exit=False) - except FileNotFoundError: - click.secho(( - "Cannot find `asv`. " - "Please install Airspeed Velocity:\n\n" - " https://asv.readthedocs.io/en/latest/installing.html\n" - "\n" - "Depending on your system, one of the following should work:\n\n" - " pip install asv\n" - " conda install asv\n" - ), fg="red") - sys.exit(1) + util.run(cmd, cwd='benchmarks', env=env) @click.command() @@ -330,13 +282,17 @@ def _run_asv(cmd): @click.option( '--verbose', '-v', is_flag=True, default=False ) +@click.option( + '--quick', '-q', is_flag=True, default=False, + help="Run each benchmark only once (timings won't be accurate)" +) @click.argument( 'commits', metavar='', required=False, nargs=-1 ) @click.pass_context -def bench(ctx, tests, compare, verbose, commits): +def bench(ctx, tests, compare, verbose, quick, commits): """🏋 Run benchmarks. \b @@ -376,6 +332,9 @@ def bench(ctx, tests, compare, verbose, commits): if verbose: bench_args = ['-v'] + bench_args + if quick: + bench_args = ['--quick'] + bench_args + if not compare: # No comparison requested; we build and benchmark the current version @@ -403,27 +362,21 @@ def bench(ctx, tests, compare, verbose, commits): cmd = [ 'asv', 'run', '--dry-run', '--show-stderr', '--python=same' ] + bench_args - _run_asv(cmd) - else: - # Benchmark comparison - # Ensure that we don't have uncommited changes commit_a, commit_b = [_commit_to_sha(c) for c in commits] - if commit_b == 'HEAD': - if _dirty_git_working_dir(): - click.secho( - "WARNING: you have uncommitted changes --- " - "these will NOT be benchmarked!", - fg="red" - ) + if commit_b == 'HEAD' and _dirty_git_working_dir(): + click.secho( + "WARNING: you have uncommitted changes --- " + "these will NOT be benchmarked!", + fg="red" + ) cmd_compare = [ 'asv', 'continuous', '--factor', '1.05', ] + bench_args + [commit_a, commit_b] - _run_asv(cmd_compare) @@ -441,7 +394,6 @@ def python(ctx, python_args): """ env = os.environ env['PYTHONWARNINGS'] = env.get('PYTHONWARNINGS', 'all') - ctx.invoke(build) ctx.forward(meson.python) @@ -472,29 +424,6 @@ def ipython(ctx, ipython_args): list(ipython_args)) -@click.command(context_settings={"ignore_unknown_options": True}) -@click.argument("args", nargs=-1) -@click.pass_context -def run(ctx, args): - """🏁 Run a shell command with PYTHONPATH set - - \b - spin run make - spin run 'echo $PYTHONPATH' - spin run python -c 'import sys; del sys.path[0]; import mypkg' - - If you'd like to expand shell variables, like `$PYTHONPATH` in the example - above, you need to provide a single, quoted command to `run`: - - spin run 'echo $SHELL && echo $PWD' - - On Windows, all shell commands are run via Bash. - Install Git for Windows if you don't have Bash already. - """ - ctx.invoke(build) - ctx.forward(meson.run) - - @click.command(context_settings={"ignore_unknown_options": True}) @click.pass_context def mypy(ctx): @@ -505,3 +434,39 @@ def mypy(ctx): ctx.params['pytest_args'] = [os.path.join('numpy', 'typing')] ctx.params['markexpr'] = 'full' ctx.forward(test) + +@click.command(context_settings={ + 'ignore_unknown_options': True +}) +@click.option( + "--with-scipy-openblas", type=click.Choice(["32", "64"]), + default=None, required=True, + help="Build with pre-installed scipy-openblas32 or scipy-openblas64 wheel" +) +def config_openblas(with_scipy_openblas): + """🔧 Create .openblas/scipy-openblas.pc file + + Also create _distributor_init_local.py + + Requires a pre-installed scipy-openblas64 or scipy-openblas32 + """ + _config_openblas(with_scipy_openblas) + + +def _config_openblas(blas_variant): + import importlib + basedir = os.getcwd() + openblas_dir = os.path.join(basedir, ".openblas") + pkg_config_fname = os.path.join(openblas_dir, "scipy-openblas.pc") + if blas_variant: + module_name = f"scipy_openblas{blas_variant}" + try: + openblas = importlib.import_module(module_name) + except ModuleNotFoundError: + raise RuntimeError(f"'pip install {module_name} first") + local = os.path.join(basedir, "numpy", "_distributor_init_local.py") + with open(local, "wt", encoding="utf8") as fid: + fid.write(f"import {module_name}\n") + os.makedirs(openblas_dir, exist_ok=True) + with open(pkg_config_fname, "wt", encoding="utf8") as fid: + fid.write(openblas.get_pkg_config().replace("\\", "/")) From 5134f9aa830edbbc2585aabfa70a977fce11068e Mon Sep 17 00:00:00 2001 From: Charles Harris Date: Tue, 10 Oct 2023 17:38:17 -0600 Subject: [PATCH 28/38] MAINT: Use `linux_musl.yml` from main. --- .github/workflows/linux_musl.yml | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/.github/workflows/linux_musl.yml b/.github/workflows/linux_musl.yml index 890a0b0e046d..5c65a2b2e8b9 100644 --- a/.github/workflows/linux_musl.yml +++ b/.github/workflows/linux_musl.yml @@ -33,12 +33,12 @@ jobs: # using git commands to clone because versioneer doesn't work when # actions/checkout is used for the clone step in a container - git config --global --add safe.directory $PWD - + git config --global --add safe.directory $PWD + if [ $GITHUB_EVENT_NAME != pull_request ]; then git clone --recursive --branch=$GITHUB_REF_NAME https://github.com/${GITHUB_REPOSITORY}.git $GITHUB_WORKSPACE git reset --hard $GITHUB_SHA - else + else git clone --recursive https://github.com/${GITHUB_REPOSITORY}.git $GITHUB_WORKSPACE git fetch origin $GITHUB_REF:my_ref_name git checkout $GITHUB_BASE_REF @@ -48,20 +48,22 @@ jobs: ln -s /usr/local/bin/python3.10 /usr/local/bin/python - - name: test musllinux_x86_64 + - name: test-musllinux_x86_64 + env: + PKG_CONFIG_PATH: ${{ github.workspace }}/.openblas run: | python -m venv test_env source test_env/bin/activate - # required for figuring out the system tags in openblas_support - pip install packaging - - # install openblas by co-opting the CIBW setup script - RUNNER_OS=Linux sh tools/wheels/cibw_before_build.sh . + pip install scipy-openblas64 - pip install -r build_requirements.txt - pip install pytest pytest-xdist hypothesis typing_extensions + pip install -r build_requirements.txt -r test_requirements.txt - # use meson to build and test + # use meson to build and test spin build --with-scipy-openblas=64 -- -Duse-ilp64=true spin test -j auto + + - name: Meson Log + shell: bash + run: | + cat build/meson-logs/meson-log.txt From a6f9ebb7afec8e1f03fcfe6d581e1fc548529197 Mon Sep 17 00:00:00 2001 From: Charles Harris Date: Tue, 10 Oct 2023 18:15:40 -0600 Subject: [PATCH 29/38] MAINT: Update ``pyproject.toml`` --- pyproject.toml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 4cbe74221c9e..cfe077d5983a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,6 +66,7 @@ documentation = "https://numpy.org/doc/" source = "https://github.com/numpy/numpy" download = "https://pypi.org/project/numpy/#files" tracker = "https://github.com/numpy/numpy/issues" +"release notes" = "https://numpy.org/doc/stable/release" [tool.towncrier] # Do no set this since it is hard to import numpy inside the source directory @@ -201,10 +202,11 @@ cli = 'vendored-meson/meson/meson.py' ".spin/cmds.py:build", ".spin/cmds.py:test", ".spin/cmds.py:mypy", + ".spin/cmds.py:config_openblas", ] "Environments" = [ - ".spin/cmds.py:run", ".spin/cmds.py:ipython", - ".spin/cmds.py:python", ".spin/cmds.py:gdb" + "spin.cmds.meson.run", ".spin/cmds.py:ipython", + ".spin/cmds.py:python", "spin.cmds.meson.gdb" ] "Documentation" = [".spin/cmds.py:docs"] "Metrics" = [".spin/cmds.py:bench"] From e8aca7cdaada125453d4ff5c50bc603bb14aca7b Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Wed, 11 Oct 2023 12:08:26 +0200 Subject: [PATCH 30/38] DEV: backport `_distributor_init.py` change to support scipy-openblas This should fix the MUSL CI job failure after the Meson auto-BLAS/LAPACK update. --- numpy/_distributor_init.py | 7 ++++++- numpy/meson.build | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/numpy/_distributor_init.py b/numpy/_distributor_init.py index d893ba37719b..25b0eed79fca 100644 --- a/numpy/_distributor_init.py +++ b/numpy/_distributor_init.py @@ -3,8 +3,13 @@ Distributors: you can add custom code here to support particular distributions of numpy. -For example, this is a good place to put any checks for hardware requirements. +For example, this is a good place to put any BLAS/LAPACK initialization code. The numpy standard source distribution will not put code in this file, so you can safely replace this file with your own version. """ + +try: + from . import _distributor_init_local +except ImportError: + pass diff --git a/numpy/meson.build b/numpy/meson.build index afeae9c2cc11..fc10acb5eb5a 100644 --- a/numpy/meson.build +++ b/numpy/meson.build @@ -225,6 +225,10 @@ python_sources = [ 'py.typed' ] +if blas_name == 'scipy-openblas' + python_sources += ['_distributor_init_local.py'] +endif + py.install_sources( python_sources, subdir: 'numpy' From 891fb2213ca7919f48e7e7705ad1be0b681df330 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Wed, 11 Oct 2023 11:59:03 +0200 Subject: [PATCH 31/38] BLD: update setup.py build for changes to ILP64 build config [skip circle] [skip cirrus] --- numpy/distutils/system_info.py | 5 ++++- numpy/linalg/setup.py | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/numpy/distutils/system_info.py b/numpy/distutils/system_info.py index edf56909ab5d..feb28f61cf07 100644 --- a/numpy/distutils/system_info.py +++ b/numpy/distutils/system_info.py @@ -2357,7 +2357,10 @@ def _calc_info(self): if self.symbol_prefix: info['define_macros'] += [('BLAS_SYMBOL_PREFIX', self.symbol_prefix)] if self.symbol_suffix: - info['define_macros'] += [('BLAS_SYMBOL_SUFFIX', self.symbol_suffix)] + info['define_macros'] += [ + ('BLAS_SYMBOL_SUFFIX', self.symbol_suffix), + ('OPENBLAS_ILP64_NAMING_SCHEME', None), + ] return info diff --git a/numpy/linalg/setup.py b/numpy/linalg/setup.py index 6f72635ab67f..e357e294f797 100644 --- a/numpy/linalg/setup.py +++ b/numpy/linalg/setup.py @@ -51,7 +51,8 @@ def calc_info(self): # but use the "64_" convention here. info['define_macros'] = [ ('HAVE_BLAS_ILP64', None), - ('BLAS_SYMBOL_SUFFIX', '64_') + ('BLAS_SYMBOL_SUFFIX', '64_'), + ('OPENBLAS_ILP64_NAMING_SCHEME', None), ] self.set_info(**info) From 067cf772728ee1ee24dfef440de83dce8487d12d Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Wed, 11 Oct 2023 20:50:47 +0200 Subject: [PATCH 32/38] DOC: add a 1.26.1 release notes section for BLAS/LAPACK build changes [skip cirrus] [skip actions] [skip azp] [skip travis] --- doc/source/release/1.26.1-notes.rst | 56 +++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/doc/source/release/1.26.1-notes.rst b/doc/source/release/1.26.1-notes.rst index 9d415a463f84..a3d7ce1f3082 100644 --- a/doc/source/release/1.26.1-notes.rst +++ b/doc/source/release/1.26.1-notes.rst @@ -3,6 +3,58 @@ ========================== NumPy 1.26.1 Release Notes ========================== + NumPy 1.26.1 is a maintenance release that fixes bugs and regressions -discovered after the 1.26.0 release. This is the last planned release in the -The Python versions supported by this release are 3.9-3.12. +discovered after the 1.26.0 release. In addition, it adds new functionality for +detecting BLAS and LAPACK when building from source. The 1.26.release series is +the last planned minor release series before NumPy 2.0. The Python versions +supported by this release are 3.9-3.12. + + +Build system changes +==================== + +Improved BLAS/LAPACK detection and control +------------------------------------------ + +Auto-detection for a number of BLAS and LAPACK is now implemented for Meson. +By default, the build system will try to detect MKL, Accelerate (on macOS +>=13.3), OpenBLAS, FlexiBLAS, BLIS and reference BLAS/LAPACK. Support for MKL +was significantly improved, and support for FlexiBLAS was added. + +New command-line flags are available to further control the selection of the +BLAS and LAPACK libraries to build against. + +To select a specific library, use the config-settings interface via ``pip`` or +``pypa/build``. E.g., to select ``libblas``/``liblapack``, use:: + + $ pip install numpy -Csetup-args=-Dblas=blas -Csetup-args=-Dlapack=lapack + $ # OR + $ python -m build . -Csetup-args=-Dblas=blas -Csetup-args=-Dlapack=lapack + +This works not only for the libraries named above, but for any library that +Meson is able to detect with the given name through ``pkg-config`` or CMake. + +Besides ``-Dblas`` and ``-Dlapack``, a number of other new flags are available +to control BLAS/LAPACK selection and behavior: + +- ``-Dblas-order`` and ``-Dlapack-order``: a list of library names to search + for in order, overriding the default search order. +- ``-Duse-ilp64``: if set to ``true``, use ILP64 (64-bit integer) BLAS and + LAPACK. Note that with this release, ILP64 support has been extended to + include MKL and FlexiBLAS. OpenBLAS and Accelerate were supported in previous + releases. +- ``-Dallow-noblas``: if set to ``true``, allow NumPy to build with its + internal (very slow) fallback routines instead of linking against an external + BLAS/LAPACK library. *The default for this flag may be changed to ``false`` + in a future 1.26.x release, however for 1.26.1 we'd prefer to keep it as + ``true`` because if failures to detect an installed library are happening, + we'd like a bug report for that, so we can quickly assess whether the new + auto-detection machinery needs further improvements.* +- ``-Dmkl-threading``: to select the threading layer for MKL. There are four + options: ``seq``, ``iomp``, ``gomp`` and ``tbb``. The default is ``auto``, + which selects from those four as appropriate given the version of MKL + selected. +- ``-Dblas-symbol-suffix``: manually select the symbol suffix to use for the + library - should only be needed for linking against libraries built in a + non-standard way. From bd780908cec25e68914d4d75446b669812b2146a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Sok=C3=B3=C5=82?= Date: Thu, 12 Oct 2023 12:15:40 +0200 Subject: [PATCH 33/38] MAINT: Backport numpy._core stubs. Remove NumpyUnpickler --- .../upcoming_changes/24870.new_feature.rst | 6 --- .../upcoming_changes/24906.new_feature.rst | 6 +++ doc/source/reference/routines.io.rst | 1 - doc/source/user/how-to-io.rst | 6 +-- numpy/_core/__init__.py | 4 ++ numpy/_core/__init__.pyi | 0 numpy/_core/_dtype.py | 6 +++ numpy/_core/_dtype_ctypes.py | 6 +++ numpy/_core/_internal.py | 6 +++ numpy/_core/_multiarray_umath.py | 6 +++ numpy/_core/multiarray.py | 6 +++ numpy/_core/umath.py | 6 +++ numpy/core/tests/data/numpy_2_0_array.pkl | Bin 0 -> 718 bytes numpy/core/tests/test_numpy_2_0_compat.py | 48 ++++++++++++++++++ numpy/lib/format.py | 16 +----- numpy/lib/format.pyi | 3 -- numpy/lib/npyio.py | 2 +- numpy/meson.build | 1 + numpy/setup.py | 1 + 19 files changed, 101 insertions(+), 29 deletions(-) delete mode 100644 doc/release/upcoming_changes/24870.new_feature.rst create mode 100644 doc/release/upcoming_changes/24906.new_feature.rst create mode 100644 numpy/_core/__init__.py create mode 100644 numpy/_core/__init__.pyi create mode 100644 numpy/_core/_dtype.py create mode 100644 numpy/_core/_dtype_ctypes.py create mode 100644 numpy/_core/_internal.py create mode 100644 numpy/_core/_multiarray_umath.py create mode 100644 numpy/_core/multiarray.py create mode 100644 numpy/_core/umath.py create mode 100644 numpy/core/tests/data/numpy_2_0_array.pkl create mode 100644 numpy/core/tests/test_numpy_2_0_compat.py diff --git a/doc/release/upcoming_changes/24870.new_feature.rst b/doc/release/upcoming_changes/24870.new_feature.rst deleted file mode 100644 index 82d4015ff05f..000000000000 --- a/doc/release/upcoming_changes/24870.new_feature.rst +++ /dev/null @@ -1,6 +0,0 @@ -`numpy.lib.format.NumpyUnpickler` ---------------------------------- - -`numpy.lib.format.NumpyUnpickler` class was added -that provides a stable way for loading pickled arrays, -created with NumPy 2.0, with Numpy 1.26. diff --git a/doc/release/upcoming_changes/24906.new_feature.rst b/doc/release/upcoming_changes/24906.new_feature.rst new file mode 100644 index 000000000000..44c73a7b9490 --- /dev/null +++ b/doc/release/upcoming_changes/24906.new_feature.rst @@ -0,0 +1,6 @@ +`numpy._core` submodules' stubs +------------------------------- + +`numpy._core` submodules' stubs were added +to provide a stable way for loading pickled arrays, +created with NumPy 2.0, with Numpy 1.26. diff --git a/doc/source/reference/routines.io.rst b/doc/source/reference/routines.io.rst index 93a2da9495d0..1ec2ccb5eea4 100644 --- a/doc/source/reference/routines.io.rst +++ b/doc/source/reference/routines.io.rst @@ -14,7 +14,6 @@ NumPy binary files (NPY, NPZ) save savez savez_compressed - lib.format.NumpyUnpickler The format of these binary file types is documented in :py:mod:`numpy.lib.format` diff --git a/doc/source/user/how-to-io.rst b/doc/source/user/how-to-io.rst index 55070ff5e727..8d8bdd7d4f5b 100644 --- a/doc/source/user/how-to-io.rst +++ b/doc/source/user/how-to-io.rst @@ -319,10 +319,8 @@ Use :func:`numpy.save` and :func:`numpy.load`. Set ``allow_pickle=False``, unless the array dtype includes Python objects, in which case pickling is required. -:func:`numpy.load` also supports unpickling files created with NumPy 2.0. -If you try to unpickle a 2.0 pickled array directly, you will get -an exception. Use :class:`numpy.lib.format.NumpyUnpickler` for -unpickling these files. +NumPy 1.26 also supports unpickling files created with NumPy 2.0, either +via :func:`numpy.load` or the pickle module directly. Convert from a pandas DataFrame to a NumPy array ================================================ diff --git a/numpy/_core/__init__.py b/numpy/_core/__init__.py new file mode 100644 index 000000000000..a2f096f3f174 --- /dev/null +++ b/numpy/_core/__init__.py @@ -0,0 +1,4 @@ +""" +This private module only contains stubs for interoperability with +NumPy 2.0 pickled arrays. It may not be used by the end user. +""" diff --git a/numpy/_core/__init__.pyi b/numpy/_core/__init__.pyi new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/numpy/_core/_dtype.py b/numpy/_core/_dtype.py new file mode 100644 index 000000000000..974d93d98cbb --- /dev/null +++ b/numpy/_core/_dtype.py @@ -0,0 +1,6 @@ +from numpy.core import _dtype + +_globals = globals() + +for item in _dtype.__dir__(): + _globals[item] = getattr(_dtype, item) diff --git a/numpy/_core/_dtype_ctypes.py b/numpy/_core/_dtype_ctypes.py new file mode 100644 index 000000000000..bfa16aabf423 --- /dev/null +++ b/numpy/_core/_dtype_ctypes.py @@ -0,0 +1,6 @@ +from numpy.core import _dtype_ctypes + +_globals = globals() + +for item in _dtype_ctypes.__dir__(): + _globals[item] = getattr(_dtype_ctypes, item) diff --git a/numpy/_core/_internal.py b/numpy/_core/_internal.py new file mode 100644 index 000000000000..52a8e907292e --- /dev/null +++ b/numpy/_core/_internal.py @@ -0,0 +1,6 @@ +from numpy.core import _internal + +_globals = globals() + +for item in _internal.__dir__(): + _globals[item] = getattr(_internal, item) diff --git a/numpy/_core/_multiarray_umath.py b/numpy/_core/_multiarray_umath.py new file mode 100644 index 000000000000..7ce48fcb258d --- /dev/null +++ b/numpy/_core/_multiarray_umath.py @@ -0,0 +1,6 @@ +from numpy.core import _multiarray_umath + +_globals = globals() + +for item in _multiarray_umath.__dir__(): + _globals[item] = getattr(_multiarray_umath, item) diff --git a/numpy/_core/multiarray.py b/numpy/_core/multiarray.py new file mode 100644 index 000000000000..6c37d1da9fe7 --- /dev/null +++ b/numpy/_core/multiarray.py @@ -0,0 +1,6 @@ +from numpy.core import multiarray + +_globals = globals() + +for item in multiarray.__dir__(): + _globals[item] = getattr(multiarray, item) diff --git a/numpy/_core/umath.py b/numpy/_core/umath.py new file mode 100644 index 000000000000..3d08c90332a3 --- /dev/null +++ b/numpy/_core/umath.py @@ -0,0 +1,6 @@ +from numpy.core import umath + +_globals = globals() + +for item in umath.__dir__(): + _globals[item] = getattr(umath, item) diff --git a/numpy/core/tests/data/numpy_2_0_array.pkl b/numpy/core/tests/data/numpy_2_0_array.pkl new file mode 100644 index 0000000000000000000000000000000000000000..958eee50c9a6a630844801fe190562b3f8d3477c GIT binary patch literal 718 zcmXYte=HPW7{~7%Y4=CX%wngtjLmI+rgc-$Ylz#oSo0yX=6*%cdGdoJVrU6DY_Py&vNB4dEw>%8`9-P zc@lQMCEwzlACJLfQiGK%kHu#OL`O$QY|;9+@fdPZ<>@dB1|vAmhjXkOkTt9+-sl2s zP~~+-679Ibb!UlV?h^sMF96f-6dZBr0JK*nMCqFVyPeJaxf;M)@hRcGHo#|VKQp`s z0o8806q_MHWlU}2?O{NUr^$KO2;iGmb8h@7ptt?reO^@8mJTHEp?ck;(dlM7cNGQ( zss>2M{i&d|53q%G_~c?IY-KO)WO z1&nep>p0j0Xm~ziU!w(VPFfxa)liVCY5LOGQNf8|Zl6ok$~5A`X2A^`BcP?jf`k8iz{Rrq z#?@(>&&4cdycw`>(AhZo1(2ua-fH^>=qT{LYD;Y0m@qYc1@x38u(FB5-4&`JqV^2; z<|6fb$+s@V6LlOzp_=|-YzHGhC)AH4FH^3}oJ*p4%B5YO8a+(;uU|2V%%saT-(}m) z0S=~?4H=e5SLW;eXAy9raZRTu-C>z+ae)DlY56_$C6VJYe!qVla5Y0Eu%4i~^)T9# zCIPKCtqz2Lr1>@-uLzt1bWQL{Ofdl}(r5dPr1QJIVSVKjU}V)S*NJ?()mO}{tOCkK G9_+u){Xawi literal 0 HcmV?d00001 diff --git a/numpy/core/tests/test_numpy_2_0_compat.py b/numpy/core/tests/test_numpy_2_0_compat.py new file mode 100644 index 000000000000..5224261fd29a --- /dev/null +++ b/numpy/core/tests/test_numpy_2_0_compat.py @@ -0,0 +1,48 @@ +from os import path +import pickle + +import numpy as np + + +class TestNumPy2Compatibility: + + data_dir = path.join(path.dirname(__file__), "data") + filename = path.join(data_dir, "numpy_2_0_array.pkl") + + def test_importable__core_stubs(self): + """ + Checks if stubs for `numpy._core` are importable. + """ + from numpy._core.multiarray import _reconstruct + from numpy._core.umath import cos + from numpy._core._multiarray_umath import exp + from numpy._core._internal import ndarray + from numpy._core._dtype import _construction_repr + from numpy._core._dtype_ctypes import dtype_from_ctypes_type + + def test_unpickle_numpy_2_0_file(self): + """ + Checks that NumPy 1.26 and pickle is able to load pickles + created with NumPy 2.0 without errors/warnings. + """ + with open(self.filename, mode="rb") as file: + content = file.read() + + # Let's make sure that the pickle object we're loading + # was built with NumPy 2.0. + assert b"numpy._core.multiarray" in content + + arr = pickle.loads(content, encoding="latin1") + + assert isinstance(arr, np.ndarray) + assert arr.shape == (73,) and arr.dtype == np.float64 + + def test_numpy_load_numpy_2_0_file(self): + """ + Checks that `numpy.load` for NumPy 1.26 is able to load pickles + created with NumPy 2.0 without errors/warnings. + """ + arr = np.load(self.filename, encoding="latin1", allow_pickle=True) + + assert isinstance(arr, np.ndarray) + assert arr.shape == (73,) and arr.dtype == np.float64 diff --git a/numpy/lib/format.py b/numpy/lib/format.py index 05c51fe5635f..d5b3fbac23ab 100644 --- a/numpy/lib/format.py +++ b/numpy/lib/format.py @@ -169,7 +169,7 @@ ) -__all__ = ["NumpyUnpickler"] +__all__ = [] EXPECTED_KEYS = {'descr', 'fortran_order', 'shape'} @@ -797,7 +797,7 @@ def read_array(fp, allow_pickle=False, pickle_kwargs=None, *, if pickle_kwargs is None: pickle_kwargs = {} try: - array = NumpyUnpickler(fp, **pickle_kwargs).load() + array = pickle.load(fp, **pickle_kwargs) except UnicodeError as err: # Friendlier error message raise UnicodeError("Unpickling a python object failed: %r\n" @@ -974,15 +974,3 @@ def _read_bytes(fp, size, error_template="ran out of data"): raise ValueError(msg % (error_template, size, len(data))) else: return data - - -class NumpyUnpickler(pickle.Unpickler): - """ - A thin wrapper for :py:class:`pickle.Unpickler` that - allows to load 2.0 array pickles with numpy 1.26. - """ - - def find_class(self, module: str, name: str) -> object: - if module.startswith("numpy._core"): - module = module.replace("_core", "core", 1) - return pickle.Unpickler.find_class(self, module, name) diff --git a/numpy/lib/format.pyi b/numpy/lib/format.pyi index a433309c2583..a4468f52f464 100644 --- a/numpy/lib/format.pyi +++ b/numpy/lib/format.pyi @@ -1,4 +1,3 @@ -import pickle from typing import Any, Literal, Final __all__: list[str] @@ -21,5 +20,3 @@ def read_array_header_2_0(fp): ... def write_array(fp, array, version=..., allow_pickle=..., pickle_kwargs=...): ... def read_array(fp, allow_pickle=..., pickle_kwargs=...): ... def open_memmap(filename, mode=..., dtype=..., shape=..., fortran_order=..., version=...): ... - -class NumpyUnpickler(pickle.Unpickler): ... diff --git a/numpy/lib/npyio.py b/numpy/lib/npyio.py index 73ef6dde900b..339b1dc62113 100644 --- a/numpy/lib/npyio.py +++ b/numpy/lib/npyio.py @@ -462,7 +462,7 @@ def load(file, mmap_mode=None, allow_pickle=False, fix_imports=True, raise ValueError("Cannot load file containing pickled data " "when allow_pickle=False") try: - return format.NumpyUnpickler(fid, **pickle_kwargs).load() + return pickle.load(fid, **pickle_kwargs) except Exception as e: raise pickle.UnpicklingError( f"Failed to interpret file {file!r} as a pickle") from e diff --git a/numpy/meson.build b/numpy/meson.build index fc10acb5eb5a..8da83ce61643 100644 --- a/numpy/meson.build +++ b/numpy/meson.build @@ -246,6 +246,7 @@ pure_subdirs = [ '_pyinstaller', '_typing', '_utils', + '_core', 'array_api', 'compat', 'doc', diff --git a/numpy/setup.py b/numpy/setup.py index b6f879bcca85..536224a81192 100644 --- a/numpy/setup.py +++ b/numpy/setup.py @@ -7,6 +7,7 @@ def configuration(parent_package='',top_path=None): config.add_subpackage('array_api') config.add_subpackage('compat') config.add_subpackage('core') + config.add_subpackage('_core') config.add_subpackage('distutils') config.add_subpackage('doc') config.add_subpackage('f2py') From cc5e90fb74c2b0319ffbd15d3de734b3fb79b47b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Oct 2023 17:56:35 +0000 Subject: [PATCH 34/38] MAINT: Bump pypa/cibuildwheel from 2.16.1 to 2.16.2 Bumps [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel) from 2.16.1 to 2.16.2. - [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/7da7df1efc530f07d1945c00934b8cfd34be0d50...fff9ec32ed25a9c576750c91e06b410ed0c15db7) --- 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 329623ce6bf4..1ac6766df35b 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -118,7 +118,7 @@ jobs: python-version: "3.x" - name: Build wheels - uses: pypa/cibuildwheel@a873dd9cbf9e3c4c73a1fd11ac31cf835f6eb502 # v2.16.0 + uses: pypa/cibuildwheel@fff9ec32ed25a9c576750c91e06b410ed0c15db7 # v2.16.2 env: CIBW_PRERELEASE_PYTHONS: True CIBW_BUILD: ${{ matrix.python }}-${{ matrix.buildplat[1] }} From 54e6e65956d9b400dc6ed636ef93c6abf4885a3e Mon Sep 17 00:00:00 2001 From: "Ivan A. Melnikov" Date: Thu, 12 Oct 2023 11:49:35 +0400 Subject: [PATCH 35/38] BUG: loongarch doesn't use REAL(10) This fixes numpy.f2py.tests.test_kind.TestKind --- numpy/f2py/crackfortran.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpy/f2py/crackfortran.py b/numpy/f2py/crackfortran.py index d39acb039073..f352bbaa2720 100755 --- a/numpy/f2py/crackfortran.py +++ b/numpy/f2py/crackfortran.py @@ -2452,7 +2452,7 @@ def _selected_real_kind_func(p, r=0, radix=0): if p < 16: return 8 machine = platform.machine().lower() - if machine.startswith(('aarch64', 'arm64', 'power', 'ppc', 'riscv', 's390x', 'sparc')): + if machine.startswith(('aarch64', 'arm64', 'loongarch', 'power', 'ppc', 'riscv', 's390x', 'sparc')): if p <= 33: return 16 else: From 48bdb177f8f7f474360b814fec621049909751c5 Mon Sep 17 00:00:00 2001 From: Charles Harris Date: Thu, 12 Oct 2023 08:08:06 -0600 Subject: [PATCH 36/38] REL: Prepare for the NumPy 1.26.1 release - Create 1.26.1-changelog.py - Update 1.26.1-notes.py - Update .mailmap - Clear ``doc/release/upcoming_changes`` [wheel build] --- .mailmap | 5 +- doc/changelog/1.26.1-changelog.rst | 46 ++++++++++++ .../upcoming_changes/24906.new_feature.rst | 6 -- doc/source/release/1.26.1-notes.rst | 73 +++++++++++++++++-- 4 files changed, 118 insertions(+), 12 deletions(-) create mode 100644 doc/changelog/1.26.1-changelog.rst delete mode 100644 doc/release/upcoming_changes/24906.new_feature.rst diff --git a/.mailmap b/.mailmap index 9f83be9356fc..c34bd81bc90a 100644 --- a/.mailmap +++ b/.mailmap @@ -42,7 +42,8 @@ @yan-wyb @yetanothercheer Aaron Baecker -arunkumarkota +Arun Kota +Arun Kota Arun Kota Aarthi Agurusa Adarsh Singh ADARSH SINGH Andrei Batomunkuev @@ -104,6 +105,7 @@ Anne Archibald Anne Bonner <35413198+bonn0062@users.noreply.github.com> Anthony Vo <43098273+anthonyhvo12@users.noreply.github.com> Antoine Pitrou +Anton Prosekin Anže Starič Arfy Slowy Aron Ahmadia @@ -428,6 +430,7 @@ Mitchell Faas <35742861+Mitchell-Faas@users.noreply.gi Muhammad Kasim Mukulika Pahari Mukulika Pahari <60316606+Mukulikaa@users.noreply.github.com> +Munira Alduraibi Namami Shanker Namami Shanker NamamiShanker Nathaniel J. Smith diff --git a/doc/changelog/1.26.1-changelog.rst b/doc/changelog/1.26.1-changelog.rst new file mode 100644 index 000000000000..bacc6b4ee0b5 --- /dev/null +++ b/doc/changelog/1.26.1-changelog.rst @@ -0,0 +1,46 @@ + +Contributors +============ + +A total of 13 people contributed to this release. People with a "+" by their +names contributed a patch for the first time. + +* Andrew Nelson +* Anton Prosekin + +* Charles Harris +* Chongyun Lee + +* Ivan A. Melnikov + +* Jake Lishman + +* Mahder Gebremedhin + +* Mateusz Sokół +* Matti Picus +* Munira Alduraibi + +* Ralf Gommers +* Rohit Goswami +* Sayed Adel + +Pull requests merged +==================== + +A total of 20 pull requests were merged for this release. + +* `#24742 `__: MAINT: Update cibuildwheel version +* `#24748 `__: MAINT: fix version string in wheels built with setup.py +* `#24771 `__: BLD, BUG: Fix build failure for host flags e.g. ``-march=native``... +* `#24773 `__: DOC: Updated the f2py docs to remove a note on -fimplicit-none +* `#24776 `__: BUG: Fix SIMD f32 trunc test on s390x when baseline is none +* `#24785 `__: BLD: add libquadmath to licences and other tweaks (#24753) +* `#24786 `__: MAINT: Activate ``use-compute-credits`` for Cirrus. +* `#24803 `__: BLD: updated vendored-meson/meson for mips64 fix +* `#24804 `__: MAINT: fix licence path win +* `#24813 `__: BUG: Fix order of Windows OS detection macros. +* `#24831 `__: BUG, SIMD: use scalar cmul on bad Apple clang x86_64 (#24828) +* `#24840 `__: BUG: Fix DATA statements for f2py +* `#24870 `__: API: Add ``NumpyUnpickler`` for backporting +* `#24872 `__: MAINT: Xfail test failing on PyPy. +* `#24879 `__: BLD: fix math func feature checks, fix FreeBSD build, add CI... +* `#24899 `__: ENH: meson: implement BLAS/LAPACK auto-detection and many CI... +* `#24902 `__: DOC: add a 1.26.1 release notes section for BLAS/LAPACK build... +* `#24906 `__: MAINT: Backport ``numpy._core`` stubs. Remove ``NumpyUnpickler`` +* `#24911 `__: MAINT: Bump pypa/cibuildwheel from 2.16.1 to 2.16.2 +* `#24912 `__: BUG: loongarch doesn't use REAL(10) diff --git a/doc/release/upcoming_changes/24906.new_feature.rst b/doc/release/upcoming_changes/24906.new_feature.rst deleted file mode 100644 index 44c73a7b9490..000000000000 --- a/doc/release/upcoming_changes/24906.new_feature.rst +++ /dev/null @@ -1,6 +0,0 @@ -`numpy._core` submodules' stubs -------------------------------- - -`numpy._core` submodules' stubs were added -to provide a stable way for loading pickled arrays, -created with NumPy 2.0, with Numpy 1.26. diff --git a/doc/source/release/1.26.1-notes.rst b/doc/source/release/1.26.1-notes.rst index a3d7ce1f3082..a508b0cd69ed 100644 --- a/doc/source/release/1.26.1-notes.rst +++ b/doc/source/release/1.26.1-notes.rst @@ -6,9 +6,13 @@ NumPy 1.26.1 Release Notes NumPy 1.26.1 is a maintenance release that fixes bugs and regressions discovered after the 1.26.0 release. In addition, it adds new functionality for -detecting BLAS and LAPACK when building from source. The 1.26.release series is -the last planned minor release series before NumPy 2.0. The Python versions -supported by this release are 3.9-3.12. +detecting BLAS and LAPACK when building from source. Highlights are: + +- Improved detection of BLAS and LAPACK libraries for meson builds +- Pickle compatibility with the upcoming NumPy 2.0. + +The 1.26.release series is the last planned minor release series before NumPy +2.0. The Python versions supported by this release are 3.9-3.12. Build system changes @@ -46,9 +50,9 @@ to control BLAS/LAPACK selection and behavior: releases. - ``-Dallow-noblas``: if set to ``true``, allow NumPy to build with its internal (very slow) fallback routines instead of linking against an external - BLAS/LAPACK library. *The default for this flag may be changed to ``false`` + BLAS/LAPACK library. *The default for this flag may be changed to ``true`` in a future 1.26.x release, however for 1.26.1 we'd prefer to keep it as - ``true`` because if failures to detect an installed library are happening, + ``false`` because if failures to detect an installed library are happening, we'd like a bug report for that, so we can quickly assess whether the new auto-detection machinery needs further improvements.* - ``-Dmkl-threading``: to select the threading layer for MKL. There are four @@ -58,3 +62,62 @@ to control BLAS/LAPACK selection and behavior: - ``-Dblas-symbol-suffix``: manually select the symbol suffix to use for the library - should only be needed for linking against libraries built in a non-standard way. + + +New features +============ + +``numpy._core`` submodule stubs +------------------------------- + +``numpy._core`` submodule stubs were added to provide compatibility with +pickled arrays created using NumPy 2.0 when running Numpy 1.26. + + +Contributors +============ + +A total of 13 people contributed to this release. People with a "+" by their +names contributed a patch for the first time. + +* Andrew Nelson +* Anton Prosekin + +* Charles Harris +* Chongyun Lee + +* Ivan A. Melnikov + +* Jake Lishman + +* Mahder Gebremedhin + +* Mateusz Sokół +* Matti Picus +* Munira Alduraibi + +* Ralf Gommers +* Rohit Goswami +* Sayed Adel + + +Pull requests merged +==================== + +A total of 20 pull requests were merged for this release. + +* `#24742 `__: MAINT: Update cibuildwheel version +* `#24748 `__: MAINT: fix version string in wheels built with setup.py +* `#24771 `__: BLD, BUG: Fix build failure for host flags e.g. ``-march=native``... +* `#24773 `__: DOC: Updated the f2py docs to remove a note on -fimplicit-none +* `#24776 `__: BUG: Fix SIMD f32 trunc test on s390x when baseline is none +* `#24785 `__: BLD: add libquadmath to licences and other tweaks (#24753) +* `#24786 `__: MAINT: Activate ``use-compute-credits`` for Cirrus. +* `#24803 `__: BLD: updated vendored-meson/meson for mips64 fix +* `#24804 `__: MAINT: fix licence path win +* `#24813 `__: BUG: Fix order of Windows OS detection macros. +* `#24831 `__: BUG, SIMD: use scalar cmul on bad Apple clang x86_64 (#24828) +* `#24840 `__: BUG: Fix DATA statements for f2py +* `#24870 `__: API: Add ``NumpyUnpickler`` for backporting +* `#24872 `__: MAINT: Xfail test failing on PyPy. +* `#24879 `__: BLD: fix math func feature checks, fix FreeBSD build, add CI... +* `#24899 `__: ENH: meson: implement BLAS/LAPACK auto-detection and many CI... +* `#24902 `__: DOC: add a 1.26.1 release notes section for BLAS/LAPACK build... +* `#24906 `__: MAINT: Backport ``numpy._core`` stubs. Remove ``NumpyUnpickler`` +* `#24911 `__: MAINT: Bump pypa/cibuildwheel from 2.16.1 to 2.16.2 +* `#24912 `__: BUG: loongarch doesn't use REAL(10) + From e27f774668c0a412d542c12506406781721ba2fc Mon Sep 17 00:00:00 2001 From: Charles Harris Date: Thu, 12 Oct 2023 18:29:32 -0600 Subject: [PATCH 37/38] MAINT: Revert cibuildwheel update --- .github/workflows/wheels.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 1ac6766df35b..76757f6f097d 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -118,7 +118,8 @@ jobs: python-version: "3.x" - name: Build wheels - uses: pypa/cibuildwheel@fff9ec32ed25a9c576750c91e06b410ed0c15db7 # v2.16.2 + uses: pypa/cibuildwheel@a873dd9cbf9e3c4c73a1fd11ac31cf835f6eb502 # v2.16.0 + #uses: pypa/cibuildwheel@fff9ec32ed25a9c576750c91e06b410ed0c15db7 # v2.16.2 env: CIBW_PRERELEASE_PYTHONS: True CIBW_BUILD: ${{ matrix.python }}-${{ matrix.buildplat[1] }} From aa91e5dda302775934ace7de30b723d26740dd38 Mon Sep 17 00:00:00 2001 From: Charles Harris Date: Sat, 14 Oct 2023 12:18:50 -0600 Subject: [PATCH 38/38] REL: Update release versions The pyproject.toml and pyproject.toml.setuppy need version set to 1.26.1. [skip ci] [skip actions] [skip azp] --- pyproject.toml | 2 +- pyproject.toml.setuppy | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index cfe077d5983a..ec8da79d3963 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,7 @@ requires = [ [project] name = "numpy" -version = "1.26.0" +version = "1.26.1" # TODO: add `license-files` once PEP 639 is accepted (see meson-python#88) license = {file = "LICENSE.txt"} diff --git a/pyproject.toml.setuppy b/pyproject.toml.setuppy index 0925099ed523..bfb093ba7648 100644 --- a/pyproject.toml.setuppy +++ b/pyproject.toml.setuppy @@ -3,7 +3,7 @@ # to avoid building with Meson (e.g., in the Emscripten/Pyodide CI job) [project] name = "numpy" -version = "1.26.0" +version = "1.26.1" [build-system] requires = [