Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/numpy/core/_exceptions.py: 39%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

109 statements  

1""" 

2Various richly-typed exceptions, that also help us deal with string formatting 

3in python where it's easier. 

4 

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 

9 

10def _unpack_tuple(tup): 

11 if len(tup) == 1: 

12 return tup[0] 

13 else: 

14 return tup 

15 

16 

17def _display_as_base(cls): 

18 """ 

19 A decorator that makes an exception class look like its base. 

20 

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. 

23 

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 

30 

31 

32class UFuncTypeError(TypeError): 

33 """ Base class for all ufunc exceptions """ 

34 def __init__(self, ufunc): 

35 self.ufunc = ufunc 

36 

37 

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 

45 

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 ) 

52 

53 

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) 

60 

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 ) 

70 

71 

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 

79 

80 

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 

87 

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 ) 

97 

98 

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 

105 

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 ) 

115 

116 

117# Exception used in shares_memory() 

118@set_module('numpy') 

119class TooHardError(RuntimeError): 

120 """max_work was exceeded. 

121 

122 This is raised whenever the maximum number of candidate solutions  

123 to consider specified by the ``max_work`` parameter is exceeded. 

124 Assigning a finite number to max_work may have caused the operation  

125 to fail. 

126 

127 """ 

128 

129 pass 

130 

131 

132@set_module('numpy') 

133class AxisError(ValueError, IndexError): 

134 """Axis supplied was invalid. 

135 

136 This is raised whenever an ``axis`` parameter is specified that is larger 

137 than the number of array dimensions. 

138 For compatibility with code written against older numpy versions, which 

139 raised a mixture of `ValueError` and `IndexError` for this situation, this 

140 exception subclasses both to ensure that ``except ValueError`` and 

141 ``except IndexError`` statements continue to catch `AxisError`. 

142 

143 .. versionadded:: 1.13 

144 

145 Parameters 

146 ---------- 

147 axis : int or str 

148 The out of bounds axis or a custom exception message. 

149 If an axis is provided, then `ndim` should be specified as well. 

150 ndim : int, optional 

151 The number of array dimensions. 

152 msg_prefix : str, optional 

153 A prefix for the exception message. 

154 

155 Attributes 

156 ---------- 

157 axis : int, optional 

158 The out of bounds axis or ``None`` if a custom exception 

159 message was provided. This should be the axis as passed by 

160 the user, before any normalization to resolve negative indices. 

161 

162 .. versionadded:: 1.22 

163 ndim : int, optional 

164 The number of array dimensions or ``None`` if a custom exception 

165 message was provided. 

166 

167 .. versionadded:: 1.22 

168 

169 

170 Examples 

171 -------- 

172 >>> array_1d = np.arange(10) 

173 >>> np.cumsum(array_1d, axis=1) 

174 Traceback (most recent call last): 

175 ... 

176 numpy.AxisError: axis 1 is out of bounds for array of dimension 1 

177 

178 Negative axes are preserved: 

179 

180 >>> np.cumsum(array_1d, axis=-2) 

181 Traceback (most recent call last): 

182 ... 

183 numpy.AxisError: axis -2 is out of bounds for array of dimension 1 

184 

185 The class constructor generally takes the axis and arrays' 

186 dimensionality as arguments: 

187 

188 >>> print(np.AxisError(2, 1, msg_prefix='error')) 

189 error: axis 2 is out of bounds for array of dimension 1 

190 

191 Alternatively, a custom exception message can be passed: 

192 

193 >>> print(np.AxisError('Custom error message')) 

194 Custom error message 

195 

196 """ 

197 

198 __slots__ = ("axis", "ndim", "_msg") 

199 

200 def __init__(self, axis, ndim=None, msg_prefix=None): 

201 if ndim is msg_prefix is None: 

202 # single-argument form: directly set the error message 

203 self._msg = axis 

204 self.axis = None 

205 self.ndim = None 

206 else: 

207 self._msg = msg_prefix 

208 self.axis = axis 

209 self.ndim = ndim 

210 

211 def __str__(self): 

212 axis = self.axis 

213 ndim = self.ndim 

214 

215 if axis is ndim is None: 

216 return self._msg 

217 else: 

218 msg = f"axis {axis} is out of bounds for array of dimension {ndim}" 

219 if self._msg is not None: 

220 msg = f"{self._msg}: {msg}" 

221 return msg 

222 

223 

224@_display_as_base 

225class _ArrayMemoryError(MemoryError): 

226 """ Thrown when an array cannot be allocated""" 

227 def __init__(self, shape, dtype): 

228 self.shape = shape 

229 self.dtype = dtype 

230 

231 @property 

232 def _total_size(self): 

233 num_bytes = self.dtype.itemsize 

234 for dim in self.shape: 

235 num_bytes *= dim 

236 return num_bytes 

237 

238 @staticmethod 

239 def _size_to_string(num_bytes): 

240 """ Convert a number of bytes into a binary size string """ 

241 

242 # https://en.wikipedia.org/wiki/Binary_prefix 

243 LOG2_STEP = 10 

244 STEP = 1024 

245 units = ['bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB'] 

246 

247 unit_i = max(num_bytes.bit_length() - 1, 1) // LOG2_STEP 

248 unit_val = 1 << (unit_i * LOG2_STEP) 

249 n_units = num_bytes / unit_val 

250 del unit_val 

251 

252 # ensure we pick a unit that is correct after rounding 

253 if round(n_units) == STEP: 

254 unit_i += 1 

255 n_units /= STEP 

256 

257 # deal with sizes so large that we don't have units for them 

258 if unit_i >= len(units): 

259 new_unit_i = len(units) - 1 

260 n_units *= 1 << ((unit_i - new_unit_i) * LOG2_STEP) 

261 unit_i = new_unit_i 

262 

263 unit_name = units[unit_i] 

264 # format with a sensible number of digits 

265 if unit_i == 0: 

266 # no decimal point on bytes 

267 return '{:.0f} {}'.format(n_units, unit_name) 

268 elif round(n_units) < 1000: 

269 # 3 significant figures, if none are dropped to the left of the . 

270 return '{:#.3g} {}'.format(n_units, unit_name) 

271 else: 

272 # just give all the digits otherwise 

273 return '{:#.0f} {}'.format(n_units, unit_name) 

274 

275 def __str__(self): 

276 size_str = self._size_to_string(self._total_size) 

277 return ( 

278 "Unable to allocate {} for an array with shape {} and data type {}" 

279 .format(size_str, self.shape, self.dtype) 

280 )