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

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 pass 

121 

122 

123@set_module('numpy') 

124class AxisError(ValueError, IndexError): 

125 """Axis supplied was invalid. 

126 

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`. 

133 

134 .. versionadded:: 1.13 

135 

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. 

145 

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. 

152 

153 .. versionadded:: 1.22 

154 ndim : int, optional 

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

156 message was provided. 

157 

158 .. versionadded:: 1.22 

159 

160 

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 

168 

169 Negative axes are preserved: 

170 

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 

175 

176 The class constructor generally takes the axis and arrays' 

177 dimensionality as arguments: 

178 

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

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

181 

182 Alternatively, a custom exception message can be passed: 

183 

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

185 Custom error message 

186 

187 """ 

188 

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

190 

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 

201 

202 def __str__(self): 

203 axis = self.axis 

204 ndim = self.ndim 

205 

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 

213 

214 

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 

221 

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 

228 

229 @staticmethod 

230 def _size_to_string(num_bytes): 

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

232 

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

234 LOG2_STEP = 10 

235 STEP = 1024 

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

237 

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 

242 

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 

247 

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 

253 

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) 

265 

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 )