diff options
| -rw-r--r-- | numpy/__init__.py | 6 | ||||
| -rw-r--r-- | numpy/core/_exceptions.py | 107 | ||||
| -rw-r--r-- | numpy/core/numeric.py | 33 | ||||
| -rw-r--r-- | numpy/core/src/multiarray/common.h | 2 | ||||
| -rw-r--r-- | numpy/core/src/multiarray/convert_datatype.c | 16 | ||||
| -rw-r--r-- | numpy/core/src/multiarray/multiarraymodule.c | 5 | ||||
| -rw-r--r-- | numpy/core/src/umath/scalarmath.c.src | 4 | ||||
| -rw-r--r-- | numpy/core/tests/test_multiarray.py | 4 | ||||
| -rw-r--r-- | numpy/exceptions.py | 123 | ||||
| -rw-r--r-- | numpy/tests/test_public_api.py | 1 |
10 files changed, 151 insertions, 150 deletions
diff --git a/numpy/__init__.py b/numpy/__init__.py index bdea595ed..5af2ac847 100644 --- a/numpy/__init__.py +++ b/numpy/__init__.py @@ -110,6 +110,7 @@ from ._globals import ( 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 @@ else: 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 db5dfea02..62579ed0d 100644 --- a/numpy/core/_exceptions.py +++ b/numpy/core/_exceptions.py @@ -114,113 +114,6 @@ class _UFuncOutputCastingError(_UFuncCastingError): ) -# 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 5b92972d1..577f8e7cd 100644 --- a/numpy/core/numeric.py +++ b/numpy/core/numeric.py @@ -26,7 +26,7 @@ from .overrides import set_array_function_like_doc, set_module 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 @@ __all__ = [ '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 e40edb0d2..06322e902 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 7f31fd656..eeb42df66 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 8c8cc3c44..6c5eb9730 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 9d703504f..70fe963b9 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 ad1d9bb04..4d3996d86 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -6197,7 +6197,7 @@ class TestStats: 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 @@ class TestStats: 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 000000000..4a63263a5 --- /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 396375d87..4cd602510 100644 --- a/numpy/tests/test_public_api.py +++ b/numpy/tests/test_public_api.py @@ -137,6 +137,7 @@ PUBLIC_MODULES = ['numpy.' + s for s in [ "doc", "doc.constants", "doc.ufuncs", + "exceptions", "f2py", "fft", "lib", |
