_internal.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901
  1. """
  2. A place for internal code
  3. Some things are more easily handled Python.
  4. """
  5. from __future__ import division, absolute_import, print_function
  6. import re
  7. import sys
  8. import platform
  9. from numpy.compat import unicode
  10. from numpy.core.overrides import set_module
  11. from .multiarray import dtype, array, ndarray
  12. try:
  13. import ctypes
  14. except ImportError:
  15. ctypes = None
  16. IS_PYPY = platform.python_implementation() == 'PyPy'
  17. if (sys.byteorder == 'little'):
  18. _nbo = b'<'
  19. else:
  20. _nbo = b'>'
  21. def _makenames_list(adict, align):
  22. allfields = []
  23. fnames = list(adict.keys())
  24. for fname in fnames:
  25. obj = adict[fname]
  26. n = len(obj)
  27. if not isinstance(obj, tuple) or n not in [2, 3]:
  28. raise ValueError("entry not a 2- or 3- tuple")
  29. if (n > 2) and (obj[2] == fname):
  30. continue
  31. num = int(obj[1])
  32. if (num < 0):
  33. raise ValueError("invalid offset.")
  34. format = dtype(obj[0], align=align)
  35. if (n > 2):
  36. title = obj[2]
  37. else:
  38. title = None
  39. allfields.append((fname, format, num, title))
  40. # sort by offsets
  41. allfields.sort(key=lambda x: x[2])
  42. names = [x[0] for x in allfields]
  43. formats = [x[1] for x in allfields]
  44. offsets = [x[2] for x in allfields]
  45. titles = [x[3] for x in allfields]
  46. return names, formats, offsets, titles
  47. # Called in PyArray_DescrConverter function when
  48. # a dictionary without "names" and "formats"
  49. # fields is used as a data-type descriptor.
  50. def _usefields(adict, align):
  51. try:
  52. names = adict[-1]
  53. except KeyError:
  54. names = None
  55. if names is None:
  56. names, formats, offsets, titles = _makenames_list(adict, align)
  57. else:
  58. formats = []
  59. offsets = []
  60. titles = []
  61. for name in names:
  62. res = adict[name]
  63. formats.append(res[0])
  64. offsets.append(res[1])
  65. if (len(res) > 2):
  66. titles.append(res[2])
  67. else:
  68. titles.append(None)
  69. return dtype({"names": names,
  70. "formats": formats,
  71. "offsets": offsets,
  72. "titles": titles}, align)
  73. # construct an array_protocol descriptor list
  74. # from the fields attribute of a descriptor
  75. # This calls itself recursively but should eventually hit
  76. # a descriptor that has no fields and then return
  77. # a simple typestring
  78. def _array_descr(descriptor):
  79. fields = descriptor.fields
  80. if fields is None:
  81. subdtype = descriptor.subdtype
  82. if subdtype is None:
  83. if descriptor.metadata is None:
  84. return descriptor.str
  85. else:
  86. new = descriptor.metadata.copy()
  87. if new:
  88. return (descriptor.str, new)
  89. else:
  90. return descriptor.str
  91. else:
  92. return (_array_descr(subdtype[0]), subdtype[1])
  93. names = descriptor.names
  94. ordered_fields = [fields[x] + (x,) for x in names]
  95. result = []
  96. offset = 0
  97. for field in ordered_fields:
  98. if field[1] > offset:
  99. num = field[1] - offset
  100. result.append(('', '|V%d' % num))
  101. offset += num
  102. elif field[1] < offset:
  103. raise ValueError(
  104. "dtype.descr is not defined for types with overlapping or "
  105. "out-of-order fields")
  106. if len(field) > 3:
  107. name = (field[2], field[3])
  108. else:
  109. name = field[2]
  110. if field[0].subdtype:
  111. tup = (name, _array_descr(field[0].subdtype[0]),
  112. field[0].subdtype[1])
  113. else:
  114. tup = (name, _array_descr(field[0]))
  115. offset += field[0].itemsize
  116. result.append(tup)
  117. if descriptor.itemsize > offset:
  118. num = descriptor.itemsize - offset
  119. result.append(('', '|V%d' % num))
  120. return result
  121. # Build a new array from the information in a pickle.
  122. # Note that the name numpy.core._internal._reconstruct is embedded in
  123. # pickles of ndarrays made with NumPy before release 1.0
  124. # so don't remove the name here, or you'll
  125. # break backward compatibility.
  126. def _reconstruct(subtype, shape, dtype):
  127. return ndarray.__new__(subtype, shape, dtype)
  128. # format_re was originally from numarray by J. Todd Miller
  129. format_re = re.compile(br'(?P<order1>[<>|=]?)'
  130. br'(?P<repeats> *[(]?[ ,0-9L]*[)]? *)'
  131. br'(?P<order2>[<>|=]?)'
  132. br'(?P<dtype>[A-Za-z0-9.?]*(?:\[[a-zA-Z0-9,.]+\])?)')
  133. sep_re = re.compile(br'\s*,\s*')
  134. space_re = re.compile(br'\s+$')
  135. # astr is a string (perhaps comma separated)
  136. _convorder = {b'=': _nbo}
  137. def _commastring(astr):
  138. startindex = 0
  139. result = []
  140. while startindex < len(astr):
  141. mo = format_re.match(astr, pos=startindex)
  142. try:
  143. (order1, repeats, order2, dtype) = mo.groups()
  144. except (TypeError, AttributeError):
  145. raise ValueError('format number %d of "%s" is not recognized' %
  146. (len(result)+1, astr))
  147. startindex = mo.end()
  148. # Separator or ending padding
  149. if startindex < len(astr):
  150. if space_re.match(astr, pos=startindex):
  151. startindex = len(astr)
  152. else:
  153. mo = sep_re.match(astr, pos=startindex)
  154. if not mo:
  155. raise ValueError(
  156. 'format number %d of "%s" is not recognized' %
  157. (len(result)+1, astr))
  158. startindex = mo.end()
  159. if order2 == b'':
  160. order = order1
  161. elif order1 == b'':
  162. order = order2
  163. else:
  164. order1 = _convorder.get(order1, order1)
  165. order2 = _convorder.get(order2, order2)
  166. if (order1 != order2):
  167. raise ValueError(
  168. 'inconsistent byte-order specification %s and %s' %
  169. (order1, order2))
  170. order = order1
  171. if order in [b'|', b'=', _nbo]:
  172. order = b''
  173. dtype = order + dtype
  174. if (repeats == b''):
  175. newitem = dtype
  176. else:
  177. newitem = (dtype, eval(repeats))
  178. result.append(newitem)
  179. return result
  180. class dummy_ctype(object):
  181. def __init__(self, cls):
  182. self._cls = cls
  183. def __mul__(self, other):
  184. return self
  185. def __call__(self, *other):
  186. return self._cls(other)
  187. def __eq__(self, other):
  188. return self._cls == other._cls
  189. def __ne__(self, other):
  190. return self._cls != other._cls
  191. def _getintp_ctype():
  192. val = _getintp_ctype.cache
  193. if val is not None:
  194. return val
  195. if ctypes is None:
  196. import numpy as np
  197. val = dummy_ctype(np.intp)
  198. else:
  199. char = dtype('p').char
  200. if (char == 'i'):
  201. val = ctypes.c_int
  202. elif char == 'l':
  203. val = ctypes.c_long
  204. elif char == 'q':
  205. val = ctypes.c_longlong
  206. else:
  207. val = ctypes.c_long
  208. _getintp_ctype.cache = val
  209. return val
  210. _getintp_ctype.cache = None
  211. # Used for .ctypes attribute of ndarray
  212. class _missing_ctypes(object):
  213. def cast(self, num, obj):
  214. return num.value
  215. class c_void_p(object):
  216. def __init__(self, ptr):
  217. self.value = ptr
  218. class _ctypes(object):
  219. def __init__(self, array, ptr=None):
  220. self._arr = array
  221. if ctypes:
  222. self._ctypes = ctypes
  223. self._data = self._ctypes.c_void_p(ptr)
  224. else:
  225. # fake a pointer-like object that holds onto the reference
  226. self._ctypes = _missing_ctypes()
  227. self._data = self._ctypes.c_void_p(ptr)
  228. self._data._objects = array
  229. if self._arr.ndim == 0:
  230. self._zerod = True
  231. else:
  232. self._zerod = False
  233. def data_as(self, obj):
  234. """
  235. Return the data pointer cast to a particular c-types object.
  236. For example, calling ``self._as_parameter_`` is equivalent to
  237. ``self.data_as(ctypes.c_void_p)``. Perhaps you want to use the data as a
  238. pointer to a ctypes array of floating-point data:
  239. ``self.data_as(ctypes.POINTER(ctypes.c_double))``.
  240. The returned pointer will keep a reference to the array.
  241. """
  242. # _ctypes.cast function causes a circular reference of self._data in
  243. # self._data._objects. Attributes of self._data cannot be released
  244. # until gc.collect is called. Make a copy of the pointer first then let
  245. # it hold the array reference. This is a workaround to circumvent the
  246. # CPython bug https://bugs.python.org/issue12836
  247. ptr = self._ctypes.cast(self._data, obj)
  248. ptr._arr = self._arr
  249. return ptr
  250. def shape_as(self, obj):
  251. """
  252. Return the shape tuple as an array of some other c-types
  253. type. For example: ``self.shape_as(ctypes.c_short)``.
  254. """
  255. if self._zerod:
  256. return None
  257. return (obj*self._arr.ndim)(*self._arr.shape)
  258. def strides_as(self, obj):
  259. """
  260. Return the strides tuple as an array of some other
  261. c-types type. For example: ``self.strides_as(ctypes.c_longlong)``.
  262. """
  263. if self._zerod:
  264. return None
  265. return (obj*self._arr.ndim)(*self._arr.strides)
  266. @property
  267. def data(self):
  268. """
  269. A pointer to the memory area of the array as a Python integer.
  270. This memory area may contain data that is not aligned, or not in correct
  271. byte-order. The memory area may not even be writeable. The array
  272. flags and data-type of this array should be respected when passing this
  273. attribute to arbitrary C-code to avoid trouble that can include Python
  274. crashing. User Beware! The value of this attribute is exactly the same
  275. as ``self._array_interface_['data'][0]``.
  276. Note that unlike `data_as`, a reference will not be kept to the array:
  277. code like ``ctypes.c_void_p((a + b).ctypes.data)`` will result in a
  278. pointer to a deallocated array, and should be spelt
  279. ``(a + b).ctypes.data_as(ctypes.c_void_p)``
  280. """
  281. return self._data.value
  282. @property
  283. def shape(self):
  284. """
  285. (c_intp*self.ndim): A ctypes array of length self.ndim where
  286. the basetype is the C-integer corresponding to ``dtype('p')`` on this
  287. platform. This base-type could be `ctypes.c_int`, `ctypes.c_long`, or
  288. `ctypes.c_longlong` depending on the platform.
  289. The c_intp type is defined accordingly in `numpy.ctypeslib`.
  290. The ctypes array contains the shape of the underlying array.
  291. """
  292. return self.shape_as(_getintp_ctype())
  293. @property
  294. def strides(self):
  295. """
  296. (c_intp*self.ndim): A ctypes array of length self.ndim where
  297. the basetype is the same as for the shape attribute. This ctypes array
  298. contains the strides information from the underlying array. This strides
  299. information is important for showing how many bytes must be jumped to
  300. get to the next element in the array.
  301. """
  302. return self.strides_as(_getintp_ctype())
  303. @property
  304. def _as_parameter_(self):
  305. """
  306. Overrides the ctypes semi-magic method
  307. Enables `c_func(some_array.ctypes)`
  308. """
  309. return self.data_as(ctypes.c_void_p)
  310. # kept for compatibility
  311. get_data = data.fget
  312. get_shape = shape.fget
  313. get_strides = strides.fget
  314. get_as_parameter = _as_parameter_.fget
  315. def _newnames(datatype, order):
  316. """
  317. Given a datatype and an order object, return a new names tuple, with the
  318. order indicated
  319. """
  320. oldnames = datatype.names
  321. nameslist = list(oldnames)
  322. if isinstance(order, (str, unicode)):
  323. order = [order]
  324. seen = set()
  325. if isinstance(order, (list, tuple)):
  326. for name in order:
  327. try:
  328. nameslist.remove(name)
  329. except ValueError:
  330. if name in seen:
  331. raise ValueError("duplicate field name: %s" % (name,))
  332. else:
  333. raise ValueError("unknown field name: %s" % (name,))
  334. seen.add(name)
  335. return tuple(list(order) + nameslist)
  336. raise ValueError("unsupported order value: %s" % (order,))
  337. def _copy_fields(ary):
  338. """Return copy of structured array with padding between fields removed.
  339. Parameters
  340. ----------
  341. ary : ndarray
  342. Structured array from which to remove padding bytes
  343. Returns
  344. -------
  345. ary_copy : ndarray
  346. Copy of ary with padding bytes removed
  347. """
  348. dt = ary.dtype
  349. copy_dtype = {'names': dt.names,
  350. 'formats': [dt.fields[name][0] for name in dt.names]}
  351. return array(ary, dtype=copy_dtype, copy=True)
  352. def _getfield_is_safe(oldtype, newtype, offset):
  353. """ Checks safety of getfield for object arrays.
  354. As in _view_is_safe, we need to check that memory containing objects is not
  355. reinterpreted as a non-object datatype and vice versa.
  356. Parameters
  357. ----------
  358. oldtype : data-type
  359. Data type of the original ndarray.
  360. newtype : data-type
  361. Data type of the field being accessed by ndarray.getfield
  362. offset : int
  363. Offset of the field being accessed by ndarray.getfield
  364. Raises
  365. ------
  366. TypeError
  367. If the field access is invalid
  368. """
  369. if newtype.hasobject or oldtype.hasobject:
  370. if offset == 0 and newtype == oldtype:
  371. return
  372. if oldtype.names is not None:
  373. for name in oldtype.names:
  374. if (oldtype.fields[name][1] == offset and
  375. oldtype.fields[name][0] == newtype):
  376. return
  377. raise TypeError("Cannot get/set field of an object array")
  378. return
  379. def _view_is_safe(oldtype, newtype):
  380. """ Checks safety of a view involving object arrays, for example when
  381. doing::
  382. np.zeros(10, dtype=oldtype).view(newtype)
  383. Parameters
  384. ----------
  385. oldtype : data-type
  386. Data type of original ndarray
  387. newtype : data-type
  388. Data type of the view
  389. Raises
  390. ------
  391. TypeError
  392. If the new type is incompatible with the old type.
  393. """
  394. # if the types are equivalent, there is no problem.
  395. # for example: dtype((np.record, 'i4,i4')) == dtype((np.void, 'i4,i4'))
  396. if oldtype == newtype:
  397. return
  398. if newtype.hasobject or oldtype.hasobject:
  399. raise TypeError("Cannot change data-type for object array.")
  400. return
  401. # Given a string containing a PEP 3118 format specifier,
  402. # construct a NumPy dtype
  403. _pep3118_native_map = {
  404. '?': '?',
  405. 'c': 'S1',
  406. 'b': 'b',
  407. 'B': 'B',
  408. 'h': 'h',
  409. 'H': 'H',
  410. 'i': 'i',
  411. 'I': 'I',
  412. 'l': 'l',
  413. 'L': 'L',
  414. 'q': 'q',
  415. 'Q': 'Q',
  416. 'e': 'e',
  417. 'f': 'f',
  418. 'd': 'd',
  419. 'g': 'g',
  420. 'Zf': 'F',
  421. 'Zd': 'D',
  422. 'Zg': 'G',
  423. 's': 'S',
  424. 'w': 'U',
  425. 'O': 'O',
  426. 'x': 'V', # padding
  427. }
  428. _pep3118_native_typechars = ''.join(_pep3118_native_map.keys())
  429. _pep3118_standard_map = {
  430. '?': '?',
  431. 'c': 'S1',
  432. 'b': 'b',
  433. 'B': 'B',
  434. 'h': 'i2',
  435. 'H': 'u2',
  436. 'i': 'i4',
  437. 'I': 'u4',
  438. 'l': 'i4',
  439. 'L': 'u4',
  440. 'q': 'i8',
  441. 'Q': 'u8',
  442. 'e': 'f2',
  443. 'f': 'f',
  444. 'd': 'd',
  445. 'Zf': 'F',
  446. 'Zd': 'D',
  447. 's': 'S',
  448. 'w': 'U',
  449. 'O': 'O',
  450. 'x': 'V', # padding
  451. }
  452. _pep3118_standard_typechars = ''.join(_pep3118_standard_map.keys())
  453. _pep3118_unsupported_map = {
  454. 'u': 'UCS-2 strings',
  455. '&': 'pointers',
  456. 't': 'bitfields',
  457. 'X': 'function pointers',
  458. }
  459. class _Stream(object):
  460. def __init__(self, s):
  461. self.s = s
  462. self.byteorder = '@'
  463. def advance(self, n):
  464. res = self.s[:n]
  465. self.s = self.s[n:]
  466. return res
  467. def consume(self, c):
  468. if self.s[:len(c)] == c:
  469. self.advance(len(c))
  470. return True
  471. return False
  472. def consume_until(self, c):
  473. if callable(c):
  474. i = 0
  475. while i < len(self.s) and not c(self.s[i]):
  476. i = i + 1
  477. return self.advance(i)
  478. else:
  479. i = self.s.index(c)
  480. res = self.advance(i)
  481. self.advance(len(c))
  482. return res
  483. @property
  484. def next(self):
  485. return self.s[0]
  486. def __bool__(self):
  487. return bool(self.s)
  488. __nonzero__ = __bool__
  489. def _dtype_from_pep3118(spec):
  490. stream = _Stream(spec)
  491. dtype, align = __dtype_from_pep3118(stream, is_subdtype=False)
  492. return dtype
  493. def __dtype_from_pep3118(stream, is_subdtype):
  494. field_spec = dict(
  495. names=[],
  496. formats=[],
  497. offsets=[],
  498. itemsize=0
  499. )
  500. offset = 0
  501. common_alignment = 1
  502. is_padding = False
  503. # Parse spec
  504. while stream:
  505. value = None
  506. # End of structure, bail out to upper level
  507. if stream.consume('}'):
  508. break
  509. # Sub-arrays (1)
  510. shape = None
  511. if stream.consume('('):
  512. shape = stream.consume_until(')')
  513. shape = tuple(map(int, shape.split(',')))
  514. # Byte order
  515. if stream.next in ('@', '=', '<', '>', '^', '!'):
  516. byteorder = stream.advance(1)
  517. if byteorder == '!':
  518. byteorder = '>'
  519. stream.byteorder = byteorder
  520. # Byte order characters also control native vs. standard type sizes
  521. if stream.byteorder in ('@', '^'):
  522. type_map = _pep3118_native_map
  523. type_map_chars = _pep3118_native_typechars
  524. else:
  525. type_map = _pep3118_standard_map
  526. type_map_chars = _pep3118_standard_typechars
  527. # Item sizes
  528. itemsize_str = stream.consume_until(lambda c: not c.isdigit())
  529. if itemsize_str:
  530. itemsize = int(itemsize_str)
  531. else:
  532. itemsize = 1
  533. # Data types
  534. is_padding = False
  535. if stream.consume('T{'):
  536. value, align = __dtype_from_pep3118(
  537. stream, is_subdtype=True)
  538. elif stream.next in type_map_chars:
  539. if stream.next == 'Z':
  540. typechar = stream.advance(2)
  541. else:
  542. typechar = stream.advance(1)
  543. is_padding = (typechar == 'x')
  544. dtypechar = type_map[typechar]
  545. if dtypechar in 'USV':
  546. dtypechar += '%d' % itemsize
  547. itemsize = 1
  548. numpy_byteorder = {'@': '=', '^': '='}.get(
  549. stream.byteorder, stream.byteorder)
  550. value = dtype(numpy_byteorder + dtypechar)
  551. align = value.alignment
  552. elif stream.next in _pep3118_unsupported_map:
  553. desc = _pep3118_unsupported_map[stream.next]
  554. raise NotImplementedError(
  555. "Unrepresentable PEP 3118 data type {!r} ({})"
  556. .format(stream.next, desc))
  557. else:
  558. raise ValueError("Unknown PEP 3118 data type specifier %r" % stream.s)
  559. #
  560. # Native alignment may require padding
  561. #
  562. # Here we assume that the presence of a '@' character implicitly implies
  563. # that the start of the array is *already* aligned.
  564. #
  565. extra_offset = 0
  566. if stream.byteorder == '@':
  567. start_padding = (-offset) % align
  568. intra_padding = (-value.itemsize) % align
  569. offset += start_padding
  570. if intra_padding != 0:
  571. if itemsize > 1 or (shape is not None and _prod(shape) > 1):
  572. # Inject internal padding to the end of the sub-item
  573. value = _add_trailing_padding(value, intra_padding)
  574. else:
  575. # We can postpone the injection of internal padding,
  576. # as the item appears at most once
  577. extra_offset += intra_padding
  578. # Update common alignment
  579. common_alignment = _lcm(align, common_alignment)
  580. # Convert itemsize to sub-array
  581. if itemsize != 1:
  582. value = dtype((value, (itemsize,)))
  583. # Sub-arrays (2)
  584. if shape is not None:
  585. value = dtype((value, shape))
  586. # Field name
  587. if stream.consume(':'):
  588. name = stream.consume_until(':')
  589. else:
  590. name = None
  591. if not (is_padding and name is None):
  592. if name is not None and name in field_spec['names']:
  593. raise RuntimeError("Duplicate field name '%s' in PEP3118 format"
  594. % name)
  595. field_spec['names'].append(name)
  596. field_spec['formats'].append(value)
  597. field_spec['offsets'].append(offset)
  598. offset += value.itemsize
  599. offset += extra_offset
  600. field_spec['itemsize'] = offset
  601. # extra final padding for aligned types
  602. if stream.byteorder == '@':
  603. field_spec['itemsize'] += (-offset) % common_alignment
  604. # Check if this was a simple 1-item type, and unwrap it
  605. if (field_spec['names'] == [None]
  606. and field_spec['offsets'][0] == 0
  607. and field_spec['itemsize'] == field_spec['formats'][0].itemsize
  608. and not is_subdtype):
  609. ret = field_spec['formats'][0]
  610. else:
  611. _fix_names(field_spec)
  612. ret = dtype(field_spec)
  613. # Finished
  614. return ret, common_alignment
  615. def _fix_names(field_spec):
  616. """ Replace names which are None with the next unused f%d name """
  617. names = field_spec['names']
  618. for i, name in enumerate(names):
  619. if name is not None:
  620. continue
  621. j = 0
  622. while True:
  623. name = 'f{}'.format(j)
  624. if name not in names:
  625. break
  626. j = j + 1
  627. names[i] = name
  628. def _add_trailing_padding(value, padding):
  629. """Inject the specified number of padding bytes at the end of a dtype"""
  630. if value.fields is None:
  631. field_spec = dict(
  632. names=['f0'],
  633. formats=[value],
  634. offsets=[0],
  635. itemsize=value.itemsize
  636. )
  637. else:
  638. fields = value.fields
  639. names = value.names
  640. field_spec = dict(
  641. names=names,
  642. formats=[fields[name][0] for name in names],
  643. offsets=[fields[name][1] for name in names],
  644. itemsize=value.itemsize
  645. )
  646. field_spec['itemsize'] += padding
  647. return dtype(field_spec)
  648. def _prod(a):
  649. p = 1
  650. for x in a:
  651. p *= x
  652. return p
  653. def _gcd(a, b):
  654. """Calculate the greatest common divisor of a and b"""
  655. while b:
  656. a, b = b, a % b
  657. return a
  658. def _lcm(a, b):
  659. return a // _gcd(a, b) * b
  660. # Exception used in shares_memory()
  661. @set_module('numpy')
  662. class TooHardError(RuntimeError):
  663. pass
  664. @set_module('numpy')
  665. class AxisError(ValueError, IndexError):
  666. """ Axis supplied was invalid. """
  667. def __init__(self, axis, ndim=None, msg_prefix=None):
  668. # single-argument form just delegates to base class
  669. if ndim is None and msg_prefix is None:
  670. msg = axis
  671. # do the string formatting here, to save work in the C code
  672. else:
  673. msg = ("axis {} is out of bounds for array of dimension {}"
  674. .format(axis, ndim))
  675. if msg_prefix is not None:
  676. msg = "{}: {}".format(msg_prefix, msg)
  677. super(AxisError, self).__init__(msg)
  678. def array_ufunc_errmsg_formatter(dummy, ufunc, method, *inputs, **kwargs):
  679. """ Format the error message for when __array_ufunc__ gives up. """
  680. args_string = ', '.join(['{!r}'.format(arg) for arg in inputs] +
  681. ['{}={!r}'.format(k, v)
  682. for k, v in kwargs.items()])
  683. args = inputs + kwargs.get('out', ())
  684. types_string = ', '.join(repr(type(arg).__name__) for arg in args)
  685. return ('operand type(s) all returned NotImplemented from '
  686. '__array_ufunc__({!r}, {!r}, {}): {}'
  687. .format(ufunc, method, args_string, types_string))
  688. def array_function_errmsg_formatter(public_api, types):
  689. """ Format the error message for when __array_ufunc__ gives up. """
  690. func_name = '{}.{}'.format(public_api.__module__, public_api.__name__)
  691. return ("no implementation found for '{}' on types that implement "
  692. '__array_function__: {}'.format(func_name, list(types)))
  693. def _ufunc_doc_signature_formatter(ufunc):
  694. """
  695. Builds a signature string which resembles PEP 457
  696. This is used to construct the first line of the docstring
  697. """
  698. # input arguments are simple
  699. if ufunc.nin == 1:
  700. in_args = 'x'
  701. else:
  702. in_args = ', '.join('x{}'.format(i+1) for i in range(ufunc.nin))
  703. # output arguments are both keyword or positional
  704. if ufunc.nout == 0:
  705. out_args = ', /, out=()'
  706. elif ufunc.nout == 1:
  707. out_args = ', /, out=None'
  708. else:
  709. out_args = '[, {positional}], / [, out={default}]'.format(
  710. positional=', '.join(
  711. 'out{}'.format(i+1) for i in range(ufunc.nout)),
  712. default=repr((None,)*ufunc.nout)
  713. )
  714. # keyword only args depend on whether this is a gufunc
  715. kwargs = (
  716. ", casting='same_kind'"
  717. ", order='K'"
  718. ", dtype=None"
  719. ", subok=True"
  720. "[, signature"
  721. ", extobj]"
  722. )
  723. if ufunc.signature is None:
  724. kwargs = ", where=True" + kwargs
  725. # join all the parts together
  726. return '{name}({in_args}{out_args}, *{kwargs})'.format(
  727. name=ufunc.__name__,
  728. in_args=in_args,
  729. out_args=out_args,
  730. kwargs=kwargs
  731. )
  732. def npy_ctypes_check(cls):
  733. # determine if a class comes from ctypes, in order to work around
  734. # a bug in the buffer protocol for those objects, bpo-10746
  735. try:
  736. # ctypes class are new-style, so have an __mro__. This probably fails
  737. # for ctypes classes with multiple inheritance.
  738. if IS_PYPY:
  739. # (..., _ctypes.basics._CData, Bufferable, object)
  740. ctype_base = cls.__mro__[-3]
  741. else:
  742. # # (..., _ctypes._CData, object)
  743. ctype_base = cls.__mro__[-2]
  744. # right now, they're part of the _ctypes module
  745. return 'ctypes' in ctype_base.__module__
  746. except Exception:
  747. return False
  748. class recursive(object):
  749. '''
  750. A decorator class for recursive nested functions.
  751. Naive recursive nested functions hold a reference to themselves:
  752. def outer(*args):
  753. def stringify_leaky(arg0, *arg1):
  754. if len(arg1) > 0:
  755. return stringify_leaky(*arg1) # <- HERE
  756. return str(arg0)
  757. stringify_leaky(*args)
  758. This design pattern creates a reference cycle that is difficult for a
  759. garbage collector to resolve. The decorator class prevents the
  760. cycle by passing the nested function in as an argument `self`:
  761. def outer(*args):
  762. @recursive
  763. def stringify(self, arg0, *arg1):
  764. if len(arg1) > 0:
  765. return self(*arg1)
  766. return str(arg0)
  767. stringify(*args)
  768. '''
  769. def __init__(self, func):
  770. self.func = func
  771. def __call__(self, *args, **kwargs):
  772. return self.func(self, *args, **kwargs)