What’s New

NumPy

Frameworks & Libraries

Fundamental package for array-based numerical computing in Python.

Latest v2.5.1 · by NumPyWebsitenumpy/numpy

Changelog

v2.5.1

v2.5.1 (July 4, 2026)

NumPy 2.5.1 Release Notes

The NumPy 2.5.1 is a patch release that fixes bugs discovered after the 2.5.0 release. The most noticeable is the fix is to the numpy datetime cython API which should allow downstream to support NumPy versions older than 2.5. Preparation for Python 3.15 continues along with typing improvements.

This release supports Python versions 3.12-3.14

Changes
  • The minimum supported GCC version has been updated from 9.3.0 to 10.3.0

    (gh-31843)

Contributors

A total of 10 people contributed to this release. People with a "+" by their names contributed a patch for the first time.

  • Adhyan Gupta +
  • Ankit Ahlawat
  • Charles Harris
  • Iason Krommydas
  • Joren Hammudoglu
  • Kumar Aditya
  • Nathan Goldbaum
  • Sebastian Berg
  • Ties Jan Hefting +
  • Vineet Kumar
Pull requests merged

A total of 20 pull requests were merged for this release.

  • #31707: MAINT: Prepare 2.5.x for further development
  • #31721: CI: fix new cython-lint errors (#31711)
  • #31723: MAINT: Update meson to match main
  • #31729: TST: use setup-sde instead of curl to get SDE binaries (#31727)
  • #31829: BUG: Relax finfo to be easier accessible for all user dtypes...
  • #31831: TYP: Fix flatiter.__next__ return type for object_ and...
  • #31832: BUG: avoid deadlocks using NpyString API (#31682)
  • #31833: BUG: fix out array leak in reduceat and accumulate when dtype...
  • #31835: BUG: fix numpy datetime cython APIs to be compatible with older...
  • #31836: TYP: Fix incorrect dtype inference of asarray([]) (#31732)
  • #31837: TYP: Fix np.ma.masked_array 2.5.0 regression
  • #31838: FIX: Refactor error handling in array_setstate to prevent typecode...
  • #31839: TST: xfail multithreaded BLAS test more generously
  • #31840: MAINT: Rename subroutine for crackfortran tests
  • #31842: BUG: fix leak in reductions when a ufunc override errors or is...
  • #31849: BLD: set minimum required gcc version to 10.3 (#31843)
  • #31855: CI: fix hangs on MacOS ASan CI (#31853)
  • #31856: BUG: fix several bugs in StringDType operations (#31846)
  • #31857: BUG: Fix segfault in MT19937 by preventing recursive seed lists...
  • #31858: BUG: Fix signed integer overflow in datetime.c (#31688)
v2.5.0

v2.5.0 (June 21, 2026)

NumPy 2.5.0 Release Notes

Numpy 2.5.0 is a transitional release. It drops support for Python 3.11, marking the end of distutils, and expires a large number of deprecations made in the 2.0.x release. It also improves free threading and brings sorting into compliance with the array-api standard with the addition of descending sorts. There is also a fair amount of preparation for Python 3.15, which will be supported starting with the first rc.

This release supports Python versions 3.12-3.14.

Highlights
  • Distutils has been removed,
  • Many expired deprecations, see below,
  • Many new deprecations, see below,
  • Many static typing improvements.
  • Improved support for free threading,
  • Support for descending sorts,

See New Features below for other additions.

Deprecations
  • numpy.char.chararray is deprecated. Use an ndarray with a string or bytes dtype instead.

    (gh-30605)

  • numpy.take now correctly checks if the result can be cast to the provided out=out under the same-kind rule. A DeprecationWarning is given now when this check fails. Previously, take incorrectly checked if out could be cast to the result (the wrong direction). This deprecation also affects compress and possibly other functions. (Future versions of NumPy may tighten the casting check further.)

    (gh-30615)

  • The numpy.char.[as]array functions are deprecated. Use an numpy.[as]array with a string or bytes dtype instead.

    (gh-30802)

  • Setting the dtype attribute is deprecated because mutating an array is unsafe if an array is shared, especially by multiple threads. As an alternative, you can create a view with a new dtype via array.view(dtype=new_dtype).

    (gh-29244)

  • Setting the shape attribute is deprecated because mutating an array is unsafe if an array is shared, especially by multiple threads. As an alternative, you can create a new view via np.reshape or np.ndarray.reshape. For example: x = np.arange(15); x = np.reshape(x, (3, 5)). To ensure no copy is made from the data, one can use np.reshape(..., copy=False).

    While setting the shape on an array is discouraged, for cases where it is difficult to work around, e.g., in __array_finalize__, it is possible with the private method np.ndarray._set_shape.

    (gh-29536)

  • Using the generic unit in numpy.timedelta64 is deprecated since this can lead to unexpected behavior such as non-transitive comparison, see gh-28287 for details. As an alternative, specify an explicit unit such as 's' (seconds) or 'D' (days) when constructing numpy.timedelta64. Due to this change, operations that implicitly rely on the generic unit are also deprecated. For example:

    arr = np.array([1, 2, 3], dtype="m8[s]")
    
    # `1` is implicitly converted to generic timedelta64
    arr + 1
    

    (gh-29619)

  • Resizing a Numpy array in place is deprecated since mutating an array is unsafe if an array is shared, especially by multiple threads. As an alternative, you can create a resized array via np.resize.

    (gh-30181)

  • numpy.fix is deprecated, use numpy.trunc instead. It is faster and follows the Array API standard. Both functions provide identical functionality: rounding array elements towards zero.

    (gh-30644)

  • numpy.ma.round_ is deprecated. numpy.ma.round can be used as a replacement.

    (gh-30738)

  • numpy.typename is deprecated because the names returned by it were outdated and inconsistent. numpy.dtype.name can be used as a replacement.

    (gh-30774)

  • Inputs other than integers are deprecated for numpy.triu_indices and numpy.tril_indices. Non-integer values for the M, k and N parameters of numpy.tri are deprecated. Non-integer values for the k parameter of both numpy.tril_indices_from and numpy.triu_indices_from are deprecated.

    (gh-30869)

  • Deprecations in custom dtype property and __array_finalize__.

    Previously arr.view(dtype=new_dtype) called arr.dtype = new_dtype also for subclasses, i.e., the attribute setting. That path is now deprecated and refined, meaning that even subclasses that do not see this DeprecationWarning may wish to update their code.

    A subclass that does any dtype specific logic (i.e. verifying the dtype in __array_finalize__ or has a dtype property) should now:

    • Set _set_dtype = None in which case arr.view(dtype=new_dtype) will call __array_finalize__ with the new dtype, ensuring that any validation __array_finalize__ will run is done.
    • Or, for a quick fix, define _set_dtype as a function (calling ndarray._set_dtype() to avoid DeprecationWarnings. (Future versions might migrate towards the _set_dtype = None path.)

    Ideally, follow NumPy's deprecation to prevent dtype mutation by users. The use of ndarray._set_dtype() may be necessary for some subclass finalization patterns, but should otherwise be avoided.

    (gh-31293)

Expired deprecations
  • numpy.distutils has been removed

    (gh-30340)

  • Passing None as dtype to np.finfo will now raise a TypeError (deprecated since 1.25)

    (gh-30460)

  • numpy.cross no longer supports 2-dimensional vectors. (Deprecated since 2.0)

    (gh-30461)

  • numpy._core.numerictypes.maximum_sctype has been removed. (deprecated since 2.0)

    (gh-30462)

  • numpy.row_stack has been removed in favor of numpy.vstack. (deprecated since 2.0)

    (gh-30463)

  • get_array_wrap has been removed. (deprecated since 2.0)

    (gh-30463)

  • recfromtxt and recfromcsv have been removed from numpy.lib._npyio in favor of numpy.genfromtxt. (deprecated since 2.0)

    (gh-30467)

  • The numpy.chararray re-export of numpy.char.chararray has been removed. (deprecated since 2.0)

    (gh-30604)

  • bincount now raises a TypeError for non-integer inputs. (deprecated since 2.1)

    (gh-30610)

  • The numpy.lib.math alias for the standard library math module has been removed. (deprecated since 1.25)

    (gh-30612)

  • Data type alias 'a' was removed in favor of 'S'. (deprecated since 2.0)

    (gh-30613)

  • _add_newdoc_ufunc(ufunc, newdoc) has been removed in favor of ufunc.__doc__ = newdoc. (deprecated since 2.2)

    (gh-30614)

Compatibility notes
linalg.eig and linalg.eigvals now always return complex arrays

Previously, the return values depended on whether the eigenvalues happen to lie on the real line (which, for a general, non-symmetric matrix, is not guaranteed).

This change makes consistent what was a value-dependent result. To retain the previous behavior, do:

w = eigvals(a)
if np.any(w.imag == 0):  # this is what NumPy used to do
    w = w.real

If your matrix is symmetrix/hermitian, use eigh and eigvalsh instead of eig and eigvals. These are guaranteed to return real values. A common case is covariance matrices, which are symmetric and positive definite by construction.

(gh-30411)

MSVC support

NumPy now requires minimum MSVC 19.35 toolchain version on Windows platforms. This corresponds to Visual Studio 2022 version 17.5 Preview 2 or newer.

(gh-30489)

Cython support

NumPy's Cython headers (accessed via cimport numpy) now require Cython 3.0 or newer to build. If you try to compile a project that depends on NumPy's Cython headers using Cython 0.29 or older, you will see a message like this:

Error compiling Cython file:
------------------------------------------------------------
...
# versions.
#
# See __init__.cython-30.pxd for the real Cython header
#

DEF err = int('Build aborted: the NumPy Cython headers require Cython 3.0.0 or newer.')
  ------------------------------------------------------------

  /path/to/site-packages/numpy/__init__.pxd:11:13: Error in compile-time expression:
  ValueError: invalid literal for int() with base 10: 
  'Build aborted: the NumPy Cython headers require Cython 3.0.0 or newer.'

Note that the invalid integer is not a bug in NumPy - we are intentionally generating this error to avoid triggering a more obscure error later in the build when an older Cython version tries to use a Cython feature that was not available in the old Cython version.

(gh-30770)

numpy.where no longer truncates Python integers

Previously, if the x or y argument of numpy.where was a Python integer that was out of range of the output type, it would be silently truncated. Now, an OverflowError will be raised instead.

This change also applies to the underlying C API function PyArray_Where.

(gh-30803)

Default memory allocator change

NumPy now uses PyMem_RawMalloc and PyMem_RawFree as the default memory allocator, instead of system's malloc and free directly.

(gh-30846)

from_dlpack raises BufferError instead of RuntimeError

np.from_dlpack now raises BufferError instead of RuntimeError when the incoming DLPack tensor has an unsupported device, dtype, or exceeds the maximum number of dimensions. This aligns with the DLPack and Array API specifications, which recommend BufferError for data that cannot be imported.

(gh-30937)

Corrections to the BTPE binomial sampler

Two independent errors in the Stirling series of the acceptance/rejection step of the BTPE algorithm used by numpy.random.Generator.binomial have been corrected:

  • The third and fourth error terms were added rather than subtracted. This sign error was inherited from section 5.3 of the original 1988 paper by Kachitvichyanukul & Schmeiser, which incorrectly adds all four terms.
  • The leading coefficient had a digit-swap typo (13680 instead of 13860) that was introduced in the initial implementation.

As a result, Generator.binomial and Generator.multinomial, which uses binomial internally, may now return different samples for the same seed.

The legacy numpy.random.RandomState.binomial and numpy.random.RandomState.multinomial are not affected: they preserve the original (incorrect) behavior, so existing streams remain reproducible.

(gh-31238)

datetime64/timedelta64 arithmetic raises on overflow

Addition, subtraction, and integer multiplication of datetime64 and timedelta64 values now raise OverflowError when the result would overflow int64 or land on the NaT sentinel value. Previously these operations silently wrapped, often producing a value that was indistinguishable from NaT. This matches the overflow checking already performed by unit-conversion casts.

(gh-31378)

C API changes
  • It is now possible to register "real" and "imag" ArrayMethods via PyUFunc_AddLoopsFromSpecs. These will be used for imag and real and should normally set *view_offset in their resolve_descriptors function to allow the array attributes to return views.

    (gh-30984)

  • New PyDataType_TYPE, PyDataType_KIND, PyDataType_BYTEORDER and PyDataType_TYPEOBJ accessor macros to the C API. Together with the other accessor macros added for the NumPy 2.0 transition, these allow accessing the fields of PyArray_Descr structs without any direct field accesses.

    (gh-30994)

  • NumPy now supports the stable ABI for free-threaded Python as described in 803{.interpreted-text role="pep"}.

    (gh-31091)

  • PyArray_DescrFromScalar now returns the full dtype descriptor for scalars of user-defined parametric data types, including any dtype parameters. Parameters were previously silently discarded, which could cause incorrect results in operations like astype on scalar objects. Internally, the function now delegates to discover_descr_from_pyobject, which handles parametric dtypes correctly.

    (gh-31067)

New Features
  • It is now possible to register user-dtypes for dlpack export and import via numpy.dtypes.register_dlpack_dtype. This functionality is meant to be used with care by user-dtype authors.

    (gh-31256)

Pixi package definitions

Pixi package definitions have been added for different kinds of from-source builds of NumPy. These can be used in downstream Pixi workspaces via the pixi-build feature.

Definitions for both default and AddressSanitizer-instrumented (asan) builds are available in the source code under the pixi-packages/ directory.

linux-64 and osx-arm64 platforms are supported.

(gh-30381)

numpy.ndarray now supports structural pattern matching

numpy.ndarray and its subclasses now have the Py_TPFLAGS_SEQUENCE flag set, enabling structural pattern matching (PEP 634) with match/case statements. This also enables Cython to optimize integer indexing operations. See `arrays.ndarray.pattern-matching{.interpreted-text role="ref"}` for details.

(gh-30653)

Added N-D evaluation functions to the polynomial package

New functions polyvalnd, chebvalnd, legvalnd, hermvalnd, hermevalnd, and lagvalnd have been added to evaluate polynomials in arbitrary dimensions, analogous to the existing 2D and 3D evaluators.

(gh-30857)

New "descending" keyword argument for numpy.sort and numpy.argsort

Users can now pass the descending=True keyword argument to numpy.sort and numpy.argsort to sort and argsort arrays in descending order. NaN values, if present, are sorted to the end of the array in both ascending and descending sorts. This feature is available for all built-in dtypes except void, object, and generic. Note that SIMD optimizations for sorting are currently not available for descending sorts, so performance may be slower.

(gh-31345)

Improvements

For f2py, the behaviour of intent(inplace) has improved. Previously, if an input array did not have the right dtype or order, the input array was modified in-place, changing its dtype and replacing its data by a corrected copy. Now, instead, the corrected copy is kept a separate array, which, after being passed and presumably modified by the fortran routine, is copied back to the input routine. The above means one no longer has the risk that pre-existing views or slices of the input array start pointing to unallocated memory (at the price of increased overhead for the write-back copy at the end of the call).

A potential problem would be that one might get very different results if one, e.g., previously passed in an integer array where a double array was expected: the writeback to integer would likely give wrong results. To avoid such situations, intent(inplace) will now only allow arrays that have equivalent type to that used in the fortran routine, i.e., dtype.kind is the same. For instance, a routine expecting double would be able to receive float, but would raise on integer input.

(gh-29929)

f2py modules now show allocatable arrays in dir()

Allocatable module variables wrapped by f2py now appear in dir() output, matching their accessibility by name.

(gh-30965)

StringDType comparisons now correctly handle embedded NULL bytes.

(gh-31662)

Performance improvements and changes
Improved performance of numpy.searchsorted

The C++ binary search implementation used by numpy.searchsorted now has a much better performance when searching for multiple keys. The new implementation batches binary search steps across all keys to leverage cache locality and out-of-order execution. Benchmarks show the new implementation can be up to 20 times faster for hundreds of thousands keys while single-key performance remains comparable to previous versions.

(gh-30517)

Improved scaling of ufuncs on free-threading

NumPy's ufuncs now scale significantly better on free-threading builds of CPython due to the following optimizations:

  • Lock-free dispatch table: The ufuncs dispatch table is now implemented as a lock-free concurrent hash map, allowing multiple threads to call ufuncs without contention.
  • Immortal shared objects: Certain shared objects, such as global memory handlers, have been made immortal. This effectively reduces reference counting contention across threads.
  • Optimized memory allocation: NumPy now utilizes PyMem_RawMalloc and PyMem_RawFree for memory allocation. On Python 3.15 and newer, this leverages mimalloc and significantly reduces memory allocation overhead in multi-threaded workloads.

(gh-30846)

Faster reductions on small/medium contiguous arrays

numpy.sum, numpy.prod, numpy.any, numpy.all, and other reductions with an identity value now use a fast path when the input is a contiguous, aligned, non-object array and the reduction covers all axes (axis=None) with no special arguments. Typical speedup is ~1.3x on small arrays; numpy.any / numpy.all on contiguous boolean arrays can see speedup up to 1.9x.

(gh-31274)

Typing improvements and changes
numpy.linalg typing improvements and preliminary shape-typing support

Input and output dtypes for numpy.linalg functions are now more precise. Several of these functions also gain preliminary shape-typing support while remaining backward compatible. For example, the return type of numpy.linalg.matmul now depends on the shape-type of its inputs, or fall back to the backward-compatible return type if the shape-types are unknown at type-checking time. Because of limitations in Python's type system and current type-checkers, shape-typing cannot cover every situation and is often only implemented for the most common lower-rank cases.

(gh-30480)

numpy.ma typing annotations

The numpy.ma module is now fully covered by typing annotations. This includes annotations for masked arrays, masks, and various functions and methods. With this, NumPy has achieved 100% typing coverage across all its submodules.

(gh-30566)

Shape-typing support for many functions and methods

Many functions and methods now have shape-aware return type annotations. Type-checkers can now infer the number of dimensions of the returned array through common operations. For example, np.linspace(0, 1) is now typed as a 1-d float64 array, and np.sum(x, keepdims=True) has the same number of dimensions as x.

This covers numpy.linalg functions, array creation functions (like asarray, from{buffer,string,file,iter,regex}), range functions (linspace, logspace, geomspace), aggregation functions and methods (sum, mean, std, var, min, max, all, any, etc.), sorting (sort, argsort, argpartition), cumulative operations (cumsum, cumprod, etc.), set operations (unique_values, intersect1d, union1d, etc.), and various other functions including nonzero, transpose, diagonal, atleast_{1,2,3}d, clip, round, inner, bincount, and fft.fftfreq. Several of these also gained more precise return dtype annotations as part of this work.

Shape-typing is still a work-in-progress, so coverage is not yet complete. Because of limitations in Python's type system and current type-checkers, shape-typing is often only implemented for the most common lower-rank cases.

(gh-31172)

numpy.fft typing improvements and preliminary shape-typing support

The numpy.fft functions now support non-float64/complex128 dtypes and gain preliminary shape-typing support. For example, the return type of numpy.fft.fft now depends on the shape-type of its inputs, falling back to the backward-compatible return type when the shape-types are unknown at type-checking time.

(gh-31226)

Changes
Structured array copies now use memcpy for contiguous dtypes

Copying structured arrays with identical dtypes now uses memcpy instead of field-by-field transfer when the dtype has a contiguous layout (no gaps between fields). A new NPY_NOT_TRIVIALLY_COPYABLE dtype flag is set on structured dtypes that have gaps in their memory layout, such as those created with explicit offsets or via multi-field indexing. Only these dtypes continue to use the slower field-by-field copy.

This means that padding bytes in contiguous structured dtypes (e.g. those created without explicit offsets) may now be copied as part of the memcpy, whereas previously they were left untouched. Code that relies on padding bytes being preserved during structured array copies may be affected.

(gh-29270)

numpy.ctypeslib.as_ctypes now does not support scalar types

The function numpy.ctypeslib.as_ctypes has been updated to only accept numpy.ndarray. Passing a scalar type (e.g., numpy.int32(5)) will now raise a TypeError. This change was made to avoid the issue gh-30354 and to enforce the readonly nature of scalar types in NumPy. The previous behavior relied on undocumented implicit temporary arrays and was not well-defined. Users who need to convert scalar types to ctypes should first convert them to an array (e.g., numpy.asarray) before passing them to numpy.ctypeslib.as_ctypes.

(gh-30538)

__array_interface__ changes on scalars

Scalars now export the __array_interface__ directly rather than including an array copy as a __ref entry. This means that scalars are now exported as read-only while they previously exported as writeable. The path via __ref was undocumented and not consistently used even within NumPy itself.

(gh-30538)

meshgrid now always returns a tuple

np.meshgrid previously used to return a list when sparse was true and copy was false. Now, it always returns a tuple regardless of the arguments.

(gh-30707)

numpy.triu_indices now accepts unsigned integers

numpy.triu_indices previously used to error in some cases when unsigned integers were given as arguments. Now, it accepts them in all cases.

(gh-30869)

object dtype in .real and .imag and related functions

The array attributes .real and .imag now behave differently for object arrays and return getattr(element, "real", element) or getattr(element, "imag", 0) elementwise. Additionally, the return for both is now read-only to avoid possible in-place changes having no effect.

This change also affects np.isreal() which uses arr.imag.

Previously, .imag always returned 0 while .real returned the original array unmodified. The new behavior now returnes the correct values for complex Python objects but may also lead to surprises for example if element.real() is a method and not a property.

(gh-30984)

NumPy's internal memory allocations now use PyMem_RawMalloc

NumPy's internal memory allocations now use PyMem_RawMalloc instead of malloc and can be tracked by tracemalloc.

(gh-31503)

v2.5.0rc1Pre-release

v2.5.0rc1 (June 2, 2026)

NumPy 2.5.0 Release Notes

Numpy 2.5.0 is a transitional release. It drops support for Python 3.11, marking the end of distutils, and expires a large number of deprecations made in the 2.0.x release. It also improves free threading and brings sorting into compliance with the array-api standard with the addition of descending sorts. Python 3.15 will be supported when it is released.

This release supports Python versions 3.12-3.14.

Highlights
  • Distutils has been removed,
  • Many expired deprecations, see below,
  • Many new deprecations, see below,
  • Many static typing improvements.
  • Improved support for free threading,
  • Support for descending sorts,

See New Features below for other additions.

Deprecations
  • numpy.char.chararray is deprecated. Use an ndarray with a string or bytes dtype instead.

    (gh-30605)

  • numpy.take now correctly checks if the result can be cast to the provided out=out under the same-kind rule. A DeprecationWarning is given now when this check fails. Previously, take incorrectly checked if out could be cast to the result (the wrong direction). This deprecation also affects compress and possibly other functions. (Future versions of NumPy may tighten the casting check further.)

    (gh-30615)

  • The numpy.char.[as]array functions are deprecated. Use an numpy.[as]array with a string or bytes dtype instead.

    (gh-30802)

  • Setting the dtype attribute is deprecated because mutating an array is unsafe if an array is shared, especially by multiple threads. As an alternative, you can create a view with a new dtype via array.view(dtype=new_dtype).

    (gh-29244)

  • Setting the shape attribute is deprecated because mutating an array is unsafe if an array is shared, especially by multiple threads. As an alternative, you can create a new view via np.reshape or np.ndarray.reshape. For example: x = np.arange(15); x = np.reshape(x, (3, 5)). To ensure no copy is made from the data, one can use np.reshape(..., copy=False).

    While setting the shape on an array is discouraged, for cases where it is difficult to work around, e.g., in __array_finalize__, it is possible with the private method np.ndarray._set_shape.

    (gh-29536)

  • Using the generic unit in numpy.timedelta64 is deprecated since this can lead to unexpected behavior such as non-transitive comparison, see gh-28287 for details. As an alternative, specify an explicit unit such as 's' (seconds) or 'D' (days) when constructing numpy.timedelta64. Due to this change, operations that implicitly rely on the generic unit are also deprecated. For example:

    arr = np.array([1, 2, 3], dtype="m8[s]")
    
    # `1` is implicitly converted to generic timedelta64
    arr + 1
    

    (gh-29619)

  • Resizing a Numpy array in place is deprecated since mutating an array is unsafe if an array is shared, especially by multiple threads. As an alternative, you can create a resized array via np.resize.

    (gh-30181)

  • numpy.fix is deprecated, use numpy.trunc instead. It is faster and follows the Array API standard. Both functions provide identical functionality: rounding array elements towards zero.

    (gh-30644)

  • numpy.ma.round_ is deprecated. numpy.ma.round can be used as a replacement.

    (gh-30738)

  • numpy.typename is deprecated because the names returned by it were outdated and inconsistent. numpy.dtype.name can be used as a replacement.

    (gh-30774)

  • Inputs other than integers are deprecated for numpy.triu_indices and numpy.tril_indices. Non-integer values for the M, k and N parameters of numpy.tri are deprecated. Non-integer values for the k parameter of both numpy.tril_indices_from and numpy.triu_indices_from are deprecated.

    (gh-30869)

  • Deprecations in custom dtype property and __array_finalize__.

    Previously arr.view(dtype=new_dtype) called arr.dtype = new_dtype also for subclasses, i.e., the attribute setting. That path is now deprecated and refined, meaning that even subclasses that do not see this DeprecationWarning may wish to update their code.

    A subclass that does any dtype specific logic (i.e. verifying the dtype in __array_finalize__ or has a dtype property) should now:

    • Set _set_dtype = None in which case arr.view(dtype=new_dtype) will call __array_finalize__ with the new dtype, ensuring that any validation __array_finalize__ will run is done.
    • Or, for a quick fix, define _set_dtype as a function (calling ndarray._set_dtype() to avoid DeprecationWarnings. (Future versions might migrate towards the _set_dtype = None path.)

    Ideally, follow NumPy's deprecation to prevent dtype mutation by users. The use of ndarray._set_dtype() may be necessary for some subclass finalization patterns, but should otherwise be avoided.

    (gh-31293)

Expired deprecations
  • numpy.distutils has been removed

    (gh-30340)

  • Passing None as dtype to np.finfo will now raise a TypeError (deprecated since 1.25)

    (gh-30460)

  • numpy.cross no longer supports 2-dimensional vectors. (Deprecated since 2.0)

    (gh-30461)

  • numpy._core.numerictypes.maximum_sctype has been removed. (deprecated since 2.0)

    (gh-30462)

  • numpy.row_stack has been removed in favor of numpy.vstack. (deprecated since 2.0)

    (gh-30463)

  • get_array_wrap has been removed. (deprecated since 2.0)

    (gh-30463)

  • recfromtxt and recfromcsv have been removed from numpy.lib._npyio in favor of numpy.genfromtxt. (deprecated since 2.0)

    (gh-30467)

  • The numpy.chararray re-export of numpy.char.chararray has been removed. (deprecated since 2.0)

    (gh-30604)

  • bincount now raises a TypeError for non-integer inputs. (deprecated since 2.1)

    (gh-30610)

  • The numpy.lib.math alias for the standard library math module has been removed. (deprecated since 1.25)

    (gh-30612)

  • Data type alias 'a' was removed in favor of 'S'. (deprecated since 2.0)

    (gh-30613)

  • _add_newdoc_ufunc(ufunc, newdoc) has been removed in favor of ufunc.__doc__ = newdoc. (deprecated since 2.2)

    (gh-30614)

Compatibility notes
linalg.eig and linalg.eigvals now always return complex arrays

Previously, the return values depended on whether the eigenvalues happen to lie on the real line (which, for a general, non-symmetric matrix, is not guaranteed).

This change makes consistent what was a value-dependent result. To retain the previous behavior, do:

w = eigvals(a)
if np.any(w.imag == 0):  # this is what NumPy used to do
    w = w.real

If your matrix is symmetrix/hermitian, use eigh and eigvalsh instead of eig and eigvals. These are guaranteed to return real values. A common case is covariance matrices, which are symmetric and positive definite by construction.

(gh-30411)

MSVC support

NumPy now requires minimum MSVC 19.35 toolchain version on Windows platforms. This corresponds to Visual Studio 2022 version 17.5 Preview 2 or newer.

(gh-30489)

Cython support

NumPy's Cython headers (accessed via cimport numpy) now require Cython 3.0 or newer to build. If you try to compile a project that depends on NumPy's Cython headers using Cython 0.29 or older, you will see a message like this:

Error compiling Cython file:
------------------------------------------------------------
...
# versions.
#
# See __init__.cython-30.pxd for the real Cython header
#

DEF err = int('Build aborted: the NumPy Cython headers require Cython 3.0.0 or newer.')
  ------------------------------------------------------------

  /path/to/site-packages/numpy/__init__.pxd:11:13: Error in compile-time expression:
  ValueError: invalid literal for int() with base 10: 
  'Build aborted: the NumPy Cython headers require Cython 3.0.0 or newer.'

Note that the invalid integer is not a bug in NumPy - we are intentionally generating this error to avoid triggering a more obscure error later in the build when an older Cython version tries to use a Cython feature that was not available in the old Cython version.

(gh-30770)

numpy.where no longer truncates Python integers

Previously, if the x or y argument of numpy.where was a Python integer that was out of range of the output type, it would be silently truncated. Now, an OverflowError will be raised instead.

This change also applies to the underlying C API function PyArray_Where.

(gh-30803)

Default memory allocator change

NumPy now uses PyMem_RawMalloc and PyMem_RawFree as the default memory allocator, instead of system's malloc and free directly.

(gh-30846)

from_dlpack raises BufferError instead of RuntimeError

np.from_dlpack now raises BufferError instead of RuntimeError when the incoming DLPack tensor has an unsupported device, dtype, or exceeds the maximum number of dimensions. This aligns with the DLPack and Array API specifications, which recommend BufferError for data that cannot be imported.

(gh-30937)

Corrections to the BTPE binomial sampler

Two independent errors in the Stirling series of the acceptance/rejection step of the BTPE algorithm used by numpy.random.Generator.binomial have been corrected:

  • The third and fourth error terms were added rather than subtracted. This sign error was inherited from section 5.3 of the original 1988 paper by Kachitvichyanukul & Schmeiser, which incorrectly adds all four terms.
  • The leading coefficient had a digit-swap typo (13680 instead of 13860) that was introduced in the initial implementation.

As a result, Generator.binomial and Generator.multinomial, which uses binomial internally, may now return different samples for the same seed.

The legacy numpy.random.RandomState.binomial and numpy.random.RandomState.multinomial are not affected: they preserve the original (incorrect) behavior, so existing streams remain reproducible.

(gh-31238)

datetime64/timedelta64 arithmetic raises on overflow

Addition, subtraction, and integer multiplication of datetime64 and timedelta64 values now raise OverflowError when the result would overflow int64 or land on the NaT sentinel value. Previously these operations silently wrapped, often producing a value that was indistinguishable from NaT. This matches the overflow checking already performed by unit-conversion casts.

(gh-31378)

C API changes
  • It is now possible to register "real" and "imag" ArrayMethods via PyUFunc_AddLoopsFromSpecs. These will be used for imag and real and should normally set *view_offset in their resolve_descriptors function to allow the array attributes to return views.

    (gh-30984)

  • New PyDataType_TYPE, PyDataType_KIND, PyDataType_BYTEORDER and PyDataType_TYPEOBJ accessor macros to the C API. Together with the other accessor macros added for the NumPy 2.0 transition, these allow accessing the fields of PyArray_Descr structs without any direct field accesses.

    (gh-30994)

  • NumPy now supports the stable ABI for free-threaded Python as described in 803{.interpreted-text role="pep"}.

    (gh-31091)

  • PyArray_DescrFromScalar now returns the full dtype descriptor for scalars of user-defined parametric data types, including any dtype parameters. Parameters were previously silently discarded, which could cause incorrect results in operations like astype on scalar objects. Internally, the function now delegates to discover_descr_from_pyobject, which handles parametric dtypes correctly.

    (gh-31067)

New Features
  • It is now possible to register user-dtypes for dlpack export and import via numpy.dtypes.register_dlpack_dtype. This functionality is meant to be used with care by user-dtype authors.

    (gh-31256)

Pixi package definitions

Pixi package definitions have been added for different kinds of from-source builds of NumPy. These can be used in downstream Pixi workspaces via the pixi-build feature.

Definitions for both default and AddressSanitizer-instrumented (asan) builds are available in the source code under the pixi-packages/ directory.

linux-64 and osx-arm64 platforms are supported.

(gh-30381)

numpy.ndarray now supports structural pattern matching

numpy.ndarray and its subclasses now have the Py_TPFLAGS_SEQUENCE flag set, enabling structural pattern matching (PEP 634) with match/case statements. This also enables Cython to optimize integer indexing operations. See `arrays.ndarray.pattern-matching{.interpreted-text role="ref"}` for details.

(gh-30653)

Added N-D evaluation functions to the polynomial package

New functions polyvalnd, chebvalnd, legvalnd, hermvalnd, hermevalnd, and lagvalnd have been added to evaluate polynomials in arbitrary dimensions, analogous to the existing 2D and 3D evaluators.

(gh-30857)

New "descending" keyword argument for numpy.sort and numpy.argsort

Users can now pass the descending=True keyword argument to numpy.sort and numpy.argsort to sort and argsort arrays in descending order. NaN values, if present, are sorted to the end of the array in both ascending and descending sorts. This feature is available for all built-in dtypes except void, object, and generic. Note that SIMD optimizations for sorting are currently not available for descending sorts, so performance may be slower.

(gh-31345)

Improvements

For f2py, the behaviour of intent(inplace) has improved. Previously, if an input array did not have the right dtype or order, the input array was modified in-place, changing its dtype and replacing its data by a corrected copy. Now, instead, the corrected copy is kept a separate array, which, after being passed and presumably modified by the fortran routine, is copied back to the input routine. The above means one no longer has the risk that pre-existing views or slices of the input array start pointing to unallocated memory (at the price of increased overhead for the write-back copy at the end of the call).

A potential problem would be that one might get very different results if one, e.g., previously passed in an integer array where a double array was expected: the writeback to integer would likely give wrong results. To avoid such situations, intent(inplace) will now only allow arrays that have equivalent type to that used in the fortran routine, i.e., dtype.kind is the same. For instance, a routine expecting double would be able to receive float, but would raise on integer input.

(gh-29929)

f2py modules now show allocatable arrays in dir()

Allocatable module variables wrapped by f2py now appear in dir() output, matching their accessibility by name.

(gh-30965)

Performance improvements and changes
Improved performance of numpy.searchsorted

The C++ binary search implementation used by numpy.searchsorted now has a much better performance when searching for multiple keys. The new implementation batches binary search steps across all keys to leverage cache locality and out-of-order execution. Benchmarks show the new implementation can be up to 20 times faster for hundreds of thousands keys while single-key performance remains comparable to previous versions.

(gh-30517)

Improved scaling of ufuncs on free-threading

NumPy's ufuncs now scale significantly better on free-threading builds of CPython due to the following optimizations:

  • Lock-free dispatch table: The ufuncs dispatch table is now implemented as a lock-free concurrent hash map, allowing multiple threads to call ufuncs without contention.
  • Immortal shared objects: Certain shared objects, such as global memory handlers, have been made immortal. This effectively reduces reference counting contention across threads.
  • Optimized memory allocation: NumPy now utilizes PyMem_RawMalloc and PyMem_RawFree for memory allocation. On Python 3.15 and newer, this leverages mimalloc and significantly reduces memory allocation overhead in multi-threaded workloads.

(gh-30846)

Faster reductions on small/medium contiguous arrays

numpy.sum, numpy.prod, numpy.any, numpy.all, and other reductions with an identity value now use a fast path when the input is a contiguous, aligned, non-object array and the reduction covers all axes (axis=None) with no special arguments. Typical speedup is ~1.3x on small arrays; numpy.any / numpy.all on contiguous boolean arrays can see speedup up to 1.9x.

(gh-31274)

Typing improvements and changes
numpy.linalg typing improvements and preliminary shape-typing support

Input and output dtypes for numpy.linalg functions are now more precise. Several of these functions also gain preliminary shape-typing support while remaining backward compatible. For example, the return type of numpy.linalg.matmul now depends on the shape-type of its inputs, or fall back to the backward-compatible return type if the shape-types are unknown at type-checking time. Because of limitations in Python's type system and current type-checkers, shape-typing cannot cover every situation and is often only implemented for the most common lower-rank cases.

(gh-30480)

numpy.ma typing annotations

The numpy.ma module is now fully covered by typing annotations. This includes annotations for masked arrays, masks, and various functions and methods. With this, NumPy has achieved 100% typing coverage across all its submodules.

(gh-30566)

Shape-typing support for many functions and methods

Many functions and methods now have shape-aware return type annotations. Type-checkers can now infer the number of dimensions of the returned array through common operations. For example, np.linspace(0, 1) is now typed as a 1-d float64 array, and np.sum(x, keepdims=True) has the same number of dimensions as x.

This covers numpy.linalg functions, array creation functions (like asarray, from{buffer,string,file,iter,regex}), range functions (linspace, logspace, geomspace), aggregation functions and methods (sum, mean, std, var, min, max, all, any, etc.), sorting (sort, argsort, argpartition), cumulative operations (cumsum, cumprod, etc.), set operations (unique_values, intersect1d, union1d, etc.), and various other functions including nonzero, transpose, diagonal, atleast_{1,2,3}d, clip, round, inner, bincount, and fft.fftfreq. Several of these also gained more precise return dtype annotations as part of this work.

Shape-typing is still a work-in-progress, so coverage is not yet complete. Because of limitations in Python's type system and current type-checkers, shape-typing is often only implemented for the most common lower-rank cases.

(gh-31172)

numpy.fft typing improvements and preliminary shape-typing support

The numpy.fft functions now support non-float64/complex128 dtypes and gain preliminary shape-typing support. For example, the return type of numpy.fft.fft now depends on the shape-type of its inputs, falling back to the backward-compatible return type when the shape-types are unknown at type-checking time.

(gh-31226)

Changes
Structured array copies now use memcpy for contiguous dtypes

Copying structured arrays with identical dtypes now uses memcpy instead of field-by-field transfer when the dtype has a contiguous layout (no gaps between fields). A new NPY_NOT_TRIVIALLY_COPYABLE dtype flag is set on structured dtypes that have gaps in their memory layout, such as those created with explicit offsets or via multi-field indexing. Only these dtypes continue to use the slower field-by-field copy.

This means that padding bytes in contiguous structured dtypes (e.g. those created without explicit offsets) may now be copied as part of the memcpy, whereas previously they were left untouched. Code that relies on padding bytes being preserved during structured array copies may be affected.

(gh-29270)

numpy.ctypeslib.as_ctypes now does not support scalar types

The function numpy.ctypeslib.as_ctypes has been updated to only accept numpy.ndarray. Passing a scalar type (e.g., numpy.int32(5)) will now raise a TypeError. This change was made to avoid the issue gh-30354 and to enforce the readonly nature of scalar types in NumPy. The previous behavior relied on undocumented implicit temporary arrays and was not well-defined. Users who need to convert scalar types to ctypes should first convert them to an array (e.g., numpy.asarray) before passing them to numpy.ctypeslib.as_ctypes.

(gh-30538)

__array_interface__ changes on scalars

Scalars now export the __array_interface__ directly rather than including an array copy as a __ref entry. This means that scalars are now exported as read-only while they previously exported as writeable. The path via __ref was undocumented and not consistently used even within NumPy itself.

(gh-30538)

meshgrid now always returns a tuple

np.meshgrid previously used to return a list when sparse was true and copy was false. Now, it always returns a tuple regardless of the arguments.

(gh-30707)

numpy.triu_indices now accepts unsigned integers

numpy.triu_indices previously used to error in some cases when unsigned integers were given as arguments. Now, it accepts them in all cases.

(gh-30869)

object dtype in .real and .imag and related functions

The array attributes .real and .imag now behave differently for object arrays and return getattr(element, "real", element) or getattr(element, "imag", 0) elementwise. Additionally, the return for both is now read-only to avoid possible in-place changes having no effect.

This change also affects np.isreal() which uses arr.imag.

Previously, .imag always returned 0 while .real returned the original array unmodified. The new behavior now returnes the correct values for complex Python objects but may also lead to surprises for example if element.real() is a method and not a property.

(gh-30984)

NumPy's internal memory allocations now use PyMem_RawMalloc

NumPy's internal memory allocations now use PyMem_RawMalloc instead of malloc and can be tracked by tracemalloc.

(gh-31503)

v2.4.6

v2.4.6 (May 18, 2026)

NumPy 2.4.6 Release Notes

NumPy 2.4.6 is a quick release that fixes a regression discovered in the 2.4.5 release.

This release supports Python versions 3.11-3.14

Contributors

A total of 4 people contributed to this release. People with a "+" by their names contributed a patch for the first time.

  • !EarlMilktea
  • Charles Harris
  • Sebastian Berg
  • Warren Weckesser
Pull requests merged

A total of 4 pull requests were merged for this release.

  • #31444: MAINT: Prepare 2.4.x for further development
  • #31453: BUG: Fix regression in arr.conj()
  • #31459: BUG: np.linalg.svd(..., hermitian=True) returns non-unitary...
  • #31460: BUG: Don't call INCREF/DECREF on descr in NpyStringAcquireAllocator...
v2.4.5

v2.4.5 (May 15, 2026)

NumPy 2.4.5 Release Notes

NumPy 2.4.5 is a patch release that fixes bugs discovered after the 2.4.4 release, has some typing improvements, and maintains infrastructure.

This release supports Python versions 3.11-3.14

Contributors

A total of 17 people contributed to this release. People with a "+" by their names contributed a patch for the first time.

  • Aleksei Nikiforov
  • Anarion Zuo +
  • Ankit Ahlawat
  • Breno Favaretto +
  • Charles Harris
  • Igor Krivenko +
  • Ijtihed Kilani +
  • Joren Hammudoglu
  • Maarten Baert +
  • Matti Picus
  • Nathan Goldbaum
  • Praneeth Kodumagulla +
  • Ralf Gommers
  • RoomWithOutRoof +
  • Sebastian Berg
  • Warren Weckesser
  • div +
Pull requests merged

A total of 28 pull requests were merged for this release.

  • #31093: MAINT: Prepare 2.4.x for further development
  • #31182: TYP: fix np.shape assignability issue for python lists (#31171)
  • #31197: ENH: Return rank 0 for empty matrices in matrix_rank (#30422)
  • #31198: CI/BUG: add native jobs for s390x, fix bug in pack_inner...
  • #31199: BUG: f2py map complex_long_double to NPY_CLONGDOUBLE
  • #31205: MAINT: f2py: Stop setting re._MAXCACHE to 50.
  • #31206: BUG: fix heap buffer overflow in timedelta to string casts
  • #31207: MAINT: Rename ppc64le and s390x workflow (#31121)
  • #31208: BUG: Fix matvec/vecmat in-place aliasing (out=input produces...
  • #31209: TYP: tile: accept numpy scalars and arrays as second argument...
  • #31211: DEP: Undo deprecation for np.dtype() signature used by old pickles...
  • #31212: REV: Manual revert of float16 svml use (#31178)
  • #31222: TYP: ix_ fix for boolean and non-1d input (#31218)
  • #31329: BUG: incorrect temp elision for new-style (NEP 43) user-defined...
  • #31330: TYP: fix sliding_window_view axis parameter typing
  • #31335: BUG: Prevent deadlock due to downstream importing NumPy in dlopen...
  • #31336: BUG: Fix segfault in nditer.multi_index when __getitem__ raises...
  • #31338: TYP: Fix ruff lint error
  • #31357: BUG: fix memory leak in np.zeros when fill-zero loop raises (#31320)
  • #31358: BUG: np.einsum() fails with a 0-dimensional out argument and...
  • #31379: BUG: Fix signed overflow issue in npy_gcd for INT_MIN on s390x...
  • #31383: CI: remove Cirrus CI FreeBSD job (#31380)
  • #31390: BUILD: newer MKL uses so.3
  • #31391: BLD/MAINT: improve support for Intel LLVM compilers
  • #31401: BUG: Avoid UB in safe[add,sub,mul] helpers (#31396)
  • #31402: BUG: exclude __pycache__ directories from wheels (#31397)
  • #31404: TYP: _NestedSequence type parameter default to work around...
  • #31426: TYP: Fix DTypeLike runtime type-checker support (#31425)
v2.4.4

2.4.4 (Mar 29, 2026)

NumPy 2.4.4 Release Notes

The NumPy 2.4.4 is a patch release that fixes bugs discovered after the 2.4.3 release. It should finally close issue #30816, the OpenBLAS threading problem on ARM.

This release supports Python versions 3.11-3.14

Contributors

A total of 8 people contributed to this release. People with a "+" by their names contributed a patch for the first time.

  • Charles Harris
  • Daniel Haag +
  • Denis Prokopenko +
  • Harshith J +
  • Koki Watanabe
  • Marten van Kerkwijk
  • Matti Picus
  • Nathan Goldbaum
Pull requests merged

A total of 7 pull requests were merged for this release.

  • #30978: MAINT: Prepare 2.4.x for further development
  • #31049: BUG: Add test to reproduce problem described in #30816 (#30818)
  • #31052: BUG: fix FNV-1a 64-bit selection by using NPY_SIZEOF_UINTP (#31035)
  • #31053: BUG: avoid warning on ufunc with where=True and no output
  • #31058: DOC: document caveats of ndarray.resize on 3.14 and newer
  • #31079: TST: fix POWER VSX feature mapping (#30801)
  • #31084: MAINT: numpy.i: Replace deprecated sprintf with snprintf...
v2.4.3

2.4.3 (Mar 9, 2026)

NumPy 2.4.3 Release Notes

The NumPy 2.4.3 is a patch release that fixes bugs discovered after the 2.4.2 release. The most user visible fix may be a threading fix for OpenBLAS on ARM, closing issue #30816.

This release supports Python versions 3.11-3.14

Contributors

A total of 11 people contributed to this release. People with a "+" by their names contributed a patch for the first time.

  • Antareep Sarkar +
  • Charles Harris
  • Joren Hammudoglu
  • Matthieu Darbois
  • Matti Picus
  • Nathan Goldbaum
  • Peter Hawkins
  • Pieter Eendebak
  • Sebastian Berg
  • Warren Weckesser
  • stratakis +
Pull requests merged

A total of 14 pull requests were merged for this release.

  • #30759: MAINT: Prepare 2.4.x for further development
  • #30827: BUG: Fix some leaks found via LeakSanitizer (#30756)
  • #30841: MAINT: Synchronize 2.4.x submodules with main
  • #30849: TYP: matlib: missing extended precision imports
  • #30850: BUG: Fix weak hash function in np.isin(). (#30840)
  • #30921: BUG: fix infinite recursion in np.ma.flatten_structured_array...
  • #30922: BUG: Fix buffer overrun in CPU baseline validation (#30877)
  • #30923: BUG: Fix busdaycalendar's handling of a bool array weekmask....
  • #30924: BUG: Fix reference leaks and NULL pointer dereferences (#30908)
  • #30925: MAINT: fix two minor issues noticed when touching the C API setup
  • #30955: ENH: Test .kind not .char in np.testing.assert_equal (#30879)
  • #30957: BUG: fix type issues in uses if PyDataType macros
  • #30958: MAINT: Don't use vulture 2.15, it has false positives
  • #30973: MAINT: update openblas (#30961)
v2.4.2

2.4.2 (Feb 1, 2026)

NumPy 2.4.2 Release Notes

The NumPy 2.4.2 is a patch release that fixes bugs discovered after the 2.4.1 release. Highlights are:

  • Fixes memory leaks
  • Updates OpenBLAS to fix hangs

This release supports Python versions 3.11-3.14

Contributors

A total of 9 people contributed to this release. People with a "+" by their names contributed a patch for the first time.

  • Charles Harris
  • Daniel Tang +
  • Joren Hammudoglu
  • Kumar Aditya
  • Matti Picus
  • Nathan Goldbaum
  • Ralf Gommers
  • Sebastian Berg
  • Vikram Kumar +
Pull requests merged

A total of 12 pull requests were merged for this release.

  • #30629: MAINT: Prepare 2.4.x for further development
  • #30636: TYP: arange: accept datetime strings
  • #30657: MAINT: avoid possible race condition by not touching os.environ...
  • #30700: BUG: validate contraction axes in tensordot (#30521)
  • #30701: DOC: __array_namespace__info__: set_module not __module__ (#30679)
  • #30702: BUG: fix free-threaded PyObject layout in replace_scalar_type_names...
  • #30703: TST: fix limited API example in tests for latest Cython
  • #30709: BUG: Fix some bugs found via valgrind (#30680)
  • #30712: MAINT: replace ob_type access with Py_TYPE in PyArray_CheckExact
  • #30713: BUG: Fixup the quantile promotion fixup
  • #30736: BUG: fix thread safety of array_getbuffer (#30667)
  • #30737: backport scipy-openblas version change
v2.4.1

2.4.1 (Jan 10, 2026)

NumPy 2.4.1 Release Notes

The NumPy 2.4.1 is a patch release that fixes bugs discoved after the 2.4.0 release. In particular, the typo SeedlessSequence is preserved to enable wheels using the random Cython API and built against NumPy < 2.4.0 to run without errors.

This release supports Python versions 3.11-3.14

Contributors

A total of 9 people contributed to this release. People with a "+" by their names contributed a patch for the first time.

  • Alexander Shadchin
  • Bill Tompkins +
  • Charles Harris
  • Joren Hammudoglu
  • Marten van Kerkwijk
  • Nathan Goldbaum
  • Raghuveer Devulapalli
  • Ralf Gommers
  • Sebastian Berg
Pull requests merged

A total of 15 pull requests were merged for this release.

  • #30490: MAINT: Prepare 2.4.x for further development
  • #30503: DOC: numpy.select: fix default parameter docstring...
  • #30504: REV: Revert part of #30164 (#30500)
  • #30506: TYP: numpy.select: allow passing array-like default...
  • #30507: MNT: use if constexpr for compile-time branch selection
  • #30513: BUG: Fix leak in flat assignment iterator
  • #30516: BUG: fix heap overflow in fixed-width string multiply (#30511)
  • #30523: BUG: Ensure summed weights returned by np.average always are...
  • #30527: TYP: Fix return type of histogram2d
  • #30594: MAINT: avoid passing ints to random functions that take double...
  • #30595: BLD: Avoiding conflict with pygit2 for static build
  • #30596: MAINT: Fix msvccompiler missing error on FreeBSD
  • #30608: BLD: update vendored Meson to 1.9.2
  • #30620: ENH: use more fine-grained critical sections in array coercion...
  • #30623: BUG: Undo result type change of quantile/percentile but keep...
v2.4.0

2.4.0 (Dec 20, 2025)

NumPy 2.4.0 Release Notes

The NumPy 2.4.0 release continues the work to improve free threaded Python support, user dtypes implementation, and annotations. There are many expired deprecations and bug fixes as well.

This release supports Python versions 3.11-3.14

Highlights

Apart from annotations and same_value kwarg, the 2.4 highlights are mostly of interest to downstream developers. They should help in implementing new user dtypes.

  • Many annotation improvements. In particular, runtime signature introspection.
  • New casting kwarg 'same_value' for casting by value.
  • New PyUFunc_AddLoopsFromSpec function that can be used to add user sort loops using the ArrayMethod API.
  • New __numpy_dtype__ protocol.
Deprecations
Setting the strides attribute is deprecated

Setting the strides attribute is now deprecated since mutating an array is unsafe if an array is shared, especially by multiple threads. As an alternative, you can create a new view (no copy) via:

  • np.lib.stride_tricks.strided_window_view if applicable,
  • np.lib.stride_tricks.as_strided for the general case,
  • or the np.ndarray constructor (buffer is the original array) for a light-weight version.

(gh-28925)

Positional out argument to np.maximum, np.minimum is deprecated

Passing the output array out positionally to numpy.maximum and numpy.minimum is deprecated. For example, np.maximum(a, b, c) will emit a deprecation warning, since c is treated as the output buffer rather than a third input.

Always pass the output with the keyword form, e.g. np.maximum(a, b, out=c). This makes intent clear and simplifies type annotations.

(gh-29052)

align= must be passed as boolean to np.dtype()

When creating a new dtype a VisibleDeprecationWarning will be given if align= is not a boolean. This is mainly to prevent accidentally passing a subarray align flag where it has no effect, such as np.dtype("f8", 3) instead of np.dtype(("f8", 3)). We strongly suggest to always pass align= as a keyword argument.

(gh-29301)

Assertion and warning control utilities are deprecated

np.testing.assert_warns and np.testing.suppress_warnings are deprecated. Use warnings.catch_warnings, warnings.filterwarnings, pytest.warns, or pytest.filterwarnings instead.

(gh-29550)

np.fix is pending deprecation

The numpy.fix function will be deprecated in a future release. It is recommended to use numpy.trunc instead, as it provides the same functionality of truncating decimal values to their integer parts. Static type checkers might already report a warning for the use of numpy.fix.

(gh-30168)

in-place modification of ndarray.shape is pending deprecation

Setting the ndarray.shape attribute directly will be deprecated in a future release. Instead of modifying the shape in place, it is recommended to use the numpy.reshape function. Static type checkers might already report a warning for assignments to ndarray.shape.

(gh-30282)

Deprecation of numpy.lib.user_array.container

The numpy.lib.user_array.container class is deprecated and will be removed in a future version.

(gh-30284)

Expired deprecations
Removed deprecated MachAr runtime discovery mechanism.

(gh-29836)

Raise TypeError on attempt to convert array with ndim > 0 to scalar

Conversion of an array with ndim > 0 to a scalar was deprecated in NumPy 1.25. Now, attempting to do so raises TypeError. Ensure you extract a single element from your array before performing this operation.

(gh-29841)

Removed numpy.linalg.linalg and numpy.fft.helper

The following were deprecated in NumPy 2.0 and have been moved to private modules:

  • numpy.linalg.linalg Use numpy.linalg instead.
  • numpy.fft.helper Use numpy.fft instead.

(gh-29909)

Removed interpolation parameter from quantile and percentile functions

The interpolation parameter was deprecated in NumPy 1.22.0 and has been removed from the following functions:

  • numpy.percentile
  • numpy.nanpercentile
  • numpy.quantile
  • numpy.nanquantile

Use the method parameter instead.

(gh-29973)

Removed numpy.in1d

numpy.in1d has been deprecated since NumPy 2.0 and is now removed in favor of numpy.isin.

(gh-29978)

Removed numpy.ndindex.ndincr()

The ndindex.ndincr() method has been deprecated since NumPy 1.20 and is now removed; use next(ndindex) instead.

(gh-29980)

Removed fix_imports parameter from numpy.save

The fix_imports parameter was deprecated in NumPy 2.1.0 and is now removed. This flag has been ignored since NumPy 1.17 and was only needed to support loading files in Python 2 that were written in Python 3.

(gh-29984)

Removal of four undocumented ndarray.ctypes methods

Four undocumented methods of the ndarray.ctypes object have been removed:

  • _ctypes.get_data() (use _ctypes.data instead)
  • _ctypes.get_shape() (use _ctypes.shape instead)
  • _ctypes.get_strides() (use _ctypes.strides instead)
  • _ctypes.get_as_parameter() (use _ctypes._as_parameter_ instead)

These methods have been deprecated since NumPy 1.21.

(gh-29986)

Removed newshape parameter from numpy.reshape

The newshape parameter was deprecated in NumPy 2.1.0 and has been removed from numpy.reshape. Pass it positionally or use shape= on newer NumPy versions.

(gh-29994)

Removal of deprecated functions and arguments

The following long-deprecated APIs have been removed:

  • numpy.trapz --- deprecated since NumPy 2.0 (2023-08-18). Use numpy.trapezoid or scipy.integrate functions instead.
  • disp function --- deprecated from 2.0 release and no longer functional. Use your own printing function instead.
  • bias and ddof arguments in numpy.corrcoef --- these had no effect since NumPy 1.10.

(gh-29997)

Removed delimitor parameter from numpy.ma.mrecords.fromtextfile()

The delimitor parameter was deprecated in NumPy 1.22.0 and has been removed from numpy.ma.mrecords.fromtextfile(). Use delimiter instead.

(gh-30021)

numpy.array2string and numpy.sum deprecations finalized

The following long-deprecated APIs have been removed or converted to errors:

  • The style parameter has been removed from numpy.array2string. This argument had no effect since Numpy 1.14.0. Any arguments following it, such as formatter have now been made keyword-only.
  • Calling np.sum(generator) directly on a generator object now raises a TypeError. This behavior was deprecated in NumPy 1.15.0. Use np.sum(np.fromiter(generator)) or the python sum builtin instead.

(gh-30068)

Compatibility notes
  • NumPy's C extension modules have begun to use multi-phase initialisation, as defined by PEP 489. As part of this, a new explicit check has been added that each such module is only imported once per Python process. This comes with the side-effect that deleting numpy from sys.modules and re-importing it will now fail with an ImportError. This has always been unsafe, with unexpected side-effects, though did not previously raise an error.

    (gh-29030)

  • numpy.round now always returns a copy. Previously, it returned a view for integer inputs for decimals >= 0 and a copy in all other cases. This change brings round in line with ceil, floor and trunc.

    (gh-29137)

  • Type-checkers will no longer accept calls to numpy.arange with start as a keyword argument. This was done for compatibility with the Array API standard. At runtime it is still possible to use numpy.arange with start as a keyword argument.

    (gh-30147)

  • The Macro NPY_ALIGNMENT_REQUIRED has been removed The macro was defined in the npy_cpu.h file, so might be regarded as semi public. As it turns out, with modern compilers and hardware it is almost always the case that alignment is required, so numpy no longer uses the macro. It is unlikely anyone uses it, but you might want to compile with the -Wundef flag or equivalent to be sure.

    (gh-29094)

C API changes
The NPY_SORTKIND enum has been enhanced with new variables

This is of interest if you are using PyArray_Sort or PyArray_ArgSort. We have changed the semantics of the old names in the NPY_SORTKIND enum and added new ones. The changes are backward compatible, and no recompilation is needed. The new names of interest are:

  • NPY_SORT_DEFAULT -- default sort (same value as NPY_QUICKSORT)
  • NPY_SORT_STABLE -- the sort must be stable (same value as NPY_MERGESORT)
  • NPY_SORT_DESCENDING -- the sort must be descending

The semantic change is that NPY_HEAPSORT is mapped to NPY_QUICKSORT when used. Note that NPY_SORT_DESCENDING is not yet implemented.

(gh-29642)

New NPY_DT_get_constant slot for DType constant retrieval

A new slot NPY_DT_get_constant has been added to the DType API, allowing dtype implementations to provide constant values such as machine limits and special values. The slot function has the signature:

int get_constant(PyArray_Descr *descr, int constant_id, void *ptr)

It returns 1 on success, 0 if the constant is not available, or -1 on error. The function is always called with the GIL held and may write to unaligned memory.

Integer constants (marked with the 1 << 16 bit) return npy_intp values, while floating-point constants return values of the dtype's native type.

Implementing this can be used by user DTypes to provide numpy.finfo values.

(gh-29836)

A new PyUFunc_AddLoopsFromSpecs convenience function has been added to the C API.

This function allows adding multiple ufunc loops from their specs in one call using a NULL-terminated array of PyUFunc_LoopSlot structs. It allows registering sorting and argsorting loops using the new ArrayMethod API.

(gh-29900)

New Features
  • Let np.size accept multiple axes.

    (gh-29240)

  • Extend numpy.pad to accept a dictionary for the pad_width argument.

    (gh-29273)

'same_value' for casting by value

The casting kwarg now has a 'same_value' option that checks the actual values can be round-trip cast without changing value. Currently it is only implemented in ndarray.astype. This will raise a ValueError if any of the values in the array would change as a result of the cast, including rounding of floats or overflowing of ints.

(gh-29129)

StringDType fill_value support in numpy.ma.MaskedArray

Masked arrays now accept and preserve a Python str as their fill_value when using the variable‑width StringDType (kind 'T'), including through slicing and views. The default is 'N/A' and may be overridden by any valid string. This fixes issue gh‑29421 and was implemented in pull request gh‑29423.

(gh-29423)

ndmax option for numpy.array

The ndmax option is now available for numpy.array. It explicitly limits the maximum number of dimensions created from nested sequences.

This is particularly useful when creating arrays of list-like objects with dtype=object. By default, NumPy recurses through all nesting levels to create the highest possible dimensional array, but this behavior may not be desired when the intent is to preserve nested structures as objects. The ndmax parameter provides explicit control over this recursion depth.

# Default behavior: Creates a 2D array
>>> a = np.array([[1, 2], [3, 4]], dtype=object)
>>> a
array([[1, 2],
       [3, 4]], dtype=object)
>>> a.shape
(2, 2)

# With ndmax=1: Creates a 1D array
>>> b = np.array([[1, 2], [3, 4]], dtype=object, ndmax=1)
>>> b
array([list([1, 2]), list([3, 4])], dtype=object)
>>> b.shape
(2,)

(gh-29569)

Warning emitted when using where without out

Ufuncs called with a where mask and without an out positional or kwarg will now emit a warning. This usage tends to trip up users who expect some value in output locations where the mask is False (the ufunc will not touch those locations). The warning can be suppressed by using out=None.

(gh-29813)

DType sorting and argsorting supports the ArrayMethod API

User-defined dtypes can now implement custom sorting and argsorting using the ArrayMethod API. This mechanism can be used in place of the PyArray_ArrFuncs slots which may be deprecated in the future.

The sorting and argsorting methods are registered by passing the arraymethod specs that implement the operations to the new PyUFunc_AddLoopsFromSpecs function. See the ArrayMethod API documentation for details.

(gh-29900)

New __numpy_dtype__ protocol

NumPy now has a new __numpy_dtype__ protocol. NumPy will check for this attribute when converting to a NumPy dtype via np.dtype(obj) or any dtype= argument.

Downstream projects are encouraged to implement this for all dtype like objects which may previously have used a .dtype attribute that returned a NumPy dtype. We expect to deprecate .dtype in the future to prevent interpreting array-like objects with a .dtype attribute as a dtype. If you wish you can implement __numpy_dtype__ to ensure an earlier warning or error (.dtype is ignored if this is found).

(gh-30179)

Improvements
Fix flatiter indexing edge cases

The flatiter object now shares the same index preparation logic as ndarray, ensuring consistent behavior and fixing several issues where invalid indices were previously accepted or misinterpreted.

Key fixes and improvements:

  • Stricter index validation

    • Boolean non-array indices like arr.flat[[True, True]] were incorrectly treated as arr.flat[np.array([1, 1], dtype=int)]. They now raise an index error. Note that indices that match the iterator's shape are expected to not raise in the future and be handled as regular boolean indices. Use np.asarray(<index>) if you want to match that behavior.
    • Float non-array indices were also cast to integer and incorrectly treated as arr.flat[np.array([1.0, 1.0], dtype=int)]. This is now deprecated and will be removed in a future version.
    • 0-dimensional boolean indices like arr.flat[True] are also deprecated and will be removed in a future version.
  • Consistent error types:

    Certain invalid flatiter indices that previously raised ValueError now correctly raise IndexError, aligning with ndarray behavior.

  • Improved error messages:

    The error message for unsupported index operations now provides more specific details, including explicitly listing the valid index types, instead of the generic IndexError: unsupported index operation.

(gh-28590)

Improved error handling in np.quantile

[np.quantile]{.title-ref} now raises errors if:

  • All weights are zero
  • At least one weight is np.nan
  • At least one weight is np.inf

(gh-28595)

Improved error message for assert_array_compare

The error message generated by assert_array_compare which is used by functions like assert_allclose, assert_array_less etc. now also includes information about the indices at which the assertion fails.

(gh-29112)

Show unit information in __repr__ for datetime64("NaT")

When a datetime64 object is "Not a Time" (NaT), its __repr__ method now includes the time unit of the datetime64 type. This makes it consistent with the behavior of a timedelta64 object.

(gh-29396)

Performance increase for scalar calculations

The speed of calculations on scalars has been improved by about a factor 6 for ufuncs that take only one input (like np.sin(scalar)), reducing the speed difference from their math equivalents from a factor 19 to 3 (the speed for arrays is left unchanged).

(gh-29819)

numpy.finfo Refactor

The numpy.finfo class has been completely refactored to obtain floating-point constants directly from C compiler macros rather than deriving them at runtime. This provides better accuracy, platform compatibility and corrected several attribute calculations:

  • Constants like eps, min, max, smallest_normal, and smallest_subnormal now come directly from standard C macros (FLT_EPSILON, DBL_MIN, etc.), ensuring platform-correct values.
  • The deprecated MachAr runtime discovery mechanism has been removed.
  • Derived attributes have been corrected to match standard definitions: machep and negep now use int(log2(eps)); nexp accounts for all exponent patterns; nmant excludes the implicit bit; and minexp follows the C standard definition.
  • longdouble constants, Specifically smallest_normal now follows the C standard definitions as per respecitive platform.
  • Special handling added for PowerPC's IBM double-double format.
  • New test suite added in test_finfo.py to validate all finfo properties against expected machine arithmetic values for float16, float32, and float64 types.

(gh-29836)

Multiple axes are now supported in numpy.trim_zeros

The axis argument of numpy.trim_zeros now accepts a sequence; for example np.trim_zeros(x, axis=(0, 1)) will trim the zeros from a multi-dimensional array x along axes 0 and 1. This fixes issue gh‑29945 and was implemented in pull request gh‑29947.

(gh-29947)

Runtime signature introspection support has been significantly improved

Many NumPy functions, classes, and methods that previously raised ValueError when passed to inspect.signature() now return meaningful signatures. This improves support for runtime type checking, IDE autocomplete, documentation generation, and runtime introspection capabilities across the NumPy API.

Over three hundred classes and functions have been updated in total, including, but not limited to, core classes such as ndarray, generic, dtype, ufunc, broadcast, nditer, etc., most methods of ndarray and scalar types, array constructor functions (array, empty, arange, fromiter, etc.), all ufuncs, and many other commonly used functions, including dot, concat, where, bincount, can_cast, and numerous others.

(gh-30208)

Performance improvements and changes
Performance improvements to np.unique for string dtypes

The hash-based algorithm for unique extraction provides an order-of-magnitude speedup on large string arrays. In an internal benchmark with about 1 billion string elements, the hash-based np.unique completed in roughly 33.5 seconds, compared to 498 seconds with the sort-based method -- about 15× faster for unsorted unique operations on strings. This improvement greatly reduces the time to find unique values in very large string datasets.

(gh-28767)

Rewrite of np.ndindex using itertools.product

The numpy.ndindex function now uses itertools.product internally, providing significant improvements in performance for large iteration spaces, while maintaining the original behavior and interface. For example, for an array of shape (50, 60, 90) the NumPy ndindex benchmark improves performance by a factor 5.2.

(gh-29165)

Performance improvements to np.unique for complex dtypes

The hash-based algorithm for unique extraction now also supports complex dtypes, offering noticeable performance gains.

In our benchmarks on complex128 arrays with 200,000 elements, the hash-based approach was about 1.4--1.5× faster than the sort-based baseline when there were 20% of unique values, and about 5× faster when there were 0.2% of unique values.

(gh-29537)

Changes
  • Multiplication between a string and integer now raises OverflowError instead of MemoryError if the result of the multiplication would create a string that is too large to be represented. This follows Python's behavior.

    (gh-29060)

  • The accuracy of np.quantile and np.percentile for 16- and 32-bit floating point input data has been improved.

    (gh-29105)

unique_values for string dtypes may return unsorted data

np.unique now supports hash‐based duplicate removal for string dtypes. This enhancement extends the hash-table algorithm to byte strings ('S'), Unicode strings ('U'), and the experimental string dtype ('T', StringDType). As a result, calling np.unique() on an array of strings will use the faster hash-based method to obtain unique values. Note that this hash-based method does not guarantee that the returned unique values will be sorted. This also works for StringDType arrays containing None (missing values) when using equal_nan=True (treating missing values as equal).

(gh-28767)

Modulate dispatched x86 CPU features

IMPORTANT: The default setting for cpu-baseline on x86 has been raised to x86-64-v2 microarchitecture. This can be changed to none during build time to support older CPUs, though SIMD optimizations for pre-2009 processors are no longer maintained.

NumPy has reorganized x86 CPU features into microarchitecture-based groups instead of individual features, aligning with Linux distribution standards and Google Highway requirements.

Key changes:

  • Replaced individual x86 features with microarchitecture levels: X86_V2, X86_V3, and X86_V4
  • Raised the baseline to X86_V2
  • Improved - operator behavior to properly exclude successor features that imply the excluded feature
  • Added meson redirections for removed feature names to maintain backward compatibility
  • Removed compiler compatibility workarounds for partial feature support (e.g., AVX512 without mask operations)
  • Removed legacy AMD features (XOP, FMA4) and discontinued Intel Xeon Phi support

New Feature Group Hierarchy:

Name Implies Includes


X86_V2 SSE SSE2 SSE3 SSSE3 SSE4_1 SSE4_2 POPCNT CX16 LAHF X86_V3 X86_V2 AVX AVX2 FMA3 BMI BMI2 LZCNT F16C MOVBE X86_V4 X86_V3 AVX512F AVX512CD AVX512VL AVX512BW AVX512DQ AVX512_ICL X86_V4 AVX512VBMI AVX512VBMI2 AVX512VNNI AVX512BITALG AVX512VPOPCNTDQ AVX512IFMA VAES GFNI VPCLMULQDQ AVX512_SPR AVX512_ICL AVX512FP16

These groups correspond to CPU generations:

  • X86_V2: x86-64-v2 microarchitectures (CPUs since 2009)
  • X86_V3: x86-64-v3 microarchitectures (CPUs since 2015)
  • X86_V4: x86-64-v4 microarchitectures (AVX-512 capable CPUs)
  • AVX512_ICL: Intel Ice Lake and similar CPUs
  • AVX512_SPR: Intel Sapphire Rapids and newer CPUs

On 32-bit x86, cx16 is excluded from X86_V2.

Documentation has been updated with details on using these new feature groups with the current meson build system.

(gh-28896)

Fix bug in matmul for non-contiguous out kwarg parameter

In some cases, if out was non-contiguous, np.matmul would cause memory corruption or a c-level assert. This was new to v2.3.0 and fixed in v2.3.1.

(gh-29179)

__array_interface__ with NULL pointer changed

The array interface now accepts NULL pointers (NumPy will do its own dummy allocation, though). Previously, these incorrectly triggered an undocumented scalar path. In the unlikely event that the scalar path was actually desired, you can (for now) achieve the previous behavior via the correct scalar path by not providing a data field at all.

(gh-29338)

unique_values for complex dtypes may return unsorted data

np.unique now supports hash‐based duplicate removal for complex dtypes. This enhancement extends the hash‐table algorithm to all complex types ('c'), and their extended precision variants. The hash‐based method provides faster extraction of unique values but does not guarantee that the result will be sorted.

(gh-29537)

Sorting kind='heapsort' now maps to kind='quicksort'

It is unlikely that this change will be noticed, but if you do see a change in execution time or unstable argsort order, that is likely the cause. Please let us know if there is a performance regression. Congratulate us if it is improved :)

(gh-29642)

numpy.typing.DTypeLike no longer accepts None

The type alias numpy.typing.DTypeLike no longer accepts None. Instead of

dtype: DTypeLike = None

it should now be

dtype: DTypeLike | None = None

instead.

(gh-29739)

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)

Discussion