Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/numpy/core/_exceptions.py: 46%
87 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1"""
2Various richly-typed exceptions, that also help us deal with string formatting
3in python where it's easier.
5By putting the formatting in `__str__`, we also avoid paying the cost for
6users who silence the exceptions.
7"""
8from numpy.core.overrides import set_module
10def _unpack_tuple(tup):
11 if len(tup) == 1:
12 return tup[0]
13 else:
14 return tup
17def _display_as_base(cls):
18 """
19 A decorator that makes an exception class look like its base.
21 We use this to hide subclasses that are implementation details - the user
22 should catch the base type, which is what the traceback will show them.
24 Classes decorated with this decorator are subject to removal without a
25 deprecation warning.
26 """
27 assert issubclass(cls, Exception)
28 cls.__name__ = cls.__base__.__name__
29 return cls
32class UFuncTypeError(TypeError):
33 """ Base class for all ufunc exceptions """
34 def __init__(self, ufunc):
35 self.ufunc = ufunc
38@_display_as_base
39class _UFuncBinaryResolutionError(UFuncTypeError):
40 """ Thrown when a binary resolution fails """
41 def __init__(self, ufunc, dtypes):
42 super().__init__(ufunc)
43 self.dtypes = tuple(dtypes)
44 assert len(self.dtypes) == 2
46 def __str__(self):
47 return (
48 "ufunc {!r} cannot use operands with types {!r} and {!r}"
49 ).format(
50 self.ufunc.__name__, *self.dtypes
51 )
54@_display_as_base
55class _UFuncNoLoopError(UFuncTypeError):
56 """ Thrown when a ufunc loop cannot be found """
57 def __init__(self, ufunc, dtypes):
58 super().__init__(ufunc)
59 self.dtypes = tuple(dtypes)
61 def __str__(self):
62 return (
63 "ufunc {!r} did not contain a loop with signature matching types "
64 "{!r} -> {!r}"
65 ).format(
66 self.ufunc.__name__,
67 _unpack_tuple(self.dtypes[:self.ufunc.nin]),
68 _unpack_tuple(self.dtypes[self.ufunc.nin:])
69 )
72@_display_as_base
73class _UFuncCastingError(UFuncTypeError):
74 def __init__(self, ufunc, casting, from_, to):
75 super().__init__(ufunc)
76 self.casting = casting
77 self.from_ = from_
78 self.to = to
81@_display_as_base
82class _UFuncInputCastingError(_UFuncCastingError):
83 """ Thrown when a ufunc input cannot be casted """
84 def __init__(self, ufunc, casting, from_, to, i):
85 super().__init__(ufunc, casting, from_, to)
86 self.in_i = i
88 def __str__(self):
89 # only show the number if more than one input exists
90 i_str = "{} ".format(self.in_i) if self.ufunc.nin != 1 else ""
91 return (
92 "Cannot cast ufunc {!r} input {}from {!r} to {!r} with casting "
93 "rule {!r}"
94 ).format(
95 self.ufunc.__name__, i_str, self.from_, self.to, self.casting
96 )
99@_display_as_base
100class _UFuncOutputCastingError(_UFuncCastingError):
101 """ Thrown when a ufunc output cannot be casted """
102 def __init__(self, ufunc, casting, from_, to, i):
103 super().__init__(ufunc, casting, from_, to)
104 self.out_i = i
106 def __str__(self):
107 # only show the number if more than one output exists
108 i_str = "{} ".format(self.out_i) if self.ufunc.nout != 1 else ""
109 return (
110 "Cannot cast ufunc {!r} output {}from {!r} to {!r} with casting "
111 "rule {!r}"
112 ).format(
113 self.ufunc.__name__, i_str, self.from_, self.to, self.casting
114 )
117# Exception used in shares_memory()
118@set_module('numpy')
119class TooHardError(RuntimeError):
120 pass
123@set_module('numpy')
124class AxisError(ValueError, IndexError):
125 """Axis supplied was invalid.
127 This is raised whenever an ``axis`` parameter is specified that is larger
128 than the number of array dimensions.
129 For compatibility with code written against older numpy versions, which
130 raised a mixture of `ValueError` and `IndexError` for this situation, this
131 exception subclasses both to ensure that ``except ValueError`` and
132 ``except IndexError`` statements continue to catch `AxisError`.
134 .. versionadded:: 1.13
136 Parameters
137 ----------
138 axis : int or str
139 The out of bounds axis or a custom exception message.
140 If an axis is provided, then `ndim` should be specified as well.
141 ndim : int, optional
142 The number of array dimensions.
143 msg_prefix : str, optional
144 A prefix for the exception message.
146 Attributes
147 ----------
148 axis : int, optional
149 The out of bounds axis or ``None`` if a custom exception
150 message was provided. This should be the axis as passed by
151 the user, before any normalization to resolve negative indices.
153 .. versionadded:: 1.22
154 ndim : int, optional
155 The number of array dimensions or ``None`` if a custom exception
156 message was provided.
158 .. versionadded:: 1.22
161 Examples
162 --------
163 >>> array_1d = np.arange(10)
164 >>> np.cumsum(array_1d, axis=1)
165 Traceback (most recent call last):
166 ...
167 numpy.AxisError: axis 1 is out of bounds for array of dimension 1
169 Negative axes are preserved:
171 >>> np.cumsum(array_1d, axis=-2)
172 Traceback (most recent call last):
173 ...
174 numpy.AxisError: axis -2 is out of bounds for array of dimension 1
176 The class constructor generally takes the axis and arrays'
177 dimensionality as arguments:
179 >>> print(np.AxisError(2, 1, msg_prefix='error'))
180 error: axis 2 is out of bounds for array of dimension 1
182 Alternatively, a custom exception message can be passed:
184 >>> print(np.AxisError('Custom error message'))
185 Custom error message
187 """
189 __slots__ = ("axis", "ndim", "_msg")
191 def __init__(self, axis, ndim=None, msg_prefix=None):
192 if ndim is msg_prefix is None:
193 # single-argument form: directly set the error message
194 self._msg = axis
195 self.axis = None
196 self.ndim = None
197 else:
198 self._msg = msg_prefix
199 self.axis = axis
200 self.ndim = ndim
202 def __str__(self):
203 axis = self.axis
204 ndim = self.ndim
206 if axis is ndim is None:
207 return self._msg
208 else:
209 msg = f"axis {axis} is out of bounds for array of dimension {ndim}"
210 if self._msg is not None:
211 msg = f"{self._msg}: {msg}"
212 return msg
215@_display_as_base
216class _ArrayMemoryError(MemoryError):
217 """ Thrown when an array cannot be allocated"""
218 def __init__(self, shape, dtype):
219 self.shape = shape
220 self.dtype = dtype
222 @property
223 def _total_size(self):
224 num_bytes = self.dtype.itemsize
225 for dim in self.shape:
226 num_bytes *= dim
227 return num_bytes
229 @staticmethod
230 def _size_to_string(num_bytes):
231 """ Convert a number of bytes into a binary size string """
233 # https://en.wikipedia.org/wiki/Binary_prefix
234 LOG2_STEP = 10
235 STEP = 1024
236 units = ['bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB']
238 unit_i = max(num_bytes.bit_length() - 1, 1) // LOG2_STEP
239 unit_val = 1 << (unit_i * LOG2_STEP)
240 n_units = num_bytes / unit_val
241 del unit_val
243 # ensure we pick a unit that is correct after rounding
244 if round(n_units) == STEP:
245 unit_i += 1
246 n_units /= STEP
248 # deal with sizes so large that we don't have units for them
249 if unit_i >= len(units):
250 new_unit_i = len(units) - 1
251 n_units *= 1 << ((unit_i - new_unit_i) * LOG2_STEP)
252 unit_i = new_unit_i
254 unit_name = units[unit_i]
255 # format with a sensible number of digits
256 if unit_i == 0:
257 # no decimal point on bytes
258 return '{:.0f} {}'.format(n_units, unit_name)
259 elif round(n_units) < 1000:
260 # 3 significant figures, if none are dropped to the left of the .
261 return '{:#.3g} {}'.format(n_units, unit_name)
262 else:
263 # just give all the digits otherwise
264 return '{:#.0f} {}'.format(n_units, unit_name)
266 def __str__(self):
267 size_str = self._size_to_string(self._total_size)
268 return (
269 "Unable to allocate {} for an array with shape {} and data type {}"
270 .format(size_str, self.shape, self.dtype)
271 )