From 52db499e7130239da0a66812b4970c4a92af3e35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Sok=C3=B3=C5=82?= Date: Fri, 25 Aug 2023 15:34:39 +0200 Subject: [PATCH 1/7] API: Add lib.array_utils namespace --- numpy/__init__.pyi | 1 - numpy/_expired_attrs_2_0.py | 3 +- numpy/lib/__init__.py | 1 + numpy/lib/_utils_impl.py | 62 +------------------- numpy/lib/_utils_impl.pyi | 8 --- numpy/lib/array_utils.py | 57 ++++++++++++++++++ numpy/lib/array_utils.pyi | 23 ++++++++ numpy/lib/tests/test_array_utils.py | 33 +++++++++++ numpy/lib/tests/test_utils.py | 34 ++--------- numpy/tests/test_public_api.py | 1 + numpy/typing/tests/data/fail/lib_utils.pyi | 4 +- numpy/typing/tests/data/pass/lib_utils.py | 6 +- numpy/typing/tests/data/reveal/lib_utils.pyi | 5 +- 13 files changed, 132 insertions(+), 106 deletions(-) create mode 100644 numpy/lib/array_utils.py create mode 100644 numpy/lib/array_utils.pyi create mode 100644 numpy/lib/tests/test_array_utils.py diff --git a/numpy/__init__.pyi b/numpy/__init__.pyi index c1a15ea8ee44..edb0da52f044 100644 --- a/numpy/__init__.pyi +++ b/numpy/__init__.pyi @@ -577,7 +577,6 @@ from numpy.lib._ufunclike_impl import ( from numpy.lib._utils_impl import ( get_include as get_include, info as info, - byte_bounds as byte_bounds, show_runtime as show_runtime, ) diff --git a/numpy/_expired_attrs_2_0.py b/numpy/_expired_attrs_2_0.py index dbe690c56063..8cf0ae95a297 100644 --- a/numpy/_expired_attrs_2_0.py +++ b/numpy/_expired_attrs_2_0.py @@ -65,7 +65,8 @@ "`scalar_types` argument, use `numpy.result_type` and pass the " "Python values `0`, `0.0`, or `0j`.", "round_": "Use `np.round` instead.", - "nbytes": "Use `np.dtype().itemsize` instead.", "get_array_wrap": "", "DataSource": "It's still available as `np.lib.npyio.DataSource`.", + "nbytes": "Use `np.dtype().itemsize` instead.", + "byte_bounds": "Now it's available under `np.lib.array_utils.byte_bounds`", } diff --git a/numpy/lib/__init__.py b/numpy/lib/__init__.py index 92f1d6561b76..fb6104665e71 100644 --- a/numpy/lib/__init__.py +++ b/numpy/lib/__init__.py @@ -36,6 +36,7 @@ from . import npyio from . import arrayterator from . import _arraypad_impl +from . import array_utils from . import _version from .arrayterator import Arrayterator diff --git a/numpy/lib/_utils_impl.py b/numpy/lib/_utils_impl.py index 4fefe152734c..fa87cdb7a2ac 100644 --- a/numpy/lib/_utils_impl.py +++ b/numpy/lib/_utils_impl.py @@ -7,12 +7,12 @@ import functools import platform -from numpy.core import ndarray, asarray +from numpy.core import ndarray from numpy._utils import set_module import numpy as np __all__ = [ - 'get_include', 'info', 'byte_bounds', 'show_runtime' + 'get_include', 'info', 'show_runtime' ] @@ -287,64 +287,6 @@ def deprecate_with_doc(msg): return _Deprecate(message=msg) -#-------------------------------------------- -# Determine if two arrays can share memory -#-------------------------------------------- - - -@set_module('numpy') -def byte_bounds(a): - """ - Returns pointers to the end-points of an array. - - Parameters - ---------- - a : ndarray - Input array. It must conform to the Python-side of the array - interface. - - Returns - ------- - (low, high) : tuple of 2 integers - The first integer is the first byte of the array, the second - integer is just past the last byte of the array. If `a` is not - contiguous it will not use every byte between the (`low`, `high`) - values. - - Examples - -------- - >>> I = np.eye(2, dtype='f'); I.dtype - dtype('float32') - >>> low, high = np.byte_bounds(I) - >>> high - low == I.size*I.itemsize - True - >>> I = np.eye(2); I.dtype - dtype('float64') - >>> low, high = np.byte_bounds(I) - >>> high - low == I.size*I.itemsize - True - - """ - ai = a.__array_interface__ - a_data = ai['data'][0] - astrides = ai['strides'] - ashape = ai['shape'] - bytes_a = asarray(a).dtype.itemsize - - a_low = a_high = a_data - if astrides is None: - # contiguous case - a_high += a.size * bytes_a - else: - for shape, stride in zip(ashape, astrides): - if stride < 0: - a_low += (shape-1)*stride - else: - a_high += (shape-1)*stride - a_high += bytes_a - return a_low, a_high - - #----------------------------------------------------------------------------- diff --git a/numpy/lib/_utils_impl.pyi b/numpy/lib/_utils_impl.pyi index 37845090441a..ccde53b7a91a 100644 --- a/numpy/lib/_utils_impl.pyi +++ b/numpy/lib/_utils_impl.pyi @@ -7,8 +7,6 @@ from typing import ( Protocol, ) -from numpy import generic -from numpy.typing import NDArray from numpy.core.numerictypes import ( issubdtype as issubdtype, ) @@ -56,12 +54,6 @@ def deprecate( def deprecate_with_doc(msg: None | str) -> _Deprecate: ... -# NOTE: In practice `byte_bounds` can (potentially) take any object -# implementing the `__array_interface__` protocol. The caveat is -# that certain keys, marked as optional in the spec, must be present for -# `byte_bounds`. This concerns `"strides"` and `"data"`. -def byte_bounds(a: generic | NDArray[Any]) -> tuple[int, int]: ... - def info( object: object = ..., maxwidth: int = ..., diff --git a/numpy/lib/array_utils.py b/numpy/lib/array_utils.py new file mode 100644 index 000000000000..02a01e82a372 --- /dev/null +++ b/numpy/lib/array_utils.py @@ -0,0 +1,57 @@ +from numpy.core import asarray +from numpy.core.numeric import normalize_axis_tuple, normalize_axis_index + + +__all__ = ["byte_bounds", "normalize_axis_tuple", "normalize_axis_index"] + + +def byte_bounds(a): + """ + Returns pointers to the end-points of an array. + + Parameters + ---------- + a : ndarray + Input array. It must conform to the Python-side of the array + interface. + + Returns + ------- + (low, high) : tuple of 2 integers + The first integer is the first byte of the array, the second + integer is just past the last byte of the array. If `a` is not + contiguous it will not use every byte between the (`low`, `high`) + values. + + Examples + -------- + >>> I = np.eye(2, dtype='f'); I.dtype + dtype('float32') + >>> low, high = np.byte_bounds(I) + >>> high - low == I.size*I.itemsize + True + >>> I = np.eye(2); I.dtype + dtype('float64') + >>> low, high = np.byte_bounds(I) + >>> high - low == I.size*I.itemsize + True + + """ + ai = a.__array_interface__ + a_data = ai['data'][0] + astrides = ai['strides'] + ashape = ai['shape'] + bytes_a = asarray(a).dtype.itemsize + + a_low = a_high = a_data + if astrides is None: + # contiguous case + a_high += a.size * bytes_a + else: + for shape, stride in zip(ashape, astrides): + if stride < 0: + a_low += (shape-1)*stride + else: + a_high += (shape-1)*stride + a_high += bytes_a + return a_low, a_high diff --git a/numpy/lib/array_utils.pyi b/numpy/lib/array_utils.pyi new file mode 100644 index 000000000000..2784a474eddc --- /dev/null +++ b/numpy/lib/array_utils.pyi @@ -0,0 +1,23 @@ +from typing import Any, Iterable, Tuple + +from numpy import generic +from numpy.typing import NDArray + +# NOTE: In practice `byte_bounds` can (potentially) take any object +# implementing the `__array_interface__` protocol. The caveat is +# that certain keys, marked as optional in the spec, must be present for +# `byte_bounds`. This concerns `"strides"` and `"data"`. +def byte_bounds(a: generic | NDArray[Any]) -> tuple[int, int]: ... + +def normalize_axis_tuple( + axis: int | Iterable[int], + ndim: int = ..., + argname: None | str = ..., + allow_duplicate: None | bool = ..., +) -> Tuple[int, int]: ... + +def normalize_axis_index( + axis: int = ..., + ndim: int = ..., + msg_prefix: None | str = ..., +) -> int: ... diff --git a/numpy/lib/tests/test_array_utils.py b/numpy/lib/tests/test_array_utils.py new file mode 100644 index 000000000000..3d8b2bd4616e --- /dev/null +++ b/numpy/lib/tests/test_array_utils.py @@ -0,0 +1,33 @@ +import numpy as np + +from numpy.lib import array_utils +from numpy.testing import assert_equal + + +class TestByteBounds: + def test_byte_bounds(self): + # pointer difference matches size * itemsize + # due to contiguity + a = np.arange(12).reshape(3, 4) + low, high = array_utils.byte_bounds(a) + assert_equal(high - low, a.size * a.itemsize) + + def test_unusual_order_positive_stride(self): + a = np.arange(12).reshape(3, 4) + b = a.T + low, high = array_utils.byte_bounds(b) + assert_equal(high - low, b.size * b.itemsize) + + def test_unusual_order_negative_stride(self): + a = np.arange(12).reshape(3, 4) + b = a.T[::-1] + low, high = array_utils.byte_bounds(b) + assert_equal(high - low, b.size * b.itemsize) + + def test_strided(self): + a = np.arange(12) + b = a[::2] + low, high = array_utils.byte_bounds(b) + # the largest pointer address is lost (even numbers only in the + # stride), and compensate addresses for striding by 2 + assert_equal(high - low, b.size * 2 * b.itemsize - b.itemsize) diff --git a/numpy/lib/tests/test_utils.py b/numpy/lib/tests/test_utils.py index bceff04d5185..eea7b1baaf06 100644 --- a/numpy/lib/tests/test_utils.py +++ b/numpy/lib/tests/test_utils.py @@ -1,40 +1,16 @@ import pytest import numpy as np -from numpy.testing import assert_equal, assert_raises_regex +from numpy.testing import assert_raises_regex import numpy.lib._utils_impl as _utils_impl from io import StringIO -class TestByteBounds: - - def test_byte_bounds(self): - # pointer difference matches size * itemsize - # due to contiguity - a = np.arange(12).reshape(3, 4) - low, high = np.byte_bounds(a) - assert_equal(high - low, a.size * a.itemsize) - - def test_unusual_order_positive_stride(self): - a = np.arange(12).reshape(3, 4) - b = a.T - low, high = np.byte_bounds(b) - assert_equal(high - low, b.size * b.itemsize) - - def test_unusual_order_negative_stride(self): - a = np.arange(12).reshape(3, 4) - b = a.T[::-1] - low, high = np.byte_bounds(b) - assert_equal(high - low, b.size * b.itemsize) - - def test_strided(self): - a = np.arange(12) - b = a[::2] - low, high = np.byte_bounds(b) - # the largest pointer address is lost (even numbers only in the - # stride), and compensate addresses for striding by 2 - assert_equal(high - low, b.size * 2 * b.itemsize - b.itemsize) +@pytest.mark.filterwarnings("ignore:.*safe_eval.*:DeprecationWarning") +def test_safe_eval_nameconstant(): + # Test if safe_eval supports Python 3.4 _ast.NameConstant + utils.safe_eval('None') def test_assert_raises_regex_context_manager(): diff --git a/numpy/tests/test_public_api.py b/numpy/tests/test_public_api.py index 19c98ea38ad2..4aded7fdde6e 100644 --- a/numpy/tests/test_public_api.py +++ b/numpy/tests/test_public_api.py @@ -123,6 +123,7 @@ def test_NPY_NO_EXPORT(): "lib.stride_tricks", "lib.npyio", "lib.introspect", + "lib.array_utils", "linalg", "ma", "ma.extras", diff --git a/numpy/typing/tests/data/fail/lib_utils.pyi b/numpy/typing/tests/data/fail/lib_utils.pyi index eee2bbe26936..8b8482eeff6d 100644 --- a/numpy/typing/tests/data/fail/lib_utils.pyi +++ b/numpy/typing/tests/data/fail/lib_utils.pyi @@ -1,3 +1,3 @@ -import numpy as np +import numpy.lib.array_utils as array_utils -np.byte_bounds(1) # E: incompatible type +array_utils.byte_bounds(1) # E: incompatible type diff --git a/numpy/typing/tests/data/pass/lib_utils.py b/numpy/typing/tests/data/pass/lib_utils.py index d6e6a3dfb068..f9b3381e13d2 100644 --- a/numpy/typing/tests/data/pass/lib_utils.py +++ b/numpy/typing/tests/data/pass/lib_utils.py @@ -3,6 +3,7 @@ from io import StringIO import numpy as np +import numpy.lib.array_utils as array_utils FILE = StringIO() AR = np.arange(10, dtype=np.float64) @@ -12,8 +13,7 @@ def func(a: int) -> bool: return True -np.byte_bounds(AR) -np.byte_bounds(np.float64()) +array_utils.byte_bounds(AR) +array_utils.byte_bounds(np.float64()) np.info(1, output=FILE) - diff --git a/numpy/typing/tests/data/reveal/lib_utils.pyi b/numpy/typing/tests/data/reveal/lib_utils.pyi index ae0c9b40b4cb..094b60140833 100644 --- a/numpy/typing/tests/data/reveal/lib_utils.pyi +++ b/numpy/typing/tests/data/reveal/lib_utils.pyi @@ -3,6 +3,7 @@ from io import StringIO import numpy as np import numpy.typing as npt +import numpy.lib.array_utils as array_utils if sys.version_info >= (3, 11): from typing import assert_type @@ -15,7 +16,7 @@ FILE: StringIO def func(a: int) -> bool: ... -assert_type(np.byte_bounds(AR), tuple[int, int]) -assert_type(np.byte_bounds(np.float64()), tuple[int, int]) +assert_type(array_utils.byte_bounds(AR), tuple[int, int]) +assert_type(array_utils.byte_bounds(np.float64()), tuple[int, int]) assert_type(np.info(1, output=FILE), None) From f764f89a5cd24f81a6be9543db56f0c5e3fc0f5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Sok=C3=B3=C5=82?= Date: Sat, 26 Aug 2023 18:47:01 +0200 Subject: [PATCH 2/7] Add *_impl file --- numpy/lib/_array_utils_impl.py | 57 +++++++++++++++++++++++++++++ numpy/lib/_array_utils_impl.pyi | 23 ++++++++++++ numpy/lib/array_utils.py | 63 ++++----------------------------- numpy/lib/array_utils.pyi | 28 +++------------ 4 files changed, 91 insertions(+), 80 deletions(-) create mode 100644 numpy/lib/_array_utils_impl.py create mode 100644 numpy/lib/_array_utils_impl.pyi diff --git a/numpy/lib/_array_utils_impl.py b/numpy/lib/_array_utils_impl.py new file mode 100644 index 000000000000..02a01e82a372 --- /dev/null +++ b/numpy/lib/_array_utils_impl.py @@ -0,0 +1,57 @@ +from numpy.core import asarray +from numpy.core.numeric import normalize_axis_tuple, normalize_axis_index + + +__all__ = ["byte_bounds", "normalize_axis_tuple", "normalize_axis_index"] + + +def byte_bounds(a): + """ + Returns pointers to the end-points of an array. + + Parameters + ---------- + a : ndarray + Input array. It must conform to the Python-side of the array + interface. + + Returns + ------- + (low, high) : tuple of 2 integers + The first integer is the first byte of the array, the second + integer is just past the last byte of the array. If `a` is not + contiguous it will not use every byte between the (`low`, `high`) + values. + + Examples + -------- + >>> I = np.eye(2, dtype='f'); I.dtype + dtype('float32') + >>> low, high = np.byte_bounds(I) + >>> high - low == I.size*I.itemsize + True + >>> I = np.eye(2); I.dtype + dtype('float64') + >>> low, high = np.byte_bounds(I) + >>> high - low == I.size*I.itemsize + True + + """ + ai = a.__array_interface__ + a_data = ai['data'][0] + astrides = ai['strides'] + ashape = ai['shape'] + bytes_a = asarray(a).dtype.itemsize + + a_low = a_high = a_data + if astrides is None: + # contiguous case + a_high += a.size * bytes_a + else: + for shape, stride in zip(ashape, astrides): + if stride < 0: + a_low += (shape-1)*stride + else: + a_high += (shape-1)*stride + a_high += bytes_a + return a_low, a_high diff --git a/numpy/lib/_array_utils_impl.pyi b/numpy/lib/_array_utils_impl.pyi new file mode 100644 index 000000000000..2784a474eddc --- /dev/null +++ b/numpy/lib/_array_utils_impl.pyi @@ -0,0 +1,23 @@ +from typing import Any, Iterable, Tuple + +from numpy import generic +from numpy.typing import NDArray + +# NOTE: In practice `byte_bounds` can (potentially) take any object +# implementing the `__array_interface__` protocol. The caveat is +# that certain keys, marked as optional in the spec, must be present for +# `byte_bounds`. This concerns `"strides"` and `"data"`. +def byte_bounds(a: generic | NDArray[Any]) -> tuple[int, int]: ... + +def normalize_axis_tuple( + axis: int | Iterable[int], + ndim: int = ..., + argname: None | str = ..., + allow_duplicate: None | bool = ..., +) -> Tuple[int, int]: ... + +def normalize_axis_index( + axis: int = ..., + ndim: int = ..., + msg_prefix: None | str = ..., +) -> int: ... diff --git a/numpy/lib/array_utils.py b/numpy/lib/array_utils.py index 02a01e82a372..94ba46eae5cd 100644 --- a/numpy/lib/array_utils.py +++ b/numpy/lib/array_utils.py @@ -1,57 +1,6 @@ -from numpy.core import asarray -from numpy.core.numeric import normalize_axis_tuple, normalize_axis_index - - -__all__ = ["byte_bounds", "normalize_axis_tuple", "normalize_axis_index"] - - -def byte_bounds(a): - """ - Returns pointers to the end-points of an array. - - Parameters - ---------- - a : ndarray - Input array. It must conform to the Python-side of the array - interface. - - Returns - ------- - (low, high) : tuple of 2 integers - The first integer is the first byte of the array, the second - integer is just past the last byte of the array. If `a` is not - contiguous it will not use every byte between the (`low`, `high`) - values. - - Examples - -------- - >>> I = np.eye(2, dtype='f'); I.dtype - dtype('float32') - >>> low, high = np.byte_bounds(I) - >>> high - low == I.size*I.itemsize - True - >>> I = np.eye(2); I.dtype - dtype('float64') - >>> low, high = np.byte_bounds(I) - >>> high - low == I.size*I.itemsize - True - - """ - ai = a.__array_interface__ - a_data = ai['data'][0] - astrides = ai['strides'] - ashape = ai['shape'] - bytes_a = asarray(a).dtype.itemsize - - a_low = a_high = a_data - if astrides is None: - # contiguous case - a_high += a.size * bytes_a - else: - for shape, stride in zip(ashape, astrides): - if stride < 0: - a_low += (shape-1)*stride - else: - a_high += (shape-1)*stride - a_high += bytes_a - return a_low, a_high +from ._array_utils_impl import ( + __all__, + byte_bounds, + normalize_axis_index, + normalize_axis_tuple, +) diff --git a/numpy/lib/array_utils.pyi b/numpy/lib/array_utils.pyi index 2784a474eddc..10d960ae5839 100644 --- a/numpy/lib/array_utils.pyi +++ b/numpy/lib/array_utils.pyi @@ -1,23 +1,5 @@ -from typing import Any, Iterable, Tuple - -from numpy import generic -from numpy.typing import NDArray - -# NOTE: In practice `byte_bounds` can (potentially) take any object -# implementing the `__array_interface__` protocol. The caveat is -# that certain keys, marked as optional in the spec, must be present for -# `byte_bounds`. This concerns `"strides"` and `"data"`. -def byte_bounds(a: generic | NDArray[Any]) -> tuple[int, int]: ... - -def normalize_axis_tuple( - axis: int | Iterable[int], - ndim: int = ..., - argname: None | str = ..., - allow_duplicate: None | bool = ..., -) -> Tuple[int, int]: ... - -def normalize_axis_index( - axis: int = ..., - ndim: int = ..., - msg_prefix: None | str = ..., -) -> int: ... +from ._array_utils_impl import ( + byte_bounds as byte_bounds, + normalize_axis_index as normalize_axis_index, + normalize_axis_tuple as normalize_axis_tuple, +) From 744f05df121dff394bc6689f718ccd0607db4310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Sok=C3=B3=C5=82?= Date: Mon, 28 Aug 2023 11:46:17 +0200 Subject: [PATCH 3/7] DOC: Add array_utils to autogenerated docs --- doc/source/reference/routines.other.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/source/reference/routines.other.rst b/doc/source/reference/routines.other.rst index 52660b31f590..f7c21f5f9623 100644 --- a/doc/source/reference/routines.other.rst +++ b/doc/source/reference/routines.other.rst @@ -21,7 +21,7 @@ Memory ranges shares_memory may_share_memory - byte_bounds + lib.array_utils.byte_bounds Array mixins ------------ @@ -47,6 +47,8 @@ Utility show_config show_runtime broadcast_shapes + lib.array_utils.normalize_axis_index + lib.array_utils.normalize_axis_tuple .. automodule:: numpy.exceptions From 0ff4ac72af38c55015e024e45026bbf36a7efefe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Sok=C3=B3=C5=82?= Date: Wed, 30 Aug 2023 11:52:02 +0200 Subject: [PATCH 4/7] Fix after rebase --- numpy/__init__.py | 2 +- numpy/lib/tests/test_utils.py | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/numpy/__init__.py b/numpy/__init__.py index 12b371281ce6..3e7b48bf68a0 100644 --- a/numpy/__init__.py +++ b/numpy/__init__.py @@ -218,7 +218,7 @@ from .lib._ufunclike_impl import fix, isneginf, isposinf from .lib._arraypad_impl import pad from .lib._utils_impl import ( - byte_bounds, show_runtime, get_include, info + show_runtime, get_include, info ) from .lib._stride_tricks_impl import ( broadcast_arrays, broadcast_shapes, broadcast_to diff --git a/numpy/lib/tests/test_utils.py b/numpy/lib/tests/test_utils.py index eea7b1baaf06..e2f72ac90c92 100644 --- a/numpy/lib/tests/test_utils.py +++ b/numpy/lib/tests/test_utils.py @@ -7,12 +7,6 @@ from io import StringIO -@pytest.mark.filterwarnings("ignore:.*safe_eval.*:DeprecationWarning") -def test_safe_eval_nameconstant(): - # Test if safe_eval supports Python 3.4 _ast.NameConstant - utils.safe_eval('None') - - def test_assert_raises_regex_context_manager(): with assert_raises_regex(ValueError, 'no deprecation warning'): raise ValueError('no deprecation warning') From 4dd54b5570575d67d7f1ba3734b232ccf11de258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Sok=C3=B3=C5=82?= Date: Fri, 1 Sep 2023 12:49:14 +0200 Subject: [PATCH 5/7] Add changelog file --- doc/release/upcoming_changes/24540.change.rst | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 doc/release/upcoming_changes/24540.change.rst diff --git a/doc/release/upcoming_changes/24540.change.rst b/doc/release/upcoming_changes/24540.change.rst new file mode 100644 index 000000000000..b4ca0db59bcd --- /dev/null +++ b/doc/release/upcoming_changes/24540.change.rst @@ -0,0 +1,3 @@ +* ``np.lib.array_utils`` public module has been introduced and in its initial version + it hosts three functions: ``byte_bounds`` (moved from ``np.lib.utils``), + ``normalize_axis_tuple`` and ``normalize_axis_index`` From 906468f3efb0d91e742c1074a8bb44a3ba5e1a45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Sok=C3=B3=C5=82?= Date: Wed, 6 Sep 2023 12:19:52 +0200 Subject: [PATCH 6/7] Apply review comments --- numpy/lib/_array_utils_impl.py | 3 ++- numpy/lib/_array_utils_impl.pyi | 2 ++ numpy/lib/array_utils.pyi | 1 + numpy/typing/tests/data/pass/modules.py | 1 + 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/numpy/lib/_array_utils_impl.py b/numpy/lib/_array_utils_impl.py index 02a01e82a372..90ba24e91965 100644 --- a/numpy/lib/_array_utils_impl.py +++ b/numpy/lib/_array_utils_impl.py @@ -1,10 +1,11 @@ from numpy.core import asarray from numpy.core.numeric import normalize_axis_tuple, normalize_axis_index - +from numpy._utils import set_module __all__ = ["byte_bounds", "normalize_axis_tuple", "normalize_axis_index"] +@set_module("numpy.lib.array_utils") def byte_bounds(a): """ Returns pointers to the end-points of an array. diff --git a/numpy/lib/_array_utils_impl.pyi b/numpy/lib/_array_utils_impl.pyi index 2784a474eddc..a38a62f2813c 100644 --- a/numpy/lib/_array_utils_impl.pyi +++ b/numpy/lib/_array_utils_impl.pyi @@ -3,6 +3,8 @@ from typing import Any, Iterable, Tuple from numpy import generic from numpy.typing import NDArray +__all__: list[str] + # NOTE: In practice `byte_bounds` can (potentially) take any object # implementing the `__array_interface__` protocol. The caveat is # that certain keys, marked as optional in the spec, must be present for diff --git a/numpy/lib/array_utils.pyi b/numpy/lib/array_utils.pyi index 10d960ae5839..4b9ebe334a1f 100644 --- a/numpy/lib/array_utils.pyi +++ b/numpy/lib/array_utils.pyi @@ -1,4 +1,5 @@ from ._array_utils_impl import ( + __all__ as __all__, byte_bounds as byte_bounds, normalize_axis_index as normalize_axis_index, normalize_axis_tuple as normalize_axis_tuple, diff --git a/numpy/typing/tests/data/pass/modules.py b/numpy/typing/tests/data/pass/modules.py index f2d779e20e63..f6302f0239ed 100644 --- a/numpy/typing/tests/data/pass/modules.py +++ b/numpy/typing/tests/data/pass/modules.py @@ -19,6 +19,7 @@ np.lib.mixins np.lib.scimath np.lib.stride_tricks +np.lib.array_utils np.ma.extras np.polynomial.chebyshev np.polynomial.hermite From 383abbce8667970748d447dc625d96cc78f9c742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Sok=C3=B3=C5=82?= Date: Sat, 9 Sep 2023 14:31:43 +0200 Subject: [PATCH 7/7] update module field for array_util functions --- numpy/core/multiarray.py | 1 + numpy/core/numeric.py | 1 + 2 files changed, 2 insertions(+) diff --git a/numpy/core/multiarray.py b/numpy/core/multiarray.py index 6a1b9d3e5009..4f3fbf466a2c 100644 --- a/numpy/core/multiarray.py +++ b/numpy/core/multiarray.py @@ -69,6 +69,7 @@ zeros.__module__ = 'numpy' _get_promotion_state.__module__ = 'numpy' _set_promotion_state.__module__ = 'numpy' +normalize_axis_index.__module__ = 'numpy.lib.array_utils' # We can't verify dispatcher signatures because NumPy's C functions don't diff --git a/numpy/core/numeric.py b/numpy/core/numeric.py index f0c04ca184f9..c542a9d94e40 100644 --- a/numpy/core/numeric.py +++ b/numpy/core/numeric.py @@ -1328,6 +1328,7 @@ def rollaxis(a, axis, start=0): return a.transpose(axes) +@set_module("numpy.lib.array_utils") def normalize_axis_tuple(axis, ndim, argname=None, allow_duplicate=False): """ Normalizes an axis argument into a tuple of non-negative integer axes.