From 11f7edfd0eeba13f0affedf54735f889e4c23a24 Mon Sep 17 00:00:00 2001 From: Bas van Beek <43369155+BvB93@users.noreply.github.com> Date: Mon, 19 Jul 2021 19:34:17 +0200 Subject: [PATCH] ENH: Delay assembling of the error message until `__str__` is called Co-Authored-By: Eric Wieser <425260+eric-wieser@users.noreply.github.com> --- numpy/core/_exceptions.py | 47 +++++++++------------------- numpy/core/tests/test__exceptions.py | 10 ------ 2 files changed, 15 insertions(+), 42 deletions(-) diff --git a/numpy/core/_exceptions.py b/numpy/core/_exceptions.py index 7056d6c84eaa..157d78412a8d 100644 --- a/numpy/core/_exceptions.py +++ b/numpy/core/_exceptions.py @@ -180,47 +180,30 @@ class AxisError(ValueError, IndexError): """ - __slots__ = ("axis", "ndim") + __slots__ = ("axis", "ndim", "_msg") def __init__(self, axis, ndim=None, msg_prefix=None): - # single-argument form just delegates to base class - if ndim is None and msg_prefix is None: - msg = axis + if ndim is msg_prefix is None: + # single-argument form: directly set the error message + self._msg = axis self.axis = None self.ndim = None - - # do the string formatting here, to save work in the C code else: - msg = ("axis {} is out of bounds for array of dimension {}" - .format(axis, ndim)) - if msg_prefix is not None: - msg = "{}: {}".format(msg_prefix, msg) + self._msg = msg_prefix self.axis = axis self.ndim = ndim - super().__init__(msg) - - @classmethod - def _reconstruct(cls, axis, ndim, args): - """Auxiliary instance constructor used by `__reduce__`. - - Directly assign all instance attributes without further sanitization. - - This method avoids the `__init__` constructor in order to: - * Circumvent dealing with its axis-based overload. - * Avoid extracting the message prefix from ``self.args`` if applicable. - - """ - self = super().__new__(cls) - self.axis = axis - self.ndim = ndim - self.args = args - return self + def __str__(self): + axis = self.axis + ndim = self.ndim - def __reduce__(self): - """Return state information for `pickle`.""" - cls = type(self) - return cls._reconstruct, (self.axis, self.ndim, self.args) + 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 diff --git a/numpy/core/tests/test__exceptions.py b/numpy/core/tests/test__exceptions.py index 22ddcb06fdab..c87412aa4349 100644 --- a/numpy/core/tests/test__exceptions.py +++ b/numpy/core/tests/test__exceptions.py @@ -86,13 +86,3 @@ def test_pickling(self, args): attr1 = getattr(exc, name) attr2 = getattr(exc2, name) assert attr1 == attr2, name - - def test_pickling_compat(self, args): - """Test that `AxisError` instances pickled prior to NumPy 1.22 - can still be unpickled. - """ - # Attach a `__reduce__` method equivalent to the one used prior to 1.22 - exc = np.AxisError(*args) - exc.__reduce__ = super(np.AxisError, exc).__reduce__ - - assert pickle.loads(pickle.dumps(exc))