m2m模型翻译
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

910 lines
27 KiB

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