Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/numpy/core/_dtype.py: 8%

163 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

1""" 

2A place for code to be called from the implementation of np.dtype 

3 

4String handling is much easier to do correctly in python. 

5""" 

6import numpy as np 

7 

8 

9_kind_to_stem = { 

10 'u': 'uint', 

11 'i': 'int', 

12 'c': 'complex', 

13 'f': 'float', 

14 'b': 'bool', 

15 'V': 'void', 

16 'O': 'object', 

17 'M': 'datetime', 

18 'm': 'timedelta', 

19 'S': 'bytes', 

20 'U': 'str', 

21} 

22 

23 

24def _kind_name(dtype): 

25 try: 

26 return _kind_to_stem[dtype.kind] 

27 except KeyError as e: 

28 raise RuntimeError( 

29 "internal dtype error, unknown kind {!r}" 

30 .format(dtype.kind) 

31 ) from None 

32 

33 

34def __str__(dtype): 

35 if dtype.fields is not None: 

36 return _struct_str(dtype, include_align=True) 

37 elif dtype.subdtype: 

38 return _subarray_str(dtype) 

39 elif issubclass(dtype.type, np.flexible) or not dtype.isnative: 

40 return dtype.str 

41 else: 

42 return dtype.name 

43 

44 

45def __repr__(dtype): 

46 arg_str = _construction_repr(dtype, include_align=False) 

47 if dtype.isalignedstruct: 

48 arg_str = arg_str + ", align=True" 

49 return "dtype({})".format(arg_str) 

50 

51 

52def _unpack_field(dtype, offset, title=None): 

53 """ 

54 Helper function to normalize the items in dtype.fields. 

55 

56 Call as: 

57 

58 dtype, offset, title = _unpack_field(*dtype.fields[name]) 

59 """ 

60 return dtype, offset, title 

61 

62 

63def _isunsized(dtype): 

64 # PyDataType_ISUNSIZED 

65 return dtype.itemsize == 0 

66 

67 

68def _construction_repr(dtype, include_align=False, short=False): 

69 """ 

70 Creates a string repr of the dtype, excluding the 'dtype()' part 

71 surrounding the object. This object may be a string, a list, or 

72 a dict depending on the nature of the dtype. This 

73 is the object passed as the first parameter to the dtype 

74 constructor, and if no additional constructor parameters are 

75 given, will reproduce the exact memory layout. 

76 

77 Parameters 

78 ---------- 

79 short : bool 

80 If true, this creates a shorter repr using 'kind' and 'itemsize', instead 

81 of the longer type name. 

82 

83 include_align : bool 

84 If true, this includes the 'align=True' parameter 

85 inside the struct dtype construction dict when needed. Use this flag 

86 if you want a proper repr string without the 'dtype()' part around it. 

87 

88 If false, this does not preserve the 

89 'align=True' parameter or sticky NPY_ALIGNED_STRUCT flag for 

90 struct arrays like the regular repr does, because the 'align' 

91 flag is not part of first dtype constructor parameter. This 

92 mode is intended for a full 'repr', where the 'align=True' is 

93 provided as the second parameter. 

94 """ 

95 if dtype.fields is not None: 

96 return _struct_str(dtype, include_align=include_align) 

97 elif dtype.subdtype: 

98 return _subarray_str(dtype) 

99 else: 

100 return _scalar_str(dtype, short=short) 

101 

102 

103def _scalar_str(dtype, short): 

104 byteorder = _byte_order_str(dtype) 

105 

106 if dtype.type == np.bool_: 

107 if short: 

108 return "'?'" 

109 else: 

110 return "'bool'" 

111 

112 elif dtype.type == np.object_: 

113 # The object reference may be different sizes on different 

114 # platforms, so it should never include the itemsize here. 

115 return "'O'" 

116 

117 elif dtype.type == np.string_: 

118 if _isunsized(dtype): 

119 return "'S'" 

120 else: 

121 return "'S%d'" % dtype.itemsize 

122 

123 elif dtype.type == np.unicode_: 

124 if _isunsized(dtype): 

125 return "'%sU'" % byteorder 

126 else: 

127 return "'%sU%d'" % (byteorder, dtype.itemsize / 4) 

128 

129 # unlike the other types, subclasses of void are preserved - but 

130 # historically the repr does not actually reveal the subclass 

131 elif issubclass(dtype.type, np.void): 

132 if _isunsized(dtype): 

133 return "'V'" 

134 else: 

135 return "'V%d'" % dtype.itemsize 

136 

137 elif dtype.type == np.datetime64: 

138 return "'%sM8%s'" % (byteorder, _datetime_metadata_str(dtype)) 

139 

140 elif dtype.type == np.timedelta64: 

141 return "'%sm8%s'" % (byteorder, _datetime_metadata_str(dtype)) 

142 

143 elif np.issubdtype(dtype, np.number): 

144 # Short repr with endianness, like '<f8' 

145 if short or dtype.byteorder not in ('=', '|'): 

146 return "'%s%c%d'" % (byteorder, dtype.kind, dtype.itemsize) 

147 

148 # Longer repr, like 'float64' 

149 else: 

150 return "'%s%d'" % (_kind_name(dtype), 8*dtype.itemsize) 

151 

152 elif dtype.isbuiltin == 2: 

153 return dtype.type.__name__ 

154 

155 else: 

156 raise RuntimeError( 

157 "Internal error: NumPy dtype unrecognized type number") 

158 

159 

160def _byte_order_str(dtype): 

161 """ Normalize byteorder to '<' or '>' """ 

162 # hack to obtain the native and swapped byte order characters 

163 swapped = np.dtype(int).newbyteorder('S') 

164 native = swapped.newbyteorder('S') 

165 

166 byteorder = dtype.byteorder 

167 if byteorder == '=': 

168 return native.byteorder 

169 if byteorder == 'S': 

170 # TODO: this path can never be reached 

171 return swapped.byteorder 

172 elif byteorder == '|': 

173 return '' 

174 else: 

175 return byteorder 

176 

177 

178def _datetime_metadata_str(dtype): 

179 # TODO: this duplicates the C metastr_to_unicode functionality 

180 unit, count = np.datetime_data(dtype) 

181 if unit == 'generic': 

182 return '' 

183 elif count == 1: 

184 return '[{}]'.format(unit) 

185 else: 

186 return '[{}{}]'.format(count, unit) 

187 

188 

189def _struct_dict_str(dtype, includealignedflag): 

190 # unpack the fields dictionary into ls 

191 names = dtype.names 

192 fld_dtypes = [] 

193 offsets = [] 

194 titles = [] 

195 for name in names: 

196 fld_dtype, offset, title = _unpack_field(*dtype.fields[name]) 

197 fld_dtypes.append(fld_dtype) 

198 offsets.append(offset) 

199 titles.append(title) 

200 

201 # Build up a string to make the dictionary 

202 

203 if np.core.arrayprint._get_legacy_print_mode() <= 121: 

204 colon = ":" 

205 fieldsep = "," 

206 else: 

207 colon = ": " 

208 fieldsep = ", " 

209 

210 # First, the names 

211 ret = "{'names'%s[" % colon 

212 ret += fieldsep.join(repr(name) for name in names) 

213 

214 # Second, the formats 

215 ret += "], 'formats'%s[" % colon 

216 ret += fieldsep.join( 

217 _construction_repr(fld_dtype, short=True) for fld_dtype in fld_dtypes) 

218 

219 # Third, the offsets 

220 ret += "], 'offsets'%s[" % colon 

221 ret += fieldsep.join("%d" % offset for offset in offsets) 

222 

223 # Fourth, the titles 

224 if any(title is not None for title in titles): 

225 ret += "], 'titles'%s[" % colon 

226 ret += fieldsep.join(repr(title) for title in titles) 

227 

228 # Fifth, the itemsize 

229 ret += "], 'itemsize'%s%d" % (colon, dtype.itemsize) 

230 

231 if (includealignedflag and dtype.isalignedstruct): 

232 # Finally, the aligned flag 

233 ret += ", 'aligned'%sTrue}" % colon 

234 else: 

235 ret += "}" 

236 

237 return ret 

238 

239 

240def _aligned_offset(offset, alignment): 

241 # round up offset: 

242 return - (-offset // alignment) * alignment 

243 

244 

245def _is_packed(dtype): 

246 """ 

247 Checks whether the structured data type in 'dtype' 

248 has a simple layout, where all the fields are in order, 

249 and follow each other with no alignment padding. 

250 

251 When this returns true, the dtype can be reconstructed 

252 from a list of the field names and dtypes with no additional 

253 dtype parameters. 

254 

255 Duplicates the C `is_dtype_struct_simple_unaligned_layout` function. 

256 """ 

257 align = dtype.isalignedstruct 

258 max_alignment = 1 

259 total_offset = 0 

260 for name in dtype.names: 

261 fld_dtype, fld_offset, title = _unpack_field(*dtype.fields[name]) 

262 

263 if align: 

264 total_offset = _aligned_offset(total_offset, fld_dtype.alignment) 

265 max_alignment = max(max_alignment, fld_dtype.alignment) 

266 

267 if fld_offset != total_offset: 

268 return False 

269 total_offset += fld_dtype.itemsize 

270 

271 if align: 

272 total_offset = _aligned_offset(total_offset, max_alignment) 

273 

274 if total_offset != dtype.itemsize: 

275 return False 

276 return True 

277 

278 

279def _struct_list_str(dtype): 

280 items = [] 

281 for name in dtype.names: 

282 fld_dtype, fld_offset, title = _unpack_field(*dtype.fields[name]) 

283 

284 item = "(" 

285 if title is not None: 

286 item += "({!r}, {!r}), ".format(title, name) 

287 else: 

288 item += "{!r}, ".format(name) 

289 # Special case subarray handling here 

290 if fld_dtype.subdtype is not None: 

291 base, shape = fld_dtype.subdtype 

292 item += "{}, {}".format( 

293 _construction_repr(base, short=True), 

294 shape 

295 ) 

296 else: 

297 item += _construction_repr(fld_dtype, short=True) 

298 

299 item += ")" 

300 items.append(item) 

301 

302 return "[" + ", ".join(items) + "]" 

303 

304 

305def _struct_str(dtype, include_align): 

306 # The list str representation can't include the 'align=' flag, 

307 # so if it is requested and the struct has the aligned flag set, 

308 # we must use the dict str instead. 

309 if not (include_align and dtype.isalignedstruct) and _is_packed(dtype): 

310 sub = _struct_list_str(dtype) 

311 

312 else: 

313 sub = _struct_dict_str(dtype, include_align) 

314 

315 # If the data type isn't the default, void, show it 

316 if dtype.type != np.void: 

317 return "({t.__module__}.{t.__name__}, {f})".format(t=dtype.type, f=sub) 

318 else: 

319 return sub 

320 

321 

322def _subarray_str(dtype): 

323 base, shape = dtype.subdtype 

324 return "({}, {})".format( 

325 _construction_repr(base, short=True), 

326 shape 

327 ) 

328 

329 

330def _name_includes_bit_suffix(dtype): 

331 if dtype.type == np.object_: 

332 # pointer size varies by system, best to omit it 

333 return False 

334 elif dtype.type == np.bool_: 

335 # implied 

336 return False 

337 elif np.issubdtype(dtype, np.flexible) and _isunsized(dtype): 

338 # unspecified 

339 return False 

340 else: 

341 return True 

342 

343 

344def _name_get(dtype): 

345 # provides dtype.name.__get__, documented as returning a "bit name" 

346 

347 if dtype.isbuiltin == 2: 

348 # user dtypes don't promise to do anything special 

349 return dtype.type.__name__ 

350 

351 if issubclass(dtype.type, np.void): 

352 # historically, void subclasses preserve their name, eg `record64` 

353 name = dtype.type.__name__ 

354 else: 

355 name = _kind_name(dtype) 

356 

357 # append bit counts 

358 if _name_includes_bit_suffix(dtype): 

359 name += "{}".format(dtype.itemsize * 8) 

360 

361 # append metadata to datetimes 

362 if dtype.type in (np.datetime64, np.timedelta64): 

363 name += _datetime_metadata_str(dtype) 

364 

365 return name