diff options
Diffstat (limited to 'numpy')
-rw-r--r-- | numpy/__init__.pyi | 25 | ||||
-rw-r--r-- | numpy/core/fromnumeric.py | 12 | ||||
-rw-r--r-- | numpy/core/include/numpy/numpyconfig.h | 1 | ||||
-rw-r--r-- | numpy/core/src/multiarray/_multiarray_tests.c.src | 5 | ||||
-rw-r--r-- | numpy/core/src/multiarray/compiled_base.c | 2 | ||||
-rw-r--r-- | numpy/core/src/multiarray/mapping.c | 3 | ||||
-rw-r--r-- | numpy/core/src/multiarray/scalartypes.c.src | 14 | ||||
-rw-r--r-- | numpy/core/tests/test_multiarray.py | 4 | ||||
-rw-r--r-- | numpy/core/tests/test_scalarbuffer.py | 39 | ||||
-rw-r--r-- | numpy/f2py/__version__.py | 9 | ||||
-rw-r--r-- | numpy/f2py/capi_maps.py | 2 | ||||
-rw-r--r-- | numpy/f2py/common_rules.py | 2 | ||||
-rwxr-xr-x | numpy/f2py/f2py2e.py | 20 | ||||
-rwxr-xr-x | numpy/f2py/rules.py | 15 | ||||
-rw-r--r-- | numpy/lib/function_base.py | 6 | ||||
-rw-r--r-- | numpy/tests/test_scripts.py | 4 | ||||
-rw-r--r-- | numpy/typing/_callable.py | 9 | ||||
-rw-r--r-- | numpy/typing/tests/data/pass/comparisons.py | 247 | ||||
-rw-r--r-- | numpy/typing/tests/data/reveal/comparisons.py | 247 |
19 files changed, 606 insertions, 60 deletions
diff --git a/numpy/__init__.pyi b/numpy/__init__.pyi index 2366e9b75..ad37979ed 100644 --- a/numpy/__init__.pyi +++ b/numpy/__init__.pyi @@ -47,6 +47,7 @@ from numpy.typing._callable import ( _FloatDivMod, _ComplexOp, _NumberOp, + _ComparisonOp, ) from typing import ( @@ -1013,12 +1014,8 @@ class _ArrayOrScalarCommon: def __repr__(self) -> str: ... def __copy__(self: _ArraySelf) -> _ArraySelf: ... def __deepcopy__(self: _ArraySelf, __memo: Optional[dict] = ...) -> _ArraySelf: ... - def __lt__(self, other): ... - def __le__(self, other): ... def __eq__(self, other): ... def __ne__(self, other): ... - def __gt__(self, other): ... - def __ge__(self, other): ... def astype( self: _ArraySelf, dtype: DTypeLike, @@ -1579,6 +1576,10 @@ class ndarray(_ArrayOrScalarCommon, Iterable, Sized, Container): def __iter__(self) -> Any: ... def __contains__(self, key) -> bool: ... def __index__(self) -> int: ... + def __lt__(self, other: ArrayLike) -> Union[ndarray, bool_]: ... + def __le__(self, other: ArrayLike) -> Union[ndarray, bool_]: ... + def __gt__(self, other: ArrayLike) -> Union[ndarray, bool_]: ... + def __ge__(self, other: ArrayLike) -> Union[ndarray, bool_]: ... def __matmul__(self, other: ArrayLike) -> Any: ... # NOTE: `ndarray` does not implement `__imatmul__` def __rmatmul__(self, other: ArrayLike) -> Any: ... @@ -1689,6 +1690,10 @@ class number(generic, Generic[_NBit_co]): # type: ignore __rpow__: _NumberOp __truediv__: _NumberOp __rtruediv__: _NumberOp + __lt__: _ComparisonOp[_NumberLike] + __le__: _ComparisonOp[_NumberLike] + __gt__: _ComparisonOp[_NumberLike] + __ge__: _ComparisonOp[_NumberLike] class bool_(generic): def __init__(self, __value: object = ...) -> None: ... @@ -1727,6 +1732,10 @@ class bool_(generic): __rmod__: _BoolMod __divmod__: _BoolDivMod __rdivmod__: _BoolDivMod + __lt__: _ComparisonOp[_NumberLike] + __le__: _ComparisonOp[_NumberLike] + __gt__: _ComparisonOp[_NumberLike] + __ge__: _ComparisonOp[_NumberLike] class object_(generic): def __init__(self, __value: object = ...) -> None: ... @@ -1755,6 +1764,10 @@ class datetime64(generic): @overload def __sub__(self, other: Union[timedelta64, _IntLike, _BoolLike]) -> datetime64: ... def __rsub__(self, other: datetime64) -> timedelta64: ... + __lt__: _ComparisonOp[datetime64] + __le__: _ComparisonOp[datetime64] + __gt__: _ComparisonOp[datetime64] + __ge__: _ComparisonOp[datetime64] # Support for `__index__` was added in python 3.8 (bpo-20092) if sys.version_info >= (3, 8): @@ -1845,6 +1858,10 @@ class timedelta64(generic): def __rmod__(self, other: timedelta64) -> timedelta64: ... def __divmod__(self, other: timedelta64) -> Tuple[int64, timedelta64]: ... def __rdivmod__(self, other: timedelta64) -> Tuple[int64, timedelta64]: ... + __lt__: _ComparisonOp[Union[timedelta64, _IntLike, _BoolLike]] + __le__: _ComparisonOp[Union[timedelta64, _IntLike, _BoolLike]] + __gt__: _ComparisonOp[Union[timedelta64, _IntLike, _BoolLike]] + __ge__: _ComparisonOp[Union[timedelta64, _IntLike, _BoolLike]] class unsignedinteger(integer[_NBit_co]): # NOTE: `uint64 + signedinteger -> float64` diff --git a/numpy/core/fromnumeric.py b/numpy/core/fromnumeric.py index d65e26827..efb052bc2 100644 --- a/numpy/core/fromnumeric.py +++ b/numpy/core/fromnumeric.py @@ -1375,7 +1375,7 @@ def resize(a, new_shape): reshaped_array : ndarray The new array is formed from the data in the old array, repeated if necessary to fill out the required number of elements. The - data are repeated in the order that they are stored in memory. + data are repeated iterating over the array in C-order. See Also -------- @@ -1392,11 +1392,11 @@ def resize(a, new_shape): Warning: This functionality does **not** consider axes separately, i.e. it does not apply interpolation/extrapolation. - It fills the return array with the required number of elements, taken - from `a` as they are laid out in memory, disregarding strides and axes. - (This is in case the new shape is smaller. For larger, see above.) - This functionality is therefore not suitable to resize images, - or data where each axis represents a separate and distinct entity. + It fills the return array with the required number of elements, iterating + over `a` in C-order, disregarding axes (and cycling back from the start if + the new shape is larger). This functionality is therefore not suitable to + resize images, or data where each axis represents a separate and distinct + entity. Examples -------- diff --git a/numpy/core/include/numpy/numpyconfig.h b/numpy/core/include/numpy/numpyconfig.h index e39303123..a1b1de0ef 100644 --- a/numpy/core/include/numpy/numpyconfig.h +++ b/numpy/core/include/numpy/numpyconfig.h @@ -42,5 +42,6 @@ #define NPY_1_18_API_VERSION 0x00000008 #define NPY_1_19_API_VERSION 0x00000008 #define NPY_1_20_API_VERSION 0x0000000e +#define NPY_1_21_API_VERSION 0x0000000e #endif diff --git a/numpy/core/src/multiarray/_multiarray_tests.c.src b/numpy/core/src/multiarray/_multiarray_tests.c.src index 3811e87a8..3c8caefce 100644 --- a/numpy/core/src/multiarray/_multiarray_tests.c.src +++ b/numpy/core/src/multiarray/_multiarray_tests.c.src @@ -677,11 +677,12 @@ create_custom_field_dtype(PyObject *NPY_UNUSED(mod), PyObject *args) "invalid error argument to test function."); } if (PyArray_RegisterDataType(dtype) < 0) { - /* Fix original type in the error_path == 2 case. */ + /* Fix original type in the error_path == 2 case and delete it */ Py_SET_TYPE(dtype, original_type); + Py_DECREF(dtype); return NULL; } - Py_INCREF(dtype); + Py_INCREF(dtype); /* hold on to the original (leaks a reference) */ return (PyObject *)dtype; } diff --git a/numpy/core/src/multiarray/compiled_base.c b/numpy/core/src/multiarray/compiled_base.c index 061db2250..8ab592015 100644 --- a/numpy/core/src/multiarray/compiled_base.c +++ b/numpy/core/src/multiarray/compiled_base.c @@ -1420,7 +1420,7 @@ arr_add_docstring(PyObject *NPY_UNUSED(dummy), PyObject *args) { PyObject *obj; PyObject *str; - #if (PY_VERSION_HEX >= 0x030700A2) + #if PY_VERSION_HEX >= 0x030700A2 && (!defined(PYPY_VERSION_NUM) || PYPY_VERSION_NUM > 0x07030300) const char *docstr; #else char *docstr; diff --git a/numpy/core/src/multiarray/mapping.c b/numpy/core/src/multiarray/mapping.c index cb5c3823d..d64962f87 100644 --- a/numpy/core/src/multiarray/mapping.c +++ b/numpy/core/src/multiarray/mapping.c @@ -3194,9 +3194,10 @@ PyArray_MapIterNew(npy_index_info *indices , int index_num, int index_type, } PyObject *shape2 = convert_shape_to_string(mit->nd, mit->dimensions, ""); - if (shape2 == NULL) + if (shape2 == NULL) { Py_DECREF(shape1); goto finish; + } PyErr_Format(PyExc_ValueError, "shape mismatch: value array of shape %S could not be broadcast " diff --git a/numpy/core/src/multiarray/scalartypes.c.src b/numpy/core/src/multiarray/scalartypes.c.src index d018fccbb..e480628e7 100644 --- a/numpy/core/src/multiarray/scalartypes.c.src +++ b/numpy/core/src/multiarray/scalartypes.c.src @@ -2395,6 +2395,10 @@ gentype_arrtype_getbuffer(PyObject *self, Py_buffer *view, int flags) self); return -1; } + if ((flags & PyBUF_WRITEABLE) == PyBUF_WRITEABLE) { + PyErr_SetString(PyExc_BufferError, "scalar buffer is readonly"); + return -1; + } PyArray_Descr *descr = PyArray_DescrFromScalar(self); if (descr == NULL) { return -1; @@ -2413,6 +2417,7 @@ gentype_arrtype_getbuffer(PyObject *self, Py_buffer *view, int flags) view->shape = NULL; view->strides = NULL; view->suboffsets = NULL; + view->readonly = 1; /* assume general (user) scalars are readonly. */ Py_INCREF(self); view->obj = self; view->buf = scalar_value(self, descr); @@ -2444,6 +2449,7 @@ static int @name@_getbuffer(PyObject *self, Py_buffer *view, int flags) { if ((flags & PyBUF_WRITEABLE) == PyBUF_WRITEABLE) { + PyErr_SetString(PyExc_BufferError, "scalar buffer is readonly"); return -1; } Py@Name@ScalarObject *scalar = (Py@Name@ScalarObject *)self; @@ -2456,6 +2462,7 @@ static int view->shape = NULL; view->strides = NULL; view->suboffsets = NULL; + view->readonly = 1; Py_INCREF(self); view->obj = self; view->buf = &(scalar->obval); @@ -2482,6 +2489,7 @@ static int unicode_getbuffer(PyObject *self, Py_buffer *view, int flags) { if ((flags & PyBUF_WRITEABLE) == PyBUF_WRITEABLE) { + PyErr_SetString(PyExc_BufferError, "scalar buffer is readonly"); return -1; } PyUnicodeScalarObject *scalar = (PyUnicodeScalarObject *)self; @@ -2493,6 +2501,7 @@ unicode_getbuffer(PyObject *self, Py_buffer *view, int flags) view->shape = NULL; view->strides = NULL; view->suboffsets = NULL; + view->readonly = 1; Py_INCREF(self); view->obj = self; @@ -2522,7 +2531,7 @@ unicode_getbuffer(PyObject *self, Py_buffer *view, int flags) view->format = scalar->buffer_fmt; } else { - scalar->buffer_fmt = PyObject_Malloc(22); + scalar->buffer_fmt = PyMem_Malloc(22); if (scalar->buffer_fmt == NULL) { Py_SETREF(view->obj, NULL); return -1; @@ -2549,6 +2558,7 @@ static int @name@_getbuffer(PyObject *self, Py_buffer *view, int flags) { if ((flags & PyBUF_WRITEABLE) == PyBUF_WRITEABLE) { + PyErr_SetString(PyExc_BufferError, "scalar buffer is readonly"); return -1; } Py@Name@ScalarObject *scalar = (Py@Name@ScalarObject *)self; @@ -2560,6 +2570,7 @@ static int view->shape = &length; view->strides = NULL; view->suboffsets = NULL; + view->readonly = 1; Py_INCREF(self); view->obj = self; @@ -2651,6 +2662,7 @@ unicode_arrtype_dealloc(PyObject *v) { /* note: may be null if it was never requested */ PyMem_Free(PyArrayScalar_VAL(v, Unicode)); + PyMem_Free(((PyUnicodeScalarObject *)v)->buffer_fmt); /* delegate to the base class */ PyUnicode_Type.tp_dealloc(v); } diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index 12306cbb8..bd8c51ab7 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -7350,9 +7350,9 @@ class TestNewBufferProtocol: def test_export_and_pickle_user_dtype(self, obj, error): # User dtypes should export successfully when FORMAT was not requested. with pytest.raises(error): - _multiarray_tests.get_buffer_info(obj, ("STRIDED", "FORMAT")) + _multiarray_tests.get_buffer_info(obj, ("STRIDED_RO", "FORMAT")) - _multiarray_tests.get_buffer_info(obj, ("STRIDED",)) + _multiarray_tests.get_buffer_info(obj, ("STRIDED_RO",)) # This is currently also necessary to implement pickling: pickle_obj = pickle.dumps(obj) diff --git a/numpy/core/tests/test_scalarbuffer.py b/numpy/core/tests/test_scalarbuffer.py index 574c56864..851cd3081 100644 --- a/numpy/core/tests/test_scalarbuffer.py +++ b/numpy/core/tests/test_scalarbuffer.py @@ -3,6 +3,7 @@ Test scalar buffer interface adheres to PEP 3118 """ import numpy as np from numpy.core._rational_tests import rational +from numpy.core._multiarray_tests import get_buffer_info import pytest from numpy.testing import assert_, assert_equal, assert_raises @@ -52,10 +53,20 @@ class TestScalarPEP3118: assert_equal(mv_x.suboffsets, ()) @pytest.mark.parametrize('scalar, code', scalars_and_codes, ids=codes_only) - def test_scalar_known_code(self, scalar, code): + def test_scalar_code_and_properties(self, scalar, code): x = scalar() + expected = dict(strides=(), itemsize=x.dtype.itemsize, ndim=0, + shape=(), format=code, readonly=True) + mv_x = memoryview(x) - assert_equal(mv_x.format, code) + print(mv_x.readonly, self._as_dict(mv_x)) + assert self._as_dict(mv_x) == expected + + @pytest.mark.parametrize('scalar', scalars_only, ids=codes_only) + def test_scalar_buffers_readonly(self, scalar): + x = scalar() + with pytest.raises(BufferError, match="scalar buffer is readonly"): + get_buffer_info(x, ["WRITABLE"]) def test_void_scalar_structured_data(self): dt = np.dtype([('name', np.unicode_, 16), ('grades', np.float64, (2,))]) @@ -77,9 +88,14 @@ class TestScalarPEP3118: assert_equal(mv_x.itemsize, mv_a.itemsize) assert_equal(mv_x.format, mv_a.format) + # Check that we do not allow writeable buffer export (technically + # we could allow it sometimes here...) + with pytest.raises(BufferError, match="scalar buffer is readonly"): + get_buffer_info(x, ["WRITABLE"]) + def _as_dict(self, m): return dict(strides=m.strides, shape=m.shape, itemsize=m.itemsize, - ndim=m.ndim, format=m.format) + ndim=m.ndim, format=m.format, readonly=m.readonly) def test_datetime_memoryview(self): # gh-11656 @@ -88,7 +104,7 @@ class TestScalarPEP3118: dt1 = np.datetime64('2016-01-01') dt2 = np.datetime64('2017-01-01') expected = dict(strides=(1,), itemsize=1, ndim=1, shape=(8,), - format='B') + format='B', readonly=True) v = memoryview(dt1) assert self._as_dict(v) == expected @@ -100,6 +116,10 @@ class TestScalarPEP3118: # Fails to create a PEP 3118 valid buffer assert_raises((ValueError, BufferError), memoryview, a[0]) + # Check that we do not allow writeable buffer export + with pytest.raises(BufferError, match="scalar buffer is readonly"): + get_buffer_info(dt1, ["WRITABLE"]) + @pytest.mark.parametrize('s', [ pytest.param("\x32\x32", id="ascii"), pytest.param("\uFE0F\uFE0F", id="basic multilingual"), @@ -109,7 +129,8 @@ class TestScalarPEP3118: s = np.str_(s) # only our subclass implements the buffer protocol # all the same, characters always encode as ucs4 - expected = dict(strides=(), itemsize=8, ndim=0, shape=(), format='2w') + expected = dict(strides=(), itemsize=8, ndim=0, shape=(), format='2w', + readonly=True) v = memoryview(s) assert self._as_dict(v) == expected @@ -119,7 +140,15 @@ class TestScalarPEP3118: assert_equal(code_points, [ord(c) for c in s]) + # Check that we do not allow writeable buffer export + with pytest.raises(BufferError, match="scalar buffer is readonly"): + get_buffer_info(s, ["WRITABLE"]) + def test_user_scalar_fails_buffer(self): r = rational(1) with assert_raises(TypeError): memoryview(r) + + # Check that we do not allow writeable buffer export + with pytest.raises(BufferError, match="scalar buffer is readonly"): + get_buffer_info(r, ["WRITABLE"])
\ No newline at end of file diff --git a/numpy/f2py/__version__.py b/numpy/f2py/__version__.py index 104c2e1a8..e20d7c1db 100644 --- a/numpy/f2py/__version__.py +++ b/numpy/f2py/__version__.py @@ -1,8 +1 @@ -major = 2 - -try: - from __svn_version__ import version - version_info = (major, version) - version = '%s_%s' % version_info -except (ImportError, ValueError): - version = str(major) +from numpy.version import version diff --git a/numpy/f2py/capi_maps.py b/numpy/f2py/capi_maps.py index fabbfc4c2..472ddde43 100644 --- a/numpy/f2py/capi_maps.py +++ b/numpy/f2py/capi_maps.py @@ -11,8 +11,6 @@ $Date: 2005/05/06 10:57:33 $ Pearu Peterson """ -__version__ = "$Revision: 1.60 $"[10:-1] - from . import __version__ f2py_version = __version__.version diff --git a/numpy/f2py/common_rules.py b/numpy/f2py/common_rules.py index 90483e55b..937d8bc72 100644 --- a/numpy/f2py/common_rules.py +++ b/numpy/f2py/common_rules.py @@ -13,8 +13,6 @@ $Date: 2005/05/06 10:57:33 $ Pearu Peterson """ -__version__ = "$Revision: 1.19 $"[10:-1] - from . import __version__ f2py_version = __version__.version diff --git a/numpy/f2py/f2py2e.py b/numpy/f2py/f2py2e.py index be2c345d1..b45d985aa 100755 --- a/numpy/f2py/f2py2e.py +++ b/numpy/f2py/f2py2e.py @@ -29,18 +29,14 @@ from . import __version__ from . import capi_maps f2py_version = __version__.version +numpy_version = __version__.version errmess = sys.stderr.write # outmess=sys.stdout.write show = pprint.pprint outmess = auxfuncs.outmess -try: - from numpy import __version__ as numpy_version -except ImportError: - numpy_version = 'N/A' - -__usage__ = """\ -Usage: +__usage__ =\ +f"""Usage: 1) To construct extension module sources: @@ -97,8 +93,8 @@ Options: --[no-]latex-doc Create (or not) <modulename>module.tex. Default is --no-latex-doc. --short-latex Create 'incomplete' LaTeX document (without commands - \\documentclass, \\tableofcontents, and \\begin{document}, - \\end{document}). + \\documentclass, \\tableofcontents, and \\begin{{document}}, + \\end{{document}}). --[no-]rest-doc Create (or not) <modulename>module.rst. Default is --no-rest-doc. @@ -167,12 +163,12 @@ Extra options (only effective with -c): array. Integer <int> sets the threshold for array sizes when a message should be shown. -Version: %s -numpy Version: %s +Version: {f2py_version} +numpy Version: {numpy_version} Requires: Python 3.5 or higher. License: NumPy license (see LICENSE.txt in the NumPy source code) Copyright 1999 - 2011 Pearu Peterson all rights reserved. -http://cens.ioc.ee/projects/f2py2e/""" % (f2py_version, numpy_version) +http://cens.ioc.ee/projects/f2py2e/""" def scaninputline(inputline): diff --git a/numpy/f2py/rules.py b/numpy/f2py/rules.py index a14f60194..f1490527e 100755 --- a/numpy/f2py/rules.py +++ b/numpy/f2py/rules.py @@ -50,18 +50,15 @@ $Date: 2005/08/30 08:58:42 $ Pearu Peterson """ -__version__ = "$Revision: 1.129 $"[10:-1] - -from . import __version__ -f2py_version = __version__.version - -from .. import version as _numpy_version -numpy_version = _numpy_version.version - import os import time import copy +# __version__.version is now the same as the NumPy version +from . import __version__ +f2py_version = __version__.version +numpy_version = __version__.version + from .auxfuncs import ( applyrules, debugcapi, dictappend, errmess, gentitle, getargs2, hascallstatement, hasexternals, hasinitvalue, hasnote, hasresultnote, @@ -202,7 +199,7 @@ PyMODINIT_FUNC PyInit_#modulename#(void) { \tif (PyErr_Occurred()) \t\t{PyErr_SetString(PyExc_ImportError, \"can't initialize module #modulename# (failed to import numpy)\"); return m;} \td = PyModule_GetDict(m); -\ts = PyUnicode_FromString(\"$R""" + """evision: $\"); +\ts = PyUnicode_FromString(\"#f2py_version#\"); \tPyDict_SetItemString(d, \"__version__\", s); \tPy_DECREF(s); \ts = PyUnicode_FromString( diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 984f3086e..696fe617b 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1290,7 +1290,7 @@ def _interp_dispatcher(x, xp, fp, left=None, right=None, period=None): @array_function_dispatch(_interp_dispatcher) def interp(x, xp, fp, left=None, right=None, period=None): """ - One-dimensional linear interpolation. + One-dimensional linear interpolation for monotonically increasing sample points. Returns the one-dimensional piecewise linear interpolant to a function with given discrete data points (`xp`, `fp`), evaluated at `x`. @@ -1337,8 +1337,8 @@ def interp(x, xp, fp, left=None, right=None, period=None): -------- scipy.interpolate - Notes - ----- + Warnings + -------- The x-coordinate sequence is expected to be increasing, but this is not explicitly enforced. However, if the sequence `xp` is non-increasing, interpolation results are meaningless. diff --git a/numpy/tests/test_scripts.py b/numpy/tests/test_scripts.py index a0f2ba70a..e67a82947 100644 --- a/numpy/tests/test_scripts.py +++ b/numpy/tests/test_scripts.py @@ -38,9 +38,9 @@ def find_f2py_commands(): def test_f2py(f2py_cmd): # test that we can run f2py script stdout = subprocess.check_output([f2py_cmd, '-v']) - assert_equal(stdout.strip(), b'2') + assert_equal(stdout.strip(), np.__version__.encode('ascii')) def test_pep338(): stdout = subprocess.check_output([sys.executable, '-mnumpy.f2py', '-v']) - assert_equal(stdout.strip(), b'2') + assert_equal(stdout.strip(), np.__version__.encode('ascii')) diff --git a/numpy/typing/_callable.py b/numpy/typing/_callable.py index 91b7a4ec2..c703df28a 100644 --- a/numpy/typing/_callable.py +++ b/numpy/typing/_callable.py @@ -20,6 +20,7 @@ from typing import ( ) from numpy import ( + ndarray, generic, bool_, timedelta64, @@ -41,6 +42,7 @@ from ._scalars import ( _NumberLike, ) from . import NBitBase +from ._array_like import ArrayLike if sys.version_info >= (3, 8): from typing import Protocol @@ -312,6 +314,12 @@ if TYPE_CHECKING or HAVE_PROTOCOL: class _NumberOp(Protocol): def __call__(self, __other: _NumberLike) -> number: ... + class _ComparisonOp(Protocol[_T]): + @overload + def __call__(self, __other: _T) -> bool_: ... + @overload + def __call__(self, __other: ArrayLike) -> Union[ndarray, bool_]: ... + else: _BoolOp = Any _BoolBitOp = Any @@ -334,3 +342,4 @@ else: _FloatDivMod = Any _ComplexOp = Any _NumberOp = Any + _ComparisonOp = Any diff --git a/numpy/typing/tests/data/pass/comparisons.py b/numpy/typing/tests/data/pass/comparisons.py new file mode 100644 index 000000000..b298117a6 --- /dev/null +++ b/numpy/typing/tests/data/pass/comparisons.py @@ -0,0 +1,247 @@ +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.int64) +AR.setflags(write=False) + +SEQ = (0, 1, 2, 3, 4) + +# Time structures + +dt > dt + +td > td +td > i +td > i4 +td > i8 +td > AR +td > SEQ + +# 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_ > AR +b_ > SEQ + +# 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 > SEQ + +c16 > c16 +f8 > c16 +i8 > c16 +c8 > c16 +f4 > c16 +i4 > c16 +b_ > c16 +b > c16 +c > c16 +f > c16 +i > c16 +AR > c16 +SEQ > 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 +c8 > SEQ + +c16 > c8 +f8 > c8 +i8 > c8 +c8 > c8 +f4 > c8 +i4 > c8 +b_ > c8 +b > c8 +c > c8 +f > c8 +i > c8 +AR > c8 +SEQ > c8 + +# Float + +f8 > f8 +f8 > i8 +f8 > f4 +f8 > i4 +f8 > b_ +f8 > b +f8 > c +f8 > f +f8 > i +f8 > AR +f8 > SEQ + +f8 > f8 +i8 > f8 +f4 > f8 +i4 > f8 +b_ > f8 +b > f8 +c > f8 +f > f8 +i > f8 +AR > f8 +SEQ > f8 + +f4 > f8 +f4 > i8 +f4 > f4 +f4 > i4 +f4 > b_ +f4 > b +f4 > c +f4 > f +f4 > i +f4 > AR +f4 > SEQ + +f8 > f4 +i8 > f4 +f4 > f4 +i4 > f4 +b_ > f4 +b > f4 +c > f4 +f > f4 +i > f4 +AR > f4 +SEQ > f4 + +# Int + +i8 > i8 +i8 > u8 +i8 > i4 +i8 > u4 +i8 > b_ +i8 > b +i8 > c +i8 > f +i8 > i +i8 > AR +i8 > SEQ + +u8 > u8 +u8 > i4 +u8 > u4 +u8 > b_ +u8 > b +u8 > c +u8 > f +u8 > i +u8 > AR +u8 > SEQ + +i8 > i8 +u8 > i8 +i4 > i8 +u4 > i8 +b_ > i8 +b > i8 +c > i8 +f > i8 +i > i8 +AR > i8 +SEQ > i8 + +u8 > u8 +i4 > u8 +u4 > u8 +b_ > u8 +b > u8 +c > u8 +f > u8 +i > u8 +AR > u8 +SEQ > u8 + +i4 > i8 +i4 > i4 +i4 > i +i4 > b_ +i4 > b +i4 > AR +i4 > SEQ + +u4 > i8 +u4 > i4 +u4 > u8 +u4 > u4 +u4 > i +u4 > b_ +u4 > b +u4 > AR +u4 > SEQ + +i8 > i4 +i4 > i4 +i > i4 +b_ > i4 +b > i4 +AR > i4 +SEQ > i4 + +i8 > u4 +i4 > u4 +u8 > u4 +u4 > u4 +b_ > u4 +b > u4 +i > u4 +AR > u4 +SEQ > u4 diff --git a/numpy/typing/tests/data/reveal/comparisons.py b/numpy/typing/tests/data/reveal/comparisons.py new file mode 100644 index 000000000..82d1fa6de --- /dev/null +++ b/numpy/typing/tests/data/reveal/comparisons.py @@ -0,0 +1,247 @@ +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.int64) +AR.setflags(write=False) + +SEQ = (0, 1, 2, 3, 4) + +# Time structures + +reveal_type(dt > dt) # E: numpy.bool_ + +reveal_type(td > td) # E: numpy.bool_ +reveal_type(td > i) # E: numpy.bool_ +reveal_type(td > i4) # E: numpy.bool_ +reveal_type(td > i8) # E: numpy.bool_ +reveal_type(td > AR) # E: Union[numpy.ndarray, numpy.bool_] +reveal_type(td > SEQ) # E: Union[numpy.ndarray, numpy.bool_] + +# boolean + +reveal_type(b_ > b) # E: numpy.bool_ +reveal_type(b_ > b_) # E: numpy.bool_ +reveal_type(b_ > i) # E: numpy.bool_ +reveal_type(b_ > i8) # E: numpy.bool_ +reveal_type(b_ > i4) # E: numpy.bool_ +reveal_type(b_ > u8) # E: numpy.bool_ +reveal_type(b_ > u4) # E: numpy.bool_ +reveal_type(b_ > f) # E: numpy.bool_ +reveal_type(b_ > f8) # E: numpy.bool_ +reveal_type(b_ > f4) # E: numpy.bool_ +reveal_type(b_ > c) # E: numpy.bool_ +reveal_type(b_ > c16) # E: numpy.bool_ +reveal_type(b_ > c8) # E: numpy.bool_ +reveal_type(b_ > AR) # E: Union[numpy.ndarray, numpy.bool_] +reveal_type(b_ > SEQ) # E: Union[numpy.ndarray, numpy.bool_] + +# Complex + +reveal_type(c16 > c16) # E: numpy.bool_ +reveal_type(c16 > f8) # E: numpy.bool_ +reveal_type(c16 > i8) # E: numpy.bool_ +reveal_type(c16 > c8) # E: numpy.bool_ +reveal_type(c16 > f4) # E: numpy.bool_ +reveal_type(c16 > i4) # E: numpy.bool_ +reveal_type(c16 > b_) # E: numpy.bool_ +reveal_type(c16 > b) # E: numpy.bool_ +reveal_type(c16 > c) # E: numpy.bool_ +reveal_type(c16 > f) # E: numpy.bool_ +reveal_type(c16 > i) # E: numpy.bool_ +reveal_type(c16 > AR) # E: Union[numpy.ndarray, numpy.bool_] +reveal_type(c16 > SEQ) # E: Union[numpy.ndarray, numpy.bool_] + +reveal_type(c16 > c16) # E: numpy.bool_ +reveal_type(f8 > c16) # E: numpy.bool_ +reveal_type(i8 > c16) # E: numpy.bool_ +reveal_type(c8 > c16) # E: numpy.bool_ +reveal_type(f4 > c16) # E: numpy.bool_ +reveal_type(i4 > c16) # E: numpy.bool_ +reveal_type(b_ > c16) # E: numpy.bool_ +reveal_type(b > c16) # E: numpy.bool_ +reveal_type(c > c16) # E: numpy.bool_ +reveal_type(f > c16) # E: numpy.bool_ +reveal_type(i > c16) # E: numpy.bool_ +reveal_type(AR > c16) # E: Union[numpy.ndarray, numpy.bool_] +reveal_type(SEQ > c16) # E: Union[numpy.ndarray, numpy.bool_] + +reveal_type(c8 > c16) # E: numpy.bool_ +reveal_type(c8 > f8) # E: numpy.bool_ +reveal_type(c8 > i8) # E: numpy.bool_ +reveal_type(c8 > c8) # E: numpy.bool_ +reveal_type(c8 > f4) # E: numpy.bool_ +reveal_type(c8 > i4) # E: numpy.bool_ +reveal_type(c8 > b_) # E: numpy.bool_ +reveal_type(c8 > b) # E: numpy.bool_ +reveal_type(c8 > c) # E: numpy.bool_ +reveal_type(c8 > f) # E: numpy.bool_ +reveal_type(c8 > i) # E: numpy.bool_ +reveal_type(c8 > AR) # E: Union[numpy.ndarray, numpy.bool_] +reveal_type(c8 > SEQ) # E: Union[numpy.ndarray, numpy.bool_] + +reveal_type(c16 > c8) # E: numpy.bool_ +reveal_type(f8 > c8) # E: numpy.bool_ +reveal_type(i8 > c8) # E: numpy.bool_ +reveal_type(c8 > c8) # E: numpy.bool_ +reveal_type(f4 > c8) # E: numpy.bool_ +reveal_type(i4 > c8) # E: numpy.bool_ +reveal_type(b_ > c8) # E: numpy.bool_ +reveal_type(b > c8) # E: numpy.bool_ +reveal_type(c > c8) # E: numpy.bool_ +reveal_type(f > c8) # E: numpy.bool_ +reveal_type(i > c8) # E: numpy.bool_ +reveal_type(AR > c8) # E: Union[numpy.ndarray, numpy.bool_] +reveal_type(SEQ > c8) # E: Union[numpy.ndarray, numpy.bool_] + +# Float + +reveal_type(f8 > f8) # E: numpy.bool_ +reveal_type(f8 > i8) # E: numpy.bool_ +reveal_type(f8 > f4) # E: numpy.bool_ +reveal_type(f8 > i4) # E: numpy.bool_ +reveal_type(f8 > b_) # E: numpy.bool_ +reveal_type(f8 > b) # E: numpy.bool_ +reveal_type(f8 > c) # E: numpy.bool_ +reveal_type(f8 > f) # E: numpy.bool_ +reveal_type(f8 > i) # E: numpy.bool_ +reveal_type(f8 > AR) # E: Union[numpy.ndarray, numpy.bool_] +reveal_type(f8 > SEQ) # E: Union[numpy.ndarray, numpy.bool_] + +reveal_type(f8 > f8) # E: numpy.bool_ +reveal_type(i8 > f8) # E: numpy.bool_ +reveal_type(f4 > f8) # E: numpy.bool_ +reveal_type(i4 > f8) # E: numpy.bool_ +reveal_type(b_ > f8) # E: numpy.bool_ +reveal_type(b > f8) # E: numpy.bool_ +reveal_type(c > f8) # E: numpy.bool_ +reveal_type(f > f8) # E: numpy.bool_ +reveal_type(i > f8) # E: numpy.bool_ +reveal_type(AR > f8) # E: Union[numpy.ndarray, numpy.bool_] +reveal_type(SEQ > f8) # E: Union[numpy.ndarray, numpy.bool_] + +reveal_type(f4 > f8) # E: numpy.bool_ +reveal_type(f4 > i8) # E: numpy.bool_ +reveal_type(f4 > f4) # E: numpy.bool_ +reveal_type(f4 > i4) # E: numpy.bool_ +reveal_type(f4 > b_) # E: numpy.bool_ +reveal_type(f4 > b) # E: numpy.bool_ +reveal_type(f4 > c) # E: numpy.bool_ +reveal_type(f4 > f) # E: numpy.bool_ +reveal_type(f4 > i) # E: numpy.bool_ +reveal_type(f4 > AR) # E: Union[numpy.ndarray, numpy.bool_] +reveal_type(f4 > SEQ) # E: Union[numpy.ndarray, numpy.bool_] + +reveal_type(f8 > f4) # E: numpy.bool_ +reveal_type(i8 > f4) # E: numpy.bool_ +reveal_type(f4 > f4) # E: numpy.bool_ +reveal_type(i4 > f4) # E: numpy.bool_ +reveal_type(b_ > f4) # E: numpy.bool_ +reveal_type(b > f4) # E: numpy.bool_ +reveal_type(c > f4) # E: numpy.bool_ +reveal_type(f > f4) # E: numpy.bool_ +reveal_type(i > f4) # E: numpy.bool_ +reveal_type(AR > f4) # E: Union[numpy.ndarray, numpy.bool_] +reveal_type(SEQ > f4) # E: Union[numpy.ndarray, numpy.bool_] + +# Int + +reveal_type(i8 > i8) # E: numpy.bool_ +reveal_type(i8 > u8) # E: numpy.bool_ +reveal_type(i8 > i4) # E: numpy.bool_ +reveal_type(i8 > u4) # E: numpy.bool_ +reveal_type(i8 > b_) # E: numpy.bool_ +reveal_type(i8 > b) # E: numpy.bool_ +reveal_type(i8 > c) # E: numpy.bool_ +reveal_type(i8 > f) # E: numpy.bool_ +reveal_type(i8 > i) # E: numpy.bool_ +reveal_type(i8 > AR) # E: Union[numpy.ndarray, numpy.bool_] +reveal_type(i8 > SEQ) # E: Union[numpy.ndarray, numpy.bool_] + +reveal_type(u8 > u8) # E: numpy.bool_ +reveal_type(u8 > i4) # E: numpy.bool_ +reveal_type(u8 > u4) # E: numpy.bool_ +reveal_type(u8 > b_) # E: numpy.bool_ +reveal_type(u8 > b) # E: numpy.bool_ +reveal_type(u8 > c) # E: numpy.bool_ +reveal_type(u8 > f) # E: numpy.bool_ +reveal_type(u8 > i) # E: numpy.bool_ +reveal_type(u8 > AR) # E: Union[numpy.ndarray, numpy.bool_] +reveal_type(u8 > SEQ) # E: Union[numpy.ndarray, numpy.bool_] + +reveal_type(i8 > i8) # E: numpy.bool_ +reveal_type(u8 > i8) # E: numpy.bool_ +reveal_type(i4 > i8) # E: numpy.bool_ +reveal_type(u4 > i8) # E: numpy.bool_ +reveal_type(b_ > i8) # E: numpy.bool_ +reveal_type(b > i8) # E: numpy.bool_ +reveal_type(c > i8) # E: numpy.bool_ +reveal_type(f > i8) # E: numpy.bool_ +reveal_type(i > i8) # E: numpy.bool_ +reveal_type(AR > i8) # E: Union[numpy.ndarray, numpy.bool_] +reveal_type(SEQ > i8) # E: Union[numpy.ndarray, numpy.bool_] + +reveal_type(u8 > u8) # E: numpy.bool_ +reveal_type(i4 > u8) # E: numpy.bool_ +reveal_type(u4 > u8) # E: numpy.bool_ +reveal_type(b_ > u8) # E: numpy.bool_ +reveal_type(b > u8) # E: numpy.bool_ +reveal_type(c > u8) # E: numpy.bool_ +reveal_type(f > u8) # E: numpy.bool_ +reveal_type(i > u8) # E: numpy.bool_ +reveal_type(AR > u8) # E: Union[numpy.ndarray, numpy.bool_] +reveal_type(SEQ > u8) # E: Union[numpy.ndarray, numpy.bool_] + +reveal_type(i4 > i8) # E: numpy.bool_ +reveal_type(i4 > i4) # E: numpy.bool_ +reveal_type(i4 > i) # E: numpy.bool_ +reveal_type(i4 > b_) # E: numpy.bool_ +reveal_type(i4 > b) # E: numpy.bool_ +reveal_type(i4 > AR) # E: Union[numpy.ndarray, numpy.bool_] +reveal_type(i4 > SEQ) # E: Union[numpy.ndarray, numpy.bool_] + +reveal_type(u4 > i8) # E: numpy.bool_ +reveal_type(u4 > i4) # E: numpy.bool_ +reveal_type(u4 > u8) # E: numpy.bool_ +reveal_type(u4 > u4) # E: numpy.bool_ +reveal_type(u4 > i) # E: numpy.bool_ +reveal_type(u4 > b_) # E: numpy.bool_ +reveal_type(u4 > b) # E: numpy.bool_ +reveal_type(u4 > AR) # E: Union[numpy.ndarray, numpy.bool_] +reveal_type(u4 > SEQ) # E: Union[numpy.ndarray, numpy.bool_] + +reveal_type(i8 > i4) # E: numpy.bool_ +reveal_type(i4 > i4) # E: numpy.bool_ +reveal_type(i > i4) # E: numpy.bool_ +reveal_type(b_ > i4) # E: numpy.bool_ +reveal_type(b > i4) # E: numpy.bool_ +reveal_type(AR > i4) # E: Union[numpy.ndarray, numpy.bool_] +reveal_type(SEQ > i4) # E: Union[numpy.ndarray, numpy.bool_] + +reveal_type(i8 > u4) # E: numpy.bool_ +reveal_type(i4 > u4) # E: numpy.bool_ +reveal_type(u8 > u4) # E: numpy.bool_ +reveal_type(u4 > u4) # E: numpy.bool_ +reveal_type(b_ > u4) # E: numpy.bool_ +reveal_type(b > u4) # E: numpy.bool_ +reveal_type(i > u4) # E: numpy.bool_ +reveal_type(AR > u4) # E: Union[numpy.ndarray, numpy.bool_] +reveal_type(SEQ > u4) # E: Union[numpy.ndarray, numpy.bool_] |