utils.py 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211
  1. import os
  2. import sys
  3. import textwrap
  4. import types
  5. import re
  6. import warnings
  7. import functools
  8. import platform
  9. from .._utils import set_module
  10. from numpy.core.numerictypes import issubclass_, issubsctype, issubdtype
  11. from numpy.core import ndarray, ufunc, asarray
  12. import numpy as np
  13. __all__ = [
  14. 'issubclass_', 'issubsctype', 'issubdtype', 'deprecate',
  15. 'deprecate_with_doc', 'get_include', 'info', 'source', 'who',
  16. 'lookfor', 'byte_bounds', 'safe_eval', 'show_runtime'
  17. ]
  18. def show_runtime():
  19. """
  20. Print information about various resources in the system
  21. including available intrinsic support and BLAS/LAPACK library
  22. in use
  23. .. versionadded:: 1.24.0
  24. See Also
  25. --------
  26. show_config : Show libraries in the system on which NumPy was built.
  27. Notes
  28. -----
  29. 1. Information is derived with the help of `threadpoolctl <https://pypi.org/project/threadpoolctl/>`_
  30. library if available.
  31. 2. SIMD related information is derived from ``__cpu_features__``,
  32. ``__cpu_baseline__`` and ``__cpu_dispatch__``
  33. """
  34. from numpy.core._multiarray_umath import (
  35. __cpu_features__, __cpu_baseline__, __cpu_dispatch__
  36. )
  37. from pprint import pprint
  38. config_found = [{
  39. "numpy_version": np.__version__,
  40. "python": sys.version,
  41. "uname": platform.uname(),
  42. }]
  43. features_found, features_not_found = [], []
  44. for feature in __cpu_dispatch__:
  45. if __cpu_features__[feature]:
  46. features_found.append(feature)
  47. else:
  48. features_not_found.append(feature)
  49. config_found.append({
  50. "simd_extensions": {
  51. "baseline": __cpu_baseline__,
  52. "found": features_found,
  53. "not_found": features_not_found
  54. }
  55. })
  56. try:
  57. from threadpoolctl import threadpool_info
  58. config_found.extend(threadpool_info())
  59. except ImportError:
  60. print("WARNING: `threadpoolctl` not found in system!"
  61. " Install it by `pip install threadpoolctl`."
  62. " Once installed, try `np.show_runtime` again"
  63. " for more detailed build information")
  64. pprint(config_found)
  65. def get_include():
  66. """
  67. Return the directory that contains the NumPy \\*.h header files.
  68. Extension modules that need to compile against NumPy should use this
  69. function to locate the appropriate include directory.
  70. Notes
  71. -----
  72. When using ``distutils``, for example in ``setup.py``::
  73. import numpy as np
  74. ...
  75. Extension('extension_name', ...
  76. include_dirs=[np.get_include()])
  77. ...
  78. """
  79. import numpy
  80. if numpy.show_config is None:
  81. # running from numpy source directory
  82. d = os.path.join(os.path.dirname(numpy.__file__), 'core', 'include')
  83. else:
  84. # using installed numpy core headers
  85. import numpy.core as core
  86. d = os.path.join(os.path.dirname(core.__file__), 'include')
  87. return d
  88. class _Deprecate:
  89. """
  90. Decorator class to deprecate old functions.
  91. Refer to `deprecate` for details.
  92. See Also
  93. --------
  94. deprecate
  95. """
  96. def __init__(self, old_name=None, new_name=None, message=None):
  97. self.old_name = old_name
  98. self.new_name = new_name
  99. self.message = message
  100. def __call__(self, func, *args, **kwargs):
  101. """
  102. Decorator call. Refer to ``decorate``.
  103. """
  104. old_name = self.old_name
  105. new_name = self.new_name
  106. message = self.message
  107. if old_name is None:
  108. old_name = func.__name__
  109. if new_name is None:
  110. depdoc = "`%s` is deprecated!" % old_name
  111. else:
  112. depdoc = "`%s` is deprecated, use `%s` instead!" % \
  113. (old_name, new_name)
  114. if message is not None:
  115. depdoc += "\n" + message
  116. @functools.wraps(func)
  117. def newfunc(*args, **kwds):
  118. warnings.warn(depdoc, DeprecationWarning, stacklevel=2)
  119. return func(*args, **kwds)
  120. newfunc.__name__ = old_name
  121. doc = func.__doc__
  122. if doc is None:
  123. doc = depdoc
  124. else:
  125. lines = doc.expandtabs().split('\n')
  126. indent = _get_indent(lines[1:])
  127. if lines[0].lstrip():
  128. # Indent the original first line to let inspect.cleandoc()
  129. # dedent the docstring despite the deprecation notice.
  130. doc = indent * ' ' + doc
  131. else:
  132. # Remove the same leading blank lines as cleandoc() would.
  133. skip = len(lines[0]) + 1
  134. for line in lines[1:]:
  135. if len(line) > indent:
  136. break
  137. skip += len(line) + 1
  138. doc = doc[skip:]
  139. depdoc = textwrap.indent(depdoc, ' ' * indent)
  140. doc = '\n\n'.join([depdoc, doc])
  141. newfunc.__doc__ = doc
  142. return newfunc
  143. def _get_indent(lines):
  144. """
  145. Determines the leading whitespace that could be removed from all the lines.
  146. """
  147. indent = sys.maxsize
  148. for line in lines:
  149. content = len(line.lstrip())
  150. if content:
  151. indent = min(indent, len(line) - content)
  152. if indent == sys.maxsize:
  153. indent = 0
  154. return indent
  155. def deprecate(*args, **kwargs):
  156. """
  157. Issues a DeprecationWarning, adds warning to `old_name`'s
  158. docstring, rebinds ``old_name.__name__`` and returns the new
  159. function object.
  160. This function may also be used as a decorator.
  161. Parameters
  162. ----------
  163. func : function
  164. The function to be deprecated.
  165. old_name : str, optional
  166. The name of the function to be deprecated. Default is None, in
  167. which case the name of `func` is used.
  168. new_name : str, optional
  169. The new name for the function. Default is None, in which case the
  170. deprecation message is that `old_name` is deprecated. If given, the
  171. deprecation message is that `old_name` is deprecated and `new_name`
  172. should be used instead.
  173. message : str, optional
  174. Additional explanation of the deprecation. Displayed in the
  175. docstring after the warning.
  176. Returns
  177. -------
  178. old_func : function
  179. The deprecated function.
  180. Examples
  181. --------
  182. Note that ``olduint`` returns a value after printing Deprecation
  183. Warning:
  184. >>> olduint = np.deprecate(np.uint)
  185. DeprecationWarning: `uint64` is deprecated! # may vary
  186. >>> olduint(6)
  187. 6
  188. """
  189. # Deprecate may be run as a function or as a decorator
  190. # If run as a function, we initialise the decorator class
  191. # and execute its __call__ method.
  192. if args:
  193. fn = args[0]
  194. args = args[1:]
  195. return _Deprecate(*args, **kwargs)(fn)
  196. else:
  197. return _Deprecate(*args, **kwargs)
  198. def deprecate_with_doc(msg):
  199. """
  200. Deprecates a function and includes the deprecation in its docstring.
  201. This function is used as a decorator. It returns an object that can be
  202. used to issue a DeprecationWarning, by passing the to-be decorated
  203. function as argument, this adds warning to the to-be decorated function's
  204. docstring and returns the new function object.
  205. See Also
  206. --------
  207. deprecate : Decorate a function such that it issues a `DeprecationWarning`
  208. Parameters
  209. ----------
  210. msg : str
  211. Additional explanation of the deprecation. Displayed in the
  212. docstring after the warning.
  213. Returns
  214. -------
  215. obj : object
  216. """
  217. return _Deprecate(message=msg)
  218. #--------------------------------------------
  219. # Determine if two arrays can share memory
  220. #--------------------------------------------
  221. def byte_bounds(a):
  222. """
  223. Returns pointers to the end-points of an array.
  224. Parameters
  225. ----------
  226. a : ndarray
  227. Input array. It must conform to the Python-side of the array
  228. interface.
  229. Returns
  230. -------
  231. (low, high) : tuple of 2 integers
  232. The first integer is the first byte of the array, the second
  233. integer is just past the last byte of the array. If `a` is not
  234. contiguous it will not use every byte between the (`low`, `high`)
  235. values.
  236. Examples
  237. --------
  238. >>> I = np.eye(2, dtype='f'); I.dtype
  239. dtype('float32')
  240. >>> low, high = np.byte_bounds(I)
  241. >>> high - low == I.size*I.itemsize
  242. True
  243. >>> I = np.eye(2); I.dtype
  244. dtype('float64')
  245. >>> low, high = np.byte_bounds(I)
  246. >>> high - low == I.size*I.itemsize
  247. True
  248. """
  249. ai = a.__array_interface__
  250. a_data = ai['data'][0]
  251. astrides = ai['strides']
  252. ashape = ai['shape']
  253. bytes_a = asarray(a).dtype.itemsize
  254. a_low = a_high = a_data
  255. if astrides is None:
  256. # contiguous case
  257. a_high += a.size * bytes_a
  258. else:
  259. for shape, stride in zip(ashape, astrides):
  260. if stride < 0:
  261. a_low += (shape-1)*stride
  262. else:
  263. a_high += (shape-1)*stride
  264. a_high += bytes_a
  265. return a_low, a_high
  266. #-----------------------------------------------------------------------------
  267. # Function for output and information on the variables used.
  268. #-----------------------------------------------------------------------------
  269. def who(vardict=None):
  270. """
  271. Print the NumPy arrays in the given dictionary.
  272. If there is no dictionary passed in or `vardict` is None then returns
  273. NumPy arrays in the globals() dictionary (all NumPy arrays in the
  274. namespace).
  275. Parameters
  276. ----------
  277. vardict : dict, optional
  278. A dictionary possibly containing ndarrays. Default is globals().
  279. Returns
  280. -------
  281. out : None
  282. Returns 'None'.
  283. Notes
  284. -----
  285. Prints out the name, shape, bytes and type of all of the ndarrays
  286. present in `vardict`.
  287. Examples
  288. --------
  289. >>> a = np.arange(10)
  290. >>> b = np.ones(20)
  291. >>> np.who()
  292. Name Shape Bytes Type
  293. ===========================================================
  294. a 10 80 int64
  295. b 20 160 float64
  296. Upper bound on total bytes = 240
  297. >>> d = {'x': np.arange(2.0), 'y': np.arange(3.0), 'txt': 'Some str',
  298. ... 'idx':5}
  299. >>> np.who(d)
  300. Name Shape Bytes Type
  301. ===========================================================
  302. x 2 16 float64
  303. y 3 24 float64
  304. Upper bound on total bytes = 40
  305. """
  306. if vardict is None:
  307. frame = sys._getframe().f_back
  308. vardict = frame.f_globals
  309. sta = []
  310. cache = {}
  311. for name in vardict.keys():
  312. if isinstance(vardict[name], ndarray):
  313. var = vardict[name]
  314. idv = id(var)
  315. if idv in cache.keys():
  316. namestr = name + " (%s)" % cache[idv]
  317. original = 0
  318. else:
  319. cache[idv] = name
  320. namestr = name
  321. original = 1
  322. shapestr = " x ".join(map(str, var.shape))
  323. bytestr = str(var.nbytes)
  324. sta.append([namestr, shapestr, bytestr, var.dtype.name,
  325. original])
  326. maxname = 0
  327. maxshape = 0
  328. maxbyte = 0
  329. totalbytes = 0
  330. for val in sta:
  331. if maxname < len(val[0]):
  332. maxname = len(val[0])
  333. if maxshape < len(val[1]):
  334. maxshape = len(val[1])
  335. if maxbyte < len(val[2]):
  336. maxbyte = len(val[2])
  337. if val[4]:
  338. totalbytes += int(val[2])
  339. if len(sta) > 0:
  340. sp1 = max(10, maxname)
  341. sp2 = max(10, maxshape)
  342. sp3 = max(10, maxbyte)
  343. prval = "Name %s Shape %s Bytes %s Type" % (sp1*' ', sp2*' ', sp3*' ')
  344. print(prval + "\n" + "="*(len(prval)+5) + "\n")
  345. for val in sta:
  346. print("%s %s %s %s %s %s %s" % (val[0], ' '*(sp1-len(val[0])+4),
  347. val[1], ' '*(sp2-len(val[1])+5),
  348. val[2], ' '*(sp3-len(val[2])+5),
  349. val[3]))
  350. print("\nUpper bound on total bytes = %d" % totalbytes)
  351. return
  352. #-----------------------------------------------------------------------------
  353. # NOTE: pydoc defines a help function which works similarly to this
  354. # except it uses a pager to take over the screen.
  355. # combine name and arguments and split to multiple lines of width
  356. # characters. End lines on a comma and begin argument list indented with
  357. # the rest of the arguments.
  358. def _split_line(name, arguments, width):
  359. firstwidth = len(name)
  360. k = firstwidth
  361. newstr = name
  362. sepstr = ", "
  363. arglist = arguments.split(sepstr)
  364. for argument in arglist:
  365. if k == firstwidth:
  366. addstr = ""
  367. else:
  368. addstr = sepstr
  369. k = k + len(argument) + len(addstr)
  370. if k > width:
  371. k = firstwidth + 1 + len(argument)
  372. newstr = newstr + ",\n" + " "*(firstwidth+2) + argument
  373. else:
  374. newstr = newstr + addstr + argument
  375. return newstr
  376. _namedict = None
  377. _dictlist = None
  378. # Traverse all module directories underneath globals
  379. # to see if something is defined
  380. def _makenamedict(module='numpy'):
  381. module = __import__(module, globals(), locals(), [])
  382. thedict = {module.__name__:module.__dict__}
  383. dictlist = [module.__name__]
  384. totraverse = [module.__dict__]
  385. while True:
  386. if len(totraverse) == 0:
  387. break
  388. thisdict = totraverse.pop(0)
  389. for x in thisdict.keys():
  390. if isinstance(thisdict[x], types.ModuleType):
  391. modname = thisdict[x].__name__
  392. if modname not in dictlist:
  393. moddict = thisdict[x].__dict__
  394. dictlist.append(modname)
  395. totraverse.append(moddict)
  396. thedict[modname] = moddict
  397. return thedict, dictlist
  398. def _info(obj, output=None):
  399. """Provide information about ndarray obj.
  400. Parameters
  401. ----------
  402. obj : ndarray
  403. Must be ndarray, not checked.
  404. output
  405. Where printed output goes.
  406. Notes
  407. -----
  408. Copied over from the numarray module prior to its removal.
  409. Adapted somewhat as only numpy is an option now.
  410. Called by info.
  411. """
  412. extra = ""
  413. tic = ""
  414. bp = lambda x: x
  415. cls = getattr(obj, '__class__', type(obj))
  416. nm = getattr(cls, '__name__', cls)
  417. strides = obj.strides
  418. endian = obj.dtype.byteorder
  419. if output is None:
  420. output = sys.stdout
  421. print("class: ", nm, file=output)
  422. print("shape: ", obj.shape, file=output)
  423. print("strides: ", strides, file=output)
  424. print("itemsize: ", obj.itemsize, file=output)
  425. print("aligned: ", bp(obj.flags.aligned), file=output)
  426. print("contiguous: ", bp(obj.flags.contiguous), file=output)
  427. print("fortran: ", obj.flags.fortran, file=output)
  428. print(
  429. "data pointer: %s%s" % (hex(obj.ctypes._as_parameter_.value), extra),
  430. file=output
  431. )
  432. print("byteorder: ", end=' ', file=output)
  433. if endian in ['|', '=']:
  434. print("%s%s%s" % (tic, sys.byteorder, tic), file=output)
  435. byteswap = False
  436. elif endian == '>':
  437. print("%sbig%s" % (tic, tic), file=output)
  438. byteswap = sys.byteorder != "big"
  439. else:
  440. print("%slittle%s" % (tic, tic), file=output)
  441. byteswap = sys.byteorder != "little"
  442. print("byteswap: ", bp(byteswap), file=output)
  443. print("type: %s" % obj.dtype, file=output)
  444. @set_module('numpy')
  445. def info(object=None, maxwidth=76, output=None, toplevel='numpy'):
  446. """
  447. Get help information for an array, function, class, or module.
  448. Parameters
  449. ----------
  450. object : object or str, optional
  451. Input object or name to get information about. If `object` is
  452. an `ndarray` instance, information about the array is printed.
  453. If `object` is a numpy object, its docstring is given. If it is
  454. a string, available modules are searched for matching objects.
  455. If None, information about `info` itself is returned.
  456. maxwidth : int, optional
  457. Printing width.
  458. output : file like object, optional
  459. File like object that the output is written to, default is
  460. ``None``, in which case ``sys.stdout`` will be used.
  461. The object has to be opened in 'w' or 'a' mode.
  462. toplevel : str, optional
  463. Start search at this level.
  464. See Also
  465. --------
  466. source, lookfor
  467. Notes
  468. -----
  469. When used interactively with an object, ``np.info(obj)`` is equivalent
  470. to ``help(obj)`` on the Python prompt or ``obj?`` on the IPython
  471. prompt.
  472. Examples
  473. --------
  474. >>> np.info(np.polyval) # doctest: +SKIP
  475. polyval(p, x)
  476. Evaluate the polynomial p at x.
  477. ...
  478. When using a string for `object` it is possible to get multiple results.
  479. >>> np.info('fft') # doctest: +SKIP
  480. *** Found in numpy ***
  481. Core FFT routines
  482. ...
  483. *** Found in numpy.fft ***
  484. fft(a, n=None, axis=-1)
  485. ...
  486. *** Repeat reference found in numpy.fft.fftpack ***
  487. *** Total of 3 references found. ***
  488. When the argument is an array, information about the array is printed.
  489. >>> a = np.array([[1 + 2j, 3, -4], [-5j, 6, 0]], dtype=np.complex64)
  490. >>> np.info(a)
  491. class: ndarray
  492. shape: (2, 3)
  493. strides: (24, 8)
  494. itemsize: 8
  495. aligned: True
  496. contiguous: True
  497. fortran: False
  498. data pointer: 0x562b6e0d2860 # may vary
  499. byteorder: little
  500. byteswap: False
  501. type: complex64
  502. """
  503. global _namedict, _dictlist
  504. # Local import to speed up numpy's import time.
  505. import pydoc
  506. import inspect
  507. if (hasattr(object, '_ppimport_importer') or
  508. hasattr(object, '_ppimport_module')):
  509. object = object._ppimport_module
  510. elif hasattr(object, '_ppimport_attr'):
  511. object = object._ppimport_attr
  512. if output is None:
  513. output = sys.stdout
  514. if object is None:
  515. info(info)
  516. elif isinstance(object, ndarray):
  517. _info(object, output=output)
  518. elif isinstance(object, str):
  519. if _namedict is None:
  520. _namedict, _dictlist = _makenamedict(toplevel)
  521. numfound = 0
  522. objlist = []
  523. for namestr in _dictlist:
  524. try:
  525. obj = _namedict[namestr][object]
  526. if id(obj) in objlist:
  527. print("\n "
  528. "*** Repeat reference found in %s *** " % namestr,
  529. file=output
  530. )
  531. else:
  532. objlist.append(id(obj))
  533. print(" *** Found in %s ***" % namestr, file=output)
  534. info(obj)
  535. print("-"*maxwidth, file=output)
  536. numfound += 1
  537. except KeyError:
  538. pass
  539. if numfound == 0:
  540. print("Help for %s not found." % object, file=output)
  541. else:
  542. print("\n "
  543. "*** Total of %d references found. ***" % numfound,
  544. file=output
  545. )
  546. elif inspect.isfunction(object) or inspect.ismethod(object):
  547. name = object.__name__
  548. try:
  549. arguments = str(inspect.signature(object))
  550. except Exception:
  551. arguments = "()"
  552. if len(name+arguments) > maxwidth:
  553. argstr = _split_line(name, arguments, maxwidth)
  554. else:
  555. argstr = name + arguments
  556. print(" " + argstr + "\n", file=output)
  557. print(inspect.getdoc(object), file=output)
  558. elif inspect.isclass(object):
  559. name = object.__name__
  560. try:
  561. arguments = str(inspect.signature(object))
  562. except Exception:
  563. arguments = "()"
  564. if len(name+arguments) > maxwidth:
  565. argstr = _split_line(name, arguments, maxwidth)
  566. else:
  567. argstr = name + arguments
  568. print(" " + argstr + "\n", file=output)
  569. doc1 = inspect.getdoc(object)
  570. if doc1 is None:
  571. if hasattr(object, '__init__'):
  572. print(inspect.getdoc(object.__init__), file=output)
  573. else:
  574. print(inspect.getdoc(object), file=output)
  575. methods = pydoc.allmethods(object)
  576. public_methods = [meth for meth in methods if meth[0] != '_']
  577. if public_methods:
  578. print("\n\nMethods:\n", file=output)
  579. for meth in public_methods:
  580. thisobj = getattr(object, meth, None)
  581. if thisobj is not None:
  582. methstr, other = pydoc.splitdoc(
  583. inspect.getdoc(thisobj) or "None"
  584. )
  585. print(" %s -- %s" % (meth, methstr), file=output)
  586. elif hasattr(object, '__doc__'):
  587. print(inspect.getdoc(object), file=output)
  588. @set_module('numpy')
  589. def source(object, output=sys.stdout):
  590. """
  591. Print or write to a file the source code for a NumPy object.
  592. The source code is only returned for objects written in Python. Many
  593. functions and classes are defined in C and will therefore not return
  594. useful information.
  595. Parameters
  596. ----------
  597. object : numpy object
  598. Input object. This can be any object (function, class, module,
  599. ...).
  600. output : file object, optional
  601. If `output` not supplied then source code is printed to screen
  602. (sys.stdout). File object must be created with either write 'w' or
  603. append 'a' modes.
  604. See Also
  605. --------
  606. lookfor, info
  607. Examples
  608. --------
  609. >>> np.source(np.interp) #doctest: +SKIP
  610. In file: /usr/lib/python2.6/dist-packages/numpy/lib/function_base.py
  611. def interp(x, xp, fp, left=None, right=None):
  612. \"\"\".... (full docstring printed)\"\"\"
  613. if isinstance(x, (float, int, number)):
  614. return compiled_interp([x], xp, fp, left, right).item()
  615. else:
  616. return compiled_interp(x, xp, fp, left, right)
  617. The source code is only returned for objects written in Python.
  618. >>> np.source(np.array) #doctest: +SKIP
  619. Not available for this object.
  620. """
  621. # Local import to speed up numpy's import time.
  622. import inspect
  623. try:
  624. print("In file: %s\n" % inspect.getsourcefile(object), file=output)
  625. print(inspect.getsource(object), file=output)
  626. except Exception:
  627. print("Not available for this object.", file=output)
  628. # Cache for lookfor: {id(module): {name: (docstring, kind, index), ...}...}
  629. # where kind: "func", "class", "module", "object"
  630. # and index: index in breadth-first namespace traversal
  631. _lookfor_caches = {}
  632. # regexp whose match indicates that the string may contain a function
  633. # signature
  634. _function_signature_re = re.compile(r"[a-z0-9_]+\(.*[,=].*\)", re.I)
  635. @set_module('numpy')
  636. def lookfor(what, module=None, import_modules=True, regenerate=False,
  637. output=None):
  638. """
  639. Do a keyword search on docstrings.
  640. A list of objects that matched the search is displayed,
  641. sorted by relevance. All given keywords need to be found in the
  642. docstring for it to be returned as a result, but the order does
  643. not matter.
  644. Parameters
  645. ----------
  646. what : str
  647. String containing words to look for.
  648. module : str or list, optional
  649. Name of module(s) whose docstrings to go through.
  650. import_modules : bool, optional
  651. Whether to import sub-modules in packages. Default is True.
  652. regenerate : bool, optional
  653. Whether to re-generate the docstring cache. Default is False.
  654. output : file-like, optional
  655. File-like object to write the output to. If omitted, use a pager.
  656. See Also
  657. --------
  658. source, info
  659. Notes
  660. -----
  661. Relevance is determined only roughly, by checking if the keywords occur
  662. in the function name, at the start of a docstring, etc.
  663. Examples
  664. --------
  665. >>> np.lookfor('binary representation') # doctest: +SKIP
  666. Search results for 'binary representation'
  667. ------------------------------------------
  668. numpy.binary_repr
  669. Return the binary representation of the input number as a string.
  670. numpy.core.setup_common.long_double_representation
  671. Given a binary dump as given by GNU od -b, look for long double
  672. numpy.base_repr
  673. Return a string representation of a number in the given base system.
  674. ...
  675. """
  676. import pydoc
  677. # Cache
  678. cache = _lookfor_generate_cache(module, import_modules, regenerate)
  679. # Search
  680. # XXX: maybe using a real stemming search engine would be better?
  681. found = []
  682. whats = str(what).lower().split()
  683. if not whats:
  684. return
  685. for name, (docstring, kind, index) in cache.items():
  686. if kind in ('module', 'object'):
  687. # don't show modules or objects
  688. continue
  689. doc = docstring.lower()
  690. if all(w in doc for w in whats):
  691. found.append(name)
  692. # Relevance sort
  693. # XXX: this is full Harrison-Stetson heuristics now,
  694. # XXX: it probably could be improved
  695. kind_relevance = {'func': 1000, 'class': 1000,
  696. 'module': -1000, 'object': -1000}
  697. def relevance(name, docstr, kind, index):
  698. r = 0
  699. # do the keywords occur within the start of the docstring?
  700. first_doc = "\n".join(docstr.lower().strip().split("\n")[:3])
  701. r += sum([200 for w in whats if w in first_doc])
  702. # do the keywords occur in the function name?
  703. r += sum([30 for w in whats if w in name])
  704. # is the full name long?
  705. r += -len(name) * 5
  706. # is the object of bad type?
  707. r += kind_relevance.get(kind, -1000)
  708. # is the object deep in namespace hierarchy?
  709. r += -name.count('.') * 10
  710. r += max(-index / 100, -100)
  711. return r
  712. def relevance_value(a):
  713. return relevance(a, *cache[a])
  714. found.sort(key=relevance_value)
  715. # Pretty-print
  716. s = "Search results for '%s'" % (' '.join(whats))
  717. help_text = [s, "-"*len(s)]
  718. for name in found[::-1]:
  719. doc, kind, ix = cache[name]
  720. doclines = [line.strip() for line in doc.strip().split("\n")
  721. if line.strip()]
  722. # find a suitable short description
  723. try:
  724. first_doc = doclines[0].strip()
  725. if _function_signature_re.search(first_doc):
  726. first_doc = doclines[1].strip()
  727. except IndexError:
  728. first_doc = ""
  729. help_text.append("%s\n %s" % (name, first_doc))
  730. if not found:
  731. help_text.append("Nothing found.")
  732. # Output
  733. if output is not None:
  734. output.write("\n".join(help_text))
  735. elif len(help_text) > 10:
  736. pager = pydoc.getpager()
  737. pager("\n".join(help_text))
  738. else:
  739. print("\n".join(help_text))
  740. def _lookfor_generate_cache(module, import_modules, regenerate):
  741. """
  742. Generate docstring cache for given module.
  743. Parameters
  744. ----------
  745. module : str, None, module
  746. Module for which to generate docstring cache
  747. import_modules : bool
  748. Whether to import sub-modules in packages.
  749. regenerate : bool
  750. Re-generate the docstring cache
  751. Returns
  752. -------
  753. cache : dict {obj_full_name: (docstring, kind, index), ...}
  754. Docstring cache for the module, either cached one (regenerate=False)
  755. or newly generated.
  756. """
  757. # Local import to speed up numpy's import time.
  758. import inspect
  759. from io import StringIO
  760. if module is None:
  761. module = "numpy"
  762. if isinstance(module, str):
  763. try:
  764. __import__(module)
  765. except ImportError:
  766. return {}
  767. module = sys.modules[module]
  768. elif isinstance(module, list) or isinstance(module, tuple):
  769. cache = {}
  770. for mod in module:
  771. cache.update(_lookfor_generate_cache(mod, import_modules,
  772. regenerate))
  773. return cache
  774. if id(module) in _lookfor_caches and not regenerate:
  775. return _lookfor_caches[id(module)]
  776. # walk items and collect docstrings
  777. cache = {}
  778. _lookfor_caches[id(module)] = cache
  779. seen = {}
  780. index = 0
  781. stack = [(module.__name__, module)]
  782. while stack:
  783. name, item = stack.pop(0)
  784. if id(item) in seen:
  785. continue
  786. seen[id(item)] = True
  787. index += 1
  788. kind = "object"
  789. if inspect.ismodule(item):
  790. kind = "module"
  791. try:
  792. _all = item.__all__
  793. except AttributeError:
  794. _all = None
  795. # import sub-packages
  796. if import_modules and hasattr(item, '__path__'):
  797. for pth in item.__path__:
  798. for mod_path in os.listdir(pth):
  799. this_py = os.path.join(pth, mod_path)
  800. init_py = os.path.join(pth, mod_path, '__init__.py')
  801. if (os.path.isfile(this_py) and
  802. mod_path.endswith('.py')):
  803. to_import = mod_path[:-3]
  804. elif os.path.isfile(init_py):
  805. to_import = mod_path
  806. else:
  807. continue
  808. if to_import == '__init__':
  809. continue
  810. try:
  811. old_stdout = sys.stdout
  812. old_stderr = sys.stderr
  813. try:
  814. sys.stdout = StringIO()
  815. sys.stderr = StringIO()
  816. __import__("%s.%s" % (name, to_import))
  817. finally:
  818. sys.stdout = old_stdout
  819. sys.stderr = old_stderr
  820. except KeyboardInterrupt:
  821. # Assume keyboard interrupt came from a user
  822. raise
  823. except BaseException:
  824. # Ignore also SystemExit and pytests.importorskip
  825. # `Skipped` (these are BaseExceptions; gh-22345)
  826. continue
  827. for n, v in _getmembers(item):
  828. try:
  829. item_name = getattr(v, '__name__', "%s.%s" % (name, n))
  830. mod_name = getattr(v, '__module__', None)
  831. except NameError:
  832. # ref. SWIG's global cvars
  833. # NameError: Unknown C global variable
  834. item_name = "%s.%s" % (name, n)
  835. mod_name = None
  836. if '.' not in item_name and mod_name:
  837. item_name = "%s.%s" % (mod_name, item_name)
  838. if not item_name.startswith(name + '.'):
  839. # don't crawl "foreign" objects
  840. if isinstance(v, ufunc):
  841. # ... unless they are ufuncs
  842. pass
  843. else:
  844. continue
  845. elif not (inspect.ismodule(v) or _all is None or n in _all):
  846. continue
  847. stack.append(("%s.%s" % (name, n), v))
  848. elif inspect.isclass(item):
  849. kind = "class"
  850. for n, v in _getmembers(item):
  851. stack.append(("%s.%s" % (name, n), v))
  852. elif hasattr(item, "__call__"):
  853. kind = "func"
  854. try:
  855. doc = inspect.getdoc(item)
  856. except NameError:
  857. # ref SWIG's NameError: Unknown C global variable
  858. doc = None
  859. if doc is not None:
  860. cache[name] = (doc, kind, index)
  861. return cache
  862. def _getmembers(item):
  863. import inspect
  864. try:
  865. members = inspect.getmembers(item)
  866. except Exception:
  867. members = [(x, getattr(item, x)) for x in dir(item)
  868. if hasattr(item, x)]
  869. return members
  870. def safe_eval(source):
  871. """
  872. Protected string evaluation.
  873. Evaluate a string containing a Python literal expression without
  874. allowing the execution of arbitrary non-literal code.
  875. .. warning::
  876. This function is identical to :py:meth:`ast.literal_eval` and
  877. has the same security implications. It may not always be safe
  878. to evaluate large input strings.
  879. Parameters
  880. ----------
  881. source : str
  882. The string to evaluate.
  883. Returns
  884. -------
  885. obj : object
  886. The result of evaluating `source`.
  887. Raises
  888. ------
  889. SyntaxError
  890. If the code has invalid Python syntax, or if it contains
  891. non-literal code.
  892. Examples
  893. --------
  894. >>> np.safe_eval('1')
  895. 1
  896. >>> np.safe_eval('[1, 2, 3]')
  897. [1, 2, 3]
  898. >>> np.safe_eval('{"foo": ("bar", 10.0)}')
  899. {'foo': ('bar', 10.0)}
  900. >>> np.safe_eval('import os')
  901. Traceback (most recent call last):
  902. ...
  903. SyntaxError: invalid syntax
  904. >>> np.safe_eval('open("/home/user/.ssh/id_dsa").read()')
  905. Traceback (most recent call last):
  906. ...
  907. ValueError: malformed node or string: <_ast.Call object at 0x...>
  908. """
  909. # Local import to speed up numpy's import time.
  910. import ast
  911. return ast.literal_eval(source)
  912. def _median_nancheck(data, result, axis):
  913. """
  914. Utility function to check median result from data for NaN values at the end
  915. and return NaN in that case. Input result can also be a MaskedArray.
  916. Parameters
  917. ----------
  918. data : array
  919. Sorted input data to median function
  920. result : Array or MaskedArray
  921. Result of median function.
  922. axis : int
  923. Axis along which the median was computed.
  924. Returns
  925. -------
  926. result : scalar or ndarray
  927. Median or NaN in axes which contained NaN in the input. If the input
  928. was an array, NaN will be inserted in-place. If a scalar, either the
  929. input itself or a scalar NaN.
  930. """
  931. if data.size == 0:
  932. return result
  933. potential_nans = data.take(-1, axis=axis)
  934. n = np.isnan(potential_nans)
  935. # masked NaN values are ok, although for masked the copyto may fail for
  936. # unmasked ones (this was always broken) when the result is a scalar.
  937. if np.ma.isMaskedArray(n):
  938. n = n.filled(False)
  939. if not n.any():
  940. return result
  941. # Without given output, it is possible that the current result is a
  942. # numpy scalar, which is not writeable. If so, just return nan.
  943. if isinstance(result, np.generic):
  944. return potential_nans
  945. # Otherwise copy NaNs (if there are any)
  946. np.copyto(result, potential_nans, where=n)
  947. return result
  948. def _opt_info():
  949. """
  950. Returns a string contains the supported CPU features by the current build.
  951. The string format can be explained as follows:
  952. - dispatched features that are supported by the running machine
  953. end with `*`.
  954. - dispatched features that are "not" supported by the running machine
  955. end with `?`.
  956. - remained features are representing the baseline.
  957. """
  958. from numpy.core._multiarray_umath import (
  959. __cpu_features__, __cpu_baseline__, __cpu_dispatch__
  960. )
  961. if len(__cpu_baseline__) == 0 and len(__cpu_dispatch__) == 0:
  962. return ''
  963. enabled_features = ' '.join(__cpu_baseline__)
  964. for feature in __cpu_dispatch__:
  965. if __cpu_features__[feature]:
  966. enabled_features += f" {feature}*"
  967. else:
  968. enabled_features += f" {feature}?"
  969. return enabled_features
  970. def drop_metadata(dtype, /):
  971. """
  972. Returns the dtype unchanged if it contained no metadata or a copy of the
  973. dtype if it (or any of its structure dtypes) contained metadata.
  974. This utility is used by `np.save` and `np.savez` to drop metadata before
  975. saving.
  976. .. note::
  977. Due to its limitation this function may move to a more appropriate
  978. home or change in the future and is considered semi-public API only.
  979. .. warning::
  980. This function does not preserve more strange things like record dtypes
  981. and user dtypes may simply return the wrong thing. If you need to be
  982. sure about the latter, check the result with:
  983. ``np.can_cast(new_dtype, dtype, casting="no")``.
  984. """
  985. if dtype.fields is not None:
  986. found_metadata = dtype.metadata is not None
  987. names = []
  988. formats = []
  989. offsets = []
  990. titles = []
  991. for name, field in dtype.fields.items():
  992. field_dt = drop_metadata(field[0])
  993. if field_dt is not field[0]:
  994. found_metadata = True
  995. names.append(name)
  996. formats.append(field_dt)
  997. offsets.append(field[1])
  998. titles.append(None if len(field) < 3 else field[2])
  999. if not found_metadata:
  1000. return dtype
  1001. structure = dict(
  1002. names=names, formats=formats, offsets=offsets, titles=titles,
  1003. itemsize=dtype.itemsize)
  1004. # NOTE: Could pass (dtype.type, structure) to preserve record dtypes...
  1005. return np.dtype(structure, align=dtype.isalignedstruct)
  1006. elif dtype.subdtype is not None:
  1007. # subarray dtype
  1008. subdtype, shape = dtype.subdtype
  1009. new_subdtype = drop_metadata(subdtype)
  1010. if dtype.metadata is None and new_subdtype is subdtype:
  1011. return dtype
  1012. return np.dtype((new_subdtype, shape))
  1013. else:
  1014. # Normal unstructured dtype
  1015. if dtype.metadata is None:
  1016. return dtype
  1017. # Note that `dt.str` doesn't round-trip e.g. for user-dtypes.
  1018. return np.dtype(dtype.str)