diff --git a/.circleci/config.yml b/.circleci/config.yml index 8c2b443f1e84..1760eca727dd 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,7 +9,7 @@ _defaults: &defaults docker: # CircleCI maintains a library of pre-built images # documented at https://circleci.com/developer/images/image/cimg/python - - image: cimg/python:3.11.10 + - image: cimg/python:3.11.13 working_directory: ~/repo diff --git a/.github/meson_actions/action.yml b/.github/meson_actions/action.yml index 66868cbc3be0..476c0bbd7950 100644 --- a/.github/meson_actions/action.yml +++ b/.github/meson_actions/action.yml @@ -30,8 +30,7 @@ runs: TERM: xterm-256color run: | echo "::group::Installing Test Dependencies" - pip install pytest pytest-xdist pytest-timeout hypothesis typing_extensions - pip install -r requirements/setuptools_requirement.txt + python -m pip install -r requirements/test_requirements.txt echo "::endgroup::" echo "::group::Test NumPy" spin test -- --durations=10 --timeout=600 diff --git a/.github/workflows/compiler_sanitizers.yml b/.github/workflows/compiler_sanitizers.yml index 0581f7fc591b..c6b82c0c7d70 100644 --- a/.github/workflows/compiler_sanitizers.yml +++ b/.github/workflows/compiler_sanitizers.yml @@ -88,6 +88,9 @@ jobs: - name: Uninstall pytest-xdist (conflicts with TSAN) run: pip uninstall -y pytest-xdist + - name: Upgrade spin (gh-29777) + run: pip install -U spin + - name: Build NumPy with ThreadSanitizer run: python -m spin build -j2 -- -Db_sanitize=thread diff --git a/.github/workflows/emscripten.yml b/.github/workflows/emscripten.yml index a11c6464771c..fecee4b12224 100644 --- a/.github/workflows/emscripten.yml +++ b/.github/workflows/emscripten.yml @@ -49,7 +49,7 @@ jobs: fetch-tags: true persist-credentials: false - - uses: pypa/cibuildwheel@c923d83ad9c1bc00211c5041d0c3f73294ff88f6 # v3.1.4 + - uses: pypa/cibuildwheel@9c00cb4f6b517705a3794b22395aedc36257242c # v3.2.1 env: CIBW_PLATFORM: pyodide diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 7cba11bb3281..f759a39d9864 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -253,7 +253,7 @@ jobs: run: | sudo apt-get update sudo apt-get install libopenblas-dev ninja-build - pip install asv virtualenv packaging -r requirements/build_requirements.txt + pip install "asv<0.6.5" virtualenv packaging -r requirements/build_requirements.txt - name: Install NumPy run: | spin build -- -Dcpu-dispatch=none @@ -271,7 +271,7 @@ jobs: # - name: Check docstests # shell: 'script -q -e -c "bash --noprofile --norc -eo pipefail {0}"' # run: | - # pip install scipy-doctest==1.6.0 hypothesis==6.104.1 matplotlib scipy pytz pandas + # pip install -r requirements/doc_requirements.txt -r requirements/test_requirements.txt # spin check-docs -v # spin check-tutorials -v diff --git a/.github/workflows/linux_blas.yml b/.github/workflows/linux_blas.yml index 54d217cc12fb..4aa3b1a5df99 100644 --- a/.github/workflows/linux_blas.yml +++ b/.github/workflows/linux_blas.yml @@ -76,7 +76,7 @@ jobs: - name: Install dependencies run: | - pip install -r requirements/build_requirements.txt + pip install -r requirements/build_requirements.txt -r requirements/test_requirements.txt # Install OpenBLAS if [[ $USE_NIGHTLY_OPENBLAS == "true" ]]; then python -m pip install -i https://pypi.anaconda.org/scientific-python-nightly-wheels/simple scipy-openblas32 @@ -85,16 +85,13 @@ jobs: fi mkdir -p ./.openblas python -c"import scipy_openblas32 as ob32; print(ob32.get_pkg_config())" > ./.openblas/scipy-openblas.pc - echo "PKG_CONFIG_PATH=${{ github.workspace }}/.openblas" >> $GITHUB_ENV - ld_library_path=$(python -c"import scipy_openblas32 as ob32; print(ob32.get_lib_dir())") - echo "LD_LIBRARY_PATH=$ld_library_path" >> $GITHUB_ENV - name: Build shell: 'script -q -e -c "bash --noprofile --norc -eo pipefail {0}"' env: TERM: xterm-256color run: - spin build -- --werror -Dallow-noblas=false + spin build -- --werror -Dallow-noblas=false -Dpkg_config_path=${PWD}/.openblas - name: Check build-internal dependencies run: @@ -113,7 +110,6 @@ jobs: env: TERM: xterm-256color run: | - pip install pytest pytest-xdist hypothesis typing_extensions pytest-timeout spin test -j auto -- --timeout=600 --durations=10 @@ -135,8 +131,7 @@ jobs: - name: Install dependencies run: | - pip install -r requirements/build_requirements.txt - pip install pytest hypothesis typing_extensions pytest-timeout + pip install -r requirements/build_requirements.txt -r requirements/test_requirements.txt - name: Build (LP64) run: spin build -- -Dblas=openblas -Dlapack=openblas -Ddisable-optimization=true -Dallow-noblas=false @@ -171,8 +166,7 @@ jobs: - name: Install dependencies run: | - pip install -r requirements/build_requirements.txt - pip install pytest hypothesis typing_extensions pytest-timeout + pip install -r requirements/build_requirements.txt -r requirements/test_requirements.txt - name: Build run: spin build -- -Ddisable-optimization=true -Dallow-noblas=false @@ -205,8 +199,7 @@ jobs: - name: Install dependencies run: | - pip install -r requirements/build_requirements.txt - pip install pytest pytest-xdist hypothesis typing_extensions pytest-timeout + pip install -r requirements/build_requirements.txt -r requirements/test_requirements.txt sudo apt-get update sudo apt-get install libopenblas-dev cmake sudo apt-get remove pkg-config @@ -234,7 +227,7 @@ jobs: - name: Install dependencies run: | - pip install -r requirements/build_requirements.txt + pip install -r requirements/build_requirements.txt -r requirements/test_requirements.txt sudo apt-get update sudo apt-get install liblapack-dev pkg-config @@ -244,7 +237,6 @@ jobs: - name: Test run: | - pip install pytest pytest-xdist hypothesis typing_extensions pytest-timeout spin test -j auto -- numpy/linalg --timeout=600 --durations=10 @@ -276,6 +268,8 @@ jobs: - name: Test run: | + # do not use test_requirements.txt, it includes coverage which requires + # sqlite3, which is not available on OpenSUSE python pip install --break-system-packages pytest pytest-xdist hypothesis typing_extensions pytest-timeout spin test -j auto -- numpy/linalg --timeout=600 --durations=10 @@ -297,7 +291,7 @@ jobs: - name: Install dependencies run: | pip install -r requirements/build_requirements.txt - pip install pytest pytest-xdist hypothesis typing_extensions pytest-timeout + pip install -r requirements/build_requirements.txt -r requirements/test_requirements.txt pip install mkl mkl-devel - name: Repair MKL pkg-config files and symlinks @@ -361,7 +355,7 @@ jobs: - name: Install dependencies run: | pip install -r requirements/build_requirements.txt - pip install pytest pytest-xdist hypothesis typing_extensions pytest-timeout + pip install -r requirements/build_requirements.txt -r requirements/test_requirements.txt sudo apt-get update sudo apt-get install libblis-dev libopenblas-dev pkg-config @@ -398,7 +392,7 @@ jobs: - name: Install dependencies run: | pip install -r requirements/build_requirements.txt - pip install pytest pytest-xdist hypothesis typing_extensions pytest-timeout + pip install -r requirements/build_requirements.txt -r requirements/test_requirements.txt sudo apt-get update sudo apt-get install libatlas-base-dev pkg-config diff --git a/.github/workflows/linux_qemu.yml b/.github/workflows/linux_qemu.yml index 1293e9c37c2f..9dc9e0a5839c 100644 --- a/.github/workflows/linux_qemu.yml +++ b/.github/workflows/linux_qemu.yml @@ -205,7 +205,7 @@ jobs: - name: Initialize binfmt_misc for qemu-user-static run: | - docker run --rm --privileged loongcr.lcpu.dev/multiarch/archlinux --reset -p yes + docker run --rm --privileged tonistiigi/binfmt:qemu-v10.0.4-56 --install all - name: Install GCC cross-compilers run: | diff --git a/.github/workflows/linux_simd.yml b/.github/workflows/linux_simd.yml index 9f12215eb30e..1e7e0babb5c5 100644 --- a/.github/workflows/linux_simd.yml +++ b/.github/workflows/linux_simd.yml @@ -132,8 +132,7 @@ jobs: python-version: '3.11' - name: Install dependencies run: | - python -m pip install -r requirements/build_requirements.txt - python -m pip install pytest pytest-xdist hypothesis typing_extensions pytest-timeout + python -m pip install -r requirements/build_requirements.txt -r requirements/test_requirements.txt - name: Build run: | spin build -- ${{ matrix.config.args }} @@ -208,8 +207,7 @@ jobs: - name: Install dependencies run: | - python -m pip install -r requirements/build_requirements.txt - python -m pip install pytest pytest-xdist hypothesis typing_extensions + python -m pip install -r requirements/build_requirements.txt -r requirements/test_requirements.txt - name: Build run: CC=gcc-13 CXX=g++-13 spin build -- -Denable-openmp=true -Dallow-noblas=true -Dcpu-baseline=avx512_skx -Dtest-simd='BASELINE,AVX512_KNL,AVX512_KNM,AVX512_SKX,AVX512_CLX,AVX512_CNL,AVX512_ICL,AVX512_SPR' @@ -259,8 +257,7 @@ jobs: - name: Install dependencies run: | - python -m pip install -r requirements/build_requirements.txt - python -m pip install pytest pytest-xdist hypothesis typing_extensions + python -m pip install -r requirements/build_requirements.txt -r requirements/test_requirements.txt - name: Build run: CC=gcc-13 CXX=g++-13 spin build -- -Denable-openmp=true -Dallow-noblas=true -Dcpu-baseline=avx512_spr diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 1388a756d216..e7835288cdfb 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -135,9 +135,7 @@ jobs: - name: Install dependencies run: | - pip install -r requirements/build_requirements.txt - pip install -r requirements/setuptools_requirement.txt - pip install pytest pytest-xdist pytest-timeout hypothesis + pip install -r requirements/build_requirements.txt -r requirements/test_requirements.txt - name: Build against Accelerate (LP64) run: spin build -- -Ddisable-optimization=true -Dallow-noblas=false diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 095c42f6ab5a..9b3eecc8251e 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -174,7 +174,7 @@ jobs: fi - name: Build wheels - uses: pypa/cibuildwheel@c923d83ad9c1bc00211c5041d0c3f73294ff88f6 # v3.1.4 + uses: pypa/cibuildwheel@9c00cb4f6b517705a3794b22395aedc36257242c # v3.2.1 env: CIBW_BUILD: ${{ matrix.python }}-${{ matrix.buildplat[1] }} diff --git a/.mailmap b/.mailmap index e3e3bb56ecdf..18cfb272618f 100644 --- a/.mailmap +++ b/.mailmap @@ -214,6 +214,7 @@ Chris Kerr Chris Navarro Chris Navarro <24905907+lvllvl@users.noreply.github.com> Chris Vavaliaris +Christian Barbia Christian Clauss Christopher Dahlin Christopher Hanley @@ -655,6 +656,7 @@ Saransh Chopra Saullo Giovani Saurabh Mehta Sayantika Banik +Sayed Awad Schrijvers Luc Sean Cheah Sean Cheah <67928790+thalassemia@users.noreply.github.com> @@ -750,6 +752,8 @@ Yash Pethe Yash Pethe <83630710+patient74@users.noreply.github.com> Yashasvi Misra Yashasvi Misra <54177363+yashasvimisra2798@users.noreply.github.com> +Yasir Ashfaq +Yasir Ashfaq <107119183+yasiribmcon@users.noreply.github.com> Yichi Zhang Yogesh Raisinghani <46864533+raisinghanii@users.noreply.github.com> Younes Sandi diff --git a/azure-pipelines.yml b/azure-pipelines.yml index af6e5cf52ac4..89dee2267352 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -56,6 +56,9 @@ stages: python tools/linter.py displayName: 'Run Lint Checks' failOnStderr: true + - script: | + python tools/check_python_h_first.py + displayName: 'Check Python.h is first file included' - job: Linux_Python_311_32bit_full_with_asserts pool: diff --git a/doc/changelog/2.3.4-changelog.rst b/doc/changelog/2.3.4-changelog.rst new file mode 100644 index 000000000000..f94b46a07573 --- /dev/null +++ b/doc/changelog/2.3.4-changelog.rst @@ -0,0 +1,61 @@ + +Contributors +============ + +A total of 17 people contributed to this release. People with a "+" by their +names contributed a patch for the first time. + +* !DWesl +* Charles Harris +* Christian Barbia + +* Evgeni Burovski +* Joren Hammudoglu +* Maaz + +* Mateusz Sokół +* Matti Picus +* Nathan Goldbaum +* Ralf Gommers +* Riku Sakamoto + +* Sandeep Gupta + +* Sayed Awad +* Sebastian Berg +* Sergey Fedorov + +* Warren Weckesser +* dependabot[bot] + +Pull requests merged +==================== + +A total of 30 pull requests were merged for this release. + +* `#29725 `__: MAINT: Prepare 2.3.x for further development +* `#29781 `__: MAINT: Pin some upstream dependences +* `#29782 `__: BLD: enable x86-simd-sort to build on KNL with -mavx512f +* `#29783 `__: BUG: Include python-including headers first (#29281) +* `#29784 `__: TYP: fix np.number and np.\*integer method declaration +* `#29785 `__: TYP: mypy 1.18.1 +* `#29788 `__: TYP: replace scalar type __init__ with __new__ +* `#29790 `__: BUG: Fix ``dtype`` refcount in ``__array__`` (#29715) +* `#29791 `__: TYP: fix method declarations in floating, timedelta64, and datetime64Backport +* `#29792 `__: MAINT: delete unused variables in unary logical dispatch +* `#29797 `__: BUG: Fix pocketfft umath strides for AIX compatibility (#29768) +* `#29798 `__: BUG: np.setbufsize should raise ValueError for negative input +* `#29799 `__: BUG: Fix assert in nditer buffer setup +* `#29800 `__: BUG: Stable ScalarType ordering +* `#29838 `__: TST: Pin pyparsing to avoid matplotlib errors. +* `#29839 `__: BUG: linalg: emit a MemoryError on a malloc failure (#29811) +* `#29840 `__: BLD: change file extension for libnpymath on win-arm64 from .a... +* `#29864 `__: CI: Fix loongarch64 CI (#29856) +* `#29865 `__: TYP: Various typing fixes +* `#29910 `__: BUG: Fix float16-sort failures on 32-bit x86 MSVC (#29908) +* `#29911 `__: TYP: add missing ``__slots__`` (#29901) +* `#29913 `__: TYP: wrong argument defaults in ``testing._private`` (#29902) +* `#29920 `__: BUG: avoid segmentation fault in string_expandtabs_length_promoter +* `#29921 `__: BUG: Fix INT_MIN % -1 to return 0 for all signed integer types... +* `#29922 `__: TYP: minor fixes related to ``errstate`` (#29914) +* `#29923 `__: TST: use requirements/test_requirements across CI (#29919) +* `#29926 `__: BUG: fix negative samples generated by Wald distribution (#29609) +* `#29940 `__: MAINT: Bump pypa/cibuildwheel from 3.1.4 to 3.2.1 +* `#29949 `__: STY: rename @classmethod arg to cls +* `#29950 `__: MAINT: Simplify string arena growth strategy (#29885) + diff --git a/doc/changelog/2.3.5-changelog.rst b/doc/changelog/2.3.5-changelog.rst new file mode 100644 index 000000000000..123e1e9d0453 --- /dev/null +++ b/doc/changelog/2.3.5-changelog.rst @@ -0,0 +1,40 @@ + +Contributors +============ + +A total of 10 people contributed to this release. People with a "+" by their +names contributed a patch for the first time. + +* Aaron Kollasch + +* Charles Harris +* Joren Hammudoglu +* Matti Picus +* Nathan Goldbaum +* Rafael Laboissière + +* Sayed Awad +* Sebastian Berg +* Warren Weckesser +* Yasir Ashfaq + + +Pull requests merged +==================== + +A total of 16 pull requests were merged for this release. + +* `#29979 `__: MAINT: Prepare 2.3.x for further development +* `#30026 `__: SIMD, BLD: Backport FPMATH mode on x86-32 and filter successor... +* `#30029 `__: MAINT: Backport write_release.py +* `#30041 `__: TYP: Various typing updates +* `#30059 `__: BUG: Fix np.strings.slice if stop=None or start and stop >= len... +* `#30063 `__: BUG: Fix np.strings.slice if start > stop +* `#30076 `__: BUG: avoid negating INT_MIN in PyArray_Round implementation (#30071) +* `#30090 `__: BUG: Fix resize when it contains references (#29970) +* `#30129 `__: BLD: update scipy-openblas, use -Dpkg_config_path (#30049) +* `#30130 `__: BUG: Avoid compilation error of wrapper file generated with SWIG... +* `#30157 `__: BLD: use scipy-openblas 0.3.30.7 (#30132) +* `#30158 `__: DOC: Remove nonexistent ``order`` parameter docs of ``ma.asanyarray``... +* `#30185 `__: BUG: Fix check of PyMem_Calloc return value. (#30176) +* `#30217 `__: DOC: fix links for newly rebuilt numpy-tutorials site +* `#30218 `__: BUG: Fix build on s390x with clang (#30214) +* `#30237 `__: ENH: Make FPE blas check a runtime check for all apple arm systems + diff --git a/doc/source/reference/simd/build-options.rst b/doc/source/reference/simd/build-options.rst index 524a1532ca57..d22b96b346fb 100644 --- a/doc/source/reference/simd/build-options.rst +++ b/doc/source/reference/simd/build-options.rst @@ -97,9 +97,24 @@ Having issues with AVX512 features? You may have some reservations about including of ``AVX512`` or any other CPU feature and you want to exclude from the dispatched features:: - python -m build --wheel -Csetup-args=-Dcpu-dispatch="max -avx512f -avx512cd \ + python -m build --wheel -Csetup-args=-Dcpu-dispatch="max -avx512f" + +which is equivalent to:: + + python -m build --wheel -Csetup-args=-Dcpu-dispatch="max -avx512f -avx512cd -avx512_knl -avx512_knm -avx512_skx -avx512_clx -avx512_cnl -avx512_icl -avx512_spr" +Since excluding ``AVX512F`` also excludes all CPU features that imply it. + +You can also enable the required features without enabling ``max``:: + + python -m build --wheel -Csetup-args=-Dcpu-dispatch="avx2 fma3" + +.. note:: + + Please refer to :ref:`opt-supported-features` to know which features + are implied by others. + .. _opt-supported-features: Supported features @@ -127,6 +142,10 @@ Special options - ``NATIVE``: Enables all CPU features that supported by the host CPU, this operation is based on the compiler flags (``-march=native``, ``-xHost``, ``/QxHost``) +- ``DETECT``: Detects the features enabled by the compiler. This option is appended by default + to ``cpu-baseline`` if ``-march``, ``-mcpu``, ``-xhost``, or ``/QxHost`` is set in + the environment variable ``CFLAGS``. + - ``MIN``: Enables the minimum CPU features that can safely run on a wide range of platforms: .. table:: diff --git a/doc/source/release.rst b/doc/source/release.rst index d04c82549290..3f7e520d1a78 100644 --- a/doc/source/release.rst +++ b/doc/source/release.rst @@ -5,6 +5,8 @@ Release notes .. toctree:: :maxdepth: 2 + 2.3.5 + 2.3.4 2.3.3 2.3.2 2.3.1 diff --git a/doc/source/release/2.3.4-notes.rst b/doc/source/release/2.3.4-notes.rst new file mode 100644 index 000000000000..b939c46858d3 --- /dev/null +++ b/doc/source/release/2.3.4-notes.rst @@ -0,0 +1,83 @@ +.. currentmodule:: numpy + +========================== +NumPy 2.3.4 Release Notes +========================== + +The NumPy 2.3.4 release is a patch release split between a number of maintenance +updates and bug fixes. This release supports Python versions 3.11-3.14. This +release is based on NumPy 3.14.0 final. + + +Changes +======= + +The ``npymath`` and ``npyrandom`` libraries now have a ``.lib`` rather than a +``.a`` file extension on win-arm64, for compatibility for building with MSVC and +``setuptools``. Please note that using these static libraries is discouraged +and for existing projects using it, it's best to use it with a matching +compiler toolchain, which is ``clang-cl`` on Windows on Arm. + +(`gh-29750 `__) + + +Contributors +============ + +A total of 17 people contributed to this release. People with a "+" by their +names contributed a patch for the first time. + +* !DWesl +* Charles Harris +* Christian Barbia + +* Evgeni Burovski +* Joren Hammudoglu +* Maaz + +* Mateusz Sokół +* Matti Picus +* Nathan Goldbaum +* Ralf Gommers +* Riku Sakamoto + +* Sandeep Gupta + +* Sayed Awad +* Sebastian Berg +* Sergey Fedorov + +* Warren Weckesser +* dependabot[bot] + +Pull requests merged +==================== + +A total of 30 pull requests were merged for this release. + +* `#29725 `__: MAINT: Prepare 2.3.x for further development +* `#29781 `__: MAINT: Pin some upstream dependences +* `#29782 `__: BLD: enable x86-simd-sort to build on KNL with -mavx512f +* `#29783 `__: BUG: Include python-including headers first (#29281) +* `#29784 `__: TYP: fix np.number and np.\*integer method declaration +* `#29785 `__: TYP: mypy 1.18.1 +* `#29788 `__: TYP: replace scalar type __init__ with __new__ +* `#29790 `__: BUG: Fix ``dtype`` refcount in ``__array__`` (#29715) +* `#29791 `__: TYP: fix method declarations in floating, timedelta64, and datetime64Backport +* `#29792 `__: MAINT: delete unused variables in unary logical dispatch +* `#29797 `__: BUG: Fix pocketfft umath strides for AIX compatibility (#29768) +* `#29798 `__: BUG: np.setbufsize should raise ValueError for negative input +* `#29799 `__: BUG: Fix assert in nditer buffer setup +* `#29800 `__: BUG: Stable ScalarType ordering +* `#29838 `__: TST: Pin pyparsing to avoid matplotlib errors. +* `#29839 `__: BUG: linalg: emit a MemoryError on a malloc failure (#29811) +* `#29840 `__: BLD: change file extension for libnpymath on win-arm64 from .a... +* `#29864 `__: CI: Fix loongarch64 CI (#29856) +* `#29865 `__: TYP: Various typing fixes +* `#29910 `__: BUG: Fix float16-sort failures on 32-bit x86 MSVC (#29908) +* `#29911 `__: TYP: add missing ``__slots__`` (#29901) +* `#29913 `__: TYP: wrong argument defaults in ``testing._private`` (#29902) +* `#29920 `__: BUG: avoid segmentation fault in string_expandtabs_length_promoter +* `#29921 `__: BUG: Fix INT_MIN % -1 to return 0 for all signed integer types... +* `#29922 `__: TYP: minor fixes related to ``errstate`` (#29914) +* `#29923 `__: TST: use requirements/test_requirements across CI (#29919) +* `#29926 `__: BUG: fix negative samples generated by Wald distribution (#29609) +* `#29940 `__: MAINT: Bump pypa/cibuildwheel from 3.1.4 to 3.2.1 +* `#29949 `__: STY: rename @classmethod arg to cls +* `#29950 `__: MAINT: Simplify string arena growth strategy (#29885) + diff --git a/doc/source/release/2.3.5-notes.rst b/doc/source/release/2.3.5-notes.rst new file mode 100644 index 000000000000..8013ef468055 --- /dev/null +++ b/doc/source/release/2.3.5-notes.rst @@ -0,0 +1,50 @@ +.. currentmodule:: numpy + +========================= +NumPy 2.3.5 Release Notes +========================= + +The NumPy 2.3.5 release is a patch release split between a number of maintenance +updates and bug fixes. This release supports Python versions 3.11-3.14. + + +Contributors +============ + +A total of 10 people contributed to this release. People with a "+" by their +names contributed a patch for the first time. + +* Aaron Kollasch + +* Charles Harris +* Joren Hammudoglu +* Matti Picus +* Nathan Goldbaum +* Rafael Laboissière + +* Sayed Awad +* Sebastian Berg +* Warren Weckesser +* Yasir Ashfaq + + + +Pull requests merged +==================== + +A total of 16 pull requests were merged for this release. + +* `#29979 `__: MAINT: Prepare 2.3.x for further development +* `#30026 `__: SIMD, BLD: Backport FPMATH mode on x86-32 and filter successor... +* `#30029 `__: MAINT: Backport write_release.py +* `#30041 `__: TYP: Various typing updates +* `#30059 `__: BUG: Fix np.strings.slice if stop=None or start and stop >= len... +* `#30063 `__: BUG: Fix np.strings.slice if start > stop +* `#30076 `__: BUG: avoid negating INT_MIN in PyArray_Round implementation (#30071) +* `#30090 `__: BUG: Fix resize when it contains references (#29970) +* `#30129 `__: BLD: update scipy-openblas, use -Dpkg_config_path (#30049) +* `#30130 `__: BUG: Avoid compilation error of wrapper file generated with SWIG... +* `#30157 `__: BLD: use scipy-openblas 0.3.30.7 (#30132) +* `#30158 `__: DOC: Remove nonexistent ``order`` parameter docs of ``ma.asanyarray``... +* `#30185 `__: BUG: Fix check of PyMem_Calloc return value. (#30176) +* `#30217 `__: DOC: fix links for newly rebuilt numpy-tutorials site +* `#30218 `__: BUG: Fix build on s390x with clang (#30214) +* `#30237 `__: ENH: Make FPE blas check a runtime check for all apple arm systems + diff --git a/doc/source/user/how-to-how-to.rst b/doc/source/user/how-to-how-to.rst index 91a5c2afe09b..07640f881141 100644 --- a/doc/source/user/how-to-how-to.rst +++ b/doc/source/user/how-to-how-to.rst @@ -105,7 +105,7 @@ deep dives intended to give understanding rather than immediate assistance, and *References*, which give complete, authoritative data on some concrete part of NumPy (like its API) but aren't obligated to paint a broader picture. -For more on tutorials, see :doc:`numpy-tutorials:content/tutorial-style-guide` +For more on tutorials, see :doc:`numpy-tutorials:tutorial-style-guide` ****************************************************************************** Is this page an example of a how-to? diff --git a/doc/source/user/quickstart.rst b/doc/source/user/quickstart.rst index 3f97f005898b..ef4a0467c706 100644 --- a/doc/source/user/quickstart.rst +++ b/doc/source/user/quickstart.rst @@ -1479,4 +1479,4 @@ Further reading - `SciPy Tutorial `__ - `SciPy Lecture Notes `__ - A `matlab, R, IDL, NumPy/SciPy dictionary `__ -- :doc:`tutorial-svd ` +- :doc:`tutorial-svd ` diff --git a/environment.yml b/environment.yml index ac8c26a5c484..2587ca8d75c4 100644 --- a/environment.yml +++ b/environment.yml @@ -16,7 +16,7 @@ dependencies: - ninja - pkg-config - meson-python - - spin==0.13 + - spin==0.15 - ccache # For testing - pytest @@ -25,7 +25,7 @@ dependencies: - hypothesis # For type annotations - typing_extensions>=4.5.0 - - mypy=1.16.1 + - mypy=1.18.1 - orjson # makes mypy faster # For building docs - sphinx>=4.5.0 diff --git a/meson_cpu/meson.build b/meson_cpu/meson.build index e5b6d0fbe7be..9046b4133dd9 100644 --- a/meson_cpu/meson.build +++ b/meson_cpu/meson.build @@ -207,8 +207,17 @@ foreach opt_name, conf : parse_options endforeach else filterd = [] + # filter out the features that are in the accumulate list + # including any successor features foreach fet : result - if fet not in accumulate + escape = false + foreach fet2 : accumulate + if fet2 in mod_features.implicit_c(fet) + escape = true + break + endif + endforeach + if not escape filterd += fet endif endforeach diff --git a/meson_cpu/x86/meson.build b/meson_cpu/x86/meson.build index 4c71fe46b2ac..521ca8524696 100644 --- a/meson_cpu/x86/meson.build +++ b/meson_cpu/x86/meson.build @@ -1,8 +1,13 @@ source_root = meson.project_source_root() mod_features = import('features') - +# Use SSE for floating-point on x86-32 to ensure numeric consistency. +# The x87 FPU's 80-bit internal precision causes unpredictable rounding +# and overflow behavior when converting to smaller types. SSE maintains +# strict 32/64-bit precision throughout all calculations. +cpu_family = host_machine.cpu_family() +SSE_FPMATH = cpu_family == 'x86'? ['-mfpmath=sse'] : [] SSE = mod_features.new( - 'SSE', 1, args: '-msse', + 'SSE', 1, args: ['-msse'] + SSE_FPMATH, test_code: files(source_root + '/numpy/distutils/checks/cpu_sse.c')[0] ) SSE2 = mod_features.new( diff --git a/numpy/__init__.py b/numpy/__init__.py index 8fb2e742dfc4..097fe9f414ec 100644 --- a/numpy/__init__.py +++ b/numpy/__init__.py @@ -873,6 +873,23 @@ def _mac_os_check(): del w del _mac_os_check + def blas_fpe_check(): + # Check if BLAS adds spurious FPEs, mostly seen on M4 arms with Accelerate. + with errstate(all='raise'): + x = ones((20, 20)) + try: + x @ x + except FloatingPointError: + res = _core._multiarray_umath._blas_supports_fpe(False) + if res: # res was not modified (hardcoded to True for now) + warnings.warn( + "Spurious warnings given by blas but suppression not " + "set up on this platform. Please open a NumPy issue.", + UserWarning, stacklevel=2) + + blas_fpe_check() + del blas_fpe_check + def hugepage_setup(): """ We usually use madvise hugepages support, but on some old kernels it diff --git a/numpy/__init__.pyi b/numpy/__init__.pyi index 25397572881f..093c8e0f01a0 100644 --- a/numpy/__init__.pyi +++ b/numpy/__init__.pyi @@ -133,26 +133,6 @@ from numpy._typing import ( _GUFunc_Nin2_Nout1, ) -from numpy._typing._callable import ( - _IntTrueDiv, - _UnsignedIntOp, - _UnsignedIntBitOp, - _UnsignedIntMod, - _UnsignedIntDivMod, - _SignedIntOp, - _SignedIntBitOp, - _SignedIntMod, - _SignedIntDivMod, - _FloatOp, - _FloatMod, - _FloatDivMod, - _NumberOp, - _ComparisonOpLT, - _ComparisonOpLE, - _ComparisonOpGT, - _ComparisonOpGE, -) - # NOTE: Numpy's mypy plugin is used for removing the types unavailable to the specific platform from numpy._typing._extended_precision import ( float96, @@ -211,7 +191,7 @@ from typing import ( # library include `typing_extensions` stubs: # https://github.com/python/typeshed/blob/main/stdlib/typing_extensions.pyi from _typeshed import Incomplete, StrOrBytesPath, SupportsFlush, SupportsLenAndGetItem, SupportsWrite -from typing_extensions import CapsuleType, TypeVar +from typing_extensions import CapsuleType, TypeVar, deprecated, override from numpy import ( char, @@ -315,8 +295,7 @@ from numpy._core._ufunc_config import ( getbufsize, seterrcall, geterrcall, - _ErrKind, - _ErrCall, + errstate, ) from numpy._core.arrayprint import ( @@ -426,6 +405,8 @@ from numpy._core.shape_base import ( ) from ._expired_attrs_2_0 import __expired_attributes__ as __expired_attributes__ +from ._globals import _CopyMode as _CopyMode +from ._globals import _NoValue as _NoValue, _NoValueType from numpy.lib import ( scimath as emath, @@ -489,8 +470,6 @@ from numpy.lib._function_base_impl import ( quantile, ) -from numpy._globals import _CopyMode - from numpy.lib._histograms_impl import ( histogram_bin_edges, histogram, @@ -776,8 +755,6 @@ _T_contra = TypeVar("_T_contra", contravariant=True) _RealT_co = TypeVar("_RealT_co", covariant=True) _ImagT_co = TypeVar("_ImagT_co", covariant=True) -_CallableT = TypeVar("_CallableT", bound=Callable[..., object]) - _DTypeT = TypeVar("_DTypeT", bound=dtype) _DTypeT_co = TypeVar("_DTypeT_co", bound=dtype, default=dtype, covariant=True) _FlexDTypeT = TypeVar("_FlexDTypeT", bound=dtype[flexible]) @@ -1053,6 +1030,26 @@ class _FormerAttrsDict(TypedDict): ### Protocols (for internal use only) +@final +@type_check_only +class _SupportsLT(Protocol): + def __lt__(self, other: Any, /) -> Any: ... + +@final +@type_check_only +class _SupportsLE(Protocol): + def __le__(self, other: Any, /) -> Any: ... + +@final +@type_check_only +class _SupportsGT(Protocol): + def __gt__(self, other: Any, /) -> Any: ... + +@final +@type_check_only +class _SupportsGE(Protocol): + def __ge__(self, other: Any, /) -> Any: ... + @type_check_only class _SupportsFileMethods(SupportsFlush, Protocol): # Protocol for representing file-like-objects accepted by `ndarray.tofile` and `fromfile` @@ -1694,7 +1691,7 @@ class _ArrayOrScalarCommon: kind: _SortKind | None = ..., order: str | Sequence[str] | None = ..., *, - stable: bool | None = ..., + stable: builtins.bool | None = ..., ) -> NDArray[Any]: ... @overload # axis=None (default), out=None (default), keepdims=False (default) @@ -2355,7 +2352,7 @@ class ndarray(_ArrayOrScalarCommon, Generic[_ShapeT_co, _DTypeT_co]): kind: _SortKind | None = ..., order: str | Sequence[str] | None = ..., *, - stable: bool | None = ..., + stable: builtins.bool | None = ..., ) -> None: ... @overload @@ -3512,7 +3509,7 @@ class ndarray(_ArrayOrScalarCommon, Generic[_ShapeT_co, _DTypeT_co]): # See https://github.com/numpy/numpy-stubs/pull/80 for more details. class generic(_ArrayOrScalarCommon, Generic[_ItemT_co]): @abstractmethod - def __init__(self, *args: Any, **kwargs: Any) -> None: ... + def __new__(cls, /, *args: Any, **kwargs: Any) -> Self: ... def __hash__(self) -> int: ... @overload def __array__(self, dtype: None = None, /) -> ndarray[tuple[()], dtype[Self]]: ... @@ -3773,31 +3770,52 @@ class generic(_ArrayOrScalarCommon, Generic[_ItemT_co]): def dtype(self) -> _dtype[Self]: ... class number(generic[_NumberItemT_co], Generic[_NBit, _NumberItemT_co]): - @abstractmethod - def __init__(self, value: _NumberItemT_co, /) -> None: ... + @abstractmethod # `SupportsIndex | str | bytes` equivs `_ConvertibleToInt & _ConvertibleToFloat` + def __new__(cls, value: SupportsIndex | str | bytes = 0, /) -> Self: ... def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... def __neg__(self) -> Self: ... def __pos__(self) -> Self: ... def __abs__(self) -> Self: ... - __add__: _NumberOp - __radd__: _NumberOp - __sub__: _NumberOp - __rsub__: _NumberOp - __mul__: _NumberOp - __rmul__: _NumberOp - __floordiv__: _NumberOp - __rfloordiv__: _NumberOp - __pow__: _NumberOp - __rpow__: _NumberOp - __truediv__: _NumberOp - __rtruediv__: _NumberOp - - __lt__: _ComparisonOpLT[_NumberLike_co, _ArrayLikeNumber_co] - __le__: _ComparisonOpLE[_NumberLike_co, _ArrayLikeNumber_co] - __gt__: _ComparisonOpGT[_NumberLike_co, _ArrayLikeNumber_co] - __ge__: _ComparisonOpGE[_NumberLike_co, _ArrayLikeNumber_co] + def __add__(self, other: _NumberLike_co, /) -> Incomplete: ... + def __radd__(self, other: _NumberLike_co, /) -> Incomplete: ... + def __sub__(self, other: _NumberLike_co, /) -> Incomplete: ... + def __rsub__(self, other: _NumberLike_co, /) -> Incomplete: ... + def __mul__(self, other: _NumberLike_co, /) -> Incomplete: ... + def __rmul__(self, other: _NumberLike_co, /) -> Incomplete: ... + def __pow__(self, other: _NumberLike_co, /) -> Incomplete: ... + def __rpow__(self, other: _NumberLike_co, /) -> Incomplete: ... + def __truediv__(self, other: _NumberLike_co, /) -> Incomplete: ... + def __rtruediv__(self, other: _NumberLike_co, /) -> Incomplete: ... + + @overload + def __lt__(self, other: _NumberLike_co, /) -> bool_: ... + @overload + def __lt__(self, other: _ArrayLikeNumber_co | _NestedSequence[_SupportsGT], /) -> NDArray[bool_]: ... + @overload + def __lt__(self, other: _SupportsGT, /) -> bool_: ... + + @overload + def __le__(self, other: _NumberLike_co, /) -> bool_: ... + @overload + def __le__(self, other: _ArrayLikeNumber_co | _NestedSequence[_SupportsGE], /) -> NDArray[bool_]: ... + @overload + def __le__(self, other: _SupportsGE, /) -> bool_: ... + + @overload + def __gt__(self, other: _NumberLike_co, /) -> bool_: ... + @overload + def __gt__(self, other: _ArrayLikeNumber_co | _NestedSequence[_SupportsLT], /) -> NDArray[bool_]: ... + @overload + def __gt__(self, other: _SupportsLT, /) -> bool_: ... + + @overload + def __ge__(self, other: _NumberLike_co, /) -> bool_: ... + @overload + def __ge__(self, other: _ArrayLikeNumber_co | _NestedSequence[_SupportsLE], /) -> NDArray[bool_]: ... + @overload + def __ge__(self, other: _SupportsLE, /) -> bool_: ... class bool(generic[_BoolItemT_co], Generic[_BoolItemT_co]): @property @@ -3810,13 +3828,13 @@ class bool(generic[_BoolItemT_co], Generic[_BoolItemT_co]): def imag(self) -> np.bool[L[False]]: ... @overload # mypy bug workaround: https://github.com/numpy/numpy/issues/29245 - def __init__(self: np.bool[builtins.bool], value: Never, /) -> None: ... + def __new__(cls, value: Never, /) -> np.bool[builtins.bool]: ... @overload - def __init__(self: np.bool[L[False]], value: _Falsy = ..., /) -> None: ... + def __new__(cls, value: _Falsy = ..., /) -> np.bool[L[False]]: ... @overload - def __init__(self: np.bool[L[True]], value: _Truthy, /) -> None: ... + def __new__(cls, value: _Truthy, /) -> np.bool[L[True]]: ... @overload - def __init__(self: np.bool[builtins.bool], value: object, /) -> None: ... + def __new__(cls, value: object, /) -> np.bool[builtins.bool]: ... def __bool__(self, /) -> _BoolItemT_co: ... @@ -4064,10 +4082,33 @@ class bool(generic[_BoolItemT_co], Generic[_BoolItemT_co]): def __or__(self, other: int, /) -> np.bool | intp: ... __ror__ = __or__ - __lt__: _ComparisonOpLT[_NumberLike_co, _ArrayLikeNumber_co] - __le__: _ComparisonOpLE[_NumberLike_co, _ArrayLikeNumber_co] - __gt__: _ComparisonOpGT[_NumberLike_co, _ArrayLikeNumber_co] - __ge__: _ComparisonOpGE[_NumberLike_co, _ArrayLikeNumber_co] + @overload + def __lt__(self, other: _NumberLike_co, /) -> bool_: ... + @overload + def __lt__(self, other: _ArrayLikeNumber_co | _NestedSequence[_SupportsGT], /) -> NDArray[bool_]: ... + @overload + def __lt__(self, other: _SupportsGT, /) -> bool_: ... + + @overload + def __le__(self, other: _NumberLike_co, /) -> bool_: ... + @overload + def __le__(self, other: _ArrayLikeNumber_co | _NestedSequence[_SupportsGE], /) -> NDArray[bool_]: ... + @overload + def __le__(self, other: _SupportsGE, /) -> bool_: ... + + @overload + def __gt__(self, other: _NumberLike_co, /) -> bool_: ... + @overload + def __gt__(self, other: _ArrayLikeNumber_co | _NestedSequence[_SupportsLT], /) -> NDArray[bool_]: ... + @overload + def __gt__(self, other: _SupportsLT, /) -> bool_: ... + + @overload + def __ge__(self, other: _NumberLike_co, /) -> bool_: ... + @overload + def __ge__(self, other: _ArrayLikeNumber_co | _NestedSequence[_SupportsLE], /) -> NDArray[bool_]: ... + @overload + def __ge__(self, other: _SupportsLE, /) -> bool_: ... # NOTE: This should _not_ be `Final` or a `TypeAlias` bool_ = bool @@ -4090,7 +4131,7 @@ class object_(_RealMixin, generic): def __new__(cls, value: _T, /) -> _T: ... # type: ignore[misc] @overload # catch-all def __new__(cls, value: Any = ..., /) -> object | NDArray[Self]: ... # type: ignore[misc] - def __init__(self, value: object = ..., /) -> None: ... + def __hash__(self, /) -> int: ... def __abs__(self, /) -> object_: ... # this affects NDArray[object_].__abs__ def __call__(self, /, *args: object, **kwargs: object) -> Any: ... @@ -4100,17 +4141,32 @@ class object_(_RealMixin, generic): class integer(_IntegralMixin, _RoundMixin, number[_NBit, int]): @abstractmethod - def __init__(self, value: _ConvertibleToInt = ..., /) -> None: ... + def __new__(cls, value: _ConvertibleToInt = 0, /) -> Self: ... # NOTE: `bit_count` and `__index__` are technically defined in the concrete subtypes def bit_count(self, /) -> int: ... def __index__(self, /) -> int: ... def __invert__(self, /) -> Self: ... - __truediv__: _IntTrueDiv[_NBit] - __rtruediv__: _IntTrueDiv[_NBit] + @override # type: ignore[override] + @overload + def __truediv__(self, other: float | integer, /) -> float64: ... + @overload + def __truediv__(self, other: complex, /) -> complex128: ... + + @override # type: ignore[override] + @overload + def __rtruediv__(self, other: float | integer, /) -> float64: ... + @overload + def __rtruediv__(self, other: complex, /) -> complex128: ... + + def __floordiv__(self, value: _IntLike_co, /) -> integer: ... + def __rfloordiv__(self, value: _IntLike_co, /) -> integer: ... def __mod__(self, value: _IntLike_co, /) -> integer: ... def __rmod__(self, value: _IntLike_co, /) -> integer: ... + def __divmod__(self, value: _IntLike_co, /) -> _2Tuple[integer]: ... + def __rdivmod__(self, value: _IntLike_co, /) -> _2Tuple[integer]: ... + # Ensure that objects annotated as `integer` support bit-wise operations def __lshift__(self, other: _IntLike_co, /) -> integer: ... def __rlshift__(self, other: _IntLike_co, /) -> integer: ... @@ -4123,33 +4179,230 @@ class integer(_IntegralMixin, _RoundMixin, number[_NBit, int]): def __xor__(self, other: _IntLike_co, /) -> integer: ... def __rxor__(self, other: _IntLike_co, /) -> integer: ... -class signedinteger(integer[_NBit1]): - def __init__(self, value: _ConvertibleToInt = ..., /) -> None: ... - - __add__: _SignedIntOp[_NBit1] - __radd__: _SignedIntOp[_NBit1] - __sub__: _SignedIntOp[_NBit1] - __rsub__: _SignedIntOp[_NBit1] - __mul__: _SignedIntOp[_NBit1] - __rmul__: _SignedIntOp[_NBit1] - __floordiv__: _SignedIntOp[_NBit1] - __rfloordiv__: _SignedIntOp[_NBit1] - __pow__: _SignedIntOp[_NBit1] - __rpow__: _SignedIntOp[_NBit1] - __lshift__: _SignedIntBitOp[_NBit1] - __rlshift__: _SignedIntBitOp[_NBit1] - __rshift__: _SignedIntBitOp[_NBit1] - __rrshift__: _SignedIntBitOp[_NBit1] - __and__: _SignedIntBitOp[_NBit1] - __rand__: _SignedIntBitOp[_NBit1] - __xor__: _SignedIntBitOp[_NBit1] - __rxor__: _SignedIntBitOp[_NBit1] - __or__: _SignedIntBitOp[_NBit1] - __ror__: _SignedIntBitOp[_NBit1] - __mod__: _SignedIntMod[_NBit1] - __rmod__: _SignedIntMod[_NBit1] - __divmod__: _SignedIntDivMod[_NBit1] - __rdivmod__: _SignedIntDivMod[_NBit1] +class signedinteger(integer[_NBit]): + def __new__(cls, value: _ConvertibleToInt = 0, /) -> Self: ... + + # arithmetic ops + + @override # type: ignore[override] + @overload + def __add__(self, other: int | int8 | bool_ | Self, /) -> Self: ... + @overload + def __add__(self, other: float, /) -> float64: ... + @overload + def __add__(self, other: complex, /) -> complex128: ... + @overload + def __add__(self, other: signedinteger, /) -> signedinteger: ... + @overload + def __add__(self, other: integer, /) -> Incomplete: ... + + @override # type: ignore[override] + @overload + def __radd__(self, other: int | int8 | bool_, /) -> Self: ... + @overload + def __radd__(self, other: float, /) -> float64: ... + @overload + def __radd__(self, other: complex, /) -> complex128: ... + @overload + def __radd__(self, other: signedinteger, /) -> signedinteger: ... + @overload + def __radd__(self, other: integer, /) -> Incomplete: ... + + @override # type: ignore[override] + @overload + def __sub__(self, other: int | int8 | bool_ | Self, /) -> Self: ... + @overload + def __sub__(self, other: float, /) -> float64: ... + @overload + def __sub__(self, other: complex, /) -> complex128: ... + @overload + def __sub__(self, other: signedinteger, /) -> signedinteger: ... + @overload + def __sub__(self, other: integer, /) -> Incomplete: ... + + @override # type: ignore[override] + @overload + def __rsub__(self, other: int | int8 | bool_, /) -> Self: ... + @overload + def __rsub__(self, other: float, /) -> float64: ... + @overload + def __rsub__(self, other: complex, /) -> complex128: ... + @overload + def __rsub__(self, other: signedinteger, /) -> signedinteger: ... + @overload + def __rsub__(self, other: integer, /) -> Incomplete: ... + + @override # type: ignore[override] + @overload + def __mul__(self, other: int | int8 | bool_ | Self, /) -> Self: ... + @overload + def __mul__(self, other: float, /) -> float64: ... + @overload + def __mul__(self, other: complex, /) -> complex128: ... + @overload + def __mul__(self, other: signedinteger, /) -> signedinteger: ... + @overload + def __mul__(self, other: integer, /) -> Incomplete: ... + + @override # type: ignore[override] + @overload + def __rmul__(self, other: int | int8 | bool_, /) -> Self: ... + @overload + def __rmul__(self, other: float, /) -> float64: ... + @overload + def __rmul__(self, other: complex, /) -> complex128: ... + @overload + def __rmul__(self, other: signedinteger, /) -> signedinteger: ... + @overload + def __rmul__(self, other: integer, /) -> Incomplete: ... + + @override # type: ignore[override] + @overload + def __pow__(self, other: int | int8 | bool_ | Self, mod: None = None, /) -> Self: ... + @overload + def __pow__(self, other: float, mod: None = None, /) -> float64: ... + @overload + def __pow__(self, other: complex, mod: None = None, /) -> complex128: ... + @overload + def __pow__(self, other: signedinteger, mod: None = None, /) -> signedinteger: ... + @overload + def __pow__(self, other: integer, mod: None = None, /) -> Incomplete: ... + + @override # type: ignore[override] + @overload + def __rpow__(self, other: int | int8 | bool_, mod: None = None, /) -> Self: ... + @overload + def __rpow__(self, other: float, mod: None = None, /) -> float64: ... + @overload + def __rpow__(self, other: complex, mod: None = None, /) -> complex128: ... + @overload + def __rpow__(self, other: signedinteger, mod: None = None, /) -> signedinteger: ... + @overload + def __rpow__(self, other: integer, mod: None = None, /) -> Incomplete: ... + + # modular division ops + + @override # type: ignore[override] + @overload + def __floordiv__(self, other: int | int8 | bool_ | Self, /) -> Self: ... + @overload + def __floordiv__(self, other: float, /) -> float64: ... + @overload + def __floordiv__(self, other: signedinteger, /) -> signedinteger: ... + @overload + def __floordiv__(self, other: integer, /) -> Incomplete: ... + + @override # type: ignore[override] + @overload + def __rfloordiv__(self, other: int | int8 | bool_, /) -> Self: ... + @overload + def __rfloordiv__(self, other: float, /) -> float64: ... + @overload + def __rfloordiv__(self, other: signedinteger, /) -> signedinteger: ... + @overload + def __rfloordiv__(self, other: integer, /) -> Incomplete: ... + + @override # type: ignore[override] + @overload + def __mod__(self, other: int | int8 | bool_ | Self, /) -> Self: ... + @overload + def __mod__(self, other: float, /) -> float64: ... + @overload + def __mod__(self, other: signedinteger, /) -> signedinteger: ... + @overload + def __mod__(self, other: integer, /) -> Incomplete: ... + + @override # type: ignore[override] + @overload + def __rmod__(self, other: int | int8 | bool_, /) -> Self: ... + @overload + def __rmod__(self, other: float, /) -> float64: ... + @overload + def __rmod__(self, other: signedinteger, /) -> signedinteger: ... + @overload + def __rmod__(self, other: integer, /) -> Incomplete: ... + + @override # type: ignore[override] + @overload + def __divmod__(self, other: int | int8 | bool_ | Self, /) -> _2Tuple[Self]: ... + @overload + def __divmod__(self, other: float, /) -> _2Tuple[float64]: ... + @overload + def __divmod__(self, other: signedinteger, /) -> _2Tuple[signedinteger]: ... + @overload + def __divmod__(self, other: integer, /) -> _2Tuple[Incomplete]: ... + + @override # type: ignore[override] + @overload + def __rdivmod__(self, other: int | int8 | bool_, /) -> _2Tuple[Self]: ... + @overload + def __rdivmod__(self, other: float, /) -> _2Tuple[float64]: ... + @overload + def __rdivmod__(self, other: signedinteger, /) -> _2Tuple[signedinteger]: ... + @overload + def __rdivmod__(self, other: integer, /) -> _2Tuple[Incomplete]: ... + + # bitwise ops + + @override # type: ignore[override] + @overload + def __lshift__(self, other: int | int8 | bool_ | Self, /) -> Self: ... + @overload + def __lshift__(self, other: integer, /) -> signedinteger: ... + + @override # type: ignore[override] + @overload + def __rlshift__(self, other: int | int8 | bool_, /) -> Self: ... + @overload + def __rlshift__(self, other: integer, /) -> signedinteger: ... + + @override # type: ignore[override] + @overload + def __rshift__(self, other: int | int8 | bool_ | Self, /) -> Self: ... + @overload + def __rshift__(self, other: integer, /) -> signedinteger: ... + + @override # type: ignore[override] + @overload + def __rrshift__(self, other: int | int8 | bool_, /) -> Self: ... + @overload + def __rrshift__(self, other: integer, /) -> signedinteger: ... + + @override # type: ignore[override] + @overload + def __and__(self, other: int | int8 | bool_ | Self, /) -> Self: ... + @overload + def __and__(self, other: integer, /) -> signedinteger: ... + + @override # type: ignore[override] + @overload + def __rand__(self, other: int | int8 | bool_, /) -> Self: ... + @overload + def __rand__(self, other: integer, /) -> signedinteger: ... + + @override # type: ignore[override] + @overload + def __xor__(self, other: int | int8 | bool_ | Self, /) -> Self: ... + @overload + def __xor__(self, other: integer, /) -> signedinteger: ... + + @override # type: ignore[override] + @overload + def __rxor__(self, other: int | int8 | bool_, /) -> Self: ... + @overload + def __rxor__(self, other: integer, /) -> signedinteger: ... + + @override # type: ignore[override] + @overload + def __or__(self, other: int | int8 | bool_ | Self, /) -> Self: ... + @overload + def __or__(self, other: integer, /) -> signedinteger: ... + + @override # type: ignore[override] + @overload + def __ror__(self, other: int | int8 | bool_, /) -> Self: ... + @overload + def __ror__(self, other: integer, /) -> signedinteger: ... int8 = signedinteger[_8Bit] int16 = signedinteger[_16Bit] @@ -4165,33 +4418,249 @@ long = signedinteger[_NBitLong] longlong = signedinteger[_NBitLongLong] class unsignedinteger(integer[_NBit1]): - # NOTE: `uint64 + signedinteger -> float64` - def __init__(self, value: _ConvertibleToInt = ..., /) -> None: ... - - __add__: _UnsignedIntOp[_NBit1] - __radd__: _UnsignedIntOp[_NBit1] - __sub__: _UnsignedIntOp[_NBit1] - __rsub__: _UnsignedIntOp[_NBit1] - __mul__: _UnsignedIntOp[_NBit1] - __rmul__: _UnsignedIntOp[_NBit1] - __floordiv__: _UnsignedIntOp[_NBit1] - __rfloordiv__: _UnsignedIntOp[_NBit1] - __pow__: _UnsignedIntOp[_NBit1] - __rpow__: _UnsignedIntOp[_NBit1] - __lshift__: _UnsignedIntBitOp[_NBit1] - __rlshift__: _UnsignedIntBitOp[_NBit1] - __rshift__: _UnsignedIntBitOp[_NBit1] - __rrshift__: _UnsignedIntBitOp[_NBit1] - __and__: _UnsignedIntBitOp[_NBit1] - __rand__: _UnsignedIntBitOp[_NBit1] - __xor__: _UnsignedIntBitOp[_NBit1] - __rxor__: _UnsignedIntBitOp[_NBit1] - __or__: _UnsignedIntBitOp[_NBit1] - __ror__: _UnsignedIntBitOp[_NBit1] - __mod__: _UnsignedIntMod[_NBit1] - __rmod__: _UnsignedIntMod[_NBit1] - __divmod__: _UnsignedIntDivMod[_NBit1] - __rdivmod__: _UnsignedIntDivMod[_NBit1] + def __new__(cls, value: _ConvertibleToInt = 0, /) -> Self: ... + + # arithmetic ops + + @override # type: ignore[override] + @overload + def __add__(self, other: int | uint8 | bool_ | Self, /) -> Self: ... + @overload + def __add__(self, other: float, /) -> float64: ... + @overload + def __add__(self, other: complex, /) -> complex128: ... + @overload + def __add__(self, other: unsignedinteger, /) -> unsignedinteger: ... + @overload + def __add__(self, other: integer, /) -> Incomplete: ... + + @override # type: ignore[override] + @overload + def __radd__(self, other: int | uint8 | bool_, /) -> Self: ... + @overload + def __radd__(self, other: float, /) -> float64: ... + @overload + def __radd__(self, other: complex, /) -> complex128: ... + @overload + def __radd__(self, other: unsignedinteger, /) -> unsignedinteger: ... + @overload + def __radd__(self, other: integer, /) -> Incomplete: ... + + @override # type: ignore[override] + @overload + def __sub__(self, other: int | uint8 | bool_ | Self, /) -> Self: ... + @overload + def __sub__(self, other: float, /) -> float64: ... + @overload + def __sub__(self, other: complex, /) -> complex128: ... + @overload + def __sub__(self, other: unsignedinteger, /) -> unsignedinteger: ... + @overload + def __sub__(self, other: integer, /) -> Incomplete: ... + + @override # type: ignore[override] + @overload + def __rsub__(self, other: int | uint8 | bool_, /) -> Self: ... + @overload + def __rsub__(self, other: float, /) -> float64: ... + @overload + def __rsub__(self, other: complex, /) -> complex128: ... + @overload + def __rsub__(self, other: unsignedinteger, /) -> unsignedinteger: ... + @overload + def __rsub__(self, other: integer, /) -> Incomplete: ... + + @override # type: ignore[override] + @overload + def __mul__(self, other: int | uint8 | bool_ | Self, /) -> Self: ... + @overload + def __mul__(self, other: float, /) -> float64: ... + @overload + def __mul__(self, other: complex, /) -> complex128: ... + @overload + def __mul__(self, other: unsignedinteger, /) -> unsignedinteger: ... + @overload + def __mul__(self, other: integer, /) -> Incomplete: ... + + @override # type: ignore[override] + @overload + def __rmul__(self, other: int | uint8 | bool_, /) -> Self: ... + @overload + def __rmul__(self, other: float, /) -> float64: ... + @overload + def __rmul__(self, other: complex, /) -> complex128: ... + @overload + def __rmul__(self, other: unsignedinteger, /) -> unsignedinteger: ... + @overload + def __rmul__(self, other: integer, /) -> Incomplete: ... + + @override # type: ignore[override] + @overload + def __pow__(self, other: int | uint8 | bool_ | Self, mod: None = None, /) -> Self: ... + @overload + def __pow__(self, other: float, mod: None = None, /) -> float64: ... + @overload + def __pow__(self, other: complex, mod: None = None, /) -> complex128: ... + @overload + def __pow__(self, other: unsignedinteger, mod: None = None, /) -> unsignedinteger: ... + @overload + def __pow__(self, other: integer, mod: None = None, /) -> Incomplete: ... + + @override # type: ignore[override] + @overload + def __rpow__(self, other: int | uint8 | bool_, mod: None = None, /) -> Self: ... + @overload + def __rpow__(self, other: float, mod: None = None, /) -> float64: ... + @overload + def __rpow__(self, other: complex, mod: None = None, /) -> complex128: ... + @overload + def __rpow__(self, other: unsignedinteger, mod: None = None, /) -> unsignedinteger: ... + @overload + def __rpow__(self, other: integer, mod: None = None, /) -> Incomplete: ... + + # modular division ops + + @override # type: ignore[override] + @overload + def __floordiv__(self, other: int | uint8 | bool_ | Self, /) -> Self: ... + @overload + def __floordiv__(self, other: float, /) -> float64: ... + @overload + def __floordiv__(self, other: unsignedinteger, /) -> unsignedinteger: ... + @overload + def __floordiv__(self, other: integer, /) -> Incomplete: ... + + @override # type: ignore[override] + @overload + def __rfloordiv__(self, other: int | uint8 | bool_, /) -> Self: ... + @overload + def __rfloordiv__(self, other: float, /) -> float64: ... + @overload + def __rfloordiv__(self, other: unsignedinteger, /) -> unsignedinteger: ... + @overload + def __rfloordiv__(self, other: integer, /) -> Incomplete: ... + + @override # type: ignore[override] + @overload + def __mod__(self, other: int | uint8 | bool_ | Self, /) -> Self: ... + @overload + def __mod__(self, other: float, /) -> float64: ... + @overload + def __mod__(self, other: unsignedinteger, /) -> unsignedinteger: ... + @overload + def __mod__(self, other: integer, /) -> Incomplete: ... + + @override # type: ignore[override] + @overload + def __rmod__(self, other: int | uint8 | bool_, /) -> Self: ... + @overload + def __rmod__(self, other: float, /) -> float64: ... + @overload + def __rmod__(self, other: unsignedinteger, /) -> unsignedinteger: ... + @overload + def __rmod__(self, other: integer, /) -> Incomplete: ... + + @override # type: ignore[override] + @overload + def __divmod__(self, other: int | uint8 | bool_ | Self, /) -> _2Tuple[Self]: ... + @overload + def __divmod__(self, other: float, /) -> _2Tuple[float64]: ... + @overload + def __divmod__(self, other: unsignedinteger, /) -> _2Tuple[unsignedinteger]: ... + @overload + def __divmod__(self, other: integer, /) -> _2Tuple[Incomplete]: ... + + @override # type: ignore[override] + @overload + def __rdivmod__(self, other: int | uint8 | bool_, /) -> _2Tuple[Self]: ... + @overload + def __rdivmod__(self, other: float, /) -> _2Tuple[float64]: ... + @overload + def __rdivmod__(self, other: unsignedinteger, /) -> _2Tuple[unsignedinteger]: ... + @overload + def __rdivmod__(self, other: integer, /) -> _2Tuple[Incomplete]: ... + + # bitwise ops + + @override # type: ignore[override] + @overload + def __lshift__(self, other: int | int8 | bool_ | Self, /) -> Self: ... + @overload + def __lshift__(self, other: unsignedinteger, /) -> unsignedinteger: ... + @overload + def __lshift__(self, other: signedinteger, /) -> signedinteger: ... + + @override # type: ignore[override] + @overload + def __rlshift__(self, other: int | int8 | bool_, /) -> Self: ... + @overload + def __rlshift__(self, other: unsignedinteger, /) -> unsignedinteger: ... + @overload + def __rlshift__(self, other: signedinteger, /) -> signedinteger: ... + + @override # type: ignore[override] + @overload + def __rshift__(self, other: int | int8 | bool_ | Self, /) -> Self: ... + @overload + def __rshift__(self, other: unsignedinteger, /) -> unsignedinteger: ... + @overload + def __rshift__(self, other: signedinteger, /) -> signedinteger: ... + + @override # type: ignore[override] + @overload + def __rrshift__(self, other: int | int8 | bool_, /) -> Self: ... + @overload + def __rrshift__(self, other: unsignedinteger, /) -> unsignedinteger: ... + @overload + def __rrshift__(self, other: signedinteger, /) -> signedinteger: ... + + @override # type: ignore[override] + @overload + def __and__(self, other: int | int8 | bool_ | Self, /) -> Self: ... + @overload + def __and__(self, other: unsignedinteger, /) -> unsignedinteger: ... + @overload + def __and__(self, other: signedinteger, /) -> signedinteger: ... + + @override # type: ignore[override] + @overload + def __rand__(self, other: int | int8 | bool_, /) -> Self: ... + @overload + def __rand__(self, other: unsignedinteger, /) -> unsignedinteger: ... + @overload + def __rand__(self, other: signedinteger, /) -> signedinteger: ... + + @override # type: ignore[override] + @overload + def __xor__(self, other: int | int8 | bool_ | Self, /) -> Self: ... + @overload + def __xor__(self, other: unsignedinteger, /) -> unsignedinteger: ... + @overload + def __xor__(self, other: signedinteger, /) -> signedinteger: ... + + @override # type: ignore[override] + @overload + def __rxor__(self, other: int | int8 | bool_, /) -> Self: ... + @overload + def __rxor__(self, other: unsignedinteger, /) -> unsignedinteger: ... + @overload + def __rxor__(self, other: signedinteger, /) -> signedinteger: ... + + @override # type: ignore[override] + @overload + def __or__(self, other: int | int8 | bool_ | Self, /) -> Self: ... + @overload + def __or__(self, other: unsignedinteger, /) -> unsignedinteger: ... + @overload + def __or__(self, other: signedinteger, /) -> signedinteger: ... + + @override # type: ignore[override] + @overload + def __ror__(self, other: int | int8 | bool_, /) -> Self: ... + @overload + def __ror__(self, other: unsignedinteger, /) -> unsignedinteger: ... + @overload + def __ror__(self, other: signedinteger, /) -> signedinteger: ... uint8: TypeAlias = unsignedinteger[_8Bit] uint16: TypeAlias = unsignedinteger[_16Bit] @@ -4208,27 +4677,156 @@ ulonglong: TypeAlias = unsignedinteger[_NBitLongLong] class inexact(number[_NBit, _InexactItemT_co], Generic[_NBit, _InexactItemT_co]): @abstractmethod - def __init__(self, value: _InexactItemT_co | None = ..., /) -> None: ... + def __new__(cls, value: _ConvertibleToFloat | None = 0, /) -> Self: ... class floating(_RealMixin, _RoundMixin, inexact[_NBit1, float]): - def __init__(self, value: _ConvertibleToFloat | None = ..., /) -> None: ... - - __add__: _FloatOp[_NBit1] - __radd__: _FloatOp[_NBit1] - __sub__: _FloatOp[_NBit1] - __rsub__: _FloatOp[_NBit1] - __mul__: _FloatOp[_NBit1] - __rmul__: _FloatOp[_NBit1] - __truediv__: _FloatOp[_NBit1] - __rtruediv__: _FloatOp[_NBit1] - __floordiv__: _FloatOp[_NBit1] - __rfloordiv__: _FloatOp[_NBit1] - __pow__: _FloatOp[_NBit1] - __rpow__: _FloatOp[_NBit1] - __mod__: _FloatMod[_NBit1] - __rmod__: _FloatMod[_NBit1] - __divmod__: _FloatDivMod[_NBit1] - __rdivmod__: _FloatDivMod[_NBit1] + def __new__(cls, value: _ConvertibleToFloat | None = 0, /) -> Self: ... + + # arithmetic ops + + @override # type: ignore[override] + @overload + def __add__(self, other: int | float16 | uint8 | int8 | bool_ | Self, /) -> Self: ... + @overload + def __add__(self, other: integer | floating, /) -> floating: ... + @overload + def __add__(self, other: float, /) -> Self: ... + @overload + def __add__(self, other: complex, /) -> complexfloating: ... + + @override # type: ignore[override] + @overload + def __radd__(self, other: int | float16 | uint8 | int8 | bool_, /) -> Self: ... + @overload + def __radd__(self, other: integer | floating, /) -> floating: ... + @overload + def __radd__(self, other: float, /) -> Self: ... + @overload + def __radd__(self, other: complex, /) -> complexfloating: ... + + @override # type: ignore[override] + @overload + def __sub__(self, other: int | float16 | uint8 | int8 | bool_ | Self, /) -> Self: ... + @overload + def __sub__(self, other: integer | floating, /) -> floating: ... + @overload + def __sub__(self, other: float, /) -> Self: ... + @overload + def __sub__(self, other: complex, /) -> complexfloating: ... + + @override # type: ignore[override] + @overload + def __rsub__(self, other: int | float16 | uint8 | int8 | bool_, /) -> Self: ... + @overload + def __rsub__(self, other: integer | floating, /) -> floating: ... + @overload + def __rsub__(self, other: float, /) -> Self: ... + @overload + def __rsub__(self, other: complex, /) -> complexfloating: ... + + @override # type: ignore[override] + @overload + def __mul__(self, other: int | float16 | uint8 | int8 | bool_ | Self, /) -> Self: ... + @overload + def __mul__(self, other: integer | floating, /) -> floating: ... + @overload + def __mul__(self, other: float, /) -> Self: ... + @overload + def __mul__(self, other: complex, /) -> complexfloating: ... + + @override # type: ignore[override] + @overload + def __rmul__(self, other: int | float16 | uint8 | int8 | bool_, /) -> Self: ... + @overload + def __rmul__(self, other: integer | floating, /) -> floating: ... + @overload + def __rmul__(self, other: float, /) -> Self: ... + @overload + def __rmul__(self, other: complex, /) -> complexfloating: ... + + @override # type: ignore[override] + @overload + def __pow__(self, other: int | float16 | uint8 | int8 | bool_ | Self, mod: None = None, /) -> Self: ... + @overload + def __pow__(self, other: integer | floating, mod: None = None, /) -> floating: ... + @overload + def __pow__(self, other: float, mod: None = None, /) -> Self: ... + @overload + def __pow__(self, other: complex, mod: None = None, /) -> complexfloating: ... + + @override # type: ignore[override] + @overload + def __rpow__(self, other: int | float16 | uint8 | int8 | bool_, mod: None = None, /) -> Self: ... + @overload + def __rpow__(self, other: integer | floating, mod: None = None, /) -> floating: ... + @overload + def __rpow__(self, other: float, mod: None = None, /) -> Self: ... + @overload + def __rpow__(self, other: complex, mod: None = None, /) -> complexfloating: ... + + @override # type: ignore[override] + @overload + def __truediv__(self, other: int | float16 | uint8 | int8 | bool_ | Self, /) -> Self: ... + @overload + def __truediv__(self, other: integer | floating, /) -> floating: ... + @overload + def __truediv__(self, other: float, /) -> Self: ... + @overload + def __truediv__(self, other: complex, /) -> complexfloating: ... + + @override # type: ignore[override] + @overload + def __rtruediv__(self, other: int | float16 | uint8 | int8 | bool_, /) -> Self: ... + @overload + def __rtruediv__(self, other: integer | floating, /) -> floating: ... + @overload + def __rtruediv__(self, other: float, /) -> Self: ... + @overload + def __rtruediv__(self, other: complex, /) -> complexfloating: ... + + # modular division ops + + @overload + def __floordiv__(self, other: int | float16 | uint8 | int8 | bool_ | Self, /) -> Self: ... + @overload + def __floordiv__(self, other: integer | floating, /) -> floating: ... + @overload + def __floordiv__(self, other: float, /) -> Self: ... + + @overload + def __rfloordiv__(self, other: int | float16 | uint8 | int8 | bool_, /) -> Self: ... + @overload + def __rfloordiv__(self, other: integer | floating, /) -> floating: ... + @overload + def __rfloordiv__(self, other: float, /) -> Self: ... + + @overload + def __mod__(self, other: int | float16 | uint8 | int8 | bool_ | Self, /) -> Self: ... + @overload + def __mod__(self, other: integer | floating, /) -> floating: ... + @overload + def __mod__(self, other: float, /) -> Self: ... + + @overload + def __rmod__(self, other: int | float16 | uint8 | int8 | bool_, /) -> Self: ... + @overload + def __rmod__(self, other: integer | floating, /) -> floating: ... + @overload + def __rmod__(self, other: float, /) -> Self: ... + + @overload + def __divmod__(self, other: int | float16 | uint8 | int8 | bool_ | Self, /) -> _2Tuple[Self]: ... + @overload + def __divmod__(self, other: integer | floating, /) -> _2Tuple[floating]: ... + @overload + def __divmod__(self, other: float, /) -> _2Tuple[Self]: ... + + @overload + def __rdivmod__(self, other: int | float16 | uint8 | int8 | bool_, /) -> _2Tuple[Self]: ... + @overload + def __rdivmod__(self, other: integer | floating, /) -> _2Tuple[floating]: ... + @overload + def __rdivmod__(self, other: float, /) -> _2Tuple[Self]: ... # NOTE: `is_integer` and `as_integer_ratio` are technically defined in the concrete subtypes def is_integer(self, /) -> builtins.bool: ... @@ -4239,9 +4837,6 @@ float32: TypeAlias = floating[_32Bit] # either a C `double`, `float`, or `longdouble` class float64(floating[_64Bit], float): # type: ignore[misc] - def __new__(cls, x: _ConvertibleToFloat | None = ..., /) -> Self: ... - - # @property def itemsize(self) -> L[8]: ... @property @@ -4380,19 +4975,19 @@ longdouble: TypeAlias = floating[_NBitLongDouble] class complexfloating(inexact[_NBit1, complex], Generic[_NBit1, _NBit2]): @overload - def __init__( - self, - real: complex | SupportsComplex | SupportsFloat | SupportsIndex = ..., - imag: complex | SupportsFloat | SupportsIndex = ..., + def __new__( + cls, + real: complex | SupportsComplex | SupportsFloat | SupportsIndex = 0, + imag: complex | SupportsFloat | SupportsIndex = 0, /, - ) -> None: ... + ) -> Self: ... @overload - def __init__(self, real: _ConvertibleToComplex | None = ..., /) -> None: ... + def __new__(cls, real: _ConvertibleToComplex | None = 0, /) -> Self: ... @property - def real(self) -> floating[_NBit1]: ... # type: ignore[override] + def real(self) -> floating[_NBit1]: ... @property - def imag(self) -> floating[_NBit2]: ... # type: ignore[override] + def imag(self) -> floating[_NBit2]: ... # NOTE: `__complex__` is technically defined in the concrete subtypes def __complex__(self, /) -> complex: ... @@ -4471,18 +5066,7 @@ class complexfloating(inexact[_NBit1, complex], Generic[_NBit1, _NBit2]): complex64: TypeAlias = complexfloating[_32Bit, _32Bit] -class complex128(complexfloating[_64Bit, _64Bit], complex): # type: ignore[misc] - @overload - def __new__( - cls, - real: complex | SupportsComplex | SupportsFloat | SupportsIndex = ..., - imag: complex | SupportsFloat | SupportsIndex = ..., - /, - ) -> Self: ... - @overload - def __new__(cls, real: _ConvertibleToComplex | None = ..., /) -> Self: ... - - # +class complex128(complexfloating[_64Bit, _64Bit], complex): @property def itemsize(self) -> L[16]: ... @property @@ -4541,26 +5125,26 @@ class timedelta64(_IntegralMixin, generic[_TD64ItemT_co], Generic[_TD64ItemT_co] def nbytes(self) -> L[8]: ... @overload - def __init__(self, value: _TD64ItemT_co | timedelta64[_TD64ItemT_co], /) -> None: ... + def __new__(cls, value: _TD64ItemT_co | timedelta64[_TD64ItemT_co], /) -> Self: ... @overload - def __init__(self: timedelta64[L[0]], /) -> None: ... + def __new__(cls, /) -> timedelta64[L[0]]: ... @overload - def __init__(self: timedelta64[None], value: _NaTValue | None, format: _TimeUnitSpec, /) -> None: ... + def __new__(cls, value: _NaTValue | None, format: _TimeUnitSpec, /) -> timedelta64[None]: ... @overload - def __init__(self: timedelta64[L[0]], value: L[0], format: _TimeUnitSpec[_IntTD64Unit] = ..., /) -> None: ... + def __new__(cls, value: L[0], format: _TimeUnitSpec[_IntTD64Unit] = ..., /) -> timedelta64[L[0]]: ... @overload - def __init__(self: timedelta64[int], value: _IntLike_co, format: _TimeUnitSpec[_IntTD64Unit] = ..., /) -> None: ... + def __new__(cls, value: _IntLike_co, format: _TimeUnitSpec[_IntTD64Unit] = ..., /) -> timedelta64[int]: ... @overload - def __init__(self: timedelta64[int], value: dt.timedelta, format: _TimeUnitSpec[_IntTimeUnit], /) -> None: ... + def __new__(cls, value: dt.timedelta, format: _TimeUnitSpec[_IntTimeUnit], /) -> timedelta64[int]: ... @overload - def __init__( - self: timedelta64[dt.timedelta], + def __new__( + cls, value: dt.timedelta | _IntLike_co, format: _TimeUnitSpec[_NativeTD64Unit] = ..., /, - ) -> None: ... + ) -> timedelta64[dt.timedelta]: ... @overload - def __init__(self, value: _ConvertibleToTD64, format: _TimeUnitSpec = ..., /) -> None: ... + def __new__(cls, value: _ConvertibleToTD64, format: _TimeUnitSpec = ..., /) -> Self: ... # inherited at runtime from `signedinteger` def __class_getitem__(cls, type_arg: type | object, /) -> GenericAlias: ... @@ -4713,10 +5297,35 @@ class timedelta64(_IntegralMixin, generic[_TD64ItemT_co], Generic[_TD64ItemT_co] @overload def __rfloordiv__(self, a: timedelta64, /) -> int64: ... - __lt__: _ComparisonOpLT[_TD64Like_co, _ArrayLikeTD64_co] - __le__: _ComparisonOpLE[_TD64Like_co, _ArrayLikeTD64_co] - __gt__: _ComparisonOpGT[_TD64Like_co, _ArrayLikeTD64_co] - __ge__: _ComparisonOpGE[_TD64Like_co, _ArrayLikeTD64_co] + # comparison ops + + @overload + def __lt__(self, other: _TD64Like_co, /) -> bool_: ... + @overload + def __lt__(self, other: _ArrayLikeTD64_co | _NestedSequence[_SupportsGT], /) -> NDArray[bool_]: ... + @overload + def __lt__(self, other: _SupportsGT, /) -> bool_: ... + + @overload + def __le__(self, other: _TD64Like_co, /) -> bool_: ... + @overload + def __le__(self, other: _ArrayLikeTD64_co | _NestedSequence[_SupportsGE], /) -> NDArray[bool_]: ... + @overload + def __le__(self, other: _SupportsGT, /) -> bool_: ... + + @overload + def __gt__(self, other: _TD64Like_co, /) -> bool_: ... + @overload + def __gt__(self, other: _ArrayLikeTD64_co | _NestedSequence[_SupportsLT], /) -> NDArray[bool_]: ... + @overload + def __gt__(self, other: _SupportsGT, /) -> bool_: ... + + @overload + def __ge__(self, other: _TD64Like_co, /) -> bool_: ... + @overload + def __ge__(self, other: _ArrayLikeTD64_co | _NestedSequence[_SupportsLE], /) -> NDArray[bool_]: ... + @overload + def __ge__(self, other: _SupportsGT, /) -> bool_: ... class datetime64(_RealMixin, generic[_DT64ItemT_co], Generic[_DT64ItemT_co]): @property @@ -4725,25 +5334,25 @@ class datetime64(_RealMixin, generic[_DT64ItemT_co], Generic[_DT64ItemT_co]): def nbytes(self) -> L[8]: ... @overload - def __init__(self, value: datetime64[_DT64ItemT_co], /) -> None: ... + def __new__(cls, value: datetime64[_DT64ItemT_co], /) -> Self: ... @overload - def __init__(self: datetime64[_AnyDT64Arg], value: _AnyDT64Arg, /) -> None: ... + def __new__(cls, value: _AnyDT64Arg, /) -> datetime64[_AnyDT64Arg]: ... @overload - def __init__(self: datetime64[None], value: _NaTValue | None = ..., format: _TimeUnitSpec = ..., /) -> None: ... + def __new__(cls, value: _NaTValue | None = ..., format: _TimeUnitSpec = ..., /) -> datetime64[None]: ... @overload - def __init__(self: datetime64[dt.datetime], value: _DT64Now, format: _TimeUnitSpec[_NativeTimeUnit] = ..., /) -> None: ... + def __new__(cls, value: _DT64Now, format: _TimeUnitSpec[_NativeTimeUnit] = ..., /) -> datetime64[dt.datetime]: ... @overload - def __init__(self: datetime64[dt.date], value: _DT64Date, format: _TimeUnitSpec[_DateUnit] = ..., /) -> None: ... + def __new__(cls, value: _DT64Date, format: _TimeUnitSpec[_DateUnit] = ..., /) -> datetime64[dt.date]: ... @overload - def __init__(self: datetime64[int], value: int | bytes | str | dt.date, format: _TimeUnitSpec[_IntTimeUnit], /) -> None: ... + def __new__(cls, value: int | bytes | str | dt.date, format: _TimeUnitSpec[_IntTimeUnit], /) -> datetime64[int]: ... @overload - def __init__( - self: datetime64[dt.datetime], value: int | bytes | str | dt.date, format: _TimeUnitSpec[_NativeTimeUnit], / - ) -> None: ... + def __new__( + cls, value: int | bytes | str | dt.date, format: _TimeUnitSpec[_NativeTimeUnit], / + ) -> datetime64[dt.datetime]: ... @overload - def __init__(self: datetime64[dt.date], value: int | bytes | str | dt.date, format: _TimeUnitSpec[_DateUnit], /) -> None: ... + def __new__(cls, value: int | bytes | str | dt.date, format: _TimeUnitSpec[_DateUnit], /) -> datetime64[dt.date]: ... @overload - def __init__(self, value: bytes | str | dt.date | None, format: _TimeUnitSpec = ..., /) -> None: ... + def __new__(cls, value: bytes | str | dt.date | None, format: _TimeUnitSpec = ..., /) -> Self: ... @overload def __add__(self: datetime64[_AnyDT64Item], x: int | integer | np.bool, /) -> datetime64[_AnyDT64Item]: ... @@ -4813,18 +5422,41 @@ class datetime64(_RealMixin, generic[_DT64ItemT_co], Generic[_DT64ItemT_co]): @overload def __rsub__(self, x: datetime64, /) -> timedelta64: ... - __lt__: _ComparisonOpLT[datetime64, _ArrayLikeDT64_co] - __le__: _ComparisonOpLE[datetime64, _ArrayLikeDT64_co] - __gt__: _ComparisonOpGT[datetime64, _ArrayLikeDT64_co] - __ge__: _ComparisonOpGE[datetime64, _ArrayLikeDT64_co] + @overload + def __lt__(self, other: datetime64, /) -> bool_: ... + @overload + def __lt__(self, other: _ArrayLikeDT64_co | _NestedSequence[_SupportsGT], /) -> NDArray[bool_]: ... + @overload + def __lt__(self, other: _SupportsGT, /) -> bool_: ... + + @overload + def __le__(self, other: datetime64, /) -> bool_: ... + @overload + def __le__(self, other: _ArrayLikeDT64_co | _NestedSequence[_SupportsGE], /) -> NDArray[bool_]: ... + @overload + def __le__(self, other: _SupportsGT, /) -> bool_: ... + + @overload + def __gt__(self, other: datetime64, /) -> bool_: ... + @overload + def __gt__(self, other: _ArrayLikeDT64_co | _NestedSequence[_SupportsLT], /) -> NDArray[bool_]: ... + @overload + def __gt__(self, other: _SupportsGT, /) -> bool_: ... + + @overload + def __ge__(self, other: datetime64, /) -> bool_: ... + @overload + def __ge__(self, other: _ArrayLikeDT64_co | _NestedSequence[_SupportsLE], /) -> NDArray[bool_]: ... + @overload + def __ge__(self, other: _SupportsGT, /) -> bool_: ... -class flexible(_RealMixin, generic[_FlexibleItemT_co], Generic[_FlexibleItemT_co]): ... +class flexible(_RealMixin, generic[_FlexibleItemT_co], Generic[_FlexibleItemT_co]): ... # type: ignore[misc] class void(flexible[bytes | tuple[Any, ...]]): @overload - def __init__(self, value: _IntLike_co | bytes, /, dtype: None = None) -> None: ... + def __new__(cls, value: _IntLike_co | bytes, /, dtype: None = None) -> Self: ... @overload - def __init__(self, value: Any, /, dtype: _DTypeLikeVoid) -> None: ... + def __new__(cls, value: Any, /, dtype: _DTypeLikeVoid) -> Self: ... @overload def __getitem__(self, key: str | SupportsIndex, /) -> Any: ... @@ -4836,7 +5468,7 @@ class void(flexible[bytes | tuple[Any, ...]]): class character(flexible[_CharacterItemT_co], Generic[_CharacterItemT_co]): @abstractmethod - def __init__(self, value: _CharacterItemT_co = ..., /) -> None: ... + def __new__(cls, value: object = ..., /) -> Self: ... # NOTE: Most `np.bytes_` / `np.str_` methods return their builtin `bytes` / `str` counterpart @@ -4846,12 +5478,6 @@ class bytes_(character[bytes], bytes): @overload def __new__(cls, s: str, /, encoding: str, errors: str = ...) -> Self: ... - # - @overload - def __init__(self, o: object = ..., /) -> None: ... - @overload - def __init__(self, s: str, /, encoding: str, errors: str = ...) -> None: ... - # def __bytes__(self, /) -> bytes: ... @@ -4861,12 +5487,6 @@ class str_(character[str], str): @overload def __new__(cls, value: bytes, /, encoding: str = ..., errors: str = ...) -> Self: ... - # - @overload - def __init__(self, value: object = ..., /) -> None: ... - @overload - def __init__(self, value: bytes, /, encoding: str = ..., errors: str = ...) -> None: ... - # See `numpy._typing._ufunc` for more concrete nin-/nout-specific stubs @final class ufunc: @@ -5037,27 +5657,6 @@ bitwise_right_shift = right_shift permute_dims = transpose pow = power -class errstate: - def __init__( - self, - *, - call: _ErrCall = ..., - all: _ErrKind | None = ..., - divide: _ErrKind | None = ..., - over: _ErrKind | None = ..., - under: _ErrKind | None = ..., - invalid: _ErrKind | None = ..., - ) -> None: ... - def __enter__(self) -> None: ... - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - traceback: TracebackType | None, - /, - ) -> None: ... - def __call__(self, func: _CallableT) -> _CallableT: ... - # TODO: The type of each `__next__` and `iters` return-type depends # on the length and dtype of `args`; we can't describe this behavior yet # as we lack variadics (PEP 646). @@ -5269,12 +5868,13 @@ class vectorize: __doc__: str | None def __init__( self, - pyfunc: Callable[..., Any], - otypes: str | Iterable[DTypeLike] | None = ..., - doc: str | None = ..., - excluded: Iterable[int | str] | None = ..., - cache: builtins.bool = ..., - signature: str | None = ..., + /, + pyfunc: Callable[..., Any] | _NoValueType = ..., # = _NoValue + otypes: str | Iterable[DTypeLike] | None = None, + doc: str | None = None, + excluded: Iterable[int | str] | None = None, + cache: builtins.bool = False, + signature: str | None = None, ) -> None: ... def __call__(self, *args: Any, **kwargs: Any) -> Any: ... diff --git a/numpy/_core/_ufunc_config.py b/numpy/_core/_ufunc_config.py index 24abecd20652..b16147c18ee6 100644 --- a/numpy/_core/_ufunc_config.py +++ b/numpy/_core/_ufunc_config.py @@ -187,6 +187,8 @@ def setbufsize(size): 8192 """ + if size < 0: + raise ValueError("buffer size must be non-negative") old = _get_extobj_dict()["bufsize"] extobj = _make_extobj(bufsize=size) _extobj_contextvar.set(extobj) diff --git a/numpy/_core/_ufunc_config.pyi b/numpy/_core/_ufunc_config.pyi index 1a6613154072..008fb55122c4 100644 --- a/numpy/_core/_ufunc_config.pyi +++ b/numpy/_core/_ufunc_config.pyi @@ -1,13 +1,31 @@ from collections.abc import Callable -from typing import Any, Literal, TypeAlias, TypedDict, type_check_only +from types import TracebackType +from typing import ( + Any, + Final, + Literal, + TypeAlias, + TypedDict, + TypeVar, + type_check_only, +) from _typeshed import SupportsWrite -from numpy import errstate as errstate +__all__ = [ + "seterr", + "geterr", + "setbufsize", + "getbufsize", + "seterrcall", + "geterrcall", + "errstate", +] _ErrKind: TypeAlias = Literal["ignore", "warn", "raise", "call", "print", "log"] -_ErrFunc: TypeAlias = Callable[[str, int], Any] -_ErrCall: TypeAlias = _ErrFunc | SupportsWrite[str] +_ErrCall: TypeAlias = Callable[[str, int], Any] | SupportsWrite[str] + +_CallableT = TypeVar("_CallableT", bound=Callable[..., object]) @type_check_only class _ErrDict(TypedDict): @@ -16,6 +34,36 @@ class _ErrDict(TypedDict): under: _ErrKind invalid: _ErrKind +### + +class _unspecified: ... + +_Unspecified: Final[_unspecified] + +class errstate: + __slots__ = "_all", "_call", "_divide", "_invalid", "_over", "_token", "_under" + + def __init__( + self, + /, + *, + call: _ErrCall | _unspecified = ..., # = _Unspecified + all: _ErrKind | None = None, + divide: _ErrKind | None = None, + over: _ErrKind | None = None, + under: _ErrKind | None = None, + invalid: _ErrKind | None = None, + ) -> None: ... + def __call__(self, /, func: _CallableT) -> _CallableT: ... + def __enter__(self) -> None: ... + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + /, + ) -> None: ... + def seterr( all: _ErrKind | None = ..., divide: _ErrKind | None = ..., @@ -28,5 +76,3 @@ def setbufsize(size: int) -> int: ... def getbufsize() -> int: ... def seterrcall(func: _ErrCall | None) -> _ErrCall | None: ... def geterrcall() -> _ErrCall | None: ... - -# See `numpy/__init__.pyi` for the `errstate` class and `no_nep5_warnings` diff --git a/numpy/_core/code_generators/generate_numpy_api.py b/numpy/_core/code_generators/generate_numpy_api.py index dc11bcd2c272..23d678872ca4 100644 --- a/numpy/_core/code_generators/generate_numpy_api.py +++ b/numpy/_core/code_generators/generate_numpy_api.py @@ -157,6 +157,12 @@ return 0; } +#if (SWIG_VERSION < 0x040400) +#define _RETURN_VALUE NULL +#else +#define _RETURN_VALUE 0 +#endif + #define import_array() { \ if (_import_array() < 0) { \ PyErr_Print(); \ @@ -164,7 +170,7 @@ PyExc_ImportError, \ "numpy._core.multiarray failed to import" \ ); \ - return NULL; \ + return _RETURN_VALUE; \ } \ } diff --git a/numpy/_core/defchararray.pyi b/numpy/_core/defchararray.pyi index 2361fff6eae7..af11b5d24c4b 100644 --- a/numpy/_core/defchararray.pyi +++ b/numpy/_core/defchararray.pyi @@ -1012,9 +1012,9 @@ def startswith( @overload def startswith( a: T_co, - suffix: T_co, - start: i_co = ..., - end: i_co | None = ..., + prefix: T_co, + start: i_co = 0, + end: i_co | None = None, ) -> NDArray[np.bool]: ... def str_len(A: UST_co) -> NDArray[int_]: ... diff --git a/numpy/_core/meson.build b/numpy/_core/meson.build index cd46a20b0246..efa3d1529386 100644 --- a/numpy/_core/meson.build +++ b/numpy/_core/meson.build @@ -865,7 +865,9 @@ foreach gen_mtargets : [ [ 'x86_simd_qsort_16bit.dispatch.h', 'src/npysort/x86_simd_qsort_16bit.dispatch.cpp', - use_intel_sort ? [AVX512_SPR, AVX512_ICL] : [] + # Do not enable AVX-512 on MSVC 32-bit (x86): it’s buggy there; + # Ref: NumPy issue numpy/numpy#29808 + use_intel_sort and not (cc.get_id() == 'msvc' and cpu_family == 'x86') ? [AVX512_SPR, AVX512_ICL] : [] ], [ 'highway_qsort.dispatch.h', @@ -1103,6 +1105,7 @@ endforeach # ------------------------------ src_multiarray_umath_common = [ 'src/common/array_assign.c', + 'src/common/blas_utils.c', 'src/common/gil_utils.c', 'src/common/mem_overlap.c', 'src/common/npy_argparse.c', @@ -1117,7 +1120,6 @@ src_multiarray_umath_common = [ ] if have_blas src_multiarray_umath_common += [ - 'src/common/blas_utils.c', 'src/common/cblasfuncs.c', 'src/common/python_xerbla.c', ] diff --git a/numpy/_core/numerictypes.py b/numpy/_core/numerictypes.py index 135dc1b51d97..265ad4f8eb1f 100644 --- a/numpy/_core/numerictypes.py +++ b/numpy/_core/numerictypes.py @@ -598,7 +598,7 @@ def _scalar_type_key(typ): ScalarType = [int, float, complex, bool, bytes, str, memoryview] -ScalarType += sorted(set(sctypeDict.values()), key=_scalar_type_key) +ScalarType += sorted(dict.fromkeys(sctypeDict.values()), key=_scalar_type_key) ScalarType = tuple(ScalarType) diff --git a/numpy/_core/numerictypes.pyi b/numpy/_core/numerictypes.pyi index 753fe34800d5..5a309d4e1fc3 100644 --- a/numpy/_core/numerictypes.pyi +++ b/numpy/_core/numerictypes.pyi @@ -1,5 +1,5 @@ -import builtins -from typing import Any, TypedDict, type_check_only +from builtins import bool as py_bool +from typing import Any, Final, TypedDict, type_check_only from typing import Literal as L import numpy as np @@ -13,6 +13,8 @@ from numpy import ( clongdouble, complex64, complex128, + complex192, + complex256, complexfloating, csingle, datetime64, @@ -22,6 +24,8 @@ from numpy import ( float16, float32, float64, + float96, + float128, floating, generic, half, @@ -59,9 +63,8 @@ from numpy import ( void, ) from numpy._typing import DTypeLike -from numpy._typing._extended_precision import complex192, complex256, float96, float128 -from ._type_aliases import sctypeDict # noqa: F401 +from ._type_aliases import sctypeDict as sctypeDict from .multiarray import ( busday_count, busday_offset, @@ -142,51 +145,53 @@ __all__ = [ @type_check_only class _TypeCodes(TypedDict): - Character: L['c'] - Integer: L['bhilqnp'] - UnsignedInteger: L['BHILQNP'] - Float: L['efdg'] - Complex: L['FDG'] - AllInteger: L['bBhHiIlLqQnNpP'] - AllFloat: L['efdgFDG'] - Datetime: L['Mm'] - All: L['?bhilqnpBHILQNPefdgFDGSUVOMm'] + Character: L["c"] + Integer: L["bhilqnp"] + UnsignedInteger: L["BHILQNP"] + Float: L["efdg"] + Complex: L["FDG"] + AllInteger: L["bBhHiIlLqQnNpP"] + AllFloat: L["efdgFDG"] + Datetime: L["Mm"] + All: L["?bhilqnpBHILQNPefdgFDGSUVOMm"] -def isdtype(dtype: dtype | type[Any], kind: DTypeLike | tuple[DTypeLike, ...]) -> builtins.bool: ... +def isdtype(dtype: dtype | type, kind: DTypeLike | tuple[DTypeLike, ...]) -> py_bool: ... +def issubdtype(arg1: DTypeLike | None, arg2: DTypeLike | None) -> py_bool: ... -def issubdtype(arg1: DTypeLike, arg2: DTypeLike) -> builtins.bool: ... - -typecodes: _TypeCodes -ScalarType: tuple[ - type[int], - type[float], - type[complex], - type[builtins.bool], - type[bytes], - type[str], - type[memoryview], - type[np.bool], - type[csingle], - type[cdouble], - type[clongdouble], - type[half], - type[single], - type[double], - type[longdouble], - type[byte], - type[short], - type[intc], - type[long], - type[longlong], - type[timedelta64], - type[datetime64], - type[object_], - type[bytes_], - type[str_], - type[ubyte], - type[ushort], - type[uintc], - type[ulong], - type[ulonglong], - type[void], -] +typecodes: Final[_TypeCodes] = ... +ScalarType: Final[ + tuple[ + type[int], + type[float], + type[complex], + type[py_bool], + type[bytes], + type[str], + type[memoryview[Any]], + type[np.bool], + type[complex64], + type[complex128], + type[complex128 | complex192 | complex256], + type[float16], + type[float32], + type[float64], + type[float64 | float96 | float128], + type[int8], + type[int16], + type[int32], + type[int32 | int64], + type[int64], + type[datetime64], + type[timedelta64], + type[object_], + type[bytes_], + type[str_], + type[uint8], + type[uint16], + type[uint32], + type[uint32 | uint64], + type[uint64], + type[void], + ] +] = ... +typeDict: Final = sctypeDict diff --git a/numpy/_core/src/common/binop_override.h b/numpy/_core/src/common/binop_override.h index a6b4747ca560..e17b147c1d0a 100644 --- a/numpy/_core/src/common/binop_override.h +++ b/numpy/_core/src/common/binop_override.h @@ -1,8 +1,8 @@ #ifndef NUMPY_CORE_SRC_COMMON_BINOP_OVERRIDE_H_ #define NUMPY_CORE_SRC_COMMON_BINOP_OVERRIDE_H_ -#include #include +#include #include "numpy/arrayobject.h" #include "get_attr_string.h" diff --git a/numpy/_core/src/common/blas_utils.c b/numpy/_core/src/common/blas_utils.c index 40bbc773a92b..cbf8e0dc05c5 100644 --- a/numpy/_core/src/common/blas_utils.c +++ b/numpy/_core/src/common/blas_utils.c @@ -1,3 +1,8 @@ +#include "numpy/npy_math.h" // npy_get_floatstatus_barrier +#include "numpy/numpyconfig.h" // NPY_VISIBILITY_HIDDEN +#include "blas_utils.h" +#include "npy_cblas.h" + #include #include #include @@ -6,94 +11,9 @@ #include #endif -#include "numpy/numpyconfig.h" // NPY_VISIBILITY_HIDDEN -#include "numpy/npy_math.h" // npy_get_floatstatus_barrier -#include "blas_utils.h" - #if NPY_BLAS_CHECK_FPE_SUPPORT - -/* Return whether we're running on macOS 15.4 or later - */ -static inline bool -is_macOS_version_15_4_or_later(void){ -#if !defined(__APPLE__) - return false; -#else - char *osProductVersion = NULL; - size_t size = 0; - bool ret = false; - - // Query how large OS version string should be - if(-1 == sysctlbyname("kern.osproductversion", NULL, &size, NULL, 0)){ - goto cleanup; - } - - osProductVersion = malloc(size + 1); - - // Get the OS version string - if(-1 == sysctlbyname("kern.osproductversion", osProductVersion, &size, NULL, 0)){ - goto cleanup; - } - - osProductVersion[size] = '\0'; - - // Parse the version string - int major = 0, minor = 0; - if(2 > sscanf(osProductVersion, "%d.%d", &major, &minor)) { - goto cleanup; - } - - if(major > 15 || (major == 15 && minor >= 4)) { - ret = true; - } - -cleanup: - if(osProductVersion){ - free(osProductVersion); - } - - return ret; -#endif -} - -/* ARM Scalable Matrix Extension (SME) raises all floating-point error flags - * when it's used regardless of values or operations. As a consequence, - * when SME is used, all FPE state is lost and special handling is needed. - * - * For NumPy, SME is not currently used directly, but can be used via - * BLAS / LAPACK libraries. This function does a runtime check for whether - * BLAS / LAPACK can use SME and special handling around FPE is required. - */ -static inline bool -BLAS_can_use_ARM_SME(void) -{ -#if defined(__APPLE__) && defined(__aarch64__) && defined(ACCELERATE_NEW_LAPACK) - // ARM SME can be used by Apple's Accelerate framework for BLAS / LAPACK - // - macOS 15.4+ - // - Apple silicon M4+ - - // Does OS / Accelerate support ARM SME? - if(!is_macOS_version_15_4_or_later()){ - return false; - } - - // Does hardware support SME? - int has_SME = 0; - size_t size = sizeof(has_SME); - if(-1 == sysctlbyname("hw.optional.arm.FEAT_SME", &has_SME, &size, NULL, 0)){ - return false; - } - - if(has_SME){ - return true; - } -#endif - - // default assume SME is not used - return false; -} - -/* Static variable to cache runtime check of BLAS FPE support. +/* + * Static variable to cache runtime check of BLAS FPE support. */ static bool blas_supports_fpe = true; @@ -110,19 +30,21 @@ npy_blas_supports_fpe(void) #endif } -NPY_VISIBILITY_HIDDEN void -npy_blas_init(void) +NPY_VISIBILITY_HIDDEN bool +npy_set_blas_supports_fpe(bool value) { #if NPY_BLAS_CHECK_FPE_SUPPORT - blas_supports_fpe = !BLAS_can_use_ARM_SME(); + blas_supports_fpe = (bool)value; + return blas_supports_fpe; #endif + return true; // ignore input not set up on this platform } NPY_VISIBILITY_HIDDEN int npy_get_floatstatus_after_blas(void) { #if NPY_BLAS_CHECK_FPE_SUPPORT - if(!blas_supports_fpe){ + if (!blas_supports_fpe){ // BLAS does not support FPE and we need to return FPE state. // Instead of clearing and then grabbing state, just return // that no flags are set. diff --git a/numpy/_core/src/common/blas_utils.h b/numpy/_core/src/common/blas_utils.h index 8c1437f88899..79d1e5ce274c 100644 --- a/numpy/_core/src/common/blas_utils.h +++ b/numpy/_core/src/common/blas_utils.h @@ -1,21 +1,20 @@ -#include - #include "numpy/numpyconfig.h" // for NPY_VISIBILITY_HIDDEN -/* NPY_BLAS_CHECK_FPE_SUPPORT controls whether we need a runtime check +#include + +/* + * NPY_BLAS_CHECK_FPE_SUPPORT controls whether we need a runtime check * for floating-point error (FPE) support in BLAS. + * The known culprit right now is SVM likely only on mac, but that is not + * quite clear. + * This checks always on all ARM (it is a small check overall). */ -#if defined(__APPLE__) && defined(__aarch64__) && defined(ACCELERATE_NEW_LAPACK) +#if defined(__APPLE__) && defined(__aarch64__) && defined(HAVE_CBLAS) #define NPY_BLAS_CHECK_FPE_SUPPORT 1 #else #define NPY_BLAS_CHECK_FPE_SUPPORT 0 #endif -/* Initialize BLAS environment, if needed - */ -NPY_VISIBILITY_HIDDEN void -npy_blas_init(void); - /* Runtime check if BLAS supports floating-point errors. * true - BLAS supports FPE and one can rely on them to indicate errors * false - BLAS does not support FPE. Special handling needed for FPE state @@ -23,6 +22,10 @@ npy_blas_init(void); NPY_VISIBILITY_HIDDEN bool npy_blas_supports_fpe(void); +/* Allow setting the BLAS FPE flag from Python.*/ +NPY_VISIBILITY_HIDDEN bool +npy_set_blas_supports_fpe(bool value); + /* If BLAS supports FPE, exactly the same as npy_get_floatstatus_barrier(). * Otherwise, we can't rely on FPE state and need special handling. */ diff --git a/numpy/_core/src/common/simd/vec/utils.h b/numpy/_core/src/common/simd/vec/utils.h index f8b28cfebd8c..7e4a7b8de8fa 100644 --- a/numpy/_core/src/common/simd/vec/utils.h +++ b/numpy/_core/src/common/simd/vec/utils.h @@ -25,14 +25,16 @@ #ifndef vec_neg #define vec_neg(a) (-(a)) #endif - #ifndef vec_and - #define vec_and(a, b) ((a) & (b)) // Vector AND - #endif - #ifndef vec_or - #define vec_or(a, b) ((a) | (b)) // Vector OR - #endif - #ifndef vec_xor - #define vec_xor(a, b) ((a) ^ (b)) // Vector XOR + #if !(defined(__clang__) && __VEC__ >= 10305) + #ifndef vec_and + #define vec_and(a, b) ((a) & (b)) // Vector AND + #endif + #ifndef vec_or + #define vec_or(a, b) ((a) | (b)) // Vector OR + #endif + #ifndef vec_xor + #define vec_xor(a, b) ((a) ^ (b)) // Vector XOR + #endif #endif #ifndef vec_sl #define vec_sl(a, b) ((a) << (b)) // Vector Shift Left diff --git a/numpy/_core/src/multiarray/array_method.c b/numpy/_core/src/multiarray/array_method.c index 5554cad5e2dd..ba3b7962a632 100644 --- a/numpy/_core/src/multiarray/array_method.c +++ b/numpy/_core/src/multiarray/array_method.c @@ -30,8 +30,8 @@ #define _UMATHMODULE #define _MULTIARRAYMODULE -#include #include +#include #include "arrayobject.h" #include "array_coercion.h" #include "array_method.h" diff --git a/numpy/_core/src/multiarray/calculation.c b/numpy/_core/src/multiarray/calculation.c index 87f03a94fa5f..3c6b33e75d76 100644 --- a/numpy/_core/src/multiarray/calculation.c +++ b/numpy/_core/src/multiarray/calculation.c @@ -653,7 +653,15 @@ PyArray_Round(PyArrayObject *a, int decimals, PyArrayObject *out) else { op1 = n_ops.true_divide; op2 = n_ops.multiply; - decimals = -decimals; + if (decimals == INT_MIN) { + // not technically correct but it doesn't matter because no one in + // this millenium is using floating point numbers with enough + // accuracy for this to matter + decimals = INT_MAX; + } + else { + decimals = -decimals; + } } if (!out) { if (PyArray_ISINTEGER(a)) { diff --git a/numpy/_core/src/multiarray/common.h b/numpy/_core/src/multiarray/common.h index cde7c127c4cc..3233ae817159 100644 --- a/numpy/_core/src/multiarray/common.h +++ b/numpy/_core/src/multiarray/common.h @@ -1,6 +1,8 @@ #ifndef NUMPY_CORE_SRC_MULTIARRAY_COMMON_H_ #define NUMPY_CORE_SRC_MULTIARRAY_COMMON_H_ +#include + #include #include "numpy/npy_common.h" #include "numpy/ndarraytypes.h" diff --git a/numpy/_core/src/multiarray/methods.c b/numpy/_core/src/multiarray/methods.c index 58a554dc40be..01fa4a43e43d 100644 --- a/numpy/_core/src/multiarray/methods.c +++ b/numpy/_core/src/multiarray/methods.c @@ -934,6 +934,11 @@ array_getarray(PyArrayObject *self, PyObject *args, PyObject *kwds) return NULL; } + if (newtype == NULL) { + newtype = PyArray_DESCR(self); + Py_INCREF(newtype); // newtype is owned. + } + /* convert to PyArray_Type */ if (!PyArray_CheckExact(self)) { PyArrayObject *new; @@ -951,6 +956,7 @@ array_getarray(PyArrayObject *self, PyObject *args, PyObject *kwds) (PyObject *)self ); if (new == NULL) { + Py_DECREF(newtype); return NULL; } self = new; @@ -960,22 +966,21 @@ array_getarray(PyArrayObject *self, PyObject *args, PyObject *kwds) } if (copy == NPY_COPY_ALWAYS) { - if (newtype == NULL) { - newtype = PyArray_DESCR(self); - } - ret = PyArray_CastToType(self, newtype, 0); + ret = PyArray_CastToType(self, newtype, 0); // steals newtype reference Py_DECREF(self); return ret; } else { // copy == NPY_COPY_IF_NEEDED || copy == NPY_COPY_NEVER - if (newtype == NULL || PyArray_EquivTypes(PyArray_DESCR(self), newtype)) { + if (PyArray_EquivTypes(PyArray_DESCR(self), newtype)) { + Py_DECREF(newtype); return (PyObject *)self; } if (copy == NPY_COPY_IF_NEEDED) { - ret = PyArray_CastToType(self, newtype, 0); + ret = PyArray_CastToType(self, newtype, 0); // steals newtype reference. Py_DECREF(self); return ret; } else { // copy == NPY_COPY_NEVER PyErr_SetString(PyExc_ValueError, npy_no_copy_err_msg); + Py_DECREF(newtype); Py_DECREF(self); return NULL; } diff --git a/numpy/_core/src/multiarray/multiarraymodule.c b/numpy/_core/src/multiarray/multiarraymodule.c index 71f2e7bff573..f52b4b61ecd6 100644 --- a/numpy/_core/src/multiarray/multiarraymodule.c +++ b/numpy/_core/src/multiarray/multiarraymodule.c @@ -4350,6 +4350,25 @@ _set_numpy_warn_if_no_mem_policy(PyObject *NPY_UNUSED(self), PyObject *arg) } +static PyObject * +_blas_supports_fpe(PyObject *NPY_UNUSED(self), PyObject *arg) { + if (arg == Py_None) { + return PyBool_FromLong(npy_blas_supports_fpe()); + } + else if (arg == Py_True) { + return PyBool_FromLong(npy_set_blas_supports_fpe(true)); + } + else if (arg == Py_False) { + return PyBool_FromLong(npy_set_blas_supports_fpe(false)); + } + else { + PyErr_SetString(PyExc_TypeError, + "BLAS FPE support must be None, True, or False"); + return NULL; + } +} + + static PyObject * _reload_guard(PyObject *NPY_UNUSED(self), PyObject *NPY_UNUSED(args)) { #if !defined(PYPY_VERSION) @@ -4588,6 +4607,8 @@ static struct PyMethodDef array_module_methods[] = { METH_NOARGS, NULL}, {"_set_madvise_hugepage", (PyCFunction)_set_madvise_hugepage, METH_O, NULL}, + {"_blas_supports_fpe", (PyCFunction)_blas_supports_fpe, + METH_O, "BLAS FPE support pass None, True, or False and returns new value"}, {"_reload_guard", (PyCFunction)_reload_guard, METH_NOARGS, "Give a warning on reload and big warning in sub-interpreters."}, @@ -4813,10 +4834,6 @@ PyMODINIT_FUNC PyInit__multiarray_umath(void) { goto err; } -#if NPY_BLAS_CHECK_FPE_SUPPORT - npy_blas_init(); -#endif - #if defined(MS_WIN64) && defined(__GNUC__) PyErr_WarnEx(PyExc_Warning, "Numpy built with MINGW-W64 on Windows 64 bits is experimental, " \ diff --git a/numpy/_core/src/multiarray/nditer_constr.c b/numpy/_core/src/multiarray/nditer_constr.c index 3ed5cf1a0245..a8f13a73ee1e 100644 --- a/numpy/_core/src/multiarray/nditer_constr.c +++ b/numpy/_core/src/multiarray/nditer_constr.c @@ -2077,8 +2077,14 @@ npyiter_find_buffering_setup(NpyIter *iter, npy_intp buffersize) npy_intp *strides = NAD_STRIDES(axisdata); for (int iop = 0; iop < nop; iop++) { - /* Check that we set things up nicely (if shape is ever 1) */ - assert((axisdata->shape == 1) ? (prev_strides[iop] == strides[iop]) : 1); + /* + * Check that we set things up nicely so strides coalesc. Except + * for index operands, which currently disrupts coalescing. + * NOTE(seberg): presumably `npyiter_compute_index_strides` should + * not set the strides to 0, but this was safer for backporting. + */ + assert((axisdata->shape != 1) || (prev_strides[iop] == strides[iop]) + || (op_itflags[iop] & (NPY_ITER_C_INDEX|NPY_ITER_F_INDEX))); if (op_single_stride_dims[iop] == idim) { /* Best case: the strides still collapse for this operand. */ diff --git a/numpy/_core/src/multiarray/shape.c b/numpy/_core/src/multiarray/shape.c index 340fe7289ac8..83de9f19a574 100644 --- a/numpy/_core/src/multiarray/shape.c +++ b/numpy/_core/src/multiarray/shape.c @@ -121,6 +121,15 @@ PyArray_Resize(PyArrayObject *self, PyArray_Dims *newshape, int refcheck, "no memory handler found but OWNDATA flag set"); return NULL; } + if (newnbytes < oldnbytes) { + /* Clear now removed data (if dtype has references) */ + if (PyArray_ClearBuffer( + PyArray_DESCR(self), PyArray_BYTES(self) + newnbytes, + elsize, oldsize-newsize, PyArray_ISALIGNED(self)) < 0) { + return NULL; + } + } + new_data = PyDataMem_UserRENEW(PyArray_DATA(self), newnbytes == 0 ? elsize : newnbytes, handler); @@ -130,17 +139,17 @@ PyArray_Resize(PyArrayObject *self, PyArray_Dims *newshape, int refcheck, return NULL; } ((PyArrayObject_fields *)self)->data = new_data; - } - if (newnbytes > oldnbytes && PyArray_ISWRITEABLE(self)) { - /* Fill new memory with zeros (PyLong zero for object arrays) */ - npy_intp stride = elsize; - npy_intp size = newsize - oldsize; - char *data = PyArray_BYTES(self) + oldnbytes; - int aligned = PyArray_ISALIGNED(self); - if (PyArray_ZeroContiguousBuffer(PyArray_DESCR(self), data, - stride, size, aligned) < 0) { - return NULL; + if (newnbytes > oldnbytes && PyArray_ISWRITEABLE(self)) { + /* Fill new memory with zeros (PyLong zero for object arrays) */ + npy_intp stride = elsize; + npy_intp size = newsize - oldsize; + char *data = PyArray_BYTES(self) + oldnbytes; + int aligned = PyArray_ISALIGNED(self); + if (PyArray_ZeroContiguousBuffer(PyArray_DESCR(self), data, + stride, size, aligned) < 0) { + return NULL; + } } } diff --git a/numpy/_core/src/multiarray/stringdtype/static_string.c b/numpy/_core/src/multiarray/stringdtype/static_string.c index 89b53bcb8538..c437fab2d336 100644 --- a/numpy/_core/src/multiarray/stringdtype/static_string.c +++ b/numpy/_core/src/multiarray/stringdtype/static_string.c @@ -155,8 +155,6 @@ vstring_buffer(npy_string_arena *arena, _npy_static_string_u *string) return (char *)((size_t)arena->buffer + string->vstring.offset); } -#define ARENA_EXPAND_FACTOR 1.25 - static char * arena_malloc(npy_string_arena *arena, npy_string_realloc_func r, size_t size) { @@ -168,24 +166,17 @@ arena_malloc(npy_string_arena *arena, npy_string_realloc_func r, size_t size) else { string_storage_size = size + sizeof(size_t); } - if ((arena->size - arena->cursor) <= string_storage_size) { - // realloc the buffer so there is enough room - // first guess is to double the size of the buffer - size_t newsize; - if (arena->size == 0) { - newsize = string_storage_size; - } - else if (((ARENA_EXPAND_FACTOR * arena->size) - arena->cursor) > - string_storage_size) { - newsize = ARENA_EXPAND_FACTOR * arena->size; + if ((arena->size - arena->cursor) < string_storage_size) { + size_t minsize = arena->cursor + string_storage_size; + if (minsize < arena->cursor) { + return NULL; // overflow means out of memory } - else { - newsize = arena->size + string_storage_size; - } - if ((arena->cursor + size) >= newsize) { - // need extra room beyond the expansion factor, leave some padding - newsize = ARENA_EXPAND_FACTOR * (arena->cursor + size); + // Allocate 25% more than needed for this string. + size_t newsize = minsize + minsize / 4; + if (newsize < minsize) { + return NULL; // overflow means out of memory } + // passing a NULL buffer to realloc is the same as malloc char *newbuf = r(arena->buffer, newsize); if (newbuf == NULL) { diff --git a/numpy/_core/src/multiarray/textreading/conversions.h b/numpy/_core/src/multiarray/textreading/conversions.h index 09f2510413b5..e30b28a9a7af 100644 --- a/numpy/_core/src/multiarray/textreading/conversions.h +++ b/numpy/_core/src/multiarray/textreading/conversions.h @@ -1,12 +1,12 @@ #ifndef NUMPY_CORE_SRC_MULTIARRAY_TEXTREADING_CONVERSIONS_H_ #define NUMPY_CORE_SRC_MULTIARRAY_TEXTREADING_CONVERSIONS_H_ -#include - #define NPY_NO_DEPRECATED_API NPY_API_VERSION #define _MULTIARRAYMODULE #include "numpy/arrayobject.h" +#include + #include "textreading/parser_config.h" NPY_NO_EXPORT int diff --git a/numpy/_core/src/npysort/npysort_common.h b/numpy/_core/src/npysort/npysort_common.h index 0680ae52afe3..8b7e0ef43f88 100644 --- a/numpy/_core/src/npysort/npysort_common.h +++ b/numpy/_core/src/npysort/npysort_common.h @@ -1,8 +1,8 @@ #ifndef __NPY_SORT_COMMON_H__ #define __NPY_SORT_COMMON_H__ -#include #include +#include #include #include "dtypemeta.h" diff --git a/numpy/_core/src/npysort/x86-simd-sort b/numpy/_core/src/npysort/x86-simd-sort index c306ac581a59..6a7a01da4b0d 160000 --- a/numpy/_core/src/npysort/x86-simd-sort +++ b/numpy/_core/src/npysort/x86-simd-sort @@ -1 +1 @@ -Subproject commit c306ac581a59f89585d778254c4ed7197e64ba2d +Subproject commit 6a7a01da4b0dfde108aa626a2364c954e2c50fe1 diff --git a/numpy/_core/src/umath/clip.cpp b/numpy/_core/src/umath/clip.cpp index e051692c6d48..127b019ef8ae 100644 --- a/numpy/_core/src/umath/clip.cpp +++ b/numpy/_core/src/umath/clip.cpp @@ -1,7 +1,6 @@ /** * This module provides the inner loops for the clip ufunc */ -#include #define _UMATHMODULE #define _MULTIARRAYMODULE @@ -10,6 +9,7 @@ #define PY_SSIZE_T_CLEAN #include +#include #include "numpy/halffloat.h" #include "numpy/ndarraytypes.h" #include "numpy/npy_common.h" diff --git a/numpy/_core/src/umath/loops_logical.dispatch.cpp b/numpy/_core/src/umath/loops_logical.dispatch.cpp index ec17f90154c8..f406eb30f733 100644 --- a/numpy/_core/src/umath/loops_logical.dispatch.cpp +++ b/numpy/_core/src/umath/loops_logical.dispatch.cpp @@ -111,7 +111,6 @@ struct UnaryLogicalTraits; template<> struct UnaryLogicalTraits { - static constexpr bool is_not = true; static constexpr auto scalar_op = std::equal_to{}; HWY_INLINE HWY_ATTR vec_u8 simd_op(vec_u8 v) { @@ -122,7 +121,6 @@ struct UnaryLogicalTraits { template<> struct UnaryLogicalTraits { - static constexpr bool is_not = false; static constexpr auto scalar_op = std::not_equal_to{}; HWY_INLINE HWY_ATTR vec_u8 simd_op(vec_u8 v) { diff --git a/numpy/_core/src/umath/loops_modulo.dispatch.c.src b/numpy/_core/src/umath/loops_modulo.dispatch.c.src index 032cc3344060..4645fe14a487 100644 --- a/numpy/_core/src/umath/loops_modulo.dispatch.c.src +++ b/numpy/_core/src/umath/loops_modulo.dispatch.c.src @@ -490,12 +490,16 @@ vsx4_simd_@func@_by_scalar_contig_@sfx@(char **args, npy_intp len) #else /* fmod and remainder */ for (; len > 0; --len, ++src1, ++dst1) { const npyv_lanetype_@sfx@ a = *src1; - *dst1 = a % scalar; + if (NPY_UNLIKELY(a == NPY_MIN_INT@len@ && scalar == -1)) { + *dst1 = 0; + } else { + *dst1 = a % scalar; #if @id@ == 1 /* remainder */ - if (!((a > 0) == (scalar > 0) || *dst1 == 0)) { - *dst1 += scalar; - } + if (!((a > 0) == (scalar > 0) || *dst1 == 0)) { + *dst1 += scalar; + } #endif + } } #endif npyv_cleanup(); diff --git a/numpy/_core/src/umath/string_ufuncs.cpp b/numpy/_core/src/umath/string_ufuncs.cpp index 95f30ccb109e..9b3d86c25301 100644 --- a/numpy/_core/src/umath/string_ufuncs.cpp +++ b/numpy/_core/src/umath/string_ufuncs.cpp @@ -941,7 +941,7 @@ string_expandtabs_length_promoter(PyObject *NPY_UNUSED(ufunc), PyArray_DTypeMeta *const op_dtypes[], PyArray_DTypeMeta *const signature[], PyArray_DTypeMeta *new_op_dtypes[]) { - Py_INCREF(op_dtypes[0]); + Py_XINCREF(op_dtypes[0]); new_op_dtypes[0] = op_dtypes[0]; new_op_dtypes[1] = NPY_DT_NewRef(&PyArray_Int64DType); new_op_dtypes[2] = PyArray_DTypeFromTypeNum(NPY_DEFAULT_INT); diff --git a/numpy/_core/src/umath/stringdtype_ufuncs.cpp b/numpy/_core/src/umath/stringdtype_ufuncs.cpp index ca574f605c1a..ebc10586bf8b 100644 --- a/numpy/_core/src/umath/stringdtype_ufuncs.cpp +++ b/numpy/_core/src/umath/stringdtype_ufuncs.cpp @@ -2264,10 +2264,14 @@ slice_strided_loop(PyArrayMethod_Context *context, char *const data[], if (step == 1) { // step == 1 is the easy case, we can just use memcpy - npy_intp outsize = ((size_t)stop < num_codepoints - ? codepoint_offsets[stop] - : (unsigned char *)is.buf + is.size) - - codepoint_offsets[start]; + unsigned char *start_bounded = ((size_t)start < num_codepoints + ? codepoint_offsets[start] + : (unsigned char *)is.buf + is.size); + unsigned char *stop_bounded = ((size_t)stop < num_codepoints + ? codepoint_offsets[stop] + : (unsigned char *)is.buf + is.size); + npy_intp outsize = stop_bounded - start_bounded; + outsize = outsize < 0 ? 0 : outsize; if (load_new_string(ops, &os, outsize, oallocator, "slice") < 0) { goto fail; @@ -2276,7 +2280,7 @@ slice_strided_loop(PyArrayMethod_Context *context, char *const data[], /* explicitly discard const; initializing new buffer */ char *buf = (char *)os.buf; - memcpy(buf, codepoint_offsets[start], outsize); + memcpy(buf, start_bounded, outsize); } else { // handle step != 1 diff --git a/numpy/_core/src/umath/wrapping_array_method.c b/numpy/_core/src/umath/wrapping_array_method.c index 9b3970561f3f..b340e72bdbfd 100644 --- a/numpy/_core/src/umath/wrapping_array_method.c +++ b/numpy/_core/src/umath/wrapping_array_method.c @@ -114,7 +114,7 @@ get_wrapping_auxdata(void) } else { res = PyMem_Calloc(1, sizeof(wrapping_auxdata)); - if (res < 0) { + if (res == NULL) { PyErr_NoMemory(); return NULL; } diff --git a/numpy/_core/strings.py b/numpy/_core/strings.py index b4dc1656024f..0fd5b0359fa5 100644 --- a/numpy/_core/strings.py +++ b/numpy/_core/strings.py @@ -1743,7 +1743,7 @@ def translate(a, table, deletechars=None): ) @set_module("numpy.strings") -def slice(a, start=None, stop=None, step=None, /): +def slice(a, start=None, stop=np._NoValue, step=None, /): """ Slice the strings in `a` by slices specified by `start`, `stop`, `step`. Like in the regular Python `slice` object, if only `start` is @@ -1776,6 +1776,9 @@ def slice(a, start=None, stop=None, step=None, /): >>> np.strings.slice(a, 2) array(['he', 'wo'], dtype='>> np.strings.slice(a, 2, None) + array(['llo', 'rld'], dtype='>> np.strings.slice(a, 1, 5, 2) array(['el', 'ol'], dtype='>> np.strings.slice(b, -2) array(['hello wor', 'γεια σου κόσ', '你好', '👋'], dtype=StringDType()) + >>> np.strings.slice(b, -2, None) + array(['ld', 'με', '世界', ' 🌍'], dtype=StringDType()) + >>> np.strings.slice(b, [3, -10, 2, -3], [-1, -2, -1, 3]) array(['lo worl', ' σου κόσ', '世', '👋 🌍'], dtype=StringDType()) @@ -1801,7 +1807,7 @@ def slice(a, start=None, stop=None, step=None, /): """ # Just like in the construction of a regular slice object, if only start # is specified then start will become stop, see logic in slice_new. - if stop is None: + if stop is np._NoValue: stop = start start = None diff --git a/numpy/_core/tests/test_api.py b/numpy/_core/tests/test_api.py index 25990536809b..5bc88e93d3f4 100644 --- a/numpy/_core/tests/test_api.py +++ b/numpy/_core/tests/test_api.py @@ -91,7 +91,7 @@ def test_array_array(): # instead we get a array([...], dtype=">V18") assert_equal(bytes(np.array(o).data), bytes(a.data)) - # test array + # test __array__ def custom__array__(self, dtype=None, copy=None): return np.array(100.0, dtype=dtype, copy=copy) @@ -157,6 +157,39 @@ def custom__array__(self, dtype=None, copy=None): assert_equal(np.array([(1.0,) * 10] * 10, dtype=np.float64), np.ones((10, 10), dtype=np.float64)) + +@pytest.mark.skipif(not HAS_REFCOUNT, reason="Python lacks refcounts") +def test___array___refcount(): + class MyArray: + def __init__(self, dtype): + self.val = np.array(-1, dtype=dtype) + + def __array__(self, dtype=None, copy=None): + return self.val.__array__(dtype=dtype, copy=copy) + + # test all possible scenarios: + # dtype(none | same | different) x copy(true | false | none) + dt = np.dtype(np.int32) + old_refcount = sys.getrefcount(dt) + np.array(MyArray(dt)) + assert_equal(old_refcount, sys.getrefcount(dt)) + np.array(MyArray(dt), dtype=dt) + assert_equal(old_refcount, sys.getrefcount(dt)) + np.array(MyArray(dt), copy=None) + assert_equal(old_refcount, sys.getrefcount(dt)) + np.array(MyArray(dt), dtype=dt, copy=None) + assert_equal(old_refcount, sys.getrefcount(dt)) + dt2 = np.dtype(np.int16) + old_refcount2 = sys.getrefcount(dt2) + np.array(MyArray(dt), dtype=dt2) + assert_equal(old_refcount2, sys.getrefcount(dt2)) + np.array(MyArray(dt), dtype=dt2, copy=None) + assert_equal(old_refcount2, sys.getrefcount(dt2)) + with pytest.raises(ValueError): + np.array(MyArray(dt), dtype=dt2, copy=False) + assert_equal(old_refcount2, sys.getrefcount(dt2)) + + @pytest.mark.parametrize("array", [True, False]) def test_array_impossible_casts(array): # All builtin types can be forcibly cast, at least theoretically, diff --git a/numpy/_core/tests/test_multiarray.py b/numpy/_core/tests/test_multiarray.py index 26587b677c56..01144c19c851 100644 --- a/numpy/_core/tests/test_multiarray.py +++ b/numpy/_core/tests/test_multiarray.py @@ -6108,6 +6108,20 @@ def test_obj_obj(self): assert_array_equal(a['k'][-5:], 0) assert_array_equal(a['k'][:-5], 1) + @pytest.mark.skipif(not HAS_REFCOUNT, reason="Python lacks refcounts") + @pytest.mark.parametrize("dtype", ["O", "O,O"]) + def test_obj_obj_shrinking(self, dtype): + # check that memory is freed when shrinking an array. + test_obj = object() + expected = sys.getrefcount(test_obj) + a = np.array([test_obj, test_obj, test_obj], dtype=dtype) + assert a.size == 3 + a.resize((2, 1)) # two elements, not three! + assert a.size == 2 + del a + # if all is well, then we reclaimed all references + assert sys.getrefcount(test_obj) == expected + def test_empty_view(self): # check that sizes containing a zero don't trigger a reallocate for # already empty arrays diff --git a/numpy/_core/tests/test_numerictypes.py b/numpy/_core/tests/test_numerictypes.py index c9a2ac06472c..6d7372284e29 100644 --- a/numpy/_core/tests/test_numerictypes.py +++ b/numpy/_core/tests/test_numerictypes.py @@ -617,6 +617,35 @@ def test_names_are_undersood_by_dtype(self, t): assert np.dtype(t.__name__).type is t +class TestScalarTypeOrder: + @pytest.mark.parametrize(('a', 'b'), [ + # signedinteger + (np.byte, np.short), + (np.short, np.intc), + (np.intc, np.long), + (np.long, np.longlong), + # unsignedinteger + (np.ubyte, np.ushort), + (np.ushort, np.uintc), + (np.uintc, np.ulong), + (np.ulong, np.ulonglong), + # floating + (np.half, np.single), + (np.single, np.double), + (np.double, np.longdouble), + # complexfloating + (np.csingle, np.cdouble), + (np.cdouble, np.clongdouble), + # flexible + (np.bytes_, np.str_), + (np.str_, np.void), + # bouncy castles + (np.datetime64, np.timedelta64), + ]) + def test_stable_ordering(self, a: type[np.generic], b: type[np.generic]): + assert np.ScalarType.index(a) <= np.ScalarType.index(b) + + class TestBoolDefinition: def test_bool_definition(self): assert nt.bool is np.bool diff --git a/numpy/_core/tests/test_stringdtype.py b/numpy/_core/tests/test_stringdtype.py index e8ddcea8b0a2..139f86c3f213 100644 --- a/numpy/_core/tests/test_stringdtype.py +++ b/numpy/_core/tests/test_stringdtype.py @@ -1631,17 +1631,17 @@ class TestImplementation: """ @classmethod - def setup_class(self): - self.MISSING = 0x80 - self.INITIALIZED = 0x40 - self.OUTSIDE_ARENA = 0x20 - self.LONG = 0x10 - self.dtype = StringDType(na_object=np.nan) - self.sizeofstr = self.dtype.itemsize - sp = self.dtype.itemsize // 2 # pointer size = sizeof(size_t) + def setup_class(cls): + cls.MISSING = 0x80 + cls.INITIALIZED = 0x40 + cls.OUTSIDE_ARENA = 0x20 + cls.LONG = 0x10 + cls.dtype = StringDType(na_object=np.nan) + cls.sizeofstr = cls.dtype.itemsize + sp = cls.dtype.itemsize // 2 # pointer size = sizeof(size_t) # Below, size is not strictly correct, since it really uses # 7 (or 3) bytes, but good enough for the tests here. - self.view_dtype = np.dtype([ + cls.view_dtype = np.dtype([ ('offset', f'u{sp}'), ('size', f'u{sp // 2}'), ('xsiz', f'V{sp // 2 - 1}'), @@ -1652,13 +1652,13 @@ def setup_class(self): ('size', f'u{sp // 2}'), ('offset', f'u{sp}'), ]) - self.s_empty = "" - self.s_short = "01234" - self.s_medium = "abcdefghijklmnopqrstuvwxyz" - self.s_long = "-=+" * 100 - self.a = np.array( - [self.s_empty, self.s_short, self.s_medium, self.s_long], - self.dtype) + cls.s_empty = "" + cls.s_short = "01234" + cls.s_medium = "abcdefghijklmnopqrstuvwxyz" + cls.s_long = "-=+" * 100 + cls.a = np.array( + [cls.s_empty, cls.s_short, cls.s_medium, cls.s_long], + cls.dtype) def get_view(self, a): # Cannot view a StringDType as anything else directly, since diff --git a/numpy/_core/tests/test_strings.py b/numpy/_core/tests/test_strings.py index e29151adfffe..78c4b19c632c 100644 --- a/numpy/_core/tests/test_strings.py +++ b/numpy/_core/tests/test_strings.py @@ -4,6 +4,7 @@ import pytest import numpy as np +from numpy._core._exceptions import _UFuncNoLoopError from numpy.testing import IS_PYPY, assert_array_equal, assert_raises from numpy.testing._private.utils import requires_memory @@ -821,6 +822,20 @@ def test_expandtabs_raises_overflow(self, dt): np.strings.expandtabs(np.array("\ta\n\tb", dtype=dt), sys.maxsize) np.strings.expandtabs(np.array("\ta\n\tb", dtype=dt), 2**61) + def test_expandtabs_length_not_cause_segfault(self, dt): + # see gh-28829 + with pytest.raises( + _UFuncNoLoopError, + match="did not contain a loop with signature matching types", + ): + np._core.strings._expandtabs_length.reduce(np.zeros(200)) + + with pytest.raises( + _UFuncNoLoopError, + match="did not contain a loop with signature matching types", + ): + np.strings.expandtabs(np.zeros(200)) + FILL_ERROR = "The fill character must be exactly one character long" def test_center_raises_multiple_character_fill(self, dt): @@ -960,17 +975,39 @@ def test_rpartition(self, buf, sep, res1, res2, res3, dt): @pytest.mark.parametrize("args", [ (None,), + (None, None), + (None, None, -1), (0,), + (0, None), + (0, None, -1), (1,), + (1, None), + (1, None, -1), (3,), + (3, None), (5,), + (5, None), + (5, 5), + (5, 5, -1), (6,), # test index past the end + (6, None), + (6, None, -1), + (6, 7), # test start and stop index past the end + (4, 3), # test start > stop index (-1,), + (-1, None), + (-1, None, -1), (-3,), + (-3, None), ([3, 4],), + ([3, 4], None), ([2, 4],), ([-3, 5],), + ([-3, 5], None), + ([-3, 5], None, -1), ([0, -5],), + ([0, -5], None), + ([0, -5], None, -1), (1, 4), (-3, 5), (None, -1), @@ -980,8 +1017,16 @@ def test_rpartition(self, buf, sep, res1, res2, res3, dt): (None, None, -1), ([0, 6], [-1, 0], [2, -1]), ]) - def test_slice(self, args, dt): - buf = np.array(["hello", "world"], dtype=dt) + @pytest.mark.parametrize("buf", [ + ["hello", "world"], + ['hello world', 'γεια σου κόσμε', '你好世界', '👋 🌍'], + ]) + def test_slice(self, args, buf, dt): + if dt == "S" and "你好世界" in buf: + pytest.skip("Bytes dtype does not support non-ascii input") + if len(buf) == 4: + args = tuple(s * 2 if isinstance(s, list) else s for s in args) + buf = np.array(buf, dtype=dt) act = np.strings.slice(buf, *args) bcast_args = tuple(np.broadcast_to(arg, buf.shape) for arg in args) res = np.array([s[slice(*arg)] diff --git a/numpy/_core/tests/test_umath.py b/numpy/_core/tests/test_umath.py index 13e139de129b..8eac2364167f 100644 --- a/numpy/_core/tests/test_umath.py +++ b/numpy/_core/tests/test_umath.py @@ -4704,6 +4704,18 @@ def test_reduceat(): np.setbufsize(ncu.UFUNC_BUFSIZE_DEFAULT) assert_array_almost_equal(h1, h2) +def test_negative_value_raises(): + with pytest.raises(ValueError, match="buffer size must be non-negative"): + np.setbufsize(-5) + + old = np.getbufsize() + try: + prev = np.setbufsize(4096) + assert prev == old + assert np.getbufsize() == 4096 + finally: + np.setbufsize(old) + def test_reduceat_empty(): """Reduceat should work with empty arrays""" indices = np.array([], 'i4') diff --git a/numpy/_typing/_callable.pyi b/numpy/_typing/_callable.pyi deleted file mode 100644 index 647d1a5afb56..000000000000 --- a/numpy/_typing/_callable.pyi +++ /dev/null @@ -1,279 +0,0 @@ -""" -A module with various ``typing.Protocol`` subclasses that implement -the ``__call__`` magic method. - -See the `Mypy documentation`_ on protocols for more details. - -.. _`Mypy documentation`: https://mypy.readthedocs.io/en/stable/protocols.html#callback-protocols - -""" - -from typing import Any, Protocol, TypeAlias, TypeVar, final, overload, type_check_only - -import numpy as np -from numpy import ( - complex128, - complexfloating, - float64, - floating, - generic, - int_, - integer, - number, - signedinteger, - unsignedinteger, -) - -from . import NBitBase -from ._array_like import NDArray -from ._nbit import _NBitInt -from ._nested_sequence import _NestedSequence -from ._scalars import _NumberLike_co - -_T = TypeVar("_T") -_T1_contra = TypeVar("_T1_contra", contravariant=True) -_T2_contra = TypeVar("_T2_contra", contravariant=True) - -_2Tuple: TypeAlias = tuple[_T, _T] - -_NBit1 = TypeVar("_NBit1", bound=NBitBase) -_NBit2 = TypeVar("_NBit2", bound=NBitBase) - -_IntType = TypeVar("_IntType", bound=integer) -_FloatType = TypeVar("_FloatType", bound=floating) -_NumberType = TypeVar("_NumberType", bound=number) -_GenericType_co = TypeVar("_GenericType_co", covariant=True, bound=generic) - -@type_check_only -class _IntTrueDiv(Protocol[_NBit1]): - @overload - def __call__(self, other: bool, /) -> floating[_NBit1]: ... - @overload - def __call__(self, other: int, /) -> floating[_NBit1] | floating[_NBitInt]: ... - @overload - def __call__(self, other: float, /) -> floating[_NBit1] | float64: ... - @overload - def __call__( - self, other: complex, / - ) -> complexfloating[_NBit1, _NBit1] | complex128: ... - @overload - def __call__( - self, other: integer[_NBit2], / - ) -> floating[_NBit1] | floating[_NBit2]: ... - -@type_check_only -class _UnsignedIntOp(Protocol[_NBit1]): - # NOTE: `uint64 + signedinteger -> float64` - @overload - def __call__(self, other: int, /) -> unsignedinteger[_NBit1]: ... - @overload - def __call__(self, other: float, /) -> float64: ... - @overload - def __call__(self, other: complex, /) -> complex128: ... - @overload - def __call__(self, other: unsignedinteger[_NBit2], /) -> unsignedinteger[_NBit1] | unsignedinteger[_NBit2]: ... - @overload - def __call__(self, other: signedinteger, /) -> Any: ... - -@type_check_only -class _UnsignedIntBitOp(Protocol[_NBit1]): - @overload - def __call__(self, other: bool, /) -> unsignedinteger[_NBit1]: ... - @overload - def __call__(self, other: int, /) -> signedinteger: ... - @overload - def __call__(self, other: signedinteger, /) -> signedinteger: ... - @overload - def __call__( - self, other: unsignedinteger[_NBit2], / - ) -> unsignedinteger[_NBit1] | unsignedinteger[_NBit2]: ... - -@type_check_only -class _UnsignedIntMod(Protocol[_NBit1]): - @overload - def __call__(self, other: bool, /) -> unsignedinteger[_NBit1]: ... - @overload - def __call__(self, other: int | signedinteger, /) -> Any: ... - @overload - def __call__(self, other: float, /) -> floating[_NBit1] | float64: ... - @overload - def __call__( - self, other: unsignedinteger[_NBit2], / - ) -> unsignedinteger[_NBit1] | unsignedinteger[_NBit2]: ... - -@type_check_only -class _UnsignedIntDivMod(Protocol[_NBit1]): - @overload - def __call__(self, other: bool, /) -> _2Tuple[signedinteger[_NBit1]]: ... - @overload - def __call__(self, other: int | signedinteger, /) -> _2Tuple[Any]: ... - @overload - def __call__(self, other: float, /) -> _2Tuple[floating[_NBit1]] | _2Tuple[float64]: ... - @overload - def __call__( - self, other: unsignedinteger[_NBit2], / - ) -> _2Tuple[unsignedinteger[_NBit1]] | _2Tuple[unsignedinteger[_NBit2]]: ... - -@type_check_only -class _SignedIntOp(Protocol[_NBit1]): - @overload - def __call__(self, other: int, /) -> signedinteger[_NBit1]: ... - @overload - def __call__(self, other: float, /) -> float64: ... - @overload - def __call__(self, other: complex, /) -> complex128: ... - @overload - def __call__(self, other: signedinteger[_NBit2], /) -> signedinteger[_NBit1] | signedinteger[_NBit2]: ... - -@type_check_only -class _SignedIntBitOp(Protocol[_NBit1]): - @overload - def __call__(self, other: bool, /) -> signedinteger[_NBit1]: ... - @overload - def __call__(self, other: int, /) -> signedinteger[_NBit1] | int_: ... - @overload - def __call__( - self, other: signedinteger[_NBit2], / - ) -> signedinteger[_NBit1] | signedinteger[_NBit2]: ... - -@type_check_only -class _SignedIntMod(Protocol[_NBit1]): - @overload - def __call__(self, other: bool, /) -> signedinteger[_NBit1]: ... - @overload - def __call__(self, other: int, /) -> signedinteger[_NBit1] | int_: ... - @overload - def __call__(self, other: float, /) -> floating[_NBit1] | float64: ... - @overload - def __call__( - self, other: signedinteger[_NBit2], / - ) -> signedinteger[_NBit1] | signedinteger[_NBit2]: ... - -@type_check_only -class _SignedIntDivMod(Protocol[_NBit1]): - @overload - def __call__(self, other: bool, /) -> _2Tuple[signedinteger[_NBit1]]: ... - @overload - def __call__(self, other: int, /) -> _2Tuple[signedinteger[_NBit1]] | _2Tuple[int_]: ... - @overload - def __call__(self, other: float, /) -> _2Tuple[floating[_NBit1]] | _2Tuple[float64]: ... - @overload - def __call__( - self, other: signedinteger[_NBit2], / - ) -> _2Tuple[signedinteger[_NBit1]] | _2Tuple[signedinteger[_NBit2]]: ... - -@type_check_only -class _FloatOp(Protocol[_NBit1]): - @overload - def __call__(self, other: int, /) -> floating[_NBit1]: ... - @overload - def __call__(self, other: float, /) -> floating[_NBit1] | float64: ... - @overload - def __call__( - self, other: complex, / - ) -> complexfloating[_NBit1, _NBit1] | complex128: ... - @overload - def __call__( - self, other: integer[_NBit2] | floating[_NBit2], / - ) -> floating[_NBit1] | floating[_NBit2]: ... - -@type_check_only -class _FloatMod(Protocol[_NBit1]): - @overload - def __call__(self, other: bool, /) -> floating[_NBit1]: ... - @overload - def __call__(self, other: int, /) -> floating[_NBit1] | floating[_NBitInt]: ... - @overload - def __call__(self, other: float, /) -> floating[_NBit1] | float64: ... - @overload - def __call__( - self, other: integer[_NBit2] | floating[_NBit2], / - ) -> floating[_NBit1] | floating[_NBit2]: ... - -class _FloatDivMod(Protocol[_NBit1]): - @overload - def __call__(self, other: bool, /) -> _2Tuple[floating[_NBit1]]: ... - @overload - def __call__( - self, other: int, / - ) -> _2Tuple[floating[_NBit1]] | _2Tuple[floating[_NBitInt]]: ... - @overload - def __call__( - self, other: float, / - ) -> _2Tuple[floating[_NBit1]] | _2Tuple[float64]: ... - @overload - def __call__( - self, other: integer[_NBit2] | floating[_NBit2], / - ) -> _2Tuple[floating[_NBit1]] | _2Tuple[floating[_NBit2]]: ... - -@type_check_only -class _NumberOp(Protocol): - def __call__(self, other: _NumberLike_co, /) -> Any: ... - -@final -@type_check_only -class _SupportsLT(Protocol): - def __lt__(self, other: Any, /) -> Any: ... - -@final -@type_check_only -class _SupportsLE(Protocol): - def __le__(self, other: Any, /) -> Any: ... - -@final -@type_check_only -class _SupportsGT(Protocol): - def __gt__(self, other: Any, /) -> Any: ... - -@final -@type_check_only -class _SupportsGE(Protocol): - def __ge__(self, other: Any, /) -> Any: ... - -@final -@type_check_only -class _ComparisonOpLT(Protocol[_T1_contra, _T2_contra]): - @overload - def __call__(self, other: _T1_contra, /) -> np.bool: ... - @overload - def __call__(self, other: _T2_contra, /) -> NDArray[np.bool]: ... - @overload - def __call__(self, other: _NestedSequence[_SupportsGT], /) -> NDArray[np.bool]: ... - @overload - def __call__(self, other: _SupportsGT, /) -> np.bool: ... - -@final -@type_check_only -class _ComparisonOpLE(Protocol[_T1_contra, _T2_contra]): - @overload - def __call__(self, other: _T1_contra, /) -> np.bool: ... - @overload - def __call__(self, other: _T2_contra, /) -> NDArray[np.bool]: ... - @overload - def __call__(self, other: _NestedSequence[_SupportsGE], /) -> NDArray[np.bool]: ... - @overload - def __call__(self, other: _SupportsGE, /) -> np.bool: ... - -@final -@type_check_only -class _ComparisonOpGT(Protocol[_T1_contra, _T2_contra]): - @overload - def __call__(self, other: _T1_contra, /) -> np.bool: ... - @overload - def __call__(self, other: _T2_contra, /) -> NDArray[np.bool]: ... - @overload - def __call__(self, other: _NestedSequence[_SupportsLT], /) -> NDArray[np.bool]: ... - @overload - def __call__(self, other: _SupportsLT, /) -> np.bool: ... - -@final -@type_check_only -class _ComparisonOpGE(Protocol[_T1_contra, _T2_contra]): - @overload - def __call__(self, other: _T1_contra, /) -> np.bool: ... - @overload - def __call__(self, other: _T2_contra, /) -> NDArray[np.bool]: ... - @overload - def __call__(self, other: _NestedSequence[_SupportsGT], /) -> NDArray[np.bool]: ... - @overload - def __call__(self, other: _SupportsGT, /) -> np.bool: ... diff --git a/numpy/exceptions.pyi b/numpy/exceptions.pyi index 9ed50927d070..9bcc097dfc0f 100644 --- a/numpy/exceptions.pyi +++ b/numpy/exceptions.pyi @@ -17,6 +17,8 @@ class TooHardError(RuntimeError): ... class DTypePromotionError(TypeError): ... class AxisError(ValueError, IndexError): + __slots__ = "_msg", "axis", "ndim" + axis: int | None ndim: int | None @overload diff --git a/numpy/fft/_pocketfft_umath.cpp b/numpy/fft/_pocketfft_umath.cpp index 525b5e5a23da..28a55da29ac3 100644 --- a/numpy/fft/_pocketfft_umath.cpp +++ b/numpy/fft/_pocketfft_umath.cpp @@ -32,7 +32,7 @@ template static void wrap_legacy_cpp_ufunc(char **args, npy_intp const *dimensions, - ptrdiff_t const *steps, void *func) + npy_intp const *steps, void *func) { NPY_ALLOW_C_API_DEF try { @@ -86,14 +86,14 @@ copy_output(T buff[], char *out, npy_intp step_out, size_t n) */ template static void -fft_loop(char **args, npy_intp const *dimensions, ptrdiff_t const *steps, +fft_loop(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func) { char *ip = args[0], *fp = args[1], *op = args[2]; size_t n_outer = (size_t)dimensions[0]; - ptrdiff_t si = steps[0], sf = steps[1], so = steps[2]; + npy_intp si = steps[0], sf = steps[1], so = steps[2]; size_t nin = (size_t)dimensions[1], nout = (size_t)dimensions[2]; - ptrdiff_t step_in = steps[3], step_out = steps[4]; + npy_intp step_in = steps[3], step_out = steps[4]; bool direction = *((bool *)func); /* pocketfft::FORWARD or BACKWARD */ assert (nout > 0); @@ -144,9 +144,9 @@ rfft_impl(char **args, npy_intp const *dimensions, npy_intp const *steps, { char *ip = args[0], *fp = args[1], *op = args[2]; size_t n_outer = (size_t)dimensions[0]; - ptrdiff_t si = steps[0], sf = steps[1], so = steps[2]; + npy_intp si = steps[0], sf = steps[1], so = steps[2]; size_t nin = (size_t)dimensions[1], nout = (size_t)dimensions[2]; - ptrdiff_t step_in = steps[3], step_out = steps[4]; + npy_intp step_in = steps[3], step_out = steps[4]; assert (nout > 0 && nout == npts / 2 + 1); @@ -233,14 +233,13 @@ irfft_loop(char **args, npy_intp const *dimensions, npy_intp const *steps, void size_t nin = (size_t)dimensions[1], nout = (size_t)dimensions[2]; ptrdiff_t step_in = steps[3], step_out = steps[4]; - size_t npts_in = nout / 2 + 1; - assert(nout > 0); #ifndef POCKETFFT_NO_VECTORS /* * Call pocketfft directly if vectorization is possible. */ + size_t npts_in = nout / 2 + 1; constexpr auto vlen = pocketfft::detail::VLEN::val; if (vlen > 1 && n_outer >= vlen && nin >= npts_in && sf == 0) { std::vector axes = { 1 }; diff --git a/numpy/lib/_function_base_impl.pyi b/numpy/lib/_function_base_impl.pyi index 090fb233dde1..c2eaf1b5a96f 100644 --- a/numpy/lib/_function_base_impl.pyi +++ b/numpy/lib/_function_base_impl.pyi @@ -232,7 +232,6 @@ def piecewise( Callable[Concatenate[NDArray[_ScalarT], _Pss], NDArray[_ScalarT | Any]] | _ScalarT | object ], - /, *args: _Pss.args, **kw: _Pss.kwargs, ) -> NDArray[_ScalarT]: ... @@ -244,7 +243,6 @@ def piecewise( Callable[Concatenate[NDArray[Any], _Pss], NDArray[Any]] | object ], - /, *args: _Pss.args, **kw: _Pss.kwargs, ) -> NDArray[Any]: ... @@ -289,21 +287,21 @@ def gradient( ) -> Any: ... @overload -def diff( +def diff( # type: ignore[overload-overlap] a: _T, n: L[0], - axis: SupportsIndex = ..., - prepend: ArrayLike = ..., - append: ArrayLike = ..., + axis: SupportsIndex = -1, + prepend: ArrayLike | _NoValueType = ..., # = _NoValue + append: ArrayLike | _NoValueType = ..., # = _NoValue ) -> _T: ... @overload def diff( a: ArrayLike, - n: int = ..., - axis: SupportsIndex = ..., - prepend: ArrayLike = ..., - append: ArrayLike = ..., -) -> NDArray[Any]: ... + n: int = 1, + axis: SupportsIndex = -1, + prepend: ArrayLike | _NoValueType = ..., # = _NoValue + append: ArrayLike | _NoValueType = ..., # = _NoValue +) -> NDArray[Incomplete]: ... @overload # float scalar def interp( @@ -417,7 +415,8 @@ def sort_complex(a: ArrayLike) -> NDArray[complexfloating]: ... def trim_zeros( filt: _TrimZerosSequence[_T], - trim: L["f", "b", "fb", "bf"] = ..., + trim: L["f", "b", "fb", "bf"] = "fb", + axis: _ShapeLike | None = None, ) -> _T: ... @overload @@ -479,7 +478,7 @@ def cov( # NOTE `bias` and `ddof` are deprecated and ignored @overload def corrcoef( - m: _ArrayLikeFloat_co, + x: _ArrayLikeFloat_co, y: _ArrayLikeFloat_co | None = None, rowvar: bool = True, bias: _NoValueType = ..., @@ -489,7 +488,7 @@ def corrcoef( ) -> NDArray[floating]: ... @overload def corrcoef( - m: _ArrayLikeComplex_co, + x: _ArrayLikeComplex_co, y: _ArrayLikeComplex_co | None = None, rowvar: bool = True, bias: _NoValueType = ..., @@ -499,7 +498,7 @@ def corrcoef( ) -> NDArray[complexfloating]: ... @overload def corrcoef( - m: _ArrayLikeComplex_co, + x: _ArrayLikeComplex_co, y: _ArrayLikeComplex_co | None = None, rowvar: bool = True, bias: _NoValueType = ..., @@ -509,7 +508,7 @@ def corrcoef( ) -> NDArray[_ScalarT]: ... @overload def corrcoef( - m: _ArrayLikeComplex_co, + x: _ArrayLikeComplex_co, y: _ArrayLikeComplex_co | None = None, rowvar: bool = True, bias: _NoValueType = ..., @@ -626,7 +625,8 @@ def percentile( method: _MethodKind = ..., keepdims: L[False] = ..., *, - weights: _ArrayLikeFloat_co | None = ..., + weights: _ArrayLikeFloat_co | None = None, + interpolation: None = None, # deprecated ) -> floating: ... @overload def percentile( @@ -638,7 +638,8 @@ def percentile( method: _MethodKind = ..., keepdims: L[False] = ..., *, - weights: _ArrayLikeFloat_co | None = ..., + weights: _ArrayLikeFloat_co | None = None, + interpolation: None = None, # deprecated ) -> complexfloating: ... @overload def percentile( @@ -650,7 +651,8 @@ def percentile( method: _MethodKind = ..., keepdims: L[False] = ..., *, - weights: _ArrayLikeFloat_co | None = ..., + weights: _ArrayLikeFloat_co | None = None, + interpolation: None = None, # deprecated ) -> timedelta64: ... @overload def percentile( @@ -662,7 +664,8 @@ def percentile( method: _MethodKind = ..., keepdims: L[False] = ..., *, - weights: _ArrayLikeFloat_co | None = ..., + weights: _ArrayLikeFloat_co | None = None, + interpolation: None = None, # deprecated ) -> datetime64: ... @overload def percentile( @@ -674,7 +677,8 @@ def percentile( method: _MethodKind = ..., keepdims: L[False] = ..., *, - weights: _ArrayLikeFloat_co | None = ..., + weights: _ArrayLikeFloat_co | None = None, + interpolation: None = None, # deprecated ) -> Any: ... @overload def percentile( @@ -686,7 +690,8 @@ def percentile( method: _MethodKind = ..., keepdims: L[False] = ..., *, - weights: _ArrayLikeFloat_co | None = ..., + weights: _ArrayLikeFloat_co | None = None, + interpolation: None = None, # deprecated ) -> NDArray[floating]: ... @overload def percentile( @@ -698,7 +703,8 @@ def percentile( method: _MethodKind = ..., keepdims: L[False] = ..., *, - weights: _ArrayLikeFloat_co | None = ..., + weights: _ArrayLikeFloat_co | None = None, + interpolation: None = None, # deprecated ) -> NDArray[complexfloating]: ... @overload def percentile( @@ -710,7 +716,8 @@ def percentile( method: _MethodKind = ..., keepdims: L[False] = ..., *, - weights: _ArrayLikeFloat_co | None = ..., + weights: _ArrayLikeFloat_co | None = None, + interpolation: None = None, # deprecated ) -> NDArray[timedelta64]: ... @overload def percentile( @@ -722,7 +729,8 @@ def percentile( method: _MethodKind = ..., keepdims: L[False] = ..., *, - weights: _ArrayLikeFloat_co | None = ..., + weights: _ArrayLikeFloat_co | None = None, + interpolation: None = None, # deprecated ) -> NDArray[datetime64]: ... @overload def percentile( @@ -734,7 +742,8 @@ def percentile( method: _MethodKind = ..., keepdims: L[False] = ..., *, - weights: _ArrayLikeFloat_co | None = ..., + weights: _ArrayLikeFloat_co | None = None, + interpolation: None = None, # deprecated ) -> NDArray[object_]: ... @overload def percentile( @@ -746,7 +755,8 @@ def percentile( method: _MethodKind = ..., keepdims: bool = ..., *, - weights: _ArrayLikeFloat_co | None = ..., + weights: _ArrayLikeFloat_co | None = None, + interpolation: None = None, # deprecated ) -> Any: ... @overload def percentile( @@ -758,7 +768,8 @@ def percentile( method: _MethodKind = ..., keepdims: bool = ..., *, - weights: _ArrayLikeFloat_co | None = ..., + weights: _ArrayLikeFloat_co | None = None, + interpolation: None = None, # deprecated ) -> _ArrayT: ... @overload def percentile( @@ -767,15 +778,183 @@ def percentile( axis: _ShapeLike | None = ..., *, out: _ArrayT, - overwrite_input: bool = ..., - method: _MethodKind = ..., - keepdims: bool = ..., - weights: _ArrayLikeFloat_co | None = ..., + overwrite_input: bool = False, + method: _MethodKind = "linear", + keepdims: bool = False, + weights: _ArrayLikeFloat_co | None = None, + interpolation: None = None, # deprecated ) -> _ArrayT: ... -# NOTE: Not an alias, but they do have identical signatures -# (that we can reuse) -quantile = percentile +# NOTE: keep in sync with `percentile` +@overload +def quantile( + a: _ArrayLikeFloat_co, + q: _FloatLike_co, + axis: None = None, + out: None = None, + overwrite_input: bool = False, + method: _MethodKind = "linear", + keepdims: L[False] = False, + *, + weights: _ArrayLikeFloat_co | None = None, + interpolation: None = None, # deprecated +) -> floating: ... +@overload +def quantile( + a: _ArrayLikeComplex_co, + q: _FloatLike_co, + axis: None = None, + out: None = None, + overwrite_input: bool = False, + method: _MethodKind = "linear", + keepdims: L[False] = False, + *, + weights: _ArrayLikeFloat_co | None = None, + interpolation: None = None, # deprecated +) -> complexfloating: ... +@overload +def quantile( + a: _ArrayLikeTD64_co, + q: _FloatLike_co, + axis: None = None, + out: None = None, + overwrite_input: bool = False, + method: _MethodKind = "linear", + keepdims: L[False] = False, + *, + weights: _ArrayLikeFloat_co | None = None, + interpolation: None = None, # deprecated +) -> timedelta64: ... +@overload +def quantile( + a: _ArrayLikeDT64_co, + q: _FloatLike_co, + axis: None = None, + out: None = None, + overwrite_input: bool = False, + method: _MethodKind = "linear", + keepdims: L[False] = False, + *, + weights: _ArrayLikeFloat_co | None = None, + interpolation: None = None, # deprecated +) -> datetime64: ... +@overload +def quantile( + a: _ArrayLikeObject_co, + q: _FloatLike_co, + axis: None = None, + out: None = None, + overwrite_input: bool = False, + method: _MethodKind = "linear", + keepdims: L[False] = False, + *, + weights: _ArrayLikeFloat_co | None = None, + interpolation: None = None, # deprecated +) -> Any: ... +@overload +def quantile( + a: _ArrayLikeFloat_co, + q: _ArrayLikeFloat_co, + axis: None = None, + out: None = None, + overwrite_input: bool = False, + method: _MethodKind = "linear", + keepdims: L[False] = False, + *, + weights: _ArrayLikeFloat_co | None = None, + interpolation: None = None, # deprecated +) -> NDArray[floating]: ... +@overload +def quantile( + a: _ArrayLikeComplex_co, + q: _ArrayLikeFloat_co, + axis: None = None, + out: None = None, + overwrite_input: bool = False, + method: _MethodKind = "linear", + keepdims: L[False] = False, + *, + weights: _ArrayLikeFloat_co | None = None, + interpolation: None = None, # deprecated +) -> NDArray[complexfloating]: ... +@overload +def quantile( + a: _ArrayLikeTD64_co, + q: _ArrayLikeFloat_co, + axis: None = None, + out: None = None, + overwrite_input: bool = False, + method: _MethodKind = "linear", + keepdims: L[False] = False, + *, + weights: _ArrayLikeFloat_co | None = None, + interpolation: None = None, # deprecated +) -> NDArray[timedelta64]: ... +@overload +def quantile( + a: _ArrayLikeDT64_co, + q: _ArrayLikeFloat_co, + axis: None = None, + out: None = None, + overwrite_input: bool = False, + method: _MethodKind = "linear", + keepdims: L[False] = False, + *, + weights: _ArrayLikeFloat_co | None = None, + interpolation: None = None, # deprecated +) -> NDArray[datetime64]: ... +@overload +def quantile( + a: _ArrayLikeObject_co, + q: _ArrayLikeFloat_co, + axis: None = None, + out: None = None, + overwrite_input: bool = False, + method: _MethodKind = "linear", + keepdims: L[False] = False, + *, + weights: _ArrayLikeFloat_co | None = None, + interpolation: None = None, # deprecated +) -> NDArray[object_]: ... +@overload +def quantile( + a: _ArrayLikeComplex_co | _ArrayLikeTD64_co | _ArrayLikeDT64_co | _ArrayLikeObject_co, + q: _ArrayLikeFloat_co, + axis: _ShapeLike | None = None, + out: None = None, + overwrite_input: bool = False, + method: _MethodKind = "linear", + keepdims: bool = False, + *, + weights: _ArrayLikeFloat_co | None = None, + interpolation: None = None, # deprecated +) -> Any: ... +@overload +def quantile( + a: _ArrayLikeComplex_co | _ArrayLikeTD64_co | _ArrayLikeDT64_co | _ArrayLikeObject_co, + q: _ArrayLikeFloat_co, + axis: _ShapeLike | None, + out: _ArrayT, + overwrite_input: bool = False, + method: _MethodKind = "linear", + keepdims: bool = False, + *, + weights: _ArrayLikeFloat_co | None = None, + interpolation: None = None, # deprecated +) -> _ArrayT: ... +@overload +def quantile( + a: _ArrayLikeComplex_co | _ArrayLikeTD64_co | _ArrayLikeDT64_co | _ArrayLikeObject_co, + q: _ArrayLikeFloat_co, + axis: _ShapeLike | None = None, + *, + out: _ArrayT, + overwrite_input: bool = False, + method: _MethodKind = "linear", + keepdims: bool = False, + weights: _ArrayLikeFloat_co | None = None, + interpolation: None = None, # deprecated +) -> _ArrayT: ... _ScalarT_fm = TypeVar( "_ScalarT_fm", diff --git a/numpy/lib/_histograms_impl.pyi b/numpy/lib/_histograms_impl.pyi index 5e7afb5e397b..4a65988e476f 100644 --- a/numpy/lib/_histograms_impl.pyi +++ b/numpy/lib/_histograms_impl.pyi @@ -35,16 +35,16 @@ def histogram_bin_edges( def histogram( a: ArrayLike, - bins: _BinKind | SupportsIndex | ArrayLike = ..., - range: tuple[float, float] | None = ..., - density: bool = ..., - weights: ArrayLike | None = ..., + bins: _BinKind | SupportsIndex | ArrayLike = 10, + range: tuple[float, float] | None = None, + density: bool | None = None, + weights: ArrayLike | None = None, ) -> tuple[NDArray[Any], NDArray[Any]]: ... def histogramdd( sample: ArrayLike, - bins: SupportsIndex | ArrayLike = ..., - range: Sequence[tuple[float, float]] = ..., - density: bool | None = ..., - weights: ArrayLike | None = ..., + bins: SupportsIndex | ArrayLike = 10, + range: Sequence[tuple[float, float]] | None = None, + density: bool | None = None, + weights: ArrayLike | None = None, ) -> tuple[NDArray[Any], tuple[NDArray[Any], ...]]: ... diff --git a/numpy/lib/_index_tricks_impl.pyi b/numpy/lib/_index_tricks_impl.pyi index 7ac2b3a093e0..c6b06ddb8215 100644 --- a/numpy/lib/_index_tricks_impl.pyi +++ b/numpy/lib/_index_tricks_impl.pyi @@ -98,6 +98,8 @@ class ndindex: def ndincr(self, /) -> None: ... class nd_grid(Generic[_BoolT_co]): + __slots__ = ("sparse",) + sparse: _BoolT_co def __init__(self, sparse: _BoolT_co = ...) -> None: ... @overload @@ -107,10 +109,14 @@ class nd_grid(Generic[_BoolT_co]): @final class MGridClass(nd_grid[L[False]]): + __slots__ = () + def __init__(self) -> None: ... @final class OGridClass(nd_grid[L[True]]): + __slots__ = () + def __init__(self) -> None: ... class AxisConcatenator(Generic[_AxisT_co, _MatrixT_co, _NDMinT_co, _Trans1DT_co]): @@ -147,13 +153,19 @@ class AxisConcatenator(Generic[_AxisT_co, _MatrixT_co, _NDMinT_co, _Trans1DT_co] @final class RClass(AxisConcatenator[L[0], L[False], L[1], L[-1]]): + __slots__ = () + def __init__(self, /) -> None: ... @final class CClass(AxisConcatenator[L[-1], L[False], L[2], L[0]]): + __slots__ = () + def __init__(self, /) -> None: ... class IndexExpression(Generic[_BoolT_co]): + __slots__ = ("maketuple",) + maketuple: _BoolT_co def __init__(self, maketuple: _BoolT_co) -> None: ... @overload diff --git a/numpy/lib/_polynomial_impl.pyi b/numpy/lib/_polynomial_impl.pyi index faf2f01e6a22..3beece11115f 100644 --- a/numpy/lib/_polynomial_impl.pyi +++ b/numpy/lib/_polynomial_impl.pyi @@ -137,20 +137,22 @@ def polyfit( x: _ArrayLikeFloat_co, y: _ArrayLikeFloat_co, deg: SupportsIndex | SupportsInt, - rcond: float | None = ..., - full: L[False] = ..., - w: _ArrayLikeFloat_co | None = ..., - cov: L[True, "unscaled"] = ..., + rcond: float | None = None, + full: L[False] = False, + w: _ArrayLikeFloat_co | None = None, + *, + cov: L[True, "unscaled"], ) -> _2Tup[NDArray[float64]]: ... @overload def polyfit( x: _ArrayLikeComplex_co, y: _ArrayLikeComplex_co, deg: SupportsIndex | SupportsInt, - rcond: float | None = ..., - full: L[False] = ..., - w: _ArrayLikeFloat_co | None = ..., - cov: L[True, "unscaled"] = ..., + rcond: float | None = None, + full: L[False] = False, + w: _ArrayLikeFloat_co | None = None, + *, + cov: L[True, "unscaled"], ) -> _2Tup[NDArray[complex128]]: ... @overload def polyfit( diff --git a/numpy/lib/_utils_impl.py b/numpy/lib/_utils_impl.py index 2e1ee23d7d58..164aa4ee3d8c 100644 --- a/numpy/lib/_utils_impl.py +++ b/numpy/lib/_utils_impl.py @@ -61,6 +61,11 @@ def show_runtime(): "not_found": features_not_found } }) + config_found.append({ + "ignore_floating_point_errors_in_matmul": + not np._core._multiarray_umath._blas_supports_fpe(None), + }) + try: from threadpoolctl import threadpool_info config_found.extend(threadpool_info()) diff --git a/numpy/lib/mixins.pyi b/numpy/lib/mixins.pyi index 4f4801feac8f..730827d92b75 100644 --- a/numpy/lib/mixins.pyi +++ b/numpy/lib/mixins.pyi @@ -14,6 +14,8 @@ __all__ = ["NDArrayOperatorsMixin"] # As such, only little type safety can be provided here. class NDArrayOperatorsMixin(ABC): + __slots__ = () + @abstractmethod def __array_ufunc__( self, diff --git a/numpy/lib/tests/test_index_tricks.py b/numpy/lib/tests/test_index_tricks.py index ed8709db5238..7150a786775a 100644 --- a/numpy/lib/tests/test_index_tricks.py +++ b/numpy/lib/tests/test_index_tricks.py @@ -199,6 +199,11 @@ def test_empty_array_unravel(self): with assert_raises(ValueError): np.unravel_index([1], (2, 1, 0)) + def test_regression_size_1_index(self): + # actually tests the nditer size one index tracking + # regression test for gh-29690 + np.unravel_index(np.array([[1, 0, 1, 0]], dtype=np.uint32), (4,)) + class TestGrid: def test_basic(self): a = mgrid[-1:1:10j] diff --git a/numpy/linalg/_linalg.pyi b/numpy/linalg/_linalg.pyi index 3f318a892da5..3611053a3c97 100644 --- a/numpy/linalg/_linalg.pyi +++ b/numpy/linalg/_linalg.pyi @@ -28,6 +28,7 @@ from numpy import ( ) from numpy._core.fromnumeric import matrix_transpose from numpy._core.numeric import tensordot +from numpy._globals import _NoValueType from numpy._typing import ( ArrayLike, DTypeLike, @@ -78,7 +79,7 @@ __all__ = [ "vecdot", ] -_ArrayT = TypeVar("_ArrayT", bound=NDArray[Any]) +_NumberT = TypeVar("_NumberT", bound=np.number) _ModeKind: TypeAlias = L["reduced", "complete", "r", "raw"] @@ -182,33 +183,29 @@ def cholesky(a: _ArrayLikeFloat_co, /, *, upper: bool = False) -> NDArray[floati def cholesky(a: _ArrayLikeComplex_co, /, *, upper: bool = False) -> NDArray[complexfloating]: ... @overload -def outer(x1: _ArrayLike[Never], x2: _ArrayLike[Never]) -> NDArray[Any]: ... +def outer(x1: _ArrayLike[Never], x2: _ArrayLike[Never], /) -> NDArray[Any]: ... @overload -def outer(x1: _ArrayLikeBool_co, x2: _ArrayLikeBool_co) -> NDArray[np.bool]: ... +def outer(x1: _ArrayLikeBool_co, x2: _ArrayLikeBool_co, /) -> NDArray[np.bool]: ... @overload -def outer(x1: _ArrayLikeUInt_co, x2: _ArrayLikeUInt_co) -> NDArray[unsignedinteger]: ... +def outer(x1: _ArrayLike[_NumberT], x2: _ArrayLike[_NumberT], /) -> NDArray[_NumberT]: ... @overload -def outer(x1: _ArrayLikeInt_co, x2: _ArrayLikeInt_co) -> NDArray[signedinteger]: ... +def outer(x1: _ArrayLikeUInt_co, x2: _ArrayLikeUInt_co, /) -> NDArray[unsignedinteger]: ... @overload -def outer(x1: _ArrayLikeFloat_co, x2: _ArrayLikeFloat_co) -> NDArray[floating]: ... +def outer(x1: _ArrayLikeInt_co, x2: _ArrayLikeInt_co, /) -> NDArray[signedinteger]: ... @overload -def outer( - x1: _ArrayLikeComplex_co, - x2: _ArrayLikeComplex_co, -) -> NDArray[complexfloating]: ... +def outer(x1: _ArrayLikeFloat_co, x2: _ArrayLikeFloat_co, /) -> NDArray[floating]: ... @overload -def outer( - x1: _ArrayLikeTD64_co, - x2: _ArrayLikeTD64_co, - out: None = ..., -) -> NDArray[timedelta64]: ... +def outer(x1: _ArrayLikeComplex_co, x2: _ArrayLikeComplex_co, /) -> NDArray[complexfloating]: ... +@overload +def outer(x1: _ArrayLikeTD64_co, x2: _ArrayLikeTD64_co, /) -> NDArray[timedelta64]: ... @overload -def outer(x1: _ArrayLikeObject_co, x2: _ArrayLikeObject_co) -> NDArray[object_]: ... +def outer(x1: _ArrayLikeObject_co, x2: _ArrayLikeObject_co, /) -> NDArray[object_]: ... @overload def outer( x1: _ArrayLikeComplex_co | _ArrayLikeTD64_co | _ArrayLikeObject_co, x2: _ArrayLikeComplex_co | _ArrayLikeTD64_co | _ArrayLikeObject_co, -) -> _ArrayT: ... + /, +) -> NDArray[Any]: ... @overload def qr(a: _ArrayLikeInt_co, mode: _ModeKind = ...) -> QRResult: ... @@ -308,20 +305,26 @@ def matrix_rank( @overload def pinv( a: _ArrayLikeInt_co, - rcond: _ArrayLikeFloat_co = ..., - hermitian: bool = ..., + rcond: _ArrayLikeFloat_co | None = None, + hermitian: bool = False, + *, + rtol: _ArrayLikeFloat_co | _NoValueType = ..., ) -> NDArray[float64]: ... @overload def pinv( a: _ArrayLikeFloat_co, - rcond: _ArrayLikeFloat_co = ..., - hermitian: bool = ..., + rcond: _ArrayLikeFloat_co | None = None, + hermitian: bool = False, + *, + rtol: _ArrayLikeFloat_co | _NoValueType = ..., ) -> NDArray[floating]: ... @overload def pinv( a: _ArrayLikeComplex_co, - rcond: _ArrayLikeFloat_co = ..., - hermitian: bool = ..., + rcond: _ArrayLikeFloat_co | None = None, + hermitian: bool = False, + *, + rtol: _ArrayLikeFloat_co | _NoValueType = ..., ) -> NDArray[complexfloating]: ... # TODO: Returns a 2-tuple of scalars for 2D arrays and @@ -461,22 +464,12 @@ def cross( ) -> NDArray[complexfloating]: ... @overload -def matmul( - x1: _ArrayLikeInt_co, - x2: _ArrayLikeInt_co, -) -> NDArray[signedinteger]: ... +def matmul(x1: _ArrayLike[_NumberT], x2: _ArrayLike[_NumberT], /) -> NDArray[_NumberT]: ... @overload -def matmul( - x1: _ArrayLikeUInt_co, - x2: _ArrayLikeUInt_co, -) -> NDArray[unsignedinteger]: ... +def matmul(x1: _ArrayLikeInt_co, x2: _ArrayLikeInt_co, /) -> NDArray[signedinteger]: ... @overload -def matmul( - x1: _ArrayLikeFloat_co, - x2: _ArrayLikeFloat_co, -) -> NDArray[floating]: ... +def matmul(x1: _ArrayLikeUInt_co, x2: _ArrayLikeUInt_co, /) -> NDArray[unsignedinteger]: ... @overload -def matmul( - x1: _ArrayLikeComplex_co, - x2: _ArrayLikeComplex_co, -) -> NDArray[complexfloating]: ... +def matmul(x1: _ArrayLikeFloat_co, x2: _ArrayLikeFloat_co, /) -> NDArray[floating]: ... +@overload +def matmul(x1: _ArrayLikeComplex_co, x2: _ArrayLikeComplex_co, /) -> NDArray[complexfloating]: ... diff --git a/numpy/linalg/umath_linalg.cpp b/numpy/linalg/umath_linalg.cpp index ead6d84a73a2..bb4c62479293 100644 --- a/numpy/linalg/umath_linalg.cpp +++ b/numpy/linalg/umath_linalg.cpp @@ -448,6 +448,15 @@ set_fp_invalid_or_clear(int error_occurred) } } +static inline void +report_no_memory() +{ + NPY_ALLOW_C_API_DEF + NPY_ALLOW_C_API; + PyErr_NoMemory(); + NPY_DISABLE_C_API; +} + /* ***************************************************************************** ** Some handy constants ** @@ -1199,10 +1208,7 @@ slogdet(char **args, } else { /* TODO: Requires use of new ufunc API to indicate error return */ - NPY_ALLOW_C_API_DEF - NPY_ALLOW_C_API; - PyErr_NoMemory(); - NPY_DISABLE_C_API; + report_no_memory(); } } @@ -1255,10 +1261,7 @@ det(char **args, } else { /* TODO: Requires use of new ufunc API to indicate error return */ - NPY_ALLOW_C_API_DEF - NPY_ALLOW_C_API; - PyErr_NoMemory(); - NPY_DISABLE_C_API; + report_no_memory(); } } @@ -1331,7 +1334,7 @@ init_evd(EIGH_PARAMS_t* params, char JOBZ, char UPLO, mem_buff = (npy_uint8 *)malloc(alloc_size); if (!mem_buff) { - goto error; + goto no_memory; } a = mem_buff; w = mem_buff + safe_N * safe_N * sizeof(typ); @@ -1365,7 +1368,7 @@ init_evd(EIGH_PARAMS_t* params, char JOBZ, char UPLO, mem_buff2 = (npy_uint8 *)malloc(lwork*sizeof(typ) + liwork*sizeof(fortran_int)); if (!mem_buff2) { - goto error; + goto no_memory; } work = mem_buff2; @@ -1378,6 +1381,9 @@ init_evd(EIGH_PARAMS_t* params, char JOBZ, char UPLO, return 1; + no_memory: + report_no_memory(); + error: /* something failed */ memset(params, 0, sizeof(*params)); @@ -1440,7 +1446,7 @@ using fbasetyp = fortran_type_t; mem_buff = (npy_uint8 *)malloc(safe_N * safe_N * sizeof(typ) + safe_N * sizeof(basetyp)); if (!mem_buff) { - goto error; + goto no_memory; } a = mem_buff; w = mem_buff + safe_N * safe_N * sizeof(typ); @@ -1478,7 +1484,7 @@ using fbasetyp = fortran_type_t; lrwork*sizeof(basetyp) + liwork*sizeof(fortran_int)); if (!mem_buff2) { - goto error; + goto no_memory; } work = mem_buff2; @@ -1495,6 +1501,8 @@ using fbasetyp = fortran_type_t; return 1; /* something failed */ +no_memory: + report_no_memory(); error: memset(params, 0, sizeof(*params)); free(mem_buff2); @@ -1733,7 +1741,10 @@ init_gesv(GESV_PARAMS_t *params, fortran_int N, fortran_int NRHS) params->LDB = ld; return 1; + error: + report_no_memory(); + free(mem_buff); memset(params, 0, sizeof(*params)); @@ -1977,6 +1988,8 @@ init_potrf(POTR_PARAMS_t *params, char UPLO, fortran_int N) return 1; error: + report_no_memory(); + free(mem_buff); memset(params, 0, sizeof(*params)); @@ -2175,7 +2188,7 @@ scalar_trait) vlr_size + vrr_size + w_size + vl_size + vr_size); if (!mem_buff) { - goto error; + goto no_memory; } a = mem_buff; @@ -2218,7 +2231,7 @@ scalar_trait) mem_buff2 = (npy_uint8 *)malloc(work_count*sizeof(typ)); if (!mem_buff2) { - goto error; + goto no_memory; } work = mem_buff2; @@ -2226,6 +2239,10 @@ scalar_trait) params->WORK = (typ*)work; return 1; + + no_memory: + report_no_memory(); + error: free(mem_buff2); free(mem_buff); @@ -2392,7 +2409,7 @@ using realtyp = basetype_t; mem_buff = (npy_uint8 *)malloc(total_size); if (!mem_buff) { - goto error; + goto no_memory; } a = mem_buff; @@ -2434,7 +2451,7 @@ using realtyp = basetype_t; mem_buff2 = (npy_uint8 *)malloc(work_count*sizeof(ftyp)); if (!mem_buff2) { - goto error; + goto no_memory; } work = mem_buff2; @@ -2443,6 +2460,9 @@ using realtyp = basetype_t; params->WORK = (ftyp*)work; return 1; + + no_memory: + report_no_memory(); error: free(mem_buff2); free(mem_buff); @@ -2754,7 +2774,7 @@ init_gesdd(GESDD_PARAMS_t *params, mem_buff = (npy_uint8 *)malloc(a_size + s_size + u_size + vt_size + iwork_size); if (!mem_buff) { - goto error; + goto no_memory; } a = mem_buff; @@ -2798,7 +2818,7 @@ init_gesdd(GESDD_PARAMS_t *params, mem_buff2 = (npy_uint8 *)malloc(work_size); if (!mem_buff2) { - goto error; + goto no_memory; } work = mem_buff2; @@ -2807,6 +2827,9 @@ init_gesdd(GESDD_PARAMS_t *params, params->WORK = (ftyp*)work; return 1; + + no_memory: + report_no_memory(); error: TRACE_TXT("%s failed init\n", __FUNCTION__); free(mem_buff); @@ -2894,7 +2917,7 @@ using frealtyp = basetype_t; rwork_size + iwork_size); if (!mem_buff) { - goto error; + goto no_memory; } a = mem_buff; @@ -2939,7 +2962,7 @@ using frealtyp = basetype_t; mem_buff2 = (npy_uint8 *)malloc(work_size); if (!mem_buff2) { - goto error; + goto no_memory; } work = mem_buff2; @@ -2948,6 +2971,10 @@ using frealtyp = basetype_t; params->WORK = (ftyp*)work; return 1; + + no_memory: + report_no_memory(); + error: TRACE_TXT("%s failed init\n", __FUNCTION__); free(mem_buff2); @@ -3186,7 +3213,7 @@ using ftyp = fortran_doublereal; mem_buff = (npy_uint8 *)malloc(a_size + tau_size); if (!mem_buff) - goto error; + goto no_memory; a = mem_buff; tau = a + a_size; @@ -3219,13 +3246,17 @@ using ftyp = fortran_doublereal; work_size = (size_t) params->LWORK * sizeof(ftyp); mem_buff2 = (npy_uint8 *)malloc(work_size); if (!mem_buff2) - goto error; + goto no_memory; work = mem_buff2; params->WORK = (ftyp*)work; return 1; + + no_memory: + report_no_memory(); + error: TRACE_TXT("%s failed init\n", __FUNCTION__); free(mem_buff); @@ -3260,7 +3291,7 @@ using ftyp = fortran_doublecomplex; mem_buff = (npy_uint8 *)malloc(a_size + tau_size); if (!mem_buff) - goto error; + goto no_memory; a = mem_buff; tau = a + a_size; @@ -3295,13 +3326,17 @@ using ftyp = fortran_doublecomplex; mem_buff2 = (npy_uint8 *)malloc(work_size); if (!mem_buff2) - goto error; + goto no_memory; work = mem_buff2; params->WORK = (ftyp*)work; return 1; + + no_memory: + report_no_memory(); + error: TRACE_TXT("%s failed init\n", __FUNCTION__); free(mem_buff); @@ -3433,7 +3468,7 @@ using ftyp = fortran_doublereal; mem_buff = (npy_uint8 *)malloc(q_size + tau_size + a_size); if (!mem_buff) - goto error; + goto no_memory; q = mem_buff; tau = q + q_size; @@ -3468,13 +3503,17 @@ using ftyp = fortran_doublereal; mem_buff2 = (npy_uint8 *)malloc(work_size); if (!mem_buff2) - goto error; + goto no_memory; work = mem_buff2; params->WORK = (ftyp*)work; return 1; + + no_memory: + report_no_memory(); + error: TRACE_TXT("%s failed init\n", __FUNCTION__); free(mem_buff); @@ -3512,7 +3551,7 @@ using ftyp=fortran_doublecomplex; mem_buff = (npy_uint8 *)malloc(q_size + tau_size + a_size); if (!mem_buff) - goto error; + goto no_memory; q = mem_buff; tau = q + q_size; @@ -3548,7 +3587,7 @@ using ftyp=fortran_doublecomplex; mem_buff2 = (npy_uint8 *)malloc(work_size); if (!mem_buff2) - goto error; + goto no_memory; work = mem_buff2; @@ -3556,6 +3595,10 @@ using ftyp=fortran_doublecomplex; params->LWORK = work_count; return 1; + + no_memory: + report_no_memory(); + error: TRACE_TXT("%s failed init\n", __FUNCTION__); free(mem_buff); @@ -3898,10 +3941,7 @@ scalar_trait) return 1; no_memory: - NPY_ALLOW_C_API_DEF - NPY_ALLOW_C_API; - PyErr_NoMemory(); - NPY_DISABLE_C_API; + report_no_memory(); error: TRACE_TXT("%s failed init\n", __FUNCTION__); @@ -4034,10 +4074,7 @@ using frealtyp = basetype_t; return 1; no_memory: - NPY_ALLOW_C_API_DEF - NPY_ALLOW_C_API; - PyErr_NoMemory(); - NPY_DISABLE_C_API; + report_no_memory(); error: TRACE_TXT("%s failed init\n", __FUNCTION__); diff --git a/numpy/ma/core.py b/numpy/ma/core.py index 05ea373a6a12..8a85960f622b 100644 --- a/numpy/ma/core.py +++ b/numpy/ma/core.py @@ -8633,9 +8633,6 @@ def asanyarray(a, dtype=None): Input data, in any form that can be converted to an array. dtype : dtype, optional By default, the data-type is inferred from the input data. - order : {'C', 'F'}, optional - Whether to use row-major ('C') or column-major ('FORTRAN') memory - representation. Default is 'C'. Returns ------- diff --git a/numpy/ma/extras.pyi b/numpy/ma/extras.pyi index c3f9fcde4a0a..9b46d32dd3f9 100644 --- a/numpy/ma/extras.pyi +++ b/numpy/ma/extras.pyi @@ -110,12 +110,16 @@ def cov(x, y=..., rowvar=..., bias=..., allow_masked=..., ddof=...): ... def corrcoef(x, y=..., rowvar=..., bias=..., allow_masked=..., ddof=...): ... class MAxisConcatenator(AxisConcatenator): + __slots__ = () + @staticmethod def concatenate(arrays: Incomplete, axis: int = 0) -> Incomplete: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] @classmethod def makemat(cls, arr: Incomplete) -> Incomplete: ... # type: ignore[override] # pyright: ignore[reportIncompatibleVariableOverride] class mr_class(MAxisConcatenator): + __slots__ = () + def __init__(self) -> None: ... mr_: mr_class diff --git a/numpy/meson.build b/numpy/meson.build index 67e4861d7ad6..45d5a2b52eb8 100644 --- a/numpy/meson.build +++ b/numpy/meson.build @@ -32,7 +32,7 @@ endif # than a `.a` file extension in order not to break including them in a # distutils-based build (see gh-23981 and # https://mesonbuild.com/FAQ.html#why-does-building-my-project-with-msvc-output-static-libraries-called-libfooa) -if is_windows and cc.get_id() == 'msvc' +if is_windows and cc.get_id() in ['msvc', 'clang-cl'] name_prefix_staticlib = '' name_suffix_staticlib = 'lib' else diff --git a/numpy/random/_generator.pyi b/numpy/random/_generator.pyi index dc78a76eda70..6d7ef5e6c072 100644 --- a/numpy/random/_generator.pyi +++ b/numpy/random/_generator.pyi @@ -1,4 +1,4 @@ -from collections.abc import Callable +from collections.abc import Callable, MutableSequence from typing import Any, Literal, TypeAlias, TypeVar, overload import numpy as np @@ -849,7 +849,12 @@ class Generator: def permuted( self, x: ArrayLike, *, axis: int | None = ..., out: NDArray[Any] | None = ... ) -> NDArray[Any]: ... - def shuffle(self, x: ArrayLike, axis: int = ...) -> None: ... + + # axis must be 0 for MutableSequence + @overload + def shuffle(self, /, x: np.ndarray, axis: int = 0) -> None: ... + @overload + def shuffle(self, /, x: MutableSequence[Any], axis: Literal[0] = 0) -> None: ... def default_rng( seed: _ArrayLikeInt_co | SeedSequence | BitGenerator | Generator | RandomState | None = ... diff --git a/numpy/random/src/distributions/distributions.c b/numpy/random/src/distributions/distributions.c index aa81a4a173d4..157fd54d34c9 100644 --- a/numpy/random/src/distributions/distributions.c +++ b/numpy/random/src/distributions/distributions.c @@ -845,12 +845,12 @@ double random_noncentral_f(bitgen_t *bitgen_state, double dfnum, double dfden, double random_wald(bitgen_t *bitgen_state, double mean, double scale) { double U, X, Y; - double mu_2l; + double d; - mu_2l = mean / (2 * scale); Y = random_standard_normal(bitgen_state); Y = mean * Y * Y; - X = mean + mu_2l * (Y - sqrt(4 * scale * Y + Y * Y)); + d = 1 + sqrt(1 + 4 * scale / Y); + X = mean * (1 - 2 / d); U = next_double(bitgen_state); if (U <= mean / (mean + X)) { return X; diff --git a/numpy/random/src/mt19937/randomkit.c b/numpy/random/src/mt19937/randomkit.c index 32f40fa49cc1..21d270234c9a 100644 --- a/numpy/random/src/mt19937/randomkit.c +++ b/numpy/random/src/mt19937/randomkit.c @@ -62,6 +62,8 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include + /* static char const rcsid[] = "@(#) $Jeannot: randomkit.c,v 1.28 2005/07/21 22:14:09 js Exp $"; */ diff --git a/numpy/random/tests/test_generator_mt19937.py b/numpy/random/tests/test_generator_mt19937.py index d09cbba4ec39..68a1f7c6304a 100644 --- a/numpy/random/tests/test_generator_mt19937.py +++ b/numpy/random/tests/test_generator_mt19937.py @@ -1858,6 +1858,11 @@ def test_wald(self): [2.07093587449261, 0.73073890064369]]) assert_array_almost_equal(actual, desired, decimal=14) + def test_wald_nonnegative(self): + random = Generator(MT19937(self.seed)) + samples = random.wald(mean=1e9, scale=2.25, size=1000) + assert_(np.all(samples >= 0.0)) + def test_weibull(self): random = Generator(MT19937(self.seed)) actual = random.weibull(a=1.23, size=(3, 2)) diff --git a/numpy/testing/_private/extbuild.pyi b/numpy/testing/_private/extbuild.pyi index 609a45e79d16..c1ae507d6a49 100644 --- a/numpy/testing/_private/extbuild.pyi +++ b/numpy/testing/_private/extbuild.pyi @@ -10,7 +10,7 @@ def build_and_import_extension( *, prologue: str = "", build_dir: pathlib.Path | None = None, - include_dirs: Sequence[str] = [], + include_dirs: Sequence[str] | None = None, more_init: str = "", ) -> types.ModuleType: ... @@ -20,6 +20,6 @@ def compile_extension_module( builddir: pathlib.Path, include_dirs: Sequence[str], source_string: str, - libraries: Sequence[str] = [], - library_dirs: Sequence[str] = [], + libraries: Sequence[str] | None = None, + library_dirs: Sequence[str] | None = None, ) -> pathlib.Path: ... diff --git a/numpy/testing/_private/utils.py b/numpy/testing/_private/utils.py index 65f4059f98fd..6d4c87ba286f 100644 --- a/numpy/testing/_private/utils.py +++ b/numpy/testing/_private/utils.py @@ -90,14 +90,7 @@ class KnownFailureException(Exception): IS_PYPY = sys.implementation.name == 'pypy' IS_PYSTON = hasattr(sys, "pyston_version_info") HAS_REFCOUNT = getattr(sys, 'getrefcount', None) is not None and not IS_PYSTON -BLAS_SUPPORTS_FPE = True -if platform.system() == 'Darwin' or platform.machine() == 'arm64': - try: - blas = np.__config__.CONFIG['Build Dependencies']['blas'] - if blas['name'] == 'accelerate': - BLAS_SUPPORTS_FPE = False - except KeyError: - pass +BLAS_SUPPORTS_FPE = np._core._multiarray_umath._blas_supports_fpe(None) HAS_LAPACK64 = numpy.linalg._umath_linalg._ilp64 diff --git a/numpy/testing/_private/utils.pyi b/numpy/testing/_private/utils.pyi index 4e3b60a0ef70..43981a5decb5 100644 --- a/numpy/testing/_private/utils.pyi +++ b/numpy/testing/_private/utils.pyi @@ -170,7 +170,7 @@ else: def memusage() -> NoReturn: ... if sys.platform == "linux": - def jiffies(_proc_pid_stat: StrOrBytesPath = ..., _load_time: list[float] = []) -> int: ... + def jiffies(_proc_pid_stat: StrOrBytesPath | None = None, _load_time: list[float] | None = None) -> int: ... else: def jiffies(_load_time: list[float] = []) -> int: ... diff --git a/numpy/typing/tests/data/fail/bitwise_ops.pyi b/numpy/typing/tests/data/fail/bitwise_ops.pyi index 1d1fd09db29d..1b8d023a1c16 100644 --- a/numpy/typing/tests/data/fail/bitwise_ops.pyi +++ b/numpy/typing/tests/data/fail/bitwise_ops.pyi @@ -9,9 +9,9 @@ i = int() f8 = np.float64() b_ >> f8 # type: ignore[operator] -i8 << f8 # type: ignore[call-overload] +i8 << f8 # type: ignore[operator] i | f8 # type: ignore[operator] -i8 ^ f8 # type: ignore[call-overload] -u8 & f8 # type: ignore[call-overload] +i8 ^ f8 # type: ignore[operator] +u8 & f8 # type: ignore[operator] ~f8 # type: ignore[operator] # TODO: Certain mixes like i4 << u8 go to float and thus should fail diff --git a/numpy/typing/tests/data/pass/ndarray_misc.py b/numpy/typing/tests/data/pass/ndarray_misc.py index bb290cdf12f7..8b7df182a49a 100644 --- a/numpy/typing/tests/data/pass/ndarray_misc.py +++ b/numpy/typing/tests/data/pass/ndarray_misc.py @@ -51,7 +51,12 @@ class IntSubClass(npt.NDArray[np.intp]): ... A.argmin(out=B_int0) i4.argsort() +i4.argsort(stable=True) A.argsort() +A.argsort(stable=True) + +A.sort() +A.sort(stable=True) i4.choose([()]) _choices = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]], dtype=np.int32) diff --git a/numpy/typing/tests/data/reveal/arithmetic.pyi b/numpy/typing/tests/data/reveal/arithmetic.pyi index 5dd78a197b8f..763ff3914f53 100644 --- a/numpy/typing/tests/data/reveal/arithmetic.pyi +++ b/numpy/typing/tests/data/reveal/arithmetic.pyi @@ -3,7 +3,7 @@ from typing import Any, assert_type import numpy as np import numpy.typing as npt -from numpy._typing import _32Bit, _64Bit, _128Bit +from numpy._typing import _64Bit, _128Bit b: bool c: complex @@ -487,7 +487,7 @@ assert_type(c8 / b_, np.complex64) # Complex -assert_type(c16 + f16, np.complex128 | np.complexfloating[_128Bit, _128Bit]) +assert_type(c16 + f16, np.complexfloating) assert_type(c16 + c16, np.complex128) assert_type(c16 + f8, np.complex128) assert_type(c16 + i8, np.complex128) @@ -500,12 +500,12 @@ assert_type(c16 + c, np.complex128) assert_type(c16 + f, np.complex128) assert_type(c16 + AR_f, npt.NDArray[np.complex128]) -assert_type(f16 + c16, np.complex128 | np.complexfloating[_128Bit, _128Bit]) +assert_type(f16 + c16, np.complexfloating) assert_type(c16 + c16, np.complex128) assert_type(f8 + c16, np.complex128) assert_type(i8 + c16, np.complex128) assert_type(c8 + c16, np.complex128 | np.complex64) -assert_type(f4 + c16, np.complex128 | np.complex64) +assert_type(f4 + c16, np.complexfloating) assert_type(i4 + c16, np.complex128) assert_type(b_ + c16, np.complex128) assert_type(b + c16, np.complex128) @@ -513,10 +513,10 @@ assert_type(c + c16, np.complex128) assert_type(f + c16, np.complex128) assert_type(AR_f + c16, npt.NDArray[np.complex128]) -assert_type(c8 + f16, np.complexfloating[_32Bit, _32Bit] | np.complexfloating[_128Bit, _128Bit]) +assert_type(c8 + f16, np.complex64 | np.complexfloating[_128Bit, _128Bit]) assert_type(c8 + c16, np.complex64 | np.complex128) assert_type(c8 + f8, np.complex64 | np.complex128) -assert_type(c8 + i8, np.complexfloating[_32Bit, _32Bit] | np.complexfloating[_64Bit, _64Bit]) +assert_type(c8 + i8, np.complex64 | np.complexfloating[_64Bit, _64Bit]) assert_type(c8 + c8, np.complex64) assert_type(c8 + f4, np.complex64) assert_type(c8 + i4, np.complex64) @@ -541,7 +541,7 @@ assert_type(AR_f + c8, npt.NDArray[np.complexfloating]) # Float -assert_type(f8 + f16, np.float64 | np.floating[_128Bit]) +assert_type(f8 + f16, np.floating) assert_type(f8 + f8, np.float64) assert_type(f8 + i8, np.float64) assert_type(f8 + f4, np.float64) @@ -552,44 +552,44 @@ assert_type(f8 + c, np.float64 | np.complex128) assert_type(f8 + f, np.float64) assert_type(f8 + AR_f, npt.NDArray[np.float64]) -assert_type(f16 + f8, np.floating[_128Bit] | np.float64) +assert_type(f16 + f8, np.floating) assert_type(f8 + f8, np.float64) assert_type(i8 + f8, np.float64) -assert_type(f4 + f8, np.float32 | np.float64) -assert_type(i4 + f8,np.float64) +assert_type(f4 + f8, np.floating) +assert_type(i4 + f8, np.float64) assert_type(b_ + f8, np.float64) assert_type(b + f8, np.float64) assert_type(c + f8, np.complex128 | np.float64) assert_type(f + f8, np.float64) assert_type(AR_f + f8, npt.NDArray[np.float64]) -assert_type(f4 + f16, np.float32 | np.floating[_128Bit]) -assert_type(f4 + f8, np.float32 | np.float64) -assert_type(f4 + i8, np.float32 | np.floating[_64Bit]) +assert_type(f4 + f16, np.floating) +assert_type(f4 + f8, np.floating) +assert_type(f4 + i8, np.floating) assert_type(f4 + f4, np.float32) -assert_type(f4 + i4, np.float32) +assert_type(f4 + i4, np.floating) assert_type(f4 + b_, np.float32) assert_type(f4 + b, np.float32) -assert_type(f4 + c, np.complex64 | np.complex128) -assert_type(f4 + f, np.float32 | np.float64) +assert_type(f4 + c, np.complexfloating) +assert_type(f4 + f, np.float32) assert_type(f4 + AR_f, npt.NDArray[np.float64]) -assert_type(f16 + f4, np.floating[_128Bit] | np.float32) +assert_type(f16 + f4, np.floating) assert_type(f8 + f4, np.float64) -assert_type(i8 + f4, np.floating[_32Bit] | np.floating[_64Bit]) +assert_type(i8 + f4, np.floating) assert_type(f4 + f4, np.float32) -assert_type(i4 + f4, np.float32) +assert_type(i4 + f4, np.floating) assert_type(b_ + f4, np.float32) assert_type(b + f4, np.float32) -assert_type(c + f4, np.complex64 | np.complex128) -assert_type(f + f4, np.float64 | np.float32) +assert_type(c + f4, np.complexfloating) +assert_type(f + f4, np.float32) assert_type(AR_f + f4, npt.NDArray[np.float64]) # Int assert_type(i8 + i8, np.int64) assert_type(i8 + u8, Any) -assert_type(i8 + i4, np.signedinteger[_32Bit] | np.signedinteger[_64Bit]) +assert_type(i8 + i4, np.signedinteger) assert_type(i8 + u4, Any) assert_type(i8 + b_, np.int64) assert_type(i8 + b, np.int64) @@ -599,7 +599,7 @@ assert_type(i8 + AR_f, npt.NDArray[np.float64]) assert_type(u8 + u8, np.uint64) assert_type(u8 + i4, Any) -assert_type(u8 + u4, np.unsignedinteger[_32Bit] | np.unsignedinteger[_64Bit]) +assert_type(u8 + u4, np.unsignedinteger) assert_type(u8 + b_, np.uint64) assert_type(u8 + b, np.uint64) assert_type(u8 + c, np.complex128) @@ -608,7 +608,7 @@ assert_type(u8 + AR_f, npt.NDArray[np.float64]) assert_type(i8 + i8, np.int64) assert_type(u8 + i8, Any) -assert_type(i4 + i8, np.signedinteger[_32Bit] | np.signedinteger[_64Bit]) +assert_type(i4 + i8, np.signedinteger) assert_type(u4 + i8, Any) assert_type(b_ + i8, np.int64) assert_type(b + i8, np.int64) @@ -618,14 +618,14 @@ assert_type(AR_f + i8, npt.NDArray[np.float64]) assert_type(u8 + u8, np.uint64) assert_type(i4 + u8, Any) -assert_type(u4 + u8, np.unsignedinteger[_32Bit] | np.unsignedinteger[_64Bit]) +assert_type(u4 + u8, np.unsignedinteger) assert_type(b_ + u8, np.uint64) assert_type(b + u8, np.uint64) assert_type(c + u8, np.complex128) assert_type(f + u8, np.float64) assert_type(AR_f + u8, npt.NDArray[np.float64]) -assert_type(i4 + i8, np.signedinteger[_32Bit] | np.signedinteger[_64Bit]) +assert_type(i4 + i8, np.signedinteger) assert_type(i4 + i4, np.int32) assert_type(i4 + b_, np.int32) assert_type(i4 + b, np.int32) @@ -633,13 +633,13 @@ assert_type(i4 + AR_f, npt.NDArray[np.float64]) assert_type(u4 + i8, Any) assert_type(u4 + i4, Any) -assert_type(u4 + u8, np.unsignedinteger[_32Bit] | np.unsignedinteger[_64Bit]) +assert_type(u4 + u8, np.unsignedinteger) assert_type(u4 + u4, np.uint32) assert_type(u4 + b_, np.uint32) assert_type(u4 + b, np.uint32) assert_type(u4 + AR_f, npt.NDArray[np.float64]) -assert_type(i8 + i4, np.signedinteger[_32Bit] | np.signedinteger[_64Bit]) +assert_type(i8 + i4, np.signedinteger) assert_type(i4 + i4, np.int32) assert_type(b_ + i4, np.int32) assert_type(b + i4, np.int32) @@ -647,7 +647,7 @@ assert_type(AR_f + i4, npt.NDArray[np.float64]) assert_type(i8 + u4, Any) assert_type(i4 + u4, Any) -assert_type(u8 + u4, np.unsignedinteger[_32Bit] | np.unsignedinteger[_64Bit]) +assert_type(u8 + u4, np.unsignedinteger) assert_type(u4 + u4, np.uint32) assert_type(b_ + u4, np.uint32) assert_type(b + u4, np.uint32) diff --git a/numpy/typing/tests/data/reveal/array_constructors.pyi b/numpy/typing/tests/data/reveal/array_constructors.pyi index 45cc986d33a6..49425bb890bc 100644 --- a/numpy/typing/tests/data/reveal/array_constructors.pyi +++ b/numpy/typing/tests/data/reveal/array_constructors.pyi @@ -53,7 +53,7 @@ assert_type(np.empty([1, 5, 6], dtype='c16'), npt.NDArray[Any]) assert_type(np.empty(mixed_shape), npt.NDArray[np.float64]) assert_type(np.concatenate(A), npt.NDArray[np.float64]) -assert_type(np.concatenate([A, A]), Any) # pyright correctly infers this as NDArray[float64] +assert_type(np.concatenate([A, A]), npt.NDArray[Any]) # pyright correctly infers this as NDArray[float64] assert_type(np.concatenate([[1], A]), npt.NDArray[Any]) assert_type(np.concatenate([[1], [1]]), npt.NDArray[Any]) assert_type(np.concatenate((A, A)), npt.NDArray[np.float64]) @@ -222,19 +222,19 @@ assert_type(np.atleast_3d(A), npt.NDArray[np.float64]) assert_type(np.atleast_3d(A, A), tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]) assert_type(np.atleast_3d(A, A, A), tuple[npt.NDArray[np.float64], ...]) -assert_type(np.vstack([A, A]), np.ndarray[Any, Any]) # pyright correctly infers this as NDArray[float64] +assert_type(np.vstack([A, A]), npt.NDArray[np.float64]) assert_type(np.vstack([A, A], dtype=np.float32), npt.NDArray[np.float32]) assert_type(np.vstack([A, C]), npt.NDArray[Any]) assert_type(np.vstack([C, C]), npt.NDArray[Any]) -assert_type(np.hstack([A, A]), np.ndarray[Any, Any]) # pyright correctly infers this as NDArray[float64] +assert_type(np.hstack([A, A]), npt.NDArray[np.float64]) assert_type(np.hstack([A, A], dtype=np.float32), npt.NDArray[np.float32]) -assert_type(np.stack([A, A]), np.ndarray[Any, Any]) # pyright correctly infers this as NDArray[float64] +assert_type(np.stack([A, A]), npt.NDArray[np.float64]) assert_type(np.stack([A, A], dtype=np.float32), npt.NDArray[np.float32]) assert_type(np.stack([A, C]), npt.NDArray[Any]) assert_type(np.stack([C, C]), npt.NDArray[Any]) -assert_type(np.stack([A, A], axis=0), np.ndarray[Any, Any]) # pyright correctly infers this as NDArray[float64] +assert_type(np.stack([A, A], axis=0), npt.NDArray[np.float64]) assert_type(np.stack([A, A], out=B), SubClass[np.float64]) assert_type(np.block([[A, A], [A, A]]), npt.NDArray[Any]) # pyright correctly infers this as NDArray[float64] diff --git a/numpy/typing/tests/data/reveal/bitwise_ops.pyi b/numpy/typing/tests/data/reveal/bitwise_ops.pyi index 6c6b56197546..cd56caad1527 100644 --- a/numpy/typing/tests/data/reveal/bitwise_ops.pyi +++ b/numpy/typing/tests/data/reveal/bitwise_ops.pyi @@ -3,7 +3,6 @@ from typing import Literal as L import numpy as np import numpy.typing as npt -from numpy._typing import _32Bit, _64Bit FalseType: TypeAlias = L[False] TrueType: TypeAlias = L[True] @@ -44,11 +43,11 @@ assert_type(i4 | i4, np.int32) assert_type(i4 ^ i4, np.int32) assert_type(i4 & i4, np.int32) -assert_type(i8 << i4, np.signedinteger[_32Bit] | np.signedinteger[_64Bit]) -assert_type(i8 >> i4, np.signedinteger[_32Bit] | np.signedinteger[_64Bit]) -assert_type(i8 | i4, np.signedinteger[_32Bit] | np.signedinteger[_64Bit]) -assert_type(i8 ^ i4, np.signedinteger[_32Bit] | np.signedinteger[_64Bit]) -assert_type(i8 & i4, np.signedinteger[_32Bit] | np.signedinteger[_64Bit]) +assert_type(i8 << i4, np.signedinteger) +assert_type(i8 >> i4, np.signedinteger) +assert_type(i8 | i4, np.signedinteger) +assert_type(i8 ^ i4, np.signedinteger) +assert_type(i8 & i4, np.signedinteger) assert_type(i8 << b_, np.int64) assert_type(i8 >> b_, np.int64) @@ -86,11 +85,11 @@ assert_type(u4 | i4, np.signedinteger) assert_type(u4 ^ i4, np.signedinteger) assert_type(u4 & i4, np.signedinteger) -assert_type(u4 << i, np.signedinteger) -assert_type(u4 >> i, np.signedinteger) -assert_type(u4 | i, np.signedinteger) -assert_type(u4 ^ i, np.signedinteger) -assert_type(u4 & i, np.signedinteger) +assert_type(u4 << i, np.uint32) +assert_type(u4 >> i, np.uint32) +assert_type(u4 | i, np.uint32) +assert_type(u4 ^ i, np.uint32) +assert_type(u4 & i, np.uint32) assert_type(u8 << b_, np.uint64) assert_type(u8 >> b_, np.uint64) diff --git a/numpy/typing/tests/data/reveal/linalg.pyi b/numpy/typing/tests/data/reveal/linalg.pyi index 417fb0d8c558..fbaac3cfab0b 100644 --- a/numpy/typing/tests/data/reveal/linalg.pyi +++ b/numpy/typing/tests/data/reveal/linalg.pyi @@ -43,9 +43,9 @@ assert_type(np.linalg.cholesky(AR_i8), npt.NDArray[np.float64]) assert_type(np.linalg.cholesky(AR_f8), npt.NDArray[np.floating]) assert_type(np.linalg.cholesky(AR_c16), npt.NDArray[np.complexfloating]) -assert_type(np.linalg.outer(AR_i8, AR_i8), npt.NDArray[np.signedinteger]) -assert_type(np.linalg.outer(AR_f8, AR_f8), npt.NDArray[np.floating]) -assert_type(np.linalg.outer(AR_c16, AR_c16), npt.NDArray[np.complexfloating]) +assert_type(np.linalg.outer(AR_i8, AR_i8), npt.NDArray[np.int64]) +assert_type(np.linalg.outer(AR_f8, AR_f8), npt.NDArray[np.float64]) +assert_type(np.linalg.outer(AR_c16, AR_c16), npt.NDArray[np.complex128]) assert_type(np.linalg.outer(AR_b, AR_b), npt.NDArray[np.bool]) assert_type(np.linalg.outer(AR_O, AR_O), npt.NDArray[np.object_]) assert_type(np.linalg.outer(AR_i8, AR_m), npt.NDArray[np.timedelta64]) @@ -127,6 +127,6 @@ assert_type(np.linalg.cross(AR_i8, AR_i8), npt.NDArray[np.signedinteger]) assert_type(np.linalg.cross(AR_f8, AR_f8), npt.NDArray[np.floating]) assert_type(np.linalg.cross(AR_c16, AR_c16), npt.NDArray[np.complexfloating]) -assert_type(np.linalg.matmul(AR_i8, AR_i8), npt.NDArray[np.signedinteger]) -assert_type(np.linalg.matmul(AR_f8, AR_f8), npt.NDArray[np.floating]) -assert_type(np.linalg.matmul(AR_c16, AR_c16), npt.NDArray[np.complexfloating]) +assert_type(np.linalg.matmul(AR_i8, AR_i8), npt.NDArray[np.int64]) +assert_type(np.linalg.matmul(AR_f8, AR_f8), npt.NDArray[np.float64]) +assert_type(np.linalg.matmul(AR_c16, AR_c16), npt.NDArray[np.complex128]) diff --git a/numpy/typing/tests/data/reveal/mod.pyi b/numpy/typing/tests/data/reveal/mod.pyi index 59a6a1016479..ce74557d39d6 100644 --- a/numpy/typing/tests/data/reveal/mod.pyi +++ b/numpy/typing/tests/data/reveal/mod.pyi @@ -4,7 +4,6 @@ from typing import assert_type import numpy as np import numpy.typing as npt -from numpy._typing import _64Bit f8: np.float64 i8: np.int64 @@ -109,51 +108,51 @@ assert_type(divmod(AR_b, b_), tuple[npt.NDArray[np.int8], npt.NDArray[np.int8]]) assert_type(i8 % b, np.int64) assert_type(i8 % i8, np.int64) -assert_type(i8 % f, np.float64 | np.floating[_64Bit]) -assert_type(i8 % f8, np.float64 | np.floating[_64Bit]) -assert_type(i4 % i8, np.int64 | np.int32) -assert_type(i4 % f8, np.float64 | np.float32) +assert_type(i8 % f, np.float64) +assert_type(i8 % f8, np.float64) +assert_type(i4 % i8, np.signedinteger) +assert_type(i4 % f8, np.float64) assert_type(i4 % i4, np.int32) -assert_type(i4 % f4, np.float32) +assert_type(i4 % f4, np.floating) assert_type(i8 % AR_b, npt.NDArray[np.int64]) assert_type(divmod(i8, b), tuple[np.int64, np.int64]) -assert_type(divmod(i8, i4), tuple[np.int64, np.int64] | tuple[np.int32, np.int32]) +assert_type(divmod(i8, i4), tuple[np.signedinteger, np.signedinteger]) assert_type(divmod(i8, i8), tuple[np.int64, np.int64]) # workarounds for https://github.com/microsoft/pyright/issues/9663 -assert_type(i8.__divmod__(f), tuple[np.floating[_64Bit], np.floating[_64Bit]] | tuple[np.float64, np.float64]) -assert_type(i8.__divmod__(f8), tuple[np.floating[_64Bit], np.floating[_64Bit]] | tuple[np.float64, np.float64]) -assert_type(divmod(i8, f4), tuple[np.floating[_64Bit], np.floating[_64Bit]] | tuple[np.float32, np.float32]) +assert_type(i8.__divmod__(f), tuple[np.float64, np.float64]) +assert_type(i8.__divmod__(f8), tuple[np.float64, np.float64]) +assert_type(divmod(i8, f4), tuple[np.floating, np.floating]) assert_type(divmod(i4, i4), tuple[np.int32, np.int32]) -assert_type(divmod(i4, f4), tuple[np.float32, np.float32]) +assert_type(divmod(i4, f4), tuple[np.floating, np.floating]) assert_type(divmod(i8, AR_b), tuple[npt.NDArray[np.int64], npt.NDArray[np.int64]]) assert_type(b % i8, np.int64) -assert_type(f % i8, np.float64 | np.floating[_64Bit]) +assert_type(f % i8, np.float64) assert_type(i8 % i8, np.int64) assert_type(f8 % i8, np.float64) -assert_type(i8 % i4, np.int64 | np.int32) +assert_type(i8 % i4, np.signedinteger) assert_type(f8 % i4, np.float64) assert_type(i4 % i4, np.int32) -assert_type(f4 % i4, np.float32) +assert_type(f4 % i4, np.floating) assert_type(AR_b % i8, npt.NDArray[np.int64]) assert_type(divmod(b, i8), tuple[np.int64, np.int64]) -assert_type(divmod(f, i8), tuple[np.floating[_64Bit], np.floating[_64Bit]] | tuple[np.float64, np.float64]) +assert_type(divmod(f, i8), tuple[np.float64, np.float64]) assert_type(divmod(i8, i8), tuple[np.int64, np.int64]) assert_type(divmod(f8, i8), tuple[np.float64, np.float64]) -assert_type(divmod(i4, i8), tuple[np.int64, np.int64] | tuple[np.int32, np.int32]) +assert_type(divmod(i4, i8), tuple[np.signedinteger, np.signedinteger]) assert_type(divmod(i4, i4), tuple[np.int32, np.int32]) # workarounds for https://github.com/microsoft/pyright/issues/9663 -assert_type(f4.__divmod__(i8), tuple[np.floating[_64Bit], np.floating[_64Bit]] | tuple[np.float32, np.float32]) -assert_type(f4.__divmod__(i4), tuple[np.float32, np.float32]) +assert_type(f4.__divmod__(i8), tuple[np.floating, np.floating]) +assert_type(f4.__divmod__(i4), tuple[np.floating, np.floating]) assert_type(AR_b.__divmod__(i8), tuple[npt.NDArray[np.int64], npt.NDArray[np.int64]]) # float assert_type(f8 % b, np.float64) assert_type(f8 % f, np.float64) -assert_type(i8 % f4, np.floating[_64Bit] | np.float32) +assert_type(i8 % f4, np.floating) assert_type(f4 % f4, np.float32) assert_type(f8 % AR_b, npt.NDArray[np.float64]) diff --git a/numpy/typing/tests/data/reveal/numerictypes.pyi b/numpy/typing/tests/data/reveal/numerictypes.pyi index 4a3e02c9afa6..75d108ce5a0f 100644 --- a/numpy/typing/tests/data/reveal/numerictypes.pyi +++ b/numpy/typing/tests/data/reveal/numerictypes.pyi @@ -2,50 +2,15 @@ from typing import Literal, assert_type import numpy as np -assert_type( - np.ScalarType, - tuple[ - type[int], - type[float], - type[complex], - type[bool], - type[bytes], - type[str], - type[memoryview], - type[np.bool], - type[np.csingle], - type[np.cdouble], - type[np.clongdouble], - type[np.half], - type[np.single], - type[np.double], - type[np.longdouble], - type[np.byte], - type[np.short], - type[np.intc], - type[np.long], - type[np.longlong], - type[np.timedelta64], - type[np.datetime64], - type[np.object_], - type[np.bytes_], - type[np.str_], - type[np.ubyte], - type[np.ushort], - type[np.uintc], - type[np.ulong], - type[np.ulonglong], - type[np.void], - ], -) assert_type(np.ScalarType[0], type[int]) assert_type(np.ScalarType[3], type[bool]) -assert_type(np.ScalarType[8], type[np.csingle]) -assert_type(np.ScalarType[10], type[np.clongdouble]) +assert_type(np.ScalarType[8], type[np.complex64]) +assert_type(np.ScalarType[9], type[np.complex128]) +assert_type(np.ScalarType[-1], type[np.void]) assert_type(np.bool_(object()), np.bool) assert_type(np.typecodes["Character"], Literal["c"]) assert_type(np.typecodes["Complex"], Literal["FDG"]) assert_type(np.typecodes["All"], Literal["?bhilqnpBHILQNPefdgFDGSUVOMm"]) -assert_type(np.sctypeDict['uint8'], type[np.generic]) +assert_type(np.sctypeDict["uint8"], type[np.generic]) diff --git a/pavement.py b/pavement.py index 615d38091368..25ec23d1a1d4 100644 --- a/pavement.py +++ b/pavement.py @@ -35,7 +35,7 @@ #----------------------------------- # Path to the release notes -RELEASE_NOTES = 'doc/source/release/2.3.3-notes.rst' +RELEASE_NOTES = 'doc/source/release/2.3.5-notes.rst' #------------------------------------------------------- diff --git a/pyproject.toml b/pyproject.toml index af666bc25e31..c0340b02ca45 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ requires = [ [project] name = "numpy" -version = "2.3.3" +version = "2.3.5" # TODO: add `license-files` once PEP 639 is accepted (see meson-python#88) license = {file = "LICENSE.txt"} diff --git a/requirements/build_requirements.txt b/requirements/build_requirements.txt index a51143a780e7..1f6eb1435cfc 100644 --- a/requirements/build_requirements.txt +++ b/requirements/build_requirements.txt @@ -1,5 +1,5 @@ meson-python>=0.13.1 Cython>=3.0.6 ninja -spin==0.13 +spin==0.15 build diff --git a/requirements/ci32_requirements.txt b/requirements/ci32_requirements.txt index 87831586e01e..824934787e10 100644 --- a/requirements/ci32_requirements.txt +++ b/requirements/ci32_requirements.txt @@ -1,3 +1,3 @@ -spin==0.13 +spin==0.15 # Keep this in sync with ci_requirements.txt -scipy-openblas32==0.3.30.0.1 +scipy-openblas32==0.3.30.0.7 diff --git a/requirements/ci_requirements.txt b/requirements/ci_requirements.txt index dd16787923e3..37e685fef0cc 100644 --- a/requirements/ci_requirements.txt +++ b/requirements/ci_requirements.txt @@ -1,4 +1,4 @@ -spin==0.13 +spin==0.15 # Keep this in sync with ci32_requirements.txt -scipy-openblas32==0.3.30.0.1 -scipy-openblas64==0.3.30.0.1 +scipy-openblas32==0.3.30.0.7 +scipy-openblas64==0.3.30.0.7 diff --git a/requirements/doc_requirements.txt b/requirements/doc_requirements.txt index 330f0f7ac8b9..6c1011488588 100644 --- a/requirements/doc_requirements.txt +++ b/requirements/doc_requirements.txt @@ -6,6 +6,7 @@ sphinx-copybutton sphinx-design scipy matplotlib +pyparsing<3.3 pandas breathe>4.33.0 ipython!=8.1.0 diff --git a/requirements/test_requirements.txt b/requirements/test_requirements.txt index 96b473007bf3..a5f7b0f760a0 100644 --- a/requirements/test_requirements.txt +++ b/requirements/test_requirements.txt @@ -13,7 +13,7 @@ pytest-timeout # For testing types. Notes on the restrictions: # - Mypy relies on C API features not present in PyPy # NOTE: Keep mypy in sync with environment.yml -mypy==1.16.1; platform_python_implementation != "PyPy" +mypy==1.18.1; platform_python_implementation != "PyPy" typing_extensions>=4.5.0 # for optional f2py encoding detection charset-normalizer diff --git a/tools/check_python_h_first.py b/tools/check_python_h_first.py new file mode 100755 index 000000000000..c0d44ad635f4 --- /dev/null +++ b/tools/check_python_h_first.py @@ -0,0 +1,254 @@ +#!/usr/bin/env python +"""Check that Python.h is included before any stdlib headers. + +May be a bit overzealous, but it should get the job done. +""" +import argparse +import fnmatch +import os.path +import re +import subprocess +import sys + +from get_submodule_paths import get_submodule_paths + +HEADER_PATTERN = re.compile( + r'^\s*#\s*include\s*[<"]((?:\w+/)*\w+(?:\.h[hp+]{0,2})?)[>"]\s*$' +) + +PYTHON_INCLUDING_HEADERS = [ + "Python.h", + # This isn't all of Python.h, but it is the visibility macros + "pyconfig.h", + "numpy/npy_common.h", + "numpy/npy_math.h", + "numpy/arrayobject.h", + "numpy/ndarrayobject.h", + "numpy/ndarraytypes.h", + "numpy/random/distributions.h", + "npy_sort.h", + "npy_config.h", + "common.h", + "npy_cpu_features.h", + # Boost::Python + "boost/python.hpp", +] +LEAF_HEADERS = [ + "numpy/numpyconfig.h", + "numpy/npy_os.h", + "numpy/npy_cpu.h", + "numpy/utils.h", +] + +C_CPP_EXTENSIONS = (".c", ".h", ".cpp", ".hpp", ".cc", ".hh", ".cxx", ".hxx") +# check against list in diff_files + +PARSER = argparse.ArgumentParser(description=__doc__) +PARSER.add_argument( + "files", + nargs="*", + help="Lint these files or directories; use **/*.c to lint all files\n" + "Expects relative paths", +) + + +def check_python_h_included_first(name_to_check: str) -> int: + """Check that the passed file includes Python.h first if it does at all. + + Perhaps overzealous, but that should work around concerns with + recursion. + + Parameters + ---------- + name_to_check : str + The name of the file to check. + + Returns + ------- + int + The number of headers before Python.h + """ + included_python = False + included_non_python_header = [] + warned_python_construct = False + basename_to_check = os.path.basename(name_to_check) + in_comment = False + includes_headers = False + with open(name_to_check) as in_file: + for i, line in enumerate(in_file, 1): + # Very basic comment parsing + # Assumes /*...*/ comments are on their own lines + if "/*" in line: + if "*/" not in line: + in_comment = True + # else-branch could use regex to remove comment and continue + continue + if in_comment: + if "*/" in line: + in_comment = False + continue + line = line.split("//", 1)[0].strip() + match = HEADER_PATTERN.match(line) + if match: + includes_headers = True + this_header = match.group(1) + if this_header in PYTHON_INCLUDING_HEADERS: + if included_non_python_header and not included_python: + # Headers before python-including header + print( + f"Header before Python.h in file {name_to_check:s}\n" + f"Python.h on line {i:d}, other header(s) on line(s)" + f" {included_non_python_header}", + file=sys.stderr, + ) + # else: # no headers before python-including header + included_python = True + PYTHON_INCLUDING_HEADERS.append(basename_to_check) + if os.path.dirname(name_to_check).endswith("include/numpy"): + PYTHON_INCLUDING_HEADERS.append(f"numpy/{basename_to_check:s}") + # We just found out where Python.h comes in this file + break + elif this_header in LEAF_HEADERS: + # This header is just defines, so it won't include + # the system headers that cause problems + continue + elif not included_python and ( + "numpy/" in this_header + and this_header not in LEAF_HEADERS + or "python" in this_header.lower() + ): + print( + f"Python.h not included before python-including header " + f"in file {name_to_check:s}\n" + f"{this_header:s} on line {i:d}", + file=sys.stderr, + ) + included_python = True + PYTHON_INCLUDING_HEADERS.append(basename_to_check) + elif not included_python and this_header not in LEAF_HEADERS: + included_non_python_header.append(i) + elif ( + not included_python + and not warned_python_construct + and ".h" not in basename_to_check + ) and ("py::" in line or "PYBIND11_" in line): + print( + "Python-including header not used before python constructs " + f"in file {name_to_check:s}\nConstruct on line {i:d}", + file=sys.stderr, + ) + warned_python_construct = True + if not includes_headers: + LEAF_HEADERS.append(basename_to_check) + return included_python and len(included_non_python_header) + + +def sort_order(path: str) -> tuple[int, str]: + if "include/numpy" in path: + # Want to process numpy/*.h first, to work out which of those + # include Python.h directly + priority = 0x00 + elif "h" in os.path.splitext(path)[1].lower(): + # Then other headers, which tend to include numpy/*.h + priority = 0x10 + else: + # Source files after headers, to give the best chance of + # properly checking whether they include Python.h + priority = 0x20 + if "common" in path: + priority -= 8 + path_basename = os.path.basename(path) + if path_basename.startswith("npy_"): + priority -= 4 + elif path_basename.startswith("npy"): + priority -= 3 + elif path_basename.startswith("np"): + priority -= 2 + if "config" in path_basename: + priority -= 1 + return priority, path + + +def process_files(file_list: list[str]) -> int: + n_out_of_order = 0 + submodule_paths = get_submodule_paths() + root_directory = os.path.dirname(os.path.dirname(__file__)) + for name_to_check in sorted(file_list, key=sort_order): + name_to_check = os.path.join(root_directory, name_to_check) + if any(submodule_path in name_to_check for submodule_path in submodule_paths): + continue + if ".dispatch." in name_to_check: + continue + try: + n_out_of_order += check_python_h_included_first(name_to_check) + except UnicodeDecodeError: + print(f"File {name_to_check:s} not utf-8", sys.stdout) + return n_out_of_order + + +def find_c_cpp_files(root: str) -> list[str]: + + result = [] + + for dirpath, dirnames, filenames in os.walk(root): + # I'm assuming other people have checked boost + for name in ("build", ".git", "boost"): + try: + dirnames.remove(name) + except ValueError: + pass + for name in fnmatch.filter(dirnames, "*.p"): + dirnames.remove(name) + result.extend( + [ + os.path.join(dirpath, name) + for name in filenames + if os.path.splitext(name)[1].lower() in C_CPP_EXTENSIONS + ] + ) + # Check the headers before the source files + result.sort(key=lambda path: "h" in os.path.splitext(path)[1], reverse=True) + return result + + +def diff_files(sha: str) -> list[str]: + """Find the diff since the given SHA. + + Adapted from lint.py + """ + res = subprocess.run( + [ + "git", + "diff", + "--name-only", + "--diff-filter=ACMR", + "-z", + sha, + "--", + # Check against C_CPP_EXTENSIONS + "*.[chCH]", + "*.[ch]pp", + "*.[ch]xx", + "*.cc", + "*.hh", + ], + stdout=subprocess.PIPE, + encoding="utf-8", + ) + res.check_returncode() + return [f for f in res.stdout.split("\0") if f] + + +if __name__ == "__main__": + args = PARSER.parse_args() + + if len(args.files) == 0: + files = find_c_cpp_files("numpy") + else: + files = args.files + if len(files) == 1 and os.path.isdir(files[0]): + files = find_c_cpp_files(files[0]) + + # See which of the headers include Python.h and add them to the list + n_out_of_order = process_files(files) + sys.exit(n_out_of_order) diff --git a/tools/get_submodule_paths.py b/tools/get_submodule_paths.py new file mode 100644 index 000000000000..abab86140712 --- /dev/null +++ b/tools/get_submodule_paths.py @@ -0,0 +1,31 @@ +import glob +import os.path + + +def get_submodule_paths(): + ''' + Get paths to submodules so that we can exclude them from things like + check_test_name.py, check_unicode.py, etc. + ''' + root_directory = os.path.dirname(os.path.dirname(__file__)) + gitmodule_file = os.path.join(root_directory, '.gitmodules') + with open(gitmodule_file) as gitmodules: + data = gitmodules.read().split('\n') + submodule_paths = [datum.split(' = ')[1] for datum in data if + datum.startswith('\tpath = ')] + submodule_paths = [os.path.join(root_directory, path) for path in + submodule_paths] + # vendored with a script rather than via gitmodules + with open( + os.path.join(root_directory, ".gitattributes"), "r" + ) as attr_file: + for line in attr_file: + if "vendored" in line: + pattern = line.split(" ", 1)[0] + submodule_paths.extend(glob.glob(pattern)) + + return submodule_paths + + +if __name__ == "__main__": + print('\n'.join(get_submodule_paths())) diff --git a/tools/write_release.py b/tools/write_release.py index 7662eb7b1288..cdb5235f0bd0 100644 --- a/tools/write_release.py +++ b/tools/write_release.py @@ -18,8 +18,6 @@ import argparse import os import subprocess -import textwrap -from hashlib import md5, sha256 from pathlib import Path # Name of the notes directory @@ -29,38 +27,12 @@ # Output base name, `.rst` or `.md` will be appended OUTPUT_FILE = "README" -def compute_hash(wheel_dir, hash_func): - """ - Compute hashes of files in wheel_dir. - - Parameters - ---------- - wheel_dir: str - Path to wheel directory from repo root. - hash_func: function - Hash function, i.e., md5, sha256, etc. - - Returns - ------- - list_of_strings: list - List of of strings. Each string is the hash - followed by the file basename. - - """ - released = os.listdir(wheel_dir) - checksums = [] - for fn in sorted(released): - fn_path = Path(f"{wheel_dir}/{fn}") - m = hash_func(fn_path.read_bytes()) - checksums.append(f"{m.hexdigest()} {fn}") - return checksums - - def write_release(version): """ - Copy the -notes.rst file to the OUTPUT_DIR, append - the md5 and sha256 hashes of the wheels and sdist, and produce - README.rst and README.md files. + Copy the -notes.rst file to the OUTPUT_DIR and use + pandoc to translate it to markdown. That results in both + README.rst and README.md files that can be used for on + github for the release. Parameters ---------- @@ -73,35 +45,13 @@ def write_release(version): """ notes = Path(NOTES_DIR) / f"{version}-notes.rst" - wheel_dir = Path(OUTPUT_DIR) / "installers" - target_md = Path(OUTPUT_DIR) / f"{OUTPUT_FILE}.md" - target_rst = Path(OUTPUT_DIR) / f"{OUTPUT_FILE}.rst" - - os.system(f"cp {notes} {target_rst}") - - with open(str(target_rst), 'a') as f: - f.writelines(textwrap.dedent( - """ - Checksums - ========= - - MD5 - --- - :: - - """)) - f.writelines([f' {c}\n' for c in compute_hash(wheel_dir, md5)]) - - f.writelines(textwrap.dedent( - """ - SHA256 - ------ - :: - - """)) - f.writelines([f' {c}\n' for c in compute_hash(wheel_dir, sha256)]) + outdir = Path(OUTPUT_DIR) + outdir.mkdir(exist_ok=True) + target_md = outdir / f"{OUTPUT_FILE}.md" + target_rst = outdir / f"{OUTPUT_FILE}.rst" # translate README.rst to md for posting on GitHub + os.system(f"cp {notes} {target_rst}") subprocess.run( ["pandoc", "-s", "-o", str(target_md), str(target_rst), "--wrap=preserve"], check=True,