summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/release/upcoming_changes/22644.new_feature.rst7
-rw-r--r--doc/source/reference/routines.other.rst7
-rw-r--r--numpy/__init__.py13
-rw-r--r--numpy/__init__.pyi1
-rw-r--r--numpy/_globals.py28
-rw-r--r--numpy/core/_exceptions.py107
-rw-r--r--numpy/core/numeric.py33
-rw-r--r--numpy/core/src/multiarray/common.h2
-rw-r--r--numpy/core/src/multiarray/convert_datatype.c16
-rw-r--r--numpy/core/src/multiarray/multiarraymodule.c5
-rw-r--r--numpy/core/src/umath/scalarmath.c.src4
-rw-r--r--numpy/core/src/umath/ufunc_object.c5
-rw-r--r--numpy/core/tests/test_multiarray.py4
-rw-r--r--numpy/exceptions.py197
-rw-r--r--numpy/exceptions.pyi8
-rw-r--r--numpy/meson.build2
-rw-r--r--numpy/tests/test_public_api.py1
17 files changed, 250 insertions, 190 deletions
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 000000000..e903fc7a0
--- /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.
diff --git a/doc/source/reference/routines.other.rst b/doc/source/reference/routines.other.rst
index e980406eb..7b60545f1 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/__init__.py b/numpy/__init__.py
index bdea595ed..1e41dc8bf 100644
--- a/numpy/__init__.py
+++ b/numpy/__init__.py
@@ -106,10 +106,10 @@ Exceptions to this rule are documented.
import sys
import warnings
-from ._globals import (
- ModuleDeprecationWarning, VisibleDeprecationWarning,
- _NoValue, _CopyMode
-)
+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.
@@ -129,8 +129,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/__init__.pyi b/numpy/__init__.pyi
index 8019976d0..69ac47a76 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/_globals.py b/numpy/_globals.py
index 555777167..416a20f5e 100644
--- a/numpy/_globals.py
+++ b/numpy/_globals.py
@@ -19,10 +19,7 @@ import enum
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 @@ if '_is_loaded' in globals():
_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/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/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c
index 284af7a54..4e628f59a 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;
}
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..81a2f3c65
--- /dev/null
+++ b/numpy/exceptions.py
@@ -0,0 +1,197 @@
+"""
+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.25
+
+ The exceptions module is new in NumPy 1.25. 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", "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.)
+# This then also means that the typing stubs should be moved!
+
+
+@_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
+
+@_set_module("numpy")
+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
+ 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):
+ """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/exceptions.pyi b/numpy/exceptions.pyi
new file mode 100644
index 000000000..53b7a0c16
--- /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,
+)
+
diff --git a/numpy/meson.build b/numpy/meson.build
index bdf2d592e..23bd83a04 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'
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",