From b0f318b38e7dd305c3ca93e6c912e1391dda999e Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Fri, 18 Nov 2022 14:50:57 +0100 Subject: [PATCH 1/9] API: Add new exceptions module and move exception exposed via numeric This means moving ComplexWarning, TooHardError, and AxisError. --- numpy/__init__.py | 6 +- numpy/core/_exceptions.py | 107 ---------------- numpy/core/numeric.py | 33 ++--- numpy/core/src/multiarray/common.h | 2 +- numpy/core/src/multiarray/convert_datatype.c | 16 +-- numpy/core/src/multiarray/multiarraymodule.c | 5 +- numpy/core/src/umath/scalarmath.c.src | 4 +- numpy/core/tests/test_multiarray.py | 4 +- numpy/exceptions.py | 123 +++++++++++++++++++ numpy/tests/test_public_api.py | 1 + 10 files changed, 151 insertions(+), 150 deletions(-) create mode 100644 numpy/exceptions.py diff --git a/numpy/__init__.py b/numpy/__init__.py index bdea595ed3f5..5af2ac8475db 100644 --- a/numpy/__init__.py +++ b/numpy/__init__.py @@ -110,6 +110,7 @@ ModuleDeprecationWarning, VisibleDeprecationWarning, _NoValue, _CopyMode ) +from .exceptions import ComplexWarning, TooHardError, AxisError # We first need to detect if we're being called as part of the numpy setup # procedure itself in a reliable manner. @@ -129,8 +130,9 @@ your python interpreter from there.""" raise ImportError(msg) from e - __all__ = ['ModuleDeprecationWarning', - 'VisibleDeprecationWarning'] + __all__ = [ + 'ModuleDeprecationWarning', 'VisibleDeprecationWarning', + 'ComplexWarning', 'TooHardError', 'AxisError'] # mapping of {name: (value, deprecation_msg)} __deprecated_attrs__ = {} diff --git a/numpy/core/_exceptions.py b/numpy/core/_exceptions.py index db5dfea02a67..62579ed0d84d 100644 --- a/numpy/core/_exceptions.py +++ b/numpy/core/_exceptions.py @@ -114,113 +114,6 @@ def __str__(self): ) -# Exception used in shares_memory() -@set_module('numpy') -class TooHardError(RuntimeError): - """max_work was exceeded. - - This is raised whenever the maximum number of candidate solutions - to consider specified by the ``max_work`` parameter is exceeded. - Assigning a finite number to max_work may have caused the operation - to fail. - - """ - - pass - - -@set_module('numpy') -class AxisError(ValueError, IndexError): - """Axis supplied was invalid. - - This is raised whenever an ``axis`` parameter is specified that is larger - than the number of array dimensions. - For compatibility with code written against older numpy versions, which - raised a mixture of `ValueError` and `IndexError` for this situation, this - exception subclasses both to ensure that ``except ValueError`` and - ``except IndexError`` statements continue to catch `AxisError`. - - .. versionadded:: 1.13 - - Parameters - ---------- - axis : int or str - The out of bounds axis or a custom exception message. - If an axis is provided, then `ndim` should be specified as well. - ndim : int, optional - The number of array dimensions. - msg_prefix : str, optional - A prefix for the exception message. - - Attributes - ---------- - axis : int, optional - The out of bounds axis or ``None`` if a custom exception - message was provided. This should be the axis as passed by - the user, before any normalization to resolve negative indices. - - .. versionadded:: 1.22 - ndim : int, optional - The number of array dimensions or ``None`` if a custom exception - message was provided. - - .. versionadded:: 1.22 - - - Examples - -------- - >>> array_1d = np.arange(10) - >>> np.cumsum(array_1d, axis=1) - Traceback (most recent call last): - ... - numpy.AxisError: axis 1 is out of bounds for array of dimension 1 - - Negative axes are preserved: - - >>> np.cumsum(array_1d, axis=-2) - Traceback (most recent call last): - ... - numpy.AxisError: axis -2 is out of bounds for array of dimension 1 - - The class constructor generally takes the axis and arrays' - dimensionality as arguments: - - >>> print(np.AxisError(2, 1, msg_prefix='error')) - error: axis 2 is out of bounds for array of dimension 1 - - Alternatively, a custom exception message can be passed: - - >>> print(np.AxisError('Custom error message')) - Custom error message - - """ - - __slots__ = ("axis", "ndim", "_msg") - - def __init__(self, axis, ndim=None, msg_prefix=None): - if ndim is msg_prefix is None: - # single-argument form: directly set the error message - self._msg = axis - self.axis = None - self.ndim = None - else: - self._msg = msg_prefix - self.axis = axis - self.ndim = ndim - - def __str__(self): - axis = self.axis - ndim = self.ndim - - if axis is ndim is None: - return self._msg - else: - msg = f"axis {axis} is out of bounds for array of dimension {ndim}" - if self._msg is not None: - msg = f"{self._msg}: {msg}" - return msg - - @_display_as_base class _ArrayMemoryError(MemoryError): """ Thrown when an array cannot be allocated""" diff --git a/numpy/core/numeric.py b/numpy/core/numeric.py index 5b92972d1590..577f8e7cd53c 100644 --- a/numpy/core/numeric.py +++ b/numpy/core/numeric.py @@ -26,7 +26,7 @@ from .umath import (multiply, invert, sin, PINF, NAN) from . import numerictypes from .numerictypes import longlong, intc, int_, float_, complex_, bool_ -from ._exceptions import TooHardError, AxisError +from ..exceptions import ComplexWarning, TooHardError, AxisError from ._ufunc_config import errstate, _no_nep50_warning bitwise_not = invert @@ -52,22 +52,9 @@ 'identity', 'allclose', 'compare_chararrays', 'putmask', 'flatnonzero', 'Inf', 'inf', 'infty', 'Infinity', 'nan', 'NaN', 'False_', 'True_', 'bitwise_not', 'CLIP', 'RAISE', 'WRAP', 'MAXDIMS', - 'BUFSIZE', 'ALLOW_THREADS', 'ComplexWarning', 'full', 'full_like', + 'BUFSIZE', 'ALLOW_THREADS', 'full', 'full_like', 'matmul', 'shares_memory', 'may_share_memory', 'MAY_SHARE_BOUNDS', - 'MAY_SHARE_EXACT', 'TooHardError', 'AxisError', - '_get_promotion_state', '_set_promotion_state'] - - -@set_module('numpy') -class ComplexWarning(RuntimeWarning): - """ - The warning raised when casting a complex dtype to a real dtype. - - As implemented, casting a complex number to a real discards its imaginary - part, but this behavior may not be what the user actually wants. - - """ - pass + 'MAY_SHARE_EXACT', '_get_promotion_state', '_set_promotion_state'] def _zeros_like_dispatcher(a, dtype=None, order=None, subok=None, shape=None): @@ -707,7 +694,7 @@ def correlate(a, v, mode='valid'): -------- convolve : Discrete, linear convolution of two one-dimensional sequences. multiarray.correlate : Old, no conjugate, version of correlate. - scipy.signal.correlate : uses FFT which has superior performance on large arrays. + scipy.signal.correlate : uses FFT which has superior performance on large arrays. Notes ----- @@ -721,7 +708,7 @@ def correlate(a, v, mode='valid'): `numpy.correlate` may perform slowly in large arrays (i.e. n = 1e5) because it does not use the FFT to compute the convolution; in that case, `scipy.signal.correlate` might be preferable. - + Examples -------- @@ -738,7 +725,7 @@ def correlate(a, v, mode='valid'): array([ 0.5-0.5j, 1.0+0.j , 1.5-1.5j, 3.0-1.j , 0.0+0.j ]) Note that you get the time reversed, complex conjugated result - (:math:`\overline{c_{-k}}`) when the two input sequences a and v change + (:math:`\overline{c_{-k}}`) when the two input sequences a and v change places: >>> np.correlate([0, 1, 0.5j], [1+1j, 2, 3-1j], 'full') @@ -1300,7 +1287,7 @@ def rollaxis(a, axis, start=0): +-------------------+----------------------+ | ``arr.ndim + 1`` | raise ``AxisError`` | +-------------------+----------------------+ - + .. |vdots| unicode:: U+22EE .. Vertical Ellipsis Returns @@ -1843,11 +1830,11 @@ def fromfunction(function, shape, *, dtype=float, like=None, **kwargs): >>> np.fromfunction(lambda i, j: i, (2, 2), dtype=float) array([[0., 0.], [1., 1.]]) - - >>> np.fromfunction(lambda i, j: j, (2, 2), dtype=float) + + >>> np.fromfunction(lambda i, j: j, (2, 2), dtype=float) array([[0., 1.], [0., 1.]]) - + >>> np.fromfunction(lambda i, j: i == j, (3, 3), dtype=int) array([[ True, False, False], [False, True, False], diff --git a/numpy/core/src/multiarray/common.h b/numpy/core/src/multiarray/common.h index e40edb0d235d..06322e902eb3 100644 --- a/numpy/core/src/multiarray/common.h +++ b/numpy/core/src/multiarray/common.h @@ -149,7 +149,7 @@ check_and_adjust_axis_msg(int *axis, int ndim, PyObject *msg_prefix) static PyObject *AxisError_cls = NULL; PyObject *exc; - npy_cache_import("numpy.core._exceptions", "AxisError", &AxisError_cls); + npy_cache_import("numpy.exceptions", "AxisError", &AxisError_cls); if (AxisError_cls == NULL) { return -1; } diff --git a/numpy/core/src/multiarray/convert_datatype.c b/numpy/core/src/multiarray/convert_datatype.c index 7f31fd656d22..eeb42df66736 100644 --- a/numpy/core/src/multiarray/convert_datatype.c +++ b/numpy/core/src/multiarray/convert_datatype.c @@ -384,18 +384,14 @@ PyArray_GetCastFunc(PyArray_Descr *descr, int type_num) !PyTypeNum_ISCOMPLEX(type_num) && PyTypeNum_ISNUMBER(type_num) && !PyTypeNum_ISBOOL(type_num)) { - PyObject *cls = NULL, *obj = NULL; - int ret; - obj = PyImport_ImportModule("numpy.core"); - - if (obj) { - cls = PyObject_GetAttrString(obj, "ComplexWarning"); - Py_DECREF(obj); + static PyObject *cls = NULL; + npy_cache_import("numpy.exceptions", "ComplexWarning", &cls); + if (cls == NULL) { + return NULL; } - ret = PyErr_WarnEx(cls, + int ret = PyErr_WarnEx(cls, "Casting complex values to real discards " "the imaginary part", 1); - Py_XDECREF(cls); if (ret < 0) { return NULL; } @@ -2613,7 +2609,7 @@ complex_to_noncomplex_get_loop( { static PyObject *cls = NULL; int ret; - npy_cache_import("numpy.core", "ComplexWarning", &cls); + npy_cache_import("numpy.exceptions", "ComplexWarning", &cls); if (cls == NULL) { return -1; } diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c index 8c8cc3c4406e..6c5eb9730df4 100644 --- a/numpy/core/src/multiarray/multiarraymodule.c +++ b/numpy/core/src/multiarray/multiarraymodule.c @@ -4162,7 +4162,6 @@ array_shares_memory_impl(PyObject *args, PyObject *kwds, Py_ssize_t default_max_ static char *kwlist[] = {"self", "other", "max_work", NULL}; mem_overlap_t result; - static PyObject *too_hard_cls = NULL; Py_ssize_t max_work; NPY_BEGIN_THREADS_DEF; @@ -4242,8 +4241,8 @@ array_shares_memory_impl(PyObject *args, PyObject *kwds, Py_ssize_t default_max_ } else if (result == MEM_OVERLAP_TOO_HARD) { if (raise_exceptions) { - npy_cache_import("numpy.core._exceptions", "TooHardError", - &too_hard_cls); + static PyObject *too_hard_cls = NULL; + npy_cache_import("numpy.exceptions", "TooHardError", &too_hard_cls); if (too_hard_cls) { PyErr_SetString(too_hard_cls, "Exceeded max_work"); } diff --git a/numpy/core/src/umath/scalarmath.c.src b/numpy/core/src/umath/scalarmath.c.src index 9d703504f3b3..70fe963b9ed4 100644 --- a/numpy/core/src/umath/scalarmath.c.src +++ b/numpy/core/src/umath/scalarmath.c.src @@ -1549,7 +1549,7 @@ static PyObject * * */ -/* +/* * Complex numbers do not support remainder so we manually make sure that the * operation is not defined. This is/was especially important for longdoubles * due to their tendency to recurse for some operations, see gh-18548. @@ -1711,7 +1711,7 @@ static int emit_complexwarning(void) { static PyObject *cls = NULL; - npy_cache_import("numpy.core", "ComplexWarning", &cls); + npy_cache_import("numpy.exceptions", "ComplexWarning", &cls); if (cls == NULL) { return -1; } diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index ad1d9bb046e8..4d3996d86b70 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -6197,7 +6197,7 @@ def test_mean_float16(self): def test_mean_axis_error(self): # Ensure that AxisError is raised instead of IndexError when axis is # out of bounds, see gh-15817. - with assert_raises(np.core._exceptions.AxisError): + with assert_raises(np.exceptions.AxisError): np.arange(10).mean(axis=2) def test_mean_where(self): @@ -6281,7 +6281,7 @@ def test_var_complex_byteorder(self): def test_var_axis_error(self): # Ensure that AxisError is raised instead of IndexError when axis is # out of bounds, see gh-15817. - with assert_raises(np.core._exceptions.AxisError): + with assert_raises(np.exceptions.AxisError): np.arange(10).var(axis=2) def test_var_where(self): diff --git a/numpy/exceptions.py b/numpy/exceptions.py new file mode 100644 index 000000000000..4a63263a5bf3 --- /dev/null +++ b/numpy/exceptions.py @@ -0,0 +1,123 @@ +from ._utils import set_module as _set_module + +__all__ = ["ComplexWarning", "TooHardError", "AxisError"] + + +@_set_module('numpy') +class ComplexWarning(RuntimeWarning): + """ + The warning raised when casting a complex dtype to a real dtype. + + As implemented, casting a complex number to a real discards its imaginary + part, but this behavior may not be what the user actually wants. + + """ + pass + + + +# Exception used in shares_memory() +@_set_module('numpy') +class TooHardError(RuntimeError): + """max_work was exceeded. + + This is raised whenever the maximum number of candidate solutions + to consider specified by the ``max_work`` parameter is exceeded. + Assigning a finite number to max_work may have caused the operation + to fail. + + """ + + pass + + +@_set_module('numpy') +class AxisError(ValueError, IndexError): + """Axis supplied was invalid. + + This is raised whenever an ``axis`` parameter is specified that is larger + than the number of array dimensions. + For compatibility with code written against older numpy versions, which + raised a mixture of `ValueError` and `IndexError` for this situation, this + exception subclasses both to ensure that ``except ValueError`` and + ``except IndexError`` statements continue to catch `AxisError`. + + .. versionadded:: 1.13 + + Parameters + ---------- + axis : int or str + The out of bounds axis or a custom exception message. + If an axis is provided, then `ndim` should be specified as well. + ndim : int, optional + The number of array dimensions. + msg_prefix : str, optional + A prefix for the exception message. + + Attributes + ---------- + axis : int, optional + The out of bounds axis or ``None`` if a custom exception + message was provided. This should be the axis as passed by + the user, before any normalization to resolve negative indices. + + .. versionadded:: 1.22 + ndim : int, optional + The number of array dimensions or ``None`` if a custom exception + message was provided. + + .. versionadded:: 1.22 + + + Examples + -------- + >>> array_1d = np.arange(10) + >>> np.cumsum(array_1d, axis=1) + Traceback (most recent call last): + ... + numpy.AxisError: axis 1 is out of bounds for array of dimension 1 + + Negative axes are preserved: + + >>> np.cumsum(array_1d, axis=-2) + Traceback (most recent call last): + ... + numpy.AxisError: axis -2 is out of bounds for array of dimension 1 + + The class constructor generally takes the axis and arrays' + dimensionality as arguments: + + >>> print(np.AxisError(2, 1, msg_prefix='error')) + error: axis 2 is out of bounds for array of dimension 1 + + Alternatively, a custom exception message can be passed: + + >>> print(np.AxisError('Custom error message')) + Custom error message + + """ + + __slots__ = ("axis", "ndim", "_msg") + + def __init__(self, axis, ndim=None, msg_prefix=None): + if ndim is msg_prefix is None: + # single-argument form: directly set the error message + self._msg = axis + self.axis = None + self.ndim = None + else: + self._msg = msg_prefix + self.axis = axis + self.ndim = ndim + + def __str__(self): + axis = self.axis + ndim = self.ndim + + if axis is ndim is None: + return self._msg + else: + msg = f"axis {axis} is out of bounds for array of dimension {ndim}" + if self._msg is not None: + msg = f"{self._msg}: {msg}" + return msg diff --git a/numpy/tests/test_public_api.py b/numpy/tests/test_public_api.py index 396375d87911..4cd6025100f9 100644 --- a/numpy/tests/test_public_api.py +++ b/numpy/tests/test_public_api.py @@ -137,6 +137,7 @@ def test_NPY_NO_EXPORT(): "doc", "doc.constants", "doc.ufuncs", + "exceptions", "f2py", "fft", "lib", From 1d31511ce8081f03ac507854c94cf4793a5982e3 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Tue, 22 Nov 2022 12:27:54 +0100 Subject: [PATCH 2/9] MAINT: Move ModuleDeprecationWarning and ModuleDeprecationWarning Both should now live in the "exceptions" module. --- numpy/__init__.py | 9 ++++----- numpy/_globals.py | 28 +--------------------------- numpy/exceptions.py | 39 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 43 insertions(+), 33 deletions(-) diff --git a/numpy/__init__.py b/numpy/__init__.py index 5af2ac8475db..1e41dc8bfdcc 100644 --- a/numpy/__init__.py +++ b/numpy/__init__.py @@ -106,11 +106,10 @@ import sys import warnings -from ._globals import ( - ModuleDeprecationWarning, VisibleDeprecationWarning, - _NoValue, _CopyMode -) -from .exceptions import ComplexWarning, TooHardError, AxisError +from ._globals import _NoValue, _CopyMode +from .exceptions import ( + ComplexWarning, ModuleDeprecationWarning, VisibleDeprecationWarning, + TooHardError, AxisError) # We first need to detect if we're being called as part of the numpy setup # procedure itself in a reliable manner. diff --git a/numpy/_globals.py b/numpy/_globals.py index 555777167e3b..416a20f5e11b 100644 --- a/numpy/_globals.py +++ b/numpy/_globals.py @@ -19,10 +19,7 @@ def foo(arg=np._NoValue): from ._utils import set_module as _set_module -__all__ = [ - 'ModuleDeprecationWarning', 'VisibleDeprecationWarning', - '_NoValue', '_CopyMode' - ] +__all__ = ['_NoValue', '_CopyMode'] # Disallow reloading this module so as to preserve the identities of the @@ -32,29 +29,6 @@ def foo(arg=np._NoValue): _is_loaded = True -@_set_module("numpy") -class ModuleDeprecationWarning(DeprecationWarning): - """Module deprecation warning. - - The nose tester turns ordinary Deprecation warnings into test failures. - That makes it hard to deprecate whole modules, because they get - imported by default. So this is a special Deprecation warning that the - nose tester will let pass without making tests fail. - - """ - - -@_set_module("numpy") -class VisibleDeprecationWarning(UserWarning): - """Visible deprecation warning. - - By default, python will not show deprecation warnings, so this class - can be used when a very visible warning is helpful, for example because - the usage is most likely a user bug. - - """ - - class _NoValueType: """Special keyword value. diff --git a/numpy/exceptions.py b/numpy/exceptions.py index 4a63263a5bf3..6af5d52a16ce 100644 --- a/numpy/exceptions.py +++ b/numpy/exceptions.py @@ -1,6 +1,20 @@ from ._utils import set_module as _set_module -__all__ = ["ComplexWarning", "TooHardError", "AxisError"] +__all__ = [ + "ComplexWarning", "ModuleDeprecationWarning", "VisibleDeprecationWarning", + "TooHardError", "AxisError"] + + +# Disallow reloading this module so as to preserve the identities of the +# classes defined here. +if '_is_loaded' in globals(): + raise RuntimeError('Reloading numpy._globals is not allowed') +_is_loaded = True + + +# TODO: One day, we should remove the _set_module here before removing them +# fully. Not doing it now, just to allow unpickling to work on older +# versions for a bit. (Module exists since NumPy 1.25.) @_set_module('numpy') @@ -16,6 +30,29 @@ class ComplexWarning(RuntimeWarning): +@_set_module("numpy") +class ModuleDeprecationWarning(DeprecationWarning): + """Module deprecation warning. + + The nose tester turns ordinary Deprecation warnings into test failures. + That makes it hard to deprecate whole modules, because they get + imported by default. So this is a special Deprecation warning that the + nose tester will let pass without making tests fail. + + """ + + +@_set_module("numpy") +class VisibleDeprecationWarning(UserWarning): + """Visible deprecation warning. + + By default, python will not show deprecation warnings, so this class + can be used when a very visible warning is helpful, for example because + the usage is most likely a user bug. + + """ + + # Exception used in shares_memory() @_set_module('numpy') class TooHardError(RuntimeError): From 86029d0188e371d70b90d224c3f0061997f86fc5 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Tue, 22 Nov 2022 12:51:32 +0100 Subject: [PATCH 3/9] TYP: Modify typing stubs for new `np.exceptions` module --- numpy/__init__.pyi | 1 + numpy/exceptions.py | 1 + numpy/exceptions.pyi | 8 ++++++++ 3 files changed, 10 insertions(+) create mode 100644 numpy/exceptions.pyi diff --git a/numpy/__init__.pyi b/numpy/__init__.pyi index 8019976d0da9..69ac47a763e6 100644 --- a/numpy/__init__.pyi +++ b/numpy/__init__.pyi @@ -204,6 +204,7 @@ from typing import ( # Ensures that the stubs are picked up from numpy import ( ctypeslib as ctypeslib, + exceptions as exceptions, fft as fft, lib as lib, linalg as linalg, diff --git a/numpy/exceptions.py b/numpy/exceptions.py index 6af5d52a16ce..8c393d5e2f05 100644 --- a/numpy/exceptions.py +++ b/numpy/exceptions.py @@ -15,6 +15,7 @@ # TODO: One day, we should remove the _set_module here before removing them # fully. Not doing it now, just to allow unpickling to work on older # versions for a bit. (Module exists since NumPy 1.25.) +# This then also means that the typing stubs should be moved! @_set_module('numpy') diff --git a/numpy/exceptions.pyi b/numpy/exceptions.pyi new file mode 100644 index 000000000000..53b7a0c1645c --- /dev/null +++ b/numpy/exceptions.pyi @@ -0,0 +1,8 @@ +from numpy.exceptions import ( + ComplexWarning as ComplexWarning, + ModuleDeprecationWarning as ModuleDeprecationWarning, + VisibleDeprecationWarning as VisibleDeprecationWarning, + TooHardError as TooHardError, + AxisError as AxisError, +) + From 7dce375bcf99eb0019f6956241cce941c31ec8b4 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Tue, 22 Nov 2022 13:35:14 +0100 Subject: [PATCH 4/9] DOC: Document exceptions and warnings in the refguide AxisError did exist, but e.g. ComplexWarning wasn't even properly included. --- doc/source/reference/routines.other.rst | 7 +---- numpy/exceptions.py | 42 +++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/doc/source/reference/routines.other.rst b/doc/source/reference/routines.other.rst index e980406eb419..7b60545f1aa3 100644 --- a/doc/source/reference/routines.other.rst +++ b/doc/source/reference/routines.other.rst @@ -58,9 +58,4 @@ Matlab-like Functions who disp -Exceptions ----------- -.. autosummary:: - :toctree: generated/ - - AxisError +.. automodule:: numpy.exceptions diff --git a/numpy/exceptions.py b/numpy/exceptions.py index 8c393d5e2f05..af19fce539bd 100644 --- a/numpy/exceptions.py +++ b/numpy/exceptions.py @@ -1,7 +1,40 @@ +""" +Exceptions and Warnings (:mod:`numpy.exceptions`) +================================================= + +General exceptions used by NumPy. Note that some exceptions may be module +specific, such as linear algebra errors. + +.. versionadded:: NumPy 1.24 + + The exceptions module is new in NumPy 1.24. Older exceptions remain + available through the main NumPy namespace for compatibility. + +.. currentmodule:: numpy.exceptions + +Warnings +-------- +.. autosummary:: + :toctree: generated/ + + ComplexWarning Given when converting complex to real. + VisibleDeprecationWarning Same as a DeprecationWarning, but more visible. + +Exceptions +---------- +.. autosummary:: + :toctree: generated/ + + AxisError Given when an axis was invalid. + TooHardError Error specific to `numpy.shares_memory`. + +""" + + from ._utils import set_module as _set_module __all__ = [ - "ComplexWarning", "ModuleDeprecationWarning", "VisibleDeprecationWarning", + "ComplexWarning", "VisibleDeprecationWarning", "TooHardError", "AxisError"] @@ -14,7 +47,7 @@ # TODO: One day, we should remove the _set_module here before removing them # fully. Not doing it now, just to allow unpickling to work on older -# versions for a bit. (Module exists since NumPy 1.25.) +# versions for a bit. (Module exists since NumPy 1.24.) # This then also means that the typing stubs should be moved! @@ -35,6 +68,11 @@ class ComplexWarning(RuntimeWarning): class ModuleDeprecationWarning(DeprecationWarning): """Module deprecation warning. + .. warning:: + + This warning should not be used, since nose testing is not relvant + anymore. + The nose tester turns ordinary Deprecation warnings into test failures. That makes it hard to deprecate whole modules, because they get imported by default. So this is a special Deprecation warning that the From f2c5b1ddd37a996e3508827df06ef8fb111b8b60 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Tue, 22 Nov 2022 13:36:58 +0100 Subject: [PATCH 5/9] DOC: Add release notes for `np.exceptions` namespace --- doc/release/upcoming_changes/22644.new_feature.rst | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 doc/release/upcoming_changes/22644.new_feature.rst diff --git a/doc/release/upcoming_changes/22644.new_feature.rst b/doc/release/upcoming_changes/22644.new_feature.rst new file mode 100644 index 000000000000..e903fc7a0def --- /dev/null +++ b/doc/release/upcoming_changes/22644.new_feature.rst @@ -0,0 +1,7 @@ +NumPy now has an ``np.exceptions`` namespace +-------------------------------------------- +NumPy now has a dedicated namespace making most exceptions +and warnings available. All of these remain available in the +main namespace, although some may be moved slowly in the future. +The main reason for this is to increase discoverably and add +future exceptions. From 7b1ee55a1c17748e150ce05ceb7b7df4415ff8c2 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Tue, 22 Nov 2022 16:53:01 +0100 Subject: [PATCH 6/9] DOC: Update messages to NumPy 1.25 although I hope its 2.0 :) --- numpy/exceptions.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/numpy/exceptions.py b/numpy/exceptions.py index af19fce539bd..eb5aaeac1928 100644 --- a/numpy/exceptions.py +++ b/numpy/exceptions.py @@ -5,9 +5,9 @@ General exceptions used by NumPy. Note that some exceptions may be module specific, such as linear algebra errors. -.. versionadded:: NumPy 1.24 +.. versionadded:: NumPy 1.25 - The exceptions module is new in NumPy 1.24. Older exceptions remain + The exceptions module is new in NumPy 1.25. Older exceptions remain available through the main NumPy namespace for compatibility. .. currentmodule:: numpy.exceptions @@ -47,7 +47,7 @@ # TODO: One day, we should remove the _set_module here before removing them # fully. Not doing it now, just to allow unpickling to work on older -# versions for a bit. (Module exists since NumPy 1.24.) +# versions for a bit. (Module exists since NumPy 1.25.) # This then also means that the typing stubs should be moved! From 8cf1f69435f15d4f32bec7e550756a6151bf91f1 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Wed, 30 Nov 2022 08:55:30 +0100 Subject: [PATCH 7/9] MAINT: Fixup new ufunc AxisError use to use `numpy.exceptions` --- numpy/core/src/umath/ufunc_object.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c index 284af7a54647..4e628f59a975 100644 --- a/numpy/core/src/umath/ufunc_object.c +++ b/numpy/core/src/umath/ufunc_object.c @@ -1830,7 +1830,7 @@ _parse_axes_arg(PyUFuncObject *ufunc, int op_core_num_dims[], PyObject *axes, if (PyTuple_Size(op_axes_tuple) != op_ncore) { /* must have been a tuple with too many entries. */ npy_cache_import( - "numpy.core._exceptions", "AxisError", &AxisError_cls); + "numpy.exceptions", "AxisError", &AxisError_cls); if (AxisError_cls == NULL) { return -1; } @@ -1858,8 +1858,7 @@ _parse_axes_arg(PyUFuncObject *ufunc, int op_core_num_dims[], PyObject *axes, return -1; } /* If it is a single integer, inform user that more are needed */ - npy_cache_import( - "numpy.core._exceptions", "AxisError", &AxisError_cls); + npy_cache_import("numpy.exceptions", "AxisError", &AxisError_cls); if (AxisError_cls == NULL) { return -1; } From e9e1d039e4a3294b9b63895bb72d8d6c354732c9 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Wed, 30 Nov 2022 12:46:43 +0100 Subject: [PATCH 8/9] MAINT: (meson) Add exceptions and expctions.pyi to pure python sources --- numpy/meson.build | 2 ++ 1 file changed, 2 insertions(+) diff --git a/numpy/meson.build b/numpy/meson.build index bdf2d592e60e..23bd83a04ab9 100644 --- a/numpy/meson.build +++ b/numpy/meson.build @@ -95,6 +95,8 @@ python_sources = [ 'ctypeslib.py', 'ctypeslib.pyi', 'dual.py', + 'exceptions.py', + 'exceptions.pyi', 'matlib.py', 'py.typed', 'version.py' From 4539ecd88bd2c8ca7aee0aba254b894f1042a084 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Wed, 30 Nov 2022 13:24:17 +0100 Subject: [PATCH 9/9] Update numpy/exceptions.py Co-authored-by: Matti Picus --- numpy/exceptions.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/numpy/exceptions.py b/numpy/exceptions.py index eb5aaeac1928..81a2f3c65e89 100644 --- a/numpy/exceptions.py +++ b/numpy/exceptions.py @@ -62,8 +62,6 @@ class ComplexWarning(RuntimeWarning): """ pass - - @_set_module("numpy") class ModuleDeprecationWarning(DeprecationWarning): """Module deprecation warning.