summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
Diffstat (limited to 'numpy')
-rw-r--r--numpy/__init__.pyi181
-rw-r--r--numpy/core/_add_newdocs.py2
-rw-r--r--numpy/core/src/common/array_assign.c27
-rw-r--r--numpy/core/src/multiarray/arrayfunction_override.c4
-rw-r--r--numpy/core/src/multiarray/common.c21
-rw-r--r--numpy/core/src/multiarray/descriptor.c9
-rw-r--r--numpy/core/src/multiarray/multiarraymodule.c2
-rw-r--r--numpy/core/src/multiarray/nditer_constr.c234
-rw-r--r--numpy/core/src/multiarray/scalartypes.c.src38
-rw-r--r--numpy/core/src/multiarray/shape.c61
-rw-r--r--numpy/core/src/multiarray/shape.h7
-rw-r--r--numpy/core/src/umath/ufunc_object.c9
-rw-r--r--numpy/ma/core.py8
-rw-r--r--numpy/typing/_callable.py136
-rw-r--r--numpy/typing/tests/data/fail/arithmetic.py19
-rw-r--r--numpy/typing/tests/data/fail/scalars.py16
-rw-r--r--numpy/typing/tests/data/pass/arithmetic.py257
-rw-r--r--numpy/typing/tests/data/pass/scalars.py13
-rw-r--r--numpy/typing/tests/data/pass/ufuncs.py5
-rw-r--r--numpy/typing/tests/data/reveal/arithmetic.py256
-rw-r--r--numpy/typing/tests/data/reveal/scalars.py17
21 files changed, 987 insertions, 335 deletions
diff --git a/numpy/__init__.pyi b/numpy/__init__.pyi
index 30d15ed12..e712801eb 100644
--- a/numpy/__init__.pyi
+++ b/numpy/__init__.pyi
@@ -5,6 +5,18 @@ from abc import abstractmethod
from numpy.core._internal import _ctypes
from numpy.typing import ArrayLike, DtypeLike, _Shape, _ShapeLike
+from numpy.typing._callable import (
+ _BoolOp,
+ _BoolSub,
+ _BoolTrueDiv,
+ _TD64Div,
+ _IntTrueDiv,
+ _UnsignedIntOp,
+ _SignedIntOp,
+ _FloatOp,
+ _ComplexOp,
+ _NumberOp,
+)
from typing import (
Any,
@@ -646,23 +658,10 @@ class _ArrayOrScalarCommon(
def __ne__(self, other): ...
def __gt__(self, other): ...
def __ge__(self, other): ...
- def __add__(self, other): ...
- def __radd__(self, other): ...
- def __sub__(self, other): ...
- def __rsub__(self, other): ...
- def __mul__(self, other): ...
- def __rmul__(self, other): ...
- def __truediv__(self, other): ...
- def __rtruediv__(self, other): ...
- def __floordiv__(self, other): ...
- def __rfloordiv__(self, other): ...
def __mod__(self, other): ...
def __rmod__(self, other): ...
def __divmod__(self, other): ...
def __rdivmod__(self, other): ...
- # NumPy's __pow__ doesn't handle a third argument
- def __pow__(self, other): ...
- def __rpow__(self, other): ...
def __lshift__(self, other): ...
def __rlshift__(self, other): ...
def __rshift__(self, other): ...
@@ -834,14 +833,26 @@ class ndarray(_ArrayOrScalarCommon, Iterable, Sized, Container):
def __matmul__(self, other): ...
def __imatmul__(self, other): ...
def __rmatmul__(self, other): ...
+ def __add__(self, other: ArrayLike) -> Union[ndarray, generic]: ...
+ def __radd__(self, other: ArrayLike) -> Union[ndarray, generic]: ...
+ def __sub__(self, other: ArrayLike) -> Union[ndarray, generic]: ...
+ def __rsub__(self, other: ArrayLike) -> Union[ndarray, generic]: ...
+ def __mul__(self, other: ArrayLike) -> Union[ndarray, generic]: ...
+ def __rmul__(self, other: ArrayLike) -> Union[ndarray, generic]: ...
+ def __floordiv__(self, other: ArrayLike) -> Union[ndarray, generic]: ...
+ def __rfloordiv__(self, other: ArrayLike) -> Union[ndarray, generic]: ...
+ def __pow__(self, other: ArrayLike) -> Union[ndarray, generic]: ...
+ def __rpow__(self, other: ArrayLike) -> Union[ndarray, generic]: ...
+ def __truediv__(self, other: ArrayLike) -> Union[ndarray, generic]: ...
+ def __rtruediv__(self, other: ArrayLike) -> Union[ndarray, generic]: ...
# `np.generic` does not support inplace operations
- def __iadd__(self, other): ...
- def __isub__(self, other): ...
- def __imul__(self, other): ...
- def __itruediv__(self, other): ...
- def __ifloordiv__(self, other): ...
+ def __iadd__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __isub__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __imul__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __itruediv__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __ifloordiv__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __ipow__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
def __imod__(self, other): ...
- def __ipow__(self, other): ...
def __ilshift__(self, other): ...
def __irshift__(self, other): ...
def __iand__(self, other): ...
@@ -857,6 +868,11 @@ class ndarray(_ArrayOrScalarCommon, Iterable, Sized, Container):
# See https://github.com/numpy/numpy-stubs/pull/80 for more details.
_CharLike = Union[str, bytes]
+_BoolLike = Union[bool, bool_]
+_IntLike = Union[int, integer]
+_FloatLike = Union[_IntLike, float, floating]
+_ComplexLike = Union[_FloatLike, complex, complexfloating]
+_NumberLike = Union[int, float, complex, number, bool_]
class generic(_ArrayOrScalarCommon):
@abstractmethod
@@ -869,6 +885,19 @@ class number(generic): # type: ignore
def real(self: _ArraySelf) -> _ArraySelf: ...
@property
def imag(self: _ArraySelf) -> _ArraySelf: ...
+ # Ensure that objects annotated as `number` support arithmetic operations
+ __add__: _NumberOp
+ __radd__: _NumberOp
+ __sub__: _NumberOp
+ __rsub__: _NumberOp
+ __mul__: _NumberOp
+ __rmul__: _NumberOp
+ __floordiv__: _NumberOp
+ __rfloordiv__: _NumberOp
+ __pow__: _NumberOp
+ __rpow__: _NumberOp
+ __truediv__: _NumberOp
+ __rtruediv__: _NumberOp
class bool_(generic):
def __init__(self, __value: object = ...) -> None: ...
@@ -876,6 +905,18 @@ class bool_(generic):
def real(self: _ArraySelf) -> _ArraySelf: ...
@property
def imag(self: _ArraySelf) -> _ArraySelf: ...
+ __add__: _BoolOp[bool_]
+ __radd__: _BoolOp[bool_]
+ __sub__: _BoolSub
+ __rsub__: _BoolSub
+ __mul__: _BoolOp[bool_]
+ __rmul__: _BoolOp[bool_]
+ __floordiv__: _BoolOp[int8]
+ __rfloordiv__: _BoolOp[int8]
+ __pow__: _BoolOp[int8]
+ __rpow__: _BoolOp[int8]
+ __truediv__: _BoolTrueDiv
+ __rtruediv__: _BoolTrueDiv
class object_(generic):
def __init__(self, __value: object = ...) -> None: ...
@@ -892,10 +933,18 @@ class datetime64(generic):
__format: Union[_CharLike, Tuple[_CharLike, _IntLike]] = ...,
) -> None: ...
@overload
- def __init__(self, __value: int, __format: Union[_CharLike, Tuple[_CharLike, _IntLike]]) -> None: ...
- def __add__(self, other: Union[timedelta64, int]) -> datetime64: ...
- def __sub__(self, other: Union[timedelta64, datetime64, int]) -> timedelta64: ...
- def __rsub__(self, other: Union[datetime64, int]) -> timedelta64: ...
+ def __init__(
+ self,
+ __value: int,
+ __format: Union[_CharLike, Tuple[_CharLike, _IntLike]]
+ ) -> None: ...
+ def __add__(self, other: Union[timedelta64, _IntLike, _BoolLike]) -> datetime64: ...
+ def __radd__(self, other: Union[timedelta64, _IntLike, _BoolLike]) -> datetime64: ...
+ @overload
+ def __sub__(self, other: datetime64) -> timedelta64: ...
+ @overload
+ def __sub__(self, other: Union[timedelta64, _IntLike, _BoolLike]) -> datetime64: ...
+ def __rsub__(self, other: datetime64) -> timedelta64: ...
# Support for `__index__` was added in python 3.8 (bpo-20092)
if sys.version_info >= (3, 8):
@@ -911,8 +960,20 @@ class integer(number): # type: ignore
# NOTE: `__index__` is technically defined in the bottom-most
# sub-classes (`int64`, `uint32`, etc)
def __index__(self) -> int: ...
-
-class signedinteger(integer): ... # type: ignore
+ __truediv__: _IntTrueDiv
+ __rtruediv__: _IntTrueDiv
+
+class signedinteger(integer): # type: ignore
+ __add__: _SignedIntOp
+ __radd__: _SignedIntOp
+ __sub__: _SignedIntOp
+ __rsub__: _SignedIntOp
+ __mul__: _SignedIntOp
+ __rmul__: _SignedIntOp
+ __floordiv__: _SignedIntOp
+ __rfloordiv__: _SignedIntOp
+ __pow__: _SignedIntOp
+ __rpow__: _SignedIntOp
class int8(signedinteger):
def __init__(self, __value: _IntValue = ...) -> None: ...
@@ -926,24 +987,36 @@ class int32(signedinteger):
class int64(signedinteger):
def __init__(self, __value: _IntValue = ...) -> None: ...
-class timedelta64(signedinteger):
+class timedelta64(generic):
def __init__(
self,
__value: Union[None, int, _CharLike, dt.timedelta, timedelta64] = ...,
__format: Union[_CharLike, Tuple[_CharLike, _IntLike]] = ...,
) -> None: ...
- @overload
- def __add__(self, other: Union[timedelta64, int]) -> timedelta64: ...
- @overload
- def __add__(self, other: datetime64) -> datetime64: ...
- def __sub__(self, other: Union[timedelta64, int]) -> timedelta64: ...
- @overload
- def __truediv__(self, other: timedelta64) -> float: ...
- @overload
- def __truediv__(self, other: float) -> timedelta64: ...
+ def __add__(self, other: Union[timedelta64, _IntLike, _BoolLike]) -> timedelta64: ...
+ def __radd__(self, other: Union[timedelta64, _IntLike, _BoolLike]) -> timedelta64: ...
+ def __sub__(self, other: Union[timedelta64, _IntLike, _BoolLike]) -> timedelta64: ...
+ def __rsub__(self, other: Union[timedelta64, _IntLike, _BoolLike]) -> timedelta64: ...
+ def __mul__(self, other: Union[_FloatLike, _BoolLike]) -> timedelta64: ...
+ def __rmul__(self, other: Union[_FloatLike, _BoolLike]) -> timedelta64: ...
+ __truediv__: _TD64Div[float64]
+ __floordiv__: _TD64Div[signedinteger]
+ def __rtruediv__(self, other: timedelta64) -> float64: ...
+ def __rfloordiv__(self, other: timedelta64) -> signedinteger: ...
def __mod__(self, other: timedelta64) -> timedelta64: ...
-class unsignedinteger(integer): ... # type: ignore
+class unsignedinteger(integer): # type: ignore
+ # NOTE: `uint64 + signedinteger -> float64`
+ __add__: _UnsignedIntOp
+ __radd__: _UnsignedIntOp
+ __sub__: _UnsignedIntOp
+ __rsub__: _UnsignedIntOp
+ __mul__: _UnsignedIntOp
+ __rmul__: _UnsignedIntOp
+ __floordiv__: _UnsignedIntOp
+ __rfloordiv__: _UnsignedIntOp
+ __pow__: _UnsignedIntOp
+ __rpow__: _UnsignedIntOp
class uint8(unsignedinteger):
def __init__(self, __value: _IntValue = ...) -> None: ...
@@ -958,7 +1031,20 @@ class uint64(unsignedinteger):
def __init__(self, __value: _IntValue = ...) -> None: ...
class inexact(number): ... # type: ignore
-class floating(inexact): ... # type: ignore
+
+class floating(inexact): # type: ignore
+ __add__: _FloatOp
+ __radd__: _FloatOp
+ __sub__: _FloatOp
+ __rsub__: _FloatOp
+ __mul__: _FloatOp
+ __rmul__: _FloatOp
+ __truediv__: _FloatOp
+ __rtruediv__: _FloatOp
+ __floordiv__: _FloatOp
+ __rfloordiv__: _FloatOp
+ __pow__: _FloatOp
+ __rpow__: _FloatOp
_FloatType = TypeVar('_FloatType', bound=floating)
@@ -977,6 +1063,18 @@ class complexfloating(inexact, Generic[_FloatType]): # type: ignore
@property
def imag(self) -> _FloatType: ... # type: ignore[override]
def __abs__(self) -> _FloatType: ... # type: ignore[override]
+ __add__: _ComplexOp
+ __radd__: _ComplexOp
+ __sub__: _ComplexOp
+ __rsub__: _ComplexOp
+ __mul__: _ComplexOp
+ __rmul__: _ComplexOp
+ __truediv__: _ComplexOp
+ __rtruediv__: _ComplexOp
+ __floordiv__: _ComplexOp
+ __rfloordiv__: _ComplexOp
+ __pow__: _ComplexOp
+ __rpow__: _ComplexOp
class complex64(complexfloating[float32]):
def __init__(self, __value: _ComplexValue = ...) -> None: ...
@@ -987,7 +1085,7 @@ class complex128(complexfloating[float64], complex):
class flexible(generic): ... # type: ignore
class void(flexible):
- def __init__(self, __value: Union[int, integer, bool_, bytes]): ...
+ def __init__(self, __value: Union[_IntLike, _BoolLike, bytes]): ...
@property
def real(self: _ArraySelf) -> _ArraySelf: ...
@property
@@ -995,6 +1093,9 @@ class void(flexible):
class character(flexible): ... # type: ignore
+# NOTE: Most `np.bytes_` / `np.str_` methods return their
+# builtin `bytes` / `str` counterpart
+
class bytes_(character, bytes):
@overload
def __init__(self, __value: object = ...) -> None: ...
@@ -1396,7 +1497,3 @@ def sctype2char(sctype: object) -> str: ...
def find_common_type(
array_types: Sequence[DtypeLike], scalar_types: Sequence[DtypeLike]
) -> dtype: ...
-
-_NumberLike = Union[int, float, complex, number, bool_]
-_IntLike = Union[int, integer]
-_BoolLike = Union[bool, bool_]
diff --git a/numpy/core/_add_newdocs.py b/numpy/core/_add_newdocs.py
index 879b3645d..b8cf12c60 100644
--- a/numpy/core/_add_newdocs.py
+++ b/numpy/core/_add_newdocs.py
@@ -2618,7 +2618,7 @@ add_newdoc('numpy.core.multiarray', 'ndarray', ('argmin',
"""
a.argmin(axis=None, out=None)
- Return indices of the minimum values along the given axis of `a`.
+ Return indices of the minimum values along the given axis.
Refer to `numpy.argmin` for detailed documentation.
diff --git a/numpy/core/src/common/array_assign.c b/numpy/core/src/common/array_assign.c
index 67abcae24..c55f6bdb4 100644
--- a/numpy/core/src/common/array_assign.c
+++ b/numpy/core/src/common/array_assign.c
@@ -64,19 +64,22 @@ broadcast_strides(int ndim, npy_intp const *shape,
return 0;
broadcast_error: {
- PyObject *errmsg;
-
- errmsg = PyUnicode_FromFormat("could not broadcast %s from shape ",
- strides_name);
- PyUString_ConcatAndDel(&errmsg,
- build_shape_string(strides_ndim, strides_shape));
- PyUString_ConcatAndDel(&errmsg,
- PyUnicode_FromString(" into shape "));
- PyUString_ConcatAndDel(&errmsg,
- build_shape_string(ndim, shape));
- PyErr_SetObject(PyExc_ValueError, errmsg);
- Py_DECREF(errmsg);
+ PyObject *shape1 = convert_shape_to_string(strides_ndim,
+ strides_shape, "");
+ if (shape1 == NULL) {
+ return -1;
+ }
+ PyObject *shape2 = convert_shape_to_string(ndim, shape, "");
+ if (shape2 == NULL) {
+ Py_DECREF(shape1);
+ return -1;
+ }
+ PyErr_Format(PyExc_ValueError,
+ "could not broadcast %s from shape %S into shape %S",
+ strides_name, shape1, shape2);
+ Py_DECREF(shape1);
+ Py_DECREF(shape2);
return -1;
}
}
diff --git a/numpy/core/src/multiarray/arrayfunction_override.c b/numpy/core/src/multiarray/arrayfunction_override.c
index 613fe6b3f..8e3bde78f 100644
--- a/numpy/core/src/multiarray/arrayfunction_override.c
+++ b/numpy/core/src/multiarray/arrayfunction_override.c
@@ -388,15 +388,18 @@ array_implement_c_array_function_creation(
PyObject *numpy_module = PyImport_Import(npy_ma_str_numpy);
if (numpy_module == NULL) {
+ Py_DECREF(relevant_args);
return NULL;
}
PyObject *public_api = PyObject_GetAttrString(numpy_module, function_name);
Py_DECREF(numpy_module);
if (public_api == NULL) {
+ Py_DECREF(relevant_args);
return NULL;
}
if (!PyCallable_Check(public_api)) {
+ Py_DECREF(relevant_args);
Py_DECREF(public_api);
return PyErr_Format(PyExc_RuntimeError,
"numpy.%s is not callable.",
@@ -406,6 +409,7 @@ array_implement_c_array_function_creation(
PyObject* result = array_implement_array_function_internal(
public_api, relevant_args, args, kwargs);
+ Py_DECREF(relevant_args);
Py_DECREF(public_api);
return result;
}
diff --git a/numpy/core/src/multiarray/common.c b/numpy/core/src/multiarray/common.c
index 6af71f351..841ed799d 100644
--- a/numpy/core/src/multiarray/common.c
+++ b/numpy/core/src/multiarray/common.c
@@ -233,7 +233,6 @@ NPY_NO_EXPORT PyObject *
convert_shape_to_string(npy_intp n, npy_intp const *vals, char *ending)
{
npy_intp i;
- PyObject *ret, *tmp;
/*
* Negative dimension indicates "newaxis", which can
@@ -245,14 +244,14 @@ convert_shape_to_string(npy_intp n, npy_intp const *vals, char *ending)
if (i == n) {
return PyUnicode_FromFormat("()%s", ending);
}
- else {
- ret = PyUnicode_FromFormat("(%" NPY_INTP_FMT, vals[i++]);
- if (ret == NULL) {
- return NULL;
- }
- }
+ PyObject *ret = PyUnicode_FromFormat("%" NPY_INTP_FMT, vals[i++]);
+ if (ret == NULL) {
+ return NULL;
+ }
for (; i < n; ++i) {
+ PyObject *tmp;
+
if (vals[i] < 0) {
tmp = PyUnicode_FromString(",newaxis");
}
@@ -264,19 +263,19 @@ convert_shape_to_string(npy_intp n, npy_intp const *vals, char *ending)
return NULL;
}
- PyUString_ConcatAndDel(&ret, tmp);
+ Py_SETREF(ret, PyUnicode_Concat(ret, tmp));
+ Py_DECREF(tmp);
if (ret == NULL) {
return NULL;
}
}
if (i == 1) {
- tmp = PyUnicode_FromFormat(",)%s", ending);
+ Py_SETREF(ret, PyUnicode_FromFormat("(%S,)%s", ret, ending));
}
else {
- tmp = PyUnicode_FromFormat(")%s", ending);
+ Py_SETREF(ret, PyUnicode_FromFormat("(%S)%s", ret, ending));
}
- PyUString_ConcatAndDel(&ret, tmp);
return ret;
}
diff --git a/numpy/core/src/multiarray/descriptor.c b/numpy/core/src/multiarray/descriptor.c
index 257ededae..24a3507bc 100644
--- a/numpy/core/src/multiarray/descriptor.c
+++ b/numpy/core/src/multiarray/descriptor.c
@@ -2898,14 +2898,13 @@ arraydescr_setstate(PyArray_Descr *self, PyObject *args)
}
if (PyDataType_ISDATETIME(self) && (metadata != NULL)) {
- PyObject *old_metadata, *errmsg;
+ PyObject *old_metadata;
PyArray_DatetimeMetaData temp_dt_data;
if ((! PyTuple_Check(metadata)) || (PyTuple_Size(metadata) != 2)) {
- errmsg = PyUnicode_FromString("Invalid datetime dtype (metadata, c_metadata): ");
- PyUString_ConcatAndDel(&errmsg, PyObject_Repr(metadata));
- PyErr_SetObject(PyExc_ValueError, errmsg);
- Py_DECREF(errmsg);
+ PyErr_Format(PyExc_ValueError,
+ "Invalid datetime dtype (metadata, c_metadata): %R",
+ metadata);
return NULL;
}
diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c
index ff2b796d2..1aad70dc6 100644
--- a/numpy/core/src/multiarray/multiarraymodule.c
+++ b/numpy/core/src/multiarray/multiarraymodule.c
@@ -2296,6 +2296,7 @@ array_fromiter(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *keywds)
array_function_result = array_implement_c_array_function_creation(
"fromiter", args, keywds);
if (array_function_result != Py_NotImplemented) {
+ Py_DECREF(descr);
return array_function_result;
}
@@ -2942,6 +2943,7 @@ array_arange(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kws) {
array_function_result = array_implement_c_array_function_creation(
"arange", args, kws);
if (array_function_result != Py_NotImplemented) {
+ Py_XDECREF(typecode);
return array_function_result;
}
diff --git a/numpy/core/src/multiarray/nditer_constr.c b/numpy/core/src/multiarray/nditer_constr.c
index 4bc6d2ca1..b379a28ac 100644
--- a/numpy/core/src/multiarray/nditer_constr.c
+++ b/numpy/core/src/multiarray/nditer_constr.c
@@ -1750,73 +1750,70 @@ npyiter_fill_axisdata(NpyIter *iter, npy_uint32 flags, npyiter_opitflags *op_itf
return 1;
broadcast_error: {
- PyObject *errmsg, *tmp;
npy_intp remdims[NPY_MAXDIMS];
- char *tmpstr;
if (op_axes == NULL) {
- errmsg = PyUnicode_FromString("operands could not be broadcast "
- "together with shapes ");
- if (errmsg == NULL) {
+ PyObject *shape1 = PyUnicode_FromString("");
+ if (shape1 == NULL) {
return 0;
}
for (iop = 0; iop < nop; ++iop) {
if (op[iop] != NULL) {
- tmp = convert_shape_to_string(PyArray_NDIM(op[iop]),
- PyArray_DIMS(op[iop]),
- " ");
+ int ndims = PyArray_NDIM(op[iop]);
+ npy_intp *dims = PyArray_DIMS(op[iop]);
+ PyObject *tmp = convert_shape_to_string(ndims, dims, " ");
if (tmp == NULL) {
- Py_DECREF(errmsg);
+ Py_DECREF(shape1);
return 0;
}
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
+ Py_SETREF(shape1, PyUnicode_Concat(shape1, tmp));
+ Py_DECREF(tmp);
+ if (shape1 == NULL) {
return 0;
}
}
}
- if (itershape != NULL) {
- tmp = PyUnicode_FromString("and requested shape ");
- if (tmp == NULL) {
- Py_DECREF(errmsg);
- return 0;
- }
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
- return 0;
- }
-
- tmp = convert_shape_to_string(ndim, itershape, "");
- if (tmp == NULL) {
- Py_DECREF(errmsg);
- return 0;
- }
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
+ if (itershape == NULL) {
+ PyErr_Format(PyExc_ValueError,
+ "operands could not be broadcast together with "
+ "shapes %S", shape1);
+ Py_DECREF(shape1);
+ return 0;
+ }
+ else {
+ PyObject *shape2 = convert_shape_to_string(ndim, itershape, "");
+ if (shape2 == NULL) {
+ Py_DECREF(shape1);
return 0;
}
-
+ PyErr_Format(PyExc_ValueError,
+ "operands could not be broadcast together with "
+ "shapes %S and requested shape %S", shape1, shape2);
+ Py_DECREF(shape1);
+ Py_DECREF(shape2);
+ return 0;
}
- PyErr_SetObject(PyExc_ValueError, errmsg);
- Py_DECREF(errmsg);
}
else {
- errmsg = PyUnicode_FromString("operands could not be broadcast "
- "together with remapped shapes "
- "[original->remapped]: ");
+ PyObject *shape1 = PyUnicode_FromString("");
+ if (shape1 == NULL) {
+ return 0;
+ }
for (iop = 0; iop < nop; ++iop) {
if (op[iop] != NULL) {
int *axes = op_axes[iop];
+ int ndims = PyArray_NDIM(op[iop]);
+ npy_intp *dims = PyArray_DIMS(op[iop]);
+ char *tmpstr = (axes == NULL) ? " " : "->";
- tmpstr = (axes == NULL) ? " " : "->";
- tmp = convert_shape_to_string(PyArray_NDIM(op[iop]),
- PyArray_DIMS(op[iop]),
- tmpstr);
+ PyObject *tmp = convert_shape_to_string(ndims, dims, tmpstr);
if (tmp == NULL) {
+ Py_DECREF(shape1);
return 0;
}
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
+ Py_SETREF(shape1, PyUnicode_Concat(shape1, tmp));
+ Py_DECREF(tmp);
+ if (shape1 == NULL) {
return 0;
}
@@ -1831,80 +1828,83 @@ broadcast_error: {
remdims[idim] = -1;
}
}
- tmp = convert_shape_to_string(ndim, remdims, " ");
+ PyObject *tmp = convert_shape_to_string(ndim, remdims, " ");
if (tmp == NULL) {
+ Py_DECREF(shape1);
return 0;
}
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
+ Py_SETREF(shape1, PyUnicode_Concat(shape1, tmp));
+ Py_DECREF(tmp);
+ if (shape1 == NULL) {
return 0;
}
}
}
}
- if (itershape != NULL) {
- tmp = PyUnicode_FromString("and requested shape ");
- if (tmp == NULL) {
- Py_DECREF(errmsg);
- return 0;
- }
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
- return 0;
- }
-
- tmp = convert_shape_to_string(ndim, itershape, "");
- if (tmp == NULL) {
- Py_DECREF(errmsg);
- return 0;
- }
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
+ if (itershape == NULL) {
+ PyErr_Format(PyExc_ValueError,
+ "operands could not be broadcast together with "
+ "remapped shapes [original->remapped]: %S", shape1);
+ Py_DECREF(shape1);
+ return 0;
+ }
+ else {
+ PyObject *shape2 = convert_shape_to_string(ndim, itershape, "");
+ if (shape2 == NULL) {
+ Py_DECREF(shape1);
return 0;
}
-
+ PyErr_Format(PyExc_ValueError,
+ "operands could not be broadcast together with "
+ "remapped shapes [original->remapped]: %S and "
+ "requested shape %S", shape1, shape2);
+ Py_DECREF(shape1);
+ Py_DECREF(shape2);
+ return 0;
}
- PyErr_SetObject(PyExc_ValueError, errmsg);
- Py_DECREF(errmsg);
}
-
- return 0;
}
operand_different_than_broadcast: {
- npy_intp remdims[NPY_MAXDIMS];
- PyObject *errmsg, *tmp;
-
- /* Start of error message */
- if (op_flags[iop] & NPY_ITER_READONLY) {
- errmsg = PyUnicode_FromString("non-broadcastable operand "
- "with shape ");
- }
- else {
- errmsg = PyUnicode_FromString("non-broadcastable output "
- "operand with shape ");
- }
- if (errmsg == NULL) {
+ /* operand shape */
+ int ndims = PyArray_NDIM(op[iop]);
+ npy_intp *dims = PyArray_DIMS(op[iop]);
+ PyObject *shape1 = convert_shape_to_string(ndims, dims, "");
+ if (shape1 == NULL) {
return 0;
}
- /* Operand shape */
- tmp = convert_shape_to_string(PyArray_NDIM(op[iop]),
- PyArray_DIMS(op[iop]), "");
- if (tmp == NULL) {
+ /* Broadcast shape */
+ PyObject *shape2 = convert_shape_to_string(ndim, broadcast_shape, "");
+ if (shape2 == NULL) {
+ Py_DECREF(shape1);
return 0;
}
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
+
+ if (op_axes == NULL || op_axes[iop] == NULL) {
+ /* operand shape not remapped */
+
+ if (op_flags[iop] & NPY_ITER_READONLY) {
+ PyErr_Format(PyExc_ValueError,
+ "non-broadcastable operand with shape %S doesn't "
+ "match the broadcast shape %S", shape1, shape2);
+ }
+ else {
+ PyErr_Format(PyExc_ValueError,
+ "non-broadcastable output operand with shape %S doesn't "
+ "match the broadcast shape %S", shape1, shape2);
+ }
+ Py_DECREF(shape1);
+ Py_DECREF(shape2);
return 0;
}
- /* Remapped operand shape */
- if (op_axes != NULL && op_axes[iop] != NULL) {
- int *axes = op_axes[iop];
+ else {
+ /* operand shape remapped */
+ npy_intp remdims[NPY_MAXDIMS];
+ int *axes = op_axes[iop];
for (idim = 0; idim < ndim; ++idim) {
- npy_intp i = axes[ndim-idim-1];
-
+ npy_intp i = axes[ndim - idim - 1];
if (i >= 0 && i < PyArray_NDIM(op[iop])) {
remdims[idim] = PyArray_DIM(op[iop], i);
}
@@ -1913,48 +1913,30 @@ operand_different_than_broadcast: {
}
}
- tmp = PyUnicode_FromString(" [remapped to ");
- if (tmp == NULL) {
- return 0;
- }
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
+ PyObject *shape3 = convert_shape_to_string(ndim, remdims, "");
+ if (shape3 == NULL) {
+ Py_DECREF(shape1);
+ Py_DECREF(shape2);
return 0;
}
- tmp = convert_shape_to_string(ndim, remdims, "]");
- if (tmp == NULL) {
- return 0;
+ if (op_flags[iop] & NPY_ITER_READONLY) {
+ PyErr_Format(PyExc_ValueError,
+ "non-broadcastable operand with shape %S "
+ "[remapped to %S] doesn't match the broadcast shape %S",
+ shape1, shape3, shape2);
}
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
- return 0;
+ else {
+ PyErr_Format(PyExc_ValueError,
+ "non-broadcastable output operand with shape %S "
+ "[remapped to %S] doesn't match the broadcast shape %S",
+ shape1, shape3, shape2);
}
- }
-
- tmp = PyUnicode_FromString(" doesn't match the broadcast shape ");
- if (tmp == NULL) {
- return 0;
- }
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
+ Py_DECREF(shape1);
+ Py_DECREF(shape2);
+ Py_DECREF(shape3);
return 0;
}
-
- /* Broadcast shape */
- tmp = convert_shape_to_string(ndim, broadcast_shape, "");
- if (tmp == NULL) {
- return 0;
- }
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
- return 0;
- }
-
- PyErr_SetObject(PyExc_ValueError, errmsg);
- Py_DECREF(errmsg);
-
- return 0;
}
}
diff --git a/numpy/core/src/multiarray/scalartypes.c.src b/numpy/core/src/multiarray/scalartypes.c.src
index 74ee260af..1a50927a8 100644
--- a/numpy/core/src/multiarray/scalartypes.c.src
+++ b/numpy/core/src/multiarray/scalartypes.c.src
@@ -660,14 +660,12 @@ timedeltatype_str(PyObject *self)
* Can't use "%lld" if HAVE_LONG_LONG is not defined
*/
#if defined(HAVE_LONG_LONG)
- ret = PyUnicode_FromFormat("%lld ",
- (long long)(scal->obval * scal->obmeta.num));
+ ret = PyUnicode_FromFormat("%lld %s",
+ (long long)(scal->obval * scal->obmeta.num), basestr);
#else
- ret = PyUnicode_FromFormat("%ld ",
- (long)(scal->obval * scal->obmeta.num));
+ ret = PyUnicode_FromFormat("%ld %s",
+ (long)(scal->obval * scal->obmeta.num), basestr);
#endif
- PyUString_ConcatAndDel(&ret,
- PyUnicode_FromString(basestr));
}
return ret;
@@ -886,7 +884,7 @@ static PyObject *
static PyObject *
c@name@type_@kind@(PyObject *self)
{
- PyObject *rstr, *istr, *ret;
+ PyObject *rstr, *istr;
npy_c@name@ val = PyArrayScalar_VAL(self, C@Name@);
TrimMode trim = TrimMode_DptZeros;
@@ -899,16 +897,13 @@ c@name@type_@kind@(PyObject *self)
if (istr == NULL) {
return NULL;
}
-
- PyUString_ConcatAndDel(&istr, PyUnicode_FromString("j"));
- return istr;
+ PyObject *ret = PyUnicode_FromFormat("%Sj", istr);
+ Py_DECREF(istr);
+ return ret;
}
if (npy_isfinite(val.real)) {
rstr = @name@type_@kind@_either(val.real, trim, trim, 0);
- if (rstr == NULL) {
- return NULL;
- }
}
else if (npy_isnan(val.real)) {
rstr = PyUnicode_FromString("nan");
@@ -919,12 +914,12 @@ c@name@type_@kind@(PyObject *self)
else {
rstr = PyUnicode_FromString("-inf");
}
+ if (rstr == NULL) {
+ return NULL;
+ }
if (npy_isfinite(val.imag)) {
istr = @name@type_@kind@_either(val.imag, trim, trim, 1);
- if (istr == NULL) {
- return NULL;
- }
}
else if (npy_isnan(val.imag)) {
istr = PyUnicode_FromString("+nan");
@@ -935,11 +930,14 @@ c@name@type_@kind@(PyObject *self)
else {
istr = PyUnicode_FromString("-inf");
}
+ if (istr == NULL) {
+ Py_DECREF(rstr);
+ return NULL;
+ }
- ret = PyUnicode_FromString("(");
- PyUString_ConcatAndDel(&ret, rstr);
- PyUString_ConcatAndDel(&ret, istr);
- PyUString_ConcatAndDel(&ret, PyUnicode_FromString("j)"));
+ PyObject *ret = PyUnicode_FromFormat("(%S%Sj)", rstr, istr);
+ Py_DECREF(rstr);
+ Py_DECREF(istr);
return ret;
}
diff --git a/numpy/core/src/multiarray/shape.c b/numpy/core/src/multiarray/shape.c
index 1a38fe956..02c349759 100644
--- a/numpy/core/src/multiarray/shape.c
+++ b/numpy/core/src/multiarray/shape.c
@@ -458,14 +458,12 @@ _attempt_nocopy_reshape(PyArrayObject *self, int newnd, const npy_intp *newdims,
static void
raise_reshape_size_mismatch(PyArray_Dims *newshape, PyArrayObject *arr)
{
- PyObject *msg = PyUnicode_FromFormat("cannot reshape array of size %zd "
- "into shape ", PyArray_SIZE(arr));
PyObject *tmp = convert_shape_to_string(newshape->len, newshape->ptr, "");
-
- PyUString_ConcatAndDel(&msg, tmp);
- if (msg != NULL) {
- PyErr_SetObject(PyExc_ValueError, msg);
- Py_DECREF(msg);
+ if (tmp != NULL) {
+ PyErr_Format(PyExc_ValueError,
+ "cannot reshape array of size %zd into shape %S",
+ PyArray_SIZE(arr), tmp);
+ Py_DECREF(tmp);
}
}
@@ -979,55 +977,6 @@ PyArray_Flatten(PyArrayObject *a, NPY_ORDER order)
return (PyObject *)ret;
}
-/* See shape.h for parameters documentation */
-NPY_NO_EXPORT PyObject *
-build_shape_string(npy_intp n, npy_intp const *vals)
-{
- npy_intp i;
- PyObject *ret, *tmp;
-
- /*
- * Negative dimension indicates "newaxis", which can
- * be discarded for printing if it's a leading dimension.
- * Find the first non-"newaxis" dimension.
- */
- i = 0;
- while (i < n && vals[i] < 0) {
- ++i;
- }
-
- if (i == n) {
- return PyUnicode_FromFormat("()");
- }
- else {
- ret = PyUnicode_FromFormat("(%" NPY_INTP_FMT, vals[i++]);
- if (ret == NULL) {
- return NULL;
- }
- }
-
- for (; i < n; ++i) {
- if (vals[i] < 0) {
- tmp = PyUnicode_FromString(",newaxis");
- }
- else {
- tmp = PyUnicode_FromFormat(",%" NPY_INTP_FMT, vals[i]);
- }
- if (tmp == NULL) {
- Py_DECREF(ret);
- return NULL;
- }
-
- PyUString_ConcatAndDel(&ret, tmp);
- if (ret == NULL) {
- return NULL;
- }
- }
-
- tmp = PyUnicode_FromFormat(")");
- PyUString_ConcatAndDel(&ret, tmp);
- return ret;
-}
/*NUMPY_API
*
diff --git a/numpy/core/src/multiarray/shape.h b/numpy/core/src/multiarray/shape.h
index d25292556..875b5430f 100644
--- a/numpy/core/src/multiarray/shape.h
+++ b/numpy/core/src/multiarray/shape.h
@@ -2,13 +2,6 @@
#define _NPY_ARRAY_SHAPE_H_
/*
- * Builds a string representation of the shape given in 'vals'.
- * A negative value in 'vals' gets interpreted as newaxis.
- */
-NPY_NO_EXPORT PyObject *
-build_shape_string(npy_intp n, npy_intp const *vals);
-
-/*
* Creates a sorted stride perm matching the KEEPORDER behavior
* of the NpyIter object. Because this operates based on multiple
* input strides, the 'stride' member of the npy_stride_sort_item
diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c
index f693eb5c2..8660ee413 100644
--- a/numpy/core/src/umath/ufunc_object.c
+++ b/numpy/core/src/umath/ufunc_object.c
@@ -5977,6 +5977,7 @@ _typecharfromnum(int num) {
return ret;
}
+
static PyObject *
ufunc_get_doc(PyUFuncObject *ufunc)
{
@@ -5997,18 +5998,18 @@ ufunc_get_doc(PyUFuncObject *ufunc)
* introspection on name and nin + nout to automate the first part
* of it the doc string shouldn't need the calling convention
*/
- doc = PyObject_CallFunctionObjArgs(
- _sig_formatter, (PyObject *)ufunc, NULL);
+ doc = PyObject_CallFunctionObjArgs(_sig_formatter,
+ (PyObject *)ufunc, NULL);
if (doc == NULL) {
return NULL;
}
if (ufunc->doc != NULL) {
- PyUString_ConcatAndDel(&doc,
- PyUnicode_FromFormat("\n\n%s", ufunc->doc));
+ Py_SETREF(doc, PyUnicode_FromFormat("%S\n\n%s", doc, ufunc->doc));
}
return doc;
}
+
static PyObject *
ufunc_get_nin(PyUFuncObject *ufunc)
{
diff --git a/numpy/ma/core.py b/numpy/ma/core.py
index b5371f51a..4e320576b 100644
--- a/numpy/ma/core.py
+++ b/numpy/ma/core.py
@@ -443,9 +443,9 @@ def _check_fill_value(fill_value, ndtype):
if isinstance(fill_value, (ndarray, np.void)):
try:
fill_value = np.array(fill_value, copy=False, dtype=ndtype)
- except ValueError:
+ except ValueError as e:
err_msg = "Unable to transform %s to dtype %s"
- raise ValueError(err_msg % (fill_value, ndtype))
+ raise ValueError(err_msg % (fill_value, ndtype)) from e
else:
fill_value = np.asarray(fill_value, dtype=object)
fill_value = np.array(_recursive_set_fill_value(fill_value, ndtype),
@@ -460,12 +460,12 @@ def _check_fill_value(fill_value, ndtype):
# Also in case of converting string arrays.
try:
fill_value = np.array(fill_value, copy=False, dtype=ndtype)
- except (OverflowError, ValueError):
+ except (OverflowError, ValueError) as e:
# Raise TypeError instead of OverflowError or ValueError.
# OverflowError is seldom used, and the real problem here is
# that the passed fill_value is not compatible with the ndtype.
err_msg = "Cannot convert fill_value %s to dtype %s"
- raise TypeError(err_msg % (fill_value, ndtype))
+ raise TypeError(err_msg % (fill_value, ndtype)) from e
return np.array(fill_value)
diff --git a/numpy/typing/_callable.py b/numpy/typing/_callable.py
new file mode 100644
index 000000000..5e14b708f
--- /dev/null
+++ b/numpy/typing/_callable.py
@@ -0,0 +1,136 @@
+"""
+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
+
+"""
+
+import sys
+from typing import Union, TypeVar, overload, Any
+
+from numpy import (
+ _BoolLike,
+ _IntLike,
+ _FloatLike,
+ _ComplexLike,
+ _NumberLike,
+ generic,
+ bool_,
+ timedelta64,
+ number,
+ integer,
+ unsignedinteger,
+ signedinteger,
+ int32,
+ int64,
+ floating,
+ float32,
+ float64,
+ complexfloating,
+ complex128,
+)
+
+if sys.version_info >= (3, 8):
+ from typing import Protocol
+ HAVE_PROTOCOL = True
+else:
+ try:
+ from typing_extensions import Protocol
+ except ImportError:
+ HAVE_PROTOCOL = False
+ else:
+ HAVE_PROTOCOL = True
+
+if HAVE_PROTOCOL:
+ _NumberType = TypeVar("_NumberType", bound=number)
+ _NumberType_co = TypeVar("_NumberType_co", covariant=True, bound=number)
+ _GenericType_co = TypeVar("_GenericType_co", covariant=True, bound=generic)
+
+ class _BoolOp(Protocol[_GenericType_co]):
+ @overload
+ def __call__(self, __other: _BoolLike) -> _GenericType_co: ...
+ @overload # platform dependent
+ def __call__(self, __other: int) -> Union[int32, int64]: ...
+ @overload
+ def __call__(self, __other: float) -> float64: ...
+ @overload
+ def __call__(self, __other: complex) -> complex128: ...
+ @overload
+ def __call__(self, __other: _NumberType) -> _NumberType: ...
+
+ class _BoolSub(Protocol):
+ # Note that `__other: bool_` is absent here
+ @overload # platform dependent
+ def __call__(self, __other: int) -> Union[int32, int64]: ...
+ @overload
+ def __call__(self, __other: float) -> float64: ...
+ @overload
+ def __call__(self, __other: complex) -> complex128: ...
+ @overload
+ def __call__(self, __other: _NumberType) -> _NumberType: ...
+
+ class _BoolTrueDiv(Protocol):
+ @overload
+ def __call__(self, __other: Union[float, _IntLike, _BoolLike]) -> float64: ...
+ @overload
+ def __call__(self, __other: complex) -> complex128: ...
+ @overload
+ def __call__(self, __other: _NumberType) -> _NumberType: ...
+
+ class _TD64Div(Protocol[_NumberType_co]):
+ @overload
+ def __call__(self, __other: timedelta64) -> _NumberType_co: ...
+ @overload
+ def __call__(self, __other: _FloatLike) -> timedelta64: ...
+
+ class _IntTrueDiv(Protocol):
+ @overload
+ def __call__(self, __other: Union[_IntLike, float]) -> floating: ...
+ @overload
+ def __call__(self, __other: complex) -> complexfloating[floating]: ...
+
+ class _UnsignedIntOp(Protocol):
+ # NOTE: `uint64 + signedinteger -> float64`
+ @overload
+ def __call__(self, __other: Union[bool, unsignedinteger]) -> unsignedinteger: ...
+ @overload
+ def __call__(self, __other: Union[int, signedinteger]) -> Union[signedinteger, float64]: ...
+ @overload
+ def __call__(self, __other: float) -> floating: ...
+ @overload
+ def __call__(self, __other: complex) -> complexfloating[floating]: ...
+
+ class _SignedIntOp(Protocol):
+ @overload
+ def __call__(self, __other: Union[int, signedinteger]) -> signedinteger: ...
+ @overload
+ def __call__(self, __other: float) -> floating: ...
+ @overload
+ def __call__(self, __other: complex) -> complexfloating[floating]: ...
+
+ class _FloatOp(Protocol):
+ @overload
+ def __call__(self, __other: _FloatLike) -> floating: ...
+ @overload
+ def __call__(self, __other: complex) -> complexfloating[floating]: ...
+
+ class _ComplexOp(Protocol):
+ def __call__(self, __other: _ComplexLike) -> complexfloating[floating]: ...
+
+ class _NumberOp(Protocol):
+ def __call__(self, __other: _NumberLike) -> number: ...
+
+else:
+ _BoolOp = Any
+ _BoolSub = Any
+ _BoolTrueDiv = Any
+ _TD64Div = Any
+ _IntTrueDiv = Any
+ _UnsignedIntOp = Any
+ _SignedIntOp = Any
+ _FloatOp = Any
+ _ComplexOp = Any
+ _NumberOp = Any
diff --git a/numpy/typing/tests/data/fail/arithmetic.py b/numpy/typing/tests/data/fail/arithmetic.py
new file mode 100644
index 000000000..169e104f9
--- /dev/null
+++ b/numpy/typing/tests/data/fail/arithmetic.py
@@ -0,0 +1,19 @@
+import numpy as np
+
+b_ = np.bool_()
+dt = np.datetime64(0, "D")
+td = np.timedelta64(0, "D")
+
+b_ - b_ # E: No overload variant
+
+dt + dt # E: Unsupported operand types
+td - dt # E: Unsupported operand types
+td % 1 # E: Unsupported operand types
+td / dt # E: No overload
+
+# NOTE: The 1 tests below currently don't work due to the broad
+# (i.e. untyped) signature of `.__mod__()`.
+# TODO: Revisit this once annotations are added to the
+# `_ArrayOrScalarCommon` magic methods.
+
+# td % dt # E: Unsupported operand types
diff --git a/numpy/typing/tests/data/fail/scalars.py b/numpy/typing/tests/data/fail/scalars.py
index 47c031163..13bb45483 100644
--- a/numpy/typing/tests/data/fail/scalars.py
+++ b/numpy/typing/tests/data/fail/scalars.py
@@ -28,22 +28,6 @@ np.complex64(1, 2) # E: Too many arguments
np.datetime64(0) # E: non-matching overload
-dt_64 = np.datetime64(0, "D")
-td_64 = np.timedelta64(1, "h")
-
-dt_64 + dt_64 # E: Unsupported operand types
-td_64 - dt_64 # E: Unsupported operand types
-td_64 % 1 # E: Unsupported operand types
-
-# NOTE: The 2 tests below currently don't work due to the broad
-# (i.e. untyped) signature of `generic.__truediv__()` and `.__mod__()`.
-# TODO: Revisit this once annotations are added to the
-# `_ArrayOrScalarCommon` magic methods.
-
-# td_64 / dt_64 # E: No overload
-# td_64 % dt_64 # E: Unsupported operand types
-
-
class A:
def __float__(self):
return 1.0
diff --git a/numpy/typing/tests/data/pass/arithmetic.py b/numpy/typing/tests/data/pass/arithmetic.py
new file mode 100644
index 000000000..f26eab879
--- /dev/null
+++ b/numpy/typing/tests/data/pass/arithmetic.py
@@ -0,0 +1,257 @@
+import numpy as np
+
+c16 = np.complex128(1)
+f8 = np.float64(1)
+i8 = np.int64(1)
+u8 = np.uint64(1)
+
+c8 = np.complex64(1)
+f4 = np.float32(1)
+i4 = np.int32(1)
+u4 = np.uint32(1)
+
+dt = np.datetime64(1, "D")
+td = np.timedelta64(1, "D")
+
+b_ = np.bool_(1)
+
+b = bool(1)
+c = complex(1)
+f = float(1)
+i = int(1)
+
+AR = np.ones(1, dtype=np.float64)
+AR.setflags(write=False)
+
+# Time structures
+
+dt + td
+dt + i
+dt + i4
+dt + i8
+dt - dt
+dt - i
+dt - i4
+dt - i8
+
+td + td
+td + i
+td + i4
+td + i8
+td - td
+td - i
+td - i4
+td - i8
+td / f
+td / f4
+td / f8
+td / td
+td // td
+td % td
+
+
+# boolean
+
+b_ / b
+b_ / b_
+b_ / i
+b_ / i8
+b_ / i4
+b_ / u8
+b_ / u4
+b_ / f
+b_ / f8
+b_ / f4
+b_ / c
+b_ / c16
+b_ / c8
+
+b / b_
+b_ / b_
+i / b_
+i8 / b_
+i4 / b_
+u8 / b_
+u4 / b_
+f / b_
+f8 / b_
+f4 / b_
+c / b_
+c16 / b_
+c8 / b_
+
+# Complex
+
+c16 + c16
+c16 + f8
+c16 + i8
+c16 + c8
+c16 + f4
+c16 + i4
+c16 + b_
+c16 + b
+c16 + c
+c16 + f
+c16 + i
+c16 + AR
+
+c16 + c16
+f8 + c16
+i8 + c16
+c8 + c16
+f4 + c16
+i4 + c16
+b_ + c16
+b + c16
+c + c16
+f + c16
+i + c16
+AR + c16
+
+c8 + c16
+c8 + f8
+c8 + i8
+c8 + c8
+c8 + f4
+c8 + i4
+c8 + b_
+c8 + b
+c8 + c
+c8 + f
+c8 + i
+c8 + AR
+
+c16 + c8
+f8 + c8
+i8 + c8
+c8 + c8
+f4 + c8
+i4 + c8
+b_ + c8
+b + c8
+c + c8
+f + c8
+i + c8
+AR + c8
+
+# Float
+
+f8 + f8
+f8 + i8
+f8 + f4
+f8 + i4
+f8 + b_
+f8 + b
+f8 + c
+f8 + f
+f8 + i
+f8 + AR
+
+f8 + f8
+i8 + f8
+f4 + f8
+i4 + f8
+b_ + f8
+b + f8
+c + f8
+f + f8
+i + f8
+AR + f8
+
+f4 + f8
+f4 + i8
+f4 + f4
+f4 + i4
+f4 + b_
+f4 + b
+f4 + c
+f4 + f
+f4 + i
+f4 + AR
+
+f8 + f4
+i8 + f4
+f4 + f4
+i4 + f4
+b_ + f4
+b + f4
+c + f4
+f + f4
+i + f4
+AR + f4
+
+# Int
+
+i8 + i8
+i8 + u8
+i8 + i4
+i8 + u4
+i8 + b_
+i8 + b
+i8 + c
+i8 + f
+i8 + i
+i8 + AR
+
+u8 + u8
+u8 + i4
+u8 + u4
+u8 + b_
+u8 + b
+u8 + c
+u8 + f
+u8 + i
+u8 + AR
+
+i8 + i8
+u8 + i8
+i4 + i8
+u4 + i8
+b_ + i8
+b + i8
+c + i8
+f + i8
+i + i8
+AR + i8
+
+u8 + u8
+i4 + u8
+u4 + u8
+b_ + u8
+b + u8
+c + u8
+f + u8
+i + u8
+AR + u8
+
+i4 + i8
+i4 + i4
+i4 + i
+i4 + b_
+i4 + b
+i4 + AR
+
+u4 + i8
+u4 + i4
+u4 + u8
+u4 + u4
+u4 + i
+u4 + b_
+u4 + b
+u4 + AR
+
+i8 + i4
+i4 + i4
+i + i4
+b_ + i4
+b + i4
+AR + i4
+
+i8 + u4
+i4 + u4
+u8 + u4
+u4 + u4
+b_ + u4
+b + u4
+i + u4
+AR + u4
diff --git a/numpy/typing/tests/data/pass/scalars.py b/numpy/typing/tests/data/pass/scalars.py
index c02e1ed36..49ddb8ed9 100644
--- a/numpy/typing/tests/data/pass/scalars.py
+++ b/numpy/typing/tests/data/pass/scalars.py
@@ -108,19 +108,6 @@ np.timedelta64(dt.timedelta(2))
np.timedelta64(None)
np.timedelta64(None, "D")
-dt_64 = np.datetime64(0, "D")
-td_64 = np.timedelta64(1, "h")
-
-dt_64 + td_64
-dt_64 - dt_64
-dt_64 - td_64
-
-td_64 + td_64
-td_64 - td_64
-td_64 / 1.0
-td_64 / td_64
-td_64 % td_64
-
np.void(1)
np.void(np.int64(1))
np.void(True)
diff --git a/numpy/typing/tests/data/pass/ufuncs.py b/numpy/typing/tests/data/pass/ufuncs.py
index 82172952a..ad4d483d4 100644
--- a/numpy/typing/tests/data/pass/ufuncs.py
+++ b/numpy/typing/tests/data/pass/ufuncs.py
@@ -6,7 +6,10 @@ np.sin(1, out=np.empty(1))
np.matmul(np.ones((2, 2, 2)), np.ones((2, 2, 2)), axes=[(0, 1), (0, 1), (0, 1)])
np.sin(1, signature="D")
np.sin(1, extobj=[16, 1, lambda: None])
-np.sin(1) + np.sin(1)
+# NOTE: `np.generic` subclasses are not guaranteed to support addition;
+# re-enable this we can infer the exact return type of `np.sin(...)`.
+#
+# np.sin(1) + np.sin(1)
np.sin.types[0]
np.sin.__name__
diff --git a/numpy/typing/tests/data/reveal/arithmetic.py b/numpy/typing/tests/data/reveal/arithmetic.py
new file mode 100644
index 000000000..b8c457aaf
--- /dev/null
+++ b/numpy/typing/tests/data/reveal/arithmetic.py
@@ -0,0 +1,256 @@
+import numpy as np
+
+c16 = np.complex128()
+f8 = np.float64()
+i8 = np.int64()
+u8 = np.uint64()
+
+c8 = np.complex64()
+f4 = np.float32()
+i4 = np.int32()
+u4 = np.uint32()
+
+dt = np.datetime64(0, "D")
+td = np.timedelta64(0, "D")
+
+b_ = np.bool_()
+
+b = bool()
+c = complex()
+f = float()
+i = int()
+
+AR = np.array([0], dtype=np.float64)
+AR.setflags(write=False)
+
+# Time structures
+
+reveal_type(dt + td) # E: numpy.datetime64
+reveal_type(dt + i) # E: numpy.datetime64
+reveal_type(dt + i4) # E: numpy.datetime64
+reveal_type(dt + i8) # E: numpy.datetime64
+reveal_type(dt - dt) # E: numpy.timedelta64
+reveal_type(dt - i) # E: numpy.datetime64
+reveal_type(dt - i4) # E: numpy.datetime64
+reveal_type(dt - i8) # E: numpy.datetime64
+
+reveal_type(td + td) # E: numpy.timedelta64
+reveal_type(td + i) # E: numpy.timedelta64
+reveal_type(td + i4) # E: numpy.timedelta64
+reveal_type(td + i8) # E: numpy.timedelta64
+reveal_type(td - td) # E: numpy.timedelta64
+reveal_type(td - i) # E: numpy.timedelta64
+reveal_type(td - i4) # E: numpy.timedelta64
+reveal_type(td - i8) # E: numpy.timedelta64
+reveal_type(td / f) # E: numpy.timedelta64
+reveal_type(td / f4) # E: numpy.timedelta64
+reveal_type(td / f8) # E: numpy.timedelta64
+reveal_type(td / td) # E: float64
+reveal_type(td // td) # E: signedinteger
+reveal_type(td % td) # E: numpy.timedelta64
+
+# boolean
+
+reveal_type(b_ / b) # E: float64
+reveal_type(b_ / b_) # E: float64
+reveal_type(b_ / i) # E: float64
+reveal_type(b_ / i8) # E: float64
+reveal_type(b_ / i4) # E: float64
+reveal_type(b_ / u8) # E: float64
+reveal_type(b_ / u4) # E: float64
+reveal_type(b_ / f) # E: float64
+reveal_type(b_ / f8) # E: float64
+reveal_type(b_ / f4) # E: float32
+reveal_type(b_ / c) # E: complex128
+reveal_type(b_ / c16) # E: complex128
+reveal_type(b_ / c8) # E: complex64
+
+reveal_type(b / b_) # E: float64
+reveal_type(b_ / b_) # E: float64
+reveal_type(i / b_) # E: float64
+reveal_type(i8 / b_) # E: float64
+reveal_type(i4 / b_) # E: float64
+reveal_type(u8 / b_) # E: float64
+reveal_type(u4 / b_) # E: float64
+reveal_type(f / b_) # E: float64
+reveal_type(f8 / b_) # E: float64
+reveal_type(f4 / b_) # E: float32
+reveal_type(c / b_) # E: complex128
+reveal_type(c16 / b_) # E: complex128
+reveal_type(c8 / b_) # E: complex64
+
+# Complex
+
+reveal_type(c16 + c16) # E: complexfloating
+reveal_type(c16 + f8) # E: complexfloating
+reveal_type(c16 + i8) # E: complexfloating
+reveal_type(c16 + c8) # E: complexfloating
+reveal_type(c16 + f4) # E: complexfloating
+reveal_type(c16 + i4) # E: complexfloating
+reveal_type(c16 + b_) # E: complex128
+reveal_type(c16 + b) # E: complexfloating
+reveal_type(c16 + c) # E: complexfloating
+reveal_type(c16 + f) # E: complexfloating
+reveal_type(c16 + i) # E: complexfloating
+reveal_type(c16 + AR) # E: Union[numpy.ndarray, numpy.generic]
+
+reveal_type(c16 + c16) # E: complexfloating
+reveal_type(f8 + c16) # E: complexfloating
+reveal_type(i8 + c16) # E: complexfloating
+reveal_type(c8 + c16) # E: complexfloating
+reveal_type(f4 + c16) # E: complexfloating
+reveal_type(i4 + c16) # E: complexfloating
+reveal_type(b_ + c16) # E: complex128
+reveal_type(b + c16) # E: complexfloating
+reveal_type(c + c16) # E: complexfloating
+reveal_type(f + c16) # E: complexfloating
+reveal_type(i + c16) # E: complexfloating
+reveal_type(AR + c16) # E: Union[numpy.ndarray, numpy.generic]
+
+reveal_type(c8 + c16) # E: complexfloating
+reveal_type(c8 + f8) # E: complexfloating
+reveal_type(c8 + i8) # E: complexfloating
+reveal_type(c8 + c8) # E: complexfloating
+reveal_type(c8 + f4) # E: complexfloating
+reveal_type(c8 + i4) # E: complexfloating
+reveal_type(c8 + b_) # E: complex64
+reveal_type(c8 + b) # E: complexfloating
+reveal_type(c8 + c) # E: complexfloating
+reveal_type(c8 + f) # E: complexfloating
+reveal_type(c8 + i) # E: complexfloating
+reveal_type(c8 + AR) # E: Union[numpy.ndarray, numpy.generic]
+
+reveal_type(c16 + c8) # E: complexfloating
+reveal_type(f8 + c8) # E: complexfloating
+reveal_type(i8 + c8) # E: complexfloating
+reveal_type(c8 + c8) # E: complexfloating
+reveal_type(f4 + c8) # E: complexfloating
+reveal_type(i4 + c8) # E: complexfloating
+reveal_type(b_ + c8) # E: complex64
+reveal_type(b + c8) # E: complexfloating
+reveal_type(c + c8) # E: complexfloating
+reveal_type(f + c8) # E: complexfloating
+reveal_type(i + c8) # E: complexfloating
+reveal_type(AR + c8) # E: Union[numpy.ndarray, numpy.generic]
+
+# Float
+
+reveal_type(f8 + f8) # E: floating
+reveal_type(f8 + i8) # E: floating
+reveal_type(f8 + f4) # E: floating
+reveal_type(f8 + i4) # E: floating
+reveal_type(f8 + b_) # E: float64
+reveal_type(f8 + b) # E: floating
+reveal_type(f8 + c) # E: complexfloating
+reveal_type(f8 + f) # E: floating
+reveal_type(f8 + i) # E: floating
+reveal_type(f8 + AR) # E: Union[numpy.ndarray, numpy.generic]
+
+reveal_type(f8 + f8) # E: floating
+reveal_type(i8 + f8) # E: floating
+reveal_type(f4 + f8) # E: floating
+reveal_type(i4 + f8) # E: floating
+reveal_type(b_ + f8) # E: float64
+reveal_type(b + f8) # E: floating
+reveal_type(c + f8) # E: complexfloating
+reveal_type(f + f8) # E: floating
+reveal_type(i + f8) # E: floating
+reveal_type(AR + f8) # E: Union[numpy.ndarray, numpy.generic]
+
+reveal_type(f4 + f8) # E: floating
+reveal_type(f4 + i8) # E: floating
+reveal_type(f4 + f4) # E: floating
+reveal_type(f4 + i4) # E: floating
+reveal_type(f4 + b_) # E: float32
+reveal_type(f4 + b) # E: floating
+reveal_type(f4 + c) # E: complexfloating
+reveal_type(f4 + f) # E: floating
+reveal_type(f4 + i) # E: floating
+reveal_type(f4 + AR) # E: Union[numpy.ndarray, numpy.generic]
+
+reveal_type(f8 + f4) # E: floating
+reveal_type(i8 + f4) # E: floating
+reveal_type(f4 + f4) # E: floating
+reveal_type(i4 + f4) # E: floating
+reveal_type(b_ + f4) # E: float32
+reveal_type(b + f4) # E: floating
+reveal_type(c + f4) # E: complexfloating
+reveal_type(f + f4) # E: floating
+reveal_type(i + f4) # E: floating
+reveal_type(AR + f4) # E: Union[numpy.ndarray, numpy.generic]
+
+# Int
+
+reveal_type(i8 + i8) # E: signedinteger
+reveal_type(i8 + u8) # E: Union[numpy.signedinteger, numpy.float64]
+reveal_type(i8 + i4) # E: signedinteger
+reveal_type(i8 + u4) # E: Union[numpy.signedinteger, numpy.float64]
+reveal_type(i8 + b_) # E: int64
+reveal_type(i8 + b) # E: signedinteger
+reveal_type(i8 + c) # E: complexfloating
+reveal_type(i8 + f) # E: floating
+reveal_type(i8 + i) # E: signedinteger
+reveal_type(i8 + AR) # E: Union[numpy.ndarray, numpy.generic]
+
+reveal_type(u8 + u8) # E: unsignedinteger
+reveal_type(u8 + i4) # E: Union[numpy.signedinteger, numpy.float64]
+reveal_type(u8 + u4) # E: unsignedinteger
+reveal_type(u8 + b_) # E: uint64
+reveal_type(u8 + b) # E: unsignedinteger
+reveal_type(u8 + c) # E: complexfloating
+reveal_type(u8 + f) # E: floating
+reveal_type(u8 + i) # E: Union[numpy.signedinteger, numpy.float64]
+reveal_type(u8 + AR) # E: Union[numpy.ndarray, numpy.generic]
+
+reveal_type(i8 + i8) # E: signedinteger
+reveal_type(u8 + i8) # E: Union[numpy.signedinteger, numpy.float64]
+reveal_type(i4 + i8) # E: signedinteger
+reveal_type(u4 + i8) # E: Union[numpy.signedinteger, numpy.float64]
+reveal_type(b_ + i8) # E: int64
+reveal_type(b + i8) # E: signedinteger
+reveal_type(c + i8) # E: complexfloating
+reveal_type(f + i8) # E: floating
+reveal_type(i + i8) # E: signedinteger
+reveal_type(AR + i8) # E: Union[numpy.ndarray, numpy.generic]
+
+reveal_type(u8 + u8) # E: unsignedinteger
+reveal_type(i4 + u8) # E: Union[numpy.signedinteger, numpy.float64]
+reveal_type(u4 + u8) # E: unsignedinteger
+reveal_type(b_ + u8) # E: uint64
+reveal_type(b + u8) # E: unsignedinteger
+reveal_type(c + u8) # E: complexfloating
+reveal_type(f + u8) # E: floating
+reveal_type(i + u8) # E: Union[numpy.signedinteger, numpy.float64]
+reveal_type(AR + u8) # E: Union[numpy.ndarray, numpy.generic]
+
+reveal_type(i4 + i8) # E: signedinteger
+reveal_type(i4 + i4) # E: signedinteger
+reveal_type(i4 + i) # E: signedinteger
+reveal_type(i4 + b_) # E: int32
+reveal_type(i4 + b) # E: signedinteger
+reveal_type(i4 + AR) # E: Union[numpy.ndarray, numpy.generic]
+
+reveal_type(u4 + i8) # E: Union[numpy.signedinteger, numpy.float64]
+reveal_type(u4 + i4) # E: Union[numpy.signedinteger, numpy.float64]
+reveal_type(u4 + u8) # E: unsignedinteger
+reveal_type(u4 + u4) # E: unsignedinteger
+reveal_type(u4 + i) # E: Union[numpy.signedinteger, numpy.float64]
+reveal_type(u4 + b_) # E: uint32
+reveal_type(u4 + b) # E: unsignedinteger
+reveal_type(u4 + AR) # E: Union[numpy.ndarray, numpy.generic]
+
+reveal_type(i8 + i4) # E: signedinteger
+reveal_type(i4 + i4) # E: signedinteger
+reveal_type(i + i4) # E: signedinteger
+reveal_type(b_ + i4) # E: int32
+reveal_type(b + i4) # E: signedinteger
+reveal_type(AR + i4) # E: Union[numpy.ndarray, numpy.generic]
+
+reveal_type(i8 + u4) # E: Union[numpy.signedinteger, numpy.float64]
+reveal_type(i4 + u4) # E: Union[numpy.signedinteger, numpy.float64]
+reveal_type(u8 + u4) # E: unsignedinteger
+reveal_type(u4 + u4) # E: unsignedinteger
+reveal_type(b_ + u4) # E: uint32
+reveal_type(b + u4) # E: unsignedinteger
+reveal_type(i + u4) # E: Union[numpy.signedinteger, numpy.float64]
+reveal_type(AR + u4) # E: Union[numpy.ndarray, numpy.generic]
diff --git a/numpy/typing/tests/data/reveal/scalars.py b/numpy/typing/tests/data/reveal/scalars.py
index 882fe9612..ec3713b0f 100644
--- a/numpy/typing/tests/data/reveal/scalars.py
+++ b/numpy/typing/tests/data/reveal/scalars.py
@@ -12,22 +12,5 @@ reveal_type(x.itemsize) # E: int
reveal_type(x.shape) # E: tuple[builtins.int]
reveal_type(x.strides) # E: tuple[builtins.int]
-# Time structures
-dt = np.datetime64(0, "D")
-td = np.timedelta64(0, "D")
-
-reveal_type(dt + td) # E: numpy.datetime64
-reveal_type(dt + 1) # E: numpy.datetime64
-reveal_type(dt - dt) # E: numpy.timedelta64
-reveal_type(dt - 1) # E: numpy.timedelta64
-
-reveal_type(td + td) # E: numpy.timedelta64
-reveal_type(td + 1) # E: numpy.timedelta64
-reveal_type(td - td) # E: numpy.timedelta64
-reveal_type(td - 1) # E: numpy.timedelta64
-reveal_type(td / 1.0) # E: numpy.timedelta64
-reveal_type(td / td) # E: float
-reveal_type(td % td) # E: numpy.timedelta64
-
reveal_type(np.complex64().real) # E: numpy.float32
reveal_type(np.complex128().imag) # E: numpy.float64