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
« 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
4String handling is much easier to do correctly in python.
5"""
6import numpy as np
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}
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
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
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)
52def _unpack_field(dtype, offset, title=None):
53 """
54 Helper function to normalize the items in dtype.fields.
56 Call as:
58 dtype, offset, title = _unpack_field(*dtype.fields[name])
59 """
60 return dtype, offset, title
63def _isunsized(dtype):
64 # PyDataType_ISUNSIZED
65 return dtype.itemsize == 0
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.
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.
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.
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)
103def _scalar_str(dtype, short):
104 byteorder = _byte_order_str(dtype)
106 if dtype.type == np.bool_:
107 if short:
108 return "'?'"
109 else:
110 return "'bool'"
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'"
117 elif dtype.type == np.string_:
118 if _isunsized(dtype):
119 return "'S'"
120 else:
121 return "'S%d'" % dtype.itemsize
123 elif dtype.type == np.unicode_:
124 if _isunsized(dtype):
125 return "'%sU'" % byteorder
126 else:
127 return "'%sU%d'" % (byteorder, dtype.itemsize / 4)
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
137 elif dtype.type == np.datetime64:
138 return "'%sM8%s'" % (byteorder, _datetime_metadata_str(dtype))
140 elif dtype.type == np.timedelta64:
141 return "'%sm8%s'" % (byteorder, _datetime_metadata_str(dtype))
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)
148 # Longer repr, like 'float64'
149 else:
150 return "'%s%d'" % (_kind_name(dtype), 8*dtype.itemsize)
152 elif dtype.isbuiltin == 2:
153 return dtype.type.__name__
155 else:
156 raise RuntimeError(
157 "Internal error: NumPy dtype unrecognized type number")
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')
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
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)
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)
201 # Build up a string to make the dictionary
203 if np.core.arrayprint._get_legacy_print_mode() <= 121:
204 colon = ":"
205 fieldsep = ","
206 else:
207 colon = ": "
208 fieldsep = ", "
210 # First, the names
211 ret = "{'names'%s[" % colon
212 ret += fieldsep.join(repr(name) for name in names)
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)
219 # Third, the offsets
220 ret += "], 'offsets'%s[" % colon
221 ret += fieldsep.join("%d" % offset for offset in offsets)
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)
228 # Fifth, the itemsize
229 ret += "], 'itemsize'%s%d" % (colon, dtype.itemsize)
231 if (includealignedflag and dtype.isalignedstruct):
232 # Finally, the aligned flag
233 ret += ", 'aligned'%sTrue}" % colon
234 else:
235 ret += "}"
237 return ret
240def _aligned_offset(offset, alignment):
241 # round up offset:
242 return - (-offset // alignment) * alignment
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.
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.
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])
263 if align:
264 total_offset = _aligned_offset(total_offset, fld_dtype.alignment)
265 max_alignment = max(max_alignment, fld_dtype.alignment)
267 if fld_offset != total_offset:
268 return False
269 total_offset += fld_dtype.itemsize
271 if align:
272 total_offset = _aligned_offset(total_offset, max_alignment)
274 if total_offset != dtype.itemsize:
275 return False
276 return True
279def _struct_list_str(dtype):
280 items = []
281 for name in dtype.names:
282 fld_dtype, fld_offset, title = _unpack_field(*dtype.fields[name])
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)
299 item += ")"
300 items.append(item)
302 return "[" + ", ".join(items) + "]"
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)
312 else:
313 sub = _struct_dict_str(dtype, include_align)
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
322def _subarray_str(dtype):
323 base, shape = dtype.subdtype
324 return "({}, {})".format(
325 _construction_repr(base, short=True),
326 shape
327 )
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
344def _name_get(dtype):
345 # provides dtype.name.__get__, documented as returning a "bit name"
347 if dtype.isbuiltin == 2:
348 # user dtypes don't promise to do anything special
349 return dtype.type.__name__
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)
357 # append bit counts
358 if _name_includes_bit_suffix(dtype):
359 name += "{}".format(dtype.itemsize * 8)
361 # append metadata to datetimes
362 if dtype.type in (np.datetime64, np.timedelta64):
363 name += _datetime_metadata_str(dtype)
365 return name