Skip to main content
`Ctrl`+`K`

# NumPy 2.2.0 Release Notes

The NumPy 2.2.0 release is quick release that brings us back into sync with the usual twice yearly release cycle. There have been an number of small cleanups, as well as work bringing the new StringDType to completion and improving support for free threaded Python. Highlights are:

- New functions `matvec` and `vecmat`, see below.

- Many improved annotations.

- Improved support for the new StringDType.

- Improved support for free threaded Python

- Fixes for f2py

This release supports Python versions 3.10-3.13.

## Deprecations

- `_add_newdoc_ufunc` is now deprecated. `ufunc.__doc__ = newdoc` should be used instead.

  (gh-27735)

## Expired deprecations

- `bool(np.array([]))` and other empty arrays will now raise an error. Use `arr.size > 0` instead to check whether an array has no elements.

  (gh-27160)

## Compatibility notes

- `numpy.cov` now properly transposes single-row (2d array) design matrices when `rowvar=False`. Previously, single-row design matrices would return a scalar in this scenario, which is not correct, so this is a behavior change and an array of the appropriate shape will now be returned.

  (gh-27661)

## New Features

- New functions for matrix-vector and vector-matrix products

  Two new generalized ufuncs were defined:

  - `numpy.matvec` - matrix-vector product, treating the arguments as stacks of matrices and column vectors, respectively.

  - `numpy.vecmat` - vector-matrix product, treating the arguments as stacks of column vectors and matrices, respectively. For complex vectors, the conjugate is taken.

  These add to the existing `numpy.matmul` as well as to `numpy.vecdot`, which was added in numpy 2.0.

  Note that `numpy.matmul` never takes a complex conjugate, also not when its left input is a vector, while both `numpy.vecdot` and `numpy.vecmat` do take the conjugate for complex vectors on the left-hand side (which are taken to be the ones that are transposed, following the physics convention).

  (gh-25675)

- `np.complexfloating[T, T]` can now also be written as `np.complexfloating[T]`

  (gh-27420)

- UFuncs now support `__dict__` attribute and allow overriding `__doc__` (either directly or via `ufunc.__dict__["__doc__"]`). `__dict__` can be used to also override other properties, such as `__module__` or `__qualname__`.

  (gh-27735)

- The “nbit” type parameter of `np.number` and its subtypes now defaults to `typing.Any`. This way, type-checkers will infer annotations such as `x: np.floating` as `x: np.floating[Any]`, even in strict mode.

  (gh-27736)

## Improvements

- The `datetime64` and `timedelta64` hashes now correctly match the Pythons builtin `datetime` and `timedelta` ones. The hashes now evaluated equal even for equal values with different time units.

  (gh-14622)

- Fixed a number of issues around promotion for string ufuncs with StringDType arguments. Mixing StringDType and the fixed-width DTypes using the string ufuncs should now generate much more uniform results.

  (gh-27636)

- Improved support for empty `memmap`. Previously an empty `memmap` would fail unless a non-zero `offset` was set. Now a zero-size `memmap` is supported even if `offset=0`. To achieve this, if a `memmap` is mapped to an empty file that file is padded with a single byte.

  (gh-27723)

### `f2py` handles multiple modules and exposes variables again

A regression has been fixed which allows F2PY users to expose variables to Python in modules with only assignments, and also fixes situations where multiple modules are present within a single source file.

(gh-27695)

## Performance improvements and changes

- Improved multithreaded scaling on the free-threaded build when many threads simultaneously call the same ufunc operations.

  (gh-27896)

- NumPy now uses fast-on-failure attribute lookups for protocols. This can greatly reduce overheads of function calls or array creation especially with custom Python objects. The largest improvements will be seen on Python 3.12 or newer.

  (gh-27119)

- OpenBLAS on x86_64 and i686 is built with fewer kernels. Based on benchmarking, there are 5 clusters of performance around these kernels: `PRESCOTT NEHALEM SANDYBRIDGE HASWELL SKYLAKEX`.

- OpenBLAS on windows is linked without quadmath, simplifying licensing

- Due to a regression in OpenBLAS on windows, the performance improvements when using multiple threads for OpenBLAS 0.3.26 were reverted.

  (gh-27147)

- NumPy now indicates hugepages also for large `np.zeros` allocations on linux. Thus should generally improve performance.

  (gh-27808)

## Changes

- `numpy.fix` now won’t perform casting to a floating data-type for integer and boolean data-type input arrays.

  (gh-26766)

- The type annotations of `numpy.float64` and `numpy.complex128` now reflect that they are also subtypes of the built-in `float` and `complex` types, respectively. This update prevents static type-checkers from reporting errors in cases such as:

      x: float = numpy.float64(6.28)  # valid
      z: complex = numpy.complex128(-1j)  # valid

  (gh-27334)

- The `repr` of arrays large enough to be summarized (i.e., where elements are replaced with `...`) now includes the `shape` of the array, similar to what already was the case for arrays with zero size and non-obvious shape. With this change, the shape is always given when it cannot be inferred from the values. Note that while written as `shape=...`, this argument cannot actually be passed in to the `np.array` constructor. If you encounter problems, e.g., due to failing doctests, you can use the print option `legacy=2.1` to get the old behaviour.

  (gh-27482)

- Calling `__array_wrap__` directly on NumPy arrays or scalars now does the right thing when `return_scalar` is passed (Added in NumPy 2). It is further safe now to call the scalar `__array_wrap__` on a non-scalar result.

  (gh-27807)

Bump the musllinux CI image and wheels to 1_2 from 1_1. This is because 1_1 is end of life.

(gh-27088)

### NEP 50 promotion state option removed

The NEP 50 promotion state settings are now removed. They were always meant as temporary means for testing. A warning will be given if the environment variable is set to anything but `NPY_PROMOTION_STATE=weak` while `_set_promotion_state` and `_get_promotion_state` are removed. In case code used `_no_nep50_warning`, a `contextlib.nullcontext` could be used to replace it when not available.

(gh-27156)