Mercurial > hg > vamp-build-and-test
comparison DEPENDENCIES/mingw32/Python27/Lib/site-packages/numpy/lib/utils.py @ 87:2a2c65a20a8b
Add Python libs and headers
author | Chris Cannam |
---|---|
date | Wed, 25 Feb 2015 14:05:22 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
86:413a9d26189e | 87:2a2c65a20a8b |
---|---|
1 from __future__ import division, absolute_import, print_function | |
2 | |
3 import os | |
4 import sys | |
5 import types | |
6 import re | |
7 | |
8 from numpy.core.numerictypes import issubclass_, issubsctype, issubdtype | |
9 from numpy.core import ndarray, ufunc, asarray | |
10 | |
11 __all__ = [ | |
12 'issubclass_', 'issubsctype', 'issubdtype', 'deprecate', | |
13 'deprecate_with_doc', 'get_include', 'info', 'source', 'who', | |
14 'lookfor', 'byte_bounds', 'safe_eval' | |
15 ] | |
16 | |
17 def get_include(): | |
18 """ | |
19 Return the directory that contains the NumPy \\*.h header files. | |
20 | |
21 Extension modules that need to compile against NumPy should use this | |
22 function to locate the appropriate include directory. | |
23 | |
24 Notes | |
25 ----- | |
26 When using ``distutils``, for example in ``setup.py``. | |
27 :: | |
28 | |
29 import numpy as np | |
30 ... | |
31 Extension('extension_name', ... | |
32 include_dirs=[np.get_include()]) | |
33 ... | |
34 | |
35 """ | |
36 import numpy | |
37 if numpy.show_config is None: | |
38 # running from numpy source directory | |
39 d = os.path.join(os.path.dirname(numpy.__file__), 'core', 'include') | |
40 else: | |
41 # using installed numpy core headers | |
42 import numpy.core as core | |
43 d = os.path.join(os.path.dirname(core.__file__), 'include') | |
44 return d | |
45 | |
46 | |
47 def _set_function_name(func, name): | |
48 func.__name__ = name | |
49 return func | |
50 | |
51 | |
52 class _Deprecate(object): | |
53 """ | |
54 Decorator class to deprecate old functions. | |
55 | |
56 Refer to `deprecate` for details. | |
57 | |
58 See Also | |
59 -------- | |
60 deprecate | |
61 | |
62 """ | |
63 | |
64 def __init__(self, old_name=None, new_name=None, message=None): | |
65 self.old_name = old_name | |
66 self.new_name = new_name | |
67 self.message = message | |
68 | |
69 def __call__(self, func, *args, **kwargs): | |
70 """ | |
71 Decorator call. Refer to ``decorate``. | |
72 | |
73 """ | |
74 old_name = self.old_name | |
75 new_name = self.new_name | |
76 message = self.message | |
77 | |
78 import warnings | |
79 if old_name is None: | |
80 try: | |
81 old_name = func.__name__ | |
82 except AttributeError: | |
83 old_name = func.__name__ | |
84 if new_name is None: | |
85 depdoc = "`%s` is deprecated!" % old_name | |
86 else: | |
87 depdoc = "`%s` is deprecated, use `%s` instead!" % \ | |
88 (old_name, new_name) | |
89 | |
90 if message is not None: | |
91 depdoc += "\n" + message | |
92 | |
93 def newfunc(*args,**kwds): | |
94 """`arrayrange` is deprecated, use `arange` instead!""" | |
95 warnings.warn(depdoc, DeprecationWarning) | |
96 return func(*args, **kwds) | |
97 | |
98 newfunc = _set_function_name(newfunc, old_name) | |
99 doc = func.__doc__ | |
100 if doc is None: | |
101 doc = depdoc | |
102 else: | |
103 doc = '\n\n'.join([depdoc, doc]) | |
104 newfunc.__doc__ = doc | |
105 try: | |
106 d = func.__dict__ | |
107 except AttributeError: | |
108 pass | |
109 else: | |
110 newfunc.__dict__.update(d) | |
111 return newfunc | |
112 | |
113 def deprecate(*args, **kwargs): | |
114 """ | |
115 Issues a DeprecationWarning, adds warning to `old_name`'s | |
116 docstring, rebinds ``old_name.__name__`` and returns the new | |
117 function object. | |
118 | |
119 This function may also be used as a decorator. | |
120 | |
121 Parameters | |
122 ---------- | |
123 func : function | |
124 The function to be deprecated. | |
125 old_name : str, optional | |
126 The name of the function to be deprecated. Default is None, in | |
127 which case the name of `func` is used. | |
128 new_name : str, optional | |
129 The new name for the function. Default is None, in which case the | |
130 deprecation message is that `old_name` is deprecated. If given, the | |
131 deprecation message is that `old_name` is deprecated and `new_name` | |
132 should be used instead. | |
133 message : str, optional | |
134 Additional explanation of the deprecation. Displayed in the | |
135 docstring after the warning. | |
136 | |
137 Returns | |
138 ------- | |
139 old_func : function | |
140 The deprecated function. | |
141 | |
142 Examples | |
143 -------- | |
144 Note that ``olduint`` returns a value after printing Deprecation | |
145 Warning: | |
146 | |
147 >>> olduint = np.deprecate(np.uint) | |
148 >>> olduint(6) | |
149 /usr/lib/python2.5/site-packages/numpy/lib/utils.py:114: | |
150 DeprecationWarning: uint32 is deprecated | |
151 warnings.warn(str1, DeprecationWarning) | |
152 6 | |
153 | |
154 """ | |
155 # Deprecate may be run as a function or as a decorator | |
156 # If run as a function, we initialise the decorator class | |
157 # and execute its __call__ method. | |
158 | |
159 if args: | |
160 fn = args[0] | |
161 args = args[1:] | |
162 | |
163 # backward compatibility -- can be removed | |
164 # after next release | |
165 if 'newname' in kwargs: | |
166 kwargs['new_name'] = kwargs.pop('newname') | |
167 if 'oldname' in kwargs: | |
168 kwargs['old_name'] = kwargs.pop('oldname') | |
169 | |
170 return _Deprecate(*args, **kwargs)(fn) | |
171 else: | |
172 return _Deprecate(*args, **kwargs) | |
173 | |
174 deprecate_with_doc = lambda msg: _Deprecate(message=msg) | |
175 | |
176 | |
177 #-------------------------------------------- | |
178 # Determine if two arrays can share memory | |
179 #-------------------------------------------- | |
180 | |
181 def byte_bounds(a): | |
182 """ | |
183 Returns pointers to the end-points of an array. | |
184 | |
185 Parameters | |
186 ---------- | |
187 a : ndarray | |
188 Input array. It must conform to the Python-side of the array | |
189 interface. | |
190 | |
191 Returns | |
192 ------- | |
193 (low, high) : tuple of 2 integers | |
194 The first integer is the first byte of the array, the second | |
195 integer is just past the last byte of the array. If `a` is not | |
196 contiguous it will not use every byte between the (`low`, `high`) | |
197 values. | |
198 | |
199 Examples | |
200 -------- | |
201 >>> I = np.eye(2, dtype='f'); I.dtype | |
202 dtype('float32') | |
203 >>> low, high = np.byte_bounds(I) | |
204 >>> high - low == I.size*I.itemsize | |
205 True | |
206 >>> I = np.eye(2, dtype='G'); I.dtype | |
207 dtype('complex192') | |
208 >>> low, high = np.byte_bounds(I) | |
209 >>> high - low == I.size*I.itemsize | |
210 True | |
211 | |
212 """ | |
213 ai = a.__array_interface__ | |
214 a_data = ai['data'][0] | |
215 astrides = ai['strides'] | |
216 ashape = ai['shape'] | |
217 bytes_a = asarray(a).dtype.itemsize | |
218 | |
219 a_low = a_high = a_data | |
220 if astrides is None: | |
221 # contiguous case | |
222 a_high += a.size * bytes_a | |
223 else: | |
224 for shape, stride in zip(ashape, astrides): | |
225 if stride < 0: | |
226 a_low += (shape-1)*stride | |
227 else: | |
228 a_high += (shape-1)*stride | |
229 a_high += bytes_a | |
230 return a_low, a_high | |
231 | |
232 | |
233 #----------------------------------------------------------------------------- | |
234 # Function for output and information on the variables used. | |
235 #----------------------------------------------------------------------------- | |
236 | |
237 | |
238 def who(vardict=None): | |
239 """ | |
240 Print the Numpy arrays in the given dictionary. | |
241 | |
242 If there is no dictionary passed in or `vardict` is None then returns | |
243 Numpy arrays in the globals() dictionary (all Numpy arrays in the | |
244 namespace). | |
245 | |
246 Parameters | |
247 ---------- | |
248 vardict : dict, optional | |
249 A dictionary possibly containing ndarrays. Default is globals(). | |
250 | |
251 Returns | |
252 ------- | |
253 out : None | |
254 Returns 'None'. | |
255 | |
256 Notes | |
257 ----- | |
258 Prints out the name, shape, bytes and type of all of the ndarrays | |
259 present in `vardict`. | |
260 | |
261 Examples | |
262 -------- | |
263 >>> a = np.arange(10) | |
264 >>> b = np.ones(20) | |
265 >>> np.who() | |
266 Name Shape Bytes Type | |
267 =========================================================== | |
268 a 10 40 int32 | |
269 b 20 160 float64 | |
270 Upper bound on total bytes = 200 | |
271 | |
272 >>> d = {'x': np.arange(2.0), 'y': np.arange(3.0), 'txt': 'Some str', | |
273 ... 'idx':5} | |
274 >>> np.who(d) | |
275 Name Shape Bytes Type | |
276 =========================================================== | |
277 y 3 24 float64 | |
278 x 2 16 float64 | |
279 Upper bound on total bytes = 40 | |
280 | |
281 """ | |
282 if vardict is None: | |
283 frame = sys._getframe().f_back | |
284 vardict = frame.f_globals | |
285 sta = [] | |
286 cache = {} | |
287 for name in vardict.keys(): | |
288 if isinstance(vardict[name], ndarray): | |
289 var = vardict[name] | |
290 idv = id(var) | |
291 if idv in cache.keys(): | |
292 namestr = name + " (%s)" % cache[idv] | |
293 original = 0 | |
294 else: | |
295 cache[idv] = name | |
296 namestr = name | |
297 original = 1 | |
298 shapestr = " x ".join(map(str, var.shape)) | |
299 bytestr = str(var.nbytes) | |
300 sta.append([namestr, shapestr, bytestr, var.dtype.name, | |
301 original]) | |
302 | |
303 maxname = 0 | |
304 maxshape = 0 | |
305 maxbyte = 0 | |
306 totalbytes = 0 | |
307 for k in range(len(sta)): | |
308 val = sta[k] | |
309 if maxname < len(val[0]): | |
310 maxname = len(val[0]) | |
311 if maxshape < len(val[1]): | |
312 maxshape = len(val[1]) | |
313 if maxbyte < len(val[2]): | |
314 maxbyte = len(val[2]) | |
315 if val[4]: | |
316 totalbytes += int(val[2]) | |
317 | |
318 if len(sta) > 0: | |
319 sp1 = max(10, maxname) | |
320 sp2 = max(10, maxshape) | |
321 sp3 = max(10, maxbyte) | |
322 prval = "Name %s Shape %s Bytes %s Type" % (sp1*' ', sp2*' ', sp3*' ') | |
323 print(prval + "\n" + "="*(len(prval)+5) + "\n") | |
324 | |
325 for k in range(len(sta)): | |
326 val = sta[k] | |
327 print("%s %s %s %s %s %s %s" % (val[0], ' '*(sp1-len(val[0])+4), | |
328 val[1], ' '*(sp2-len(val[1])+5), | |
329 val[2], ' '*(sp3-len(val[2])+5), | |
330 val[3])) | |
331 print("\nUpper bound on total bytes = %d" % totalbytes) | |
332 return | |
333 | |
334 #----------------------------------------------------------------------------- | |
335 | |
336 | |
337 # NOTE: pydoc defines a help function which works simliarly to this | |
338 # except it uses a pager to take over the screen. | |
339 | |
340 # combine name and arguments and split to multiple lines of width | |
341 # characters. End lines on a comma and begin argument list indented with | |
342 # the rest of the arguments. | |
343 def _split_line(name, arguments, width): | |
344 firstwidth = len(name) | |
345 k = firstwidth | |
346 newstr = name | |
347 sepstr = ", " | |
348 arglist = arguments.split(sepstr) | |
349 for argument in arglist: | |
350 if k == firstwidth: | |
351 addstr = "" | |
352 else: | |
353 addstr = sepstr | |
354 k = k + len(argument) + len(addstr) | |
355 if k > width: | |
356 k = firstwidth + 1 + len(argument) | |
357 newstr = newstr + ",\n" + " "*(firstwidth+2) + argument | |
358 else: | |
359 newstr = newstr + addstr + argument | |
360 return newstr | |
361 | |
362 _namedict = None | |
363 _dictlist = None | |
364 | |
365 # Traverse all module directories underneath globals | |
366 # to see if something is defined | |
367 def _makenamedict(module='numpy'): | |
368 module = __import__(module, globals(), locals(), []) | |
369 thedict = {module.__name__:module.__dict__} | |
370 dictlist = [module.__name__] | |
371 totraverse = [module.__dict__] | |
372 while True: | |
373 if len(totraverse) == 0: | |
374 break | |
375 thisdict = totraverse.pop(0) | |
376 for x in thisdict.keys(): | |
377 if isinstance(thisdict[x], types.ModuleType): | |
378 modname = thisdict[x].__name__ | |
379 if modname not in dictlist: | |
380 moddict = thisdict[x].__dict__ | |
381 dictlist.append(modname) | |
382 totraverse.append(moddict) | |
383 thedict[modname] = moddict | |
384 return thedict, dictlist | |
385 | |
386 | |
387 def _info(obj, output=sys.stdout): | |
388 """Provide information about ndarray obj. | |
389 | |
390 Parameters | |
391 ---------- | |
392 obj: ndarray | |
393 Must be ndarray, not checked. | |
394 output: | |
395 Where printed output goes. | |
396 | |
397 Notes | |
398 ----- | |
399 Copied over from the numarray module prior to its removal. | |
400 Adapted somewhat as only numpy is an option now. | |
401 | |
402 Called by info. | |
403 | |
404 """ | |
405 extra = "" | |
406 tic = "" | |
407 bp = lambda x: x | |
408 cls = getattr(obj, '__class__', type(obj)) | |
409 nm = getattr(cls, '__name__', cls) | |
410 strides = obj.strides | |
411 endian = obj.dtype.byteorder | |
412 | |
413 print("class: ", nm, file=output) | |
414 print("shape: ", obj.shape, file=output) | |
415 print("strides: ", strides, file=output) | |
416 print("itemsize: ", obj.itemsize, file=output) | |
417 print("aligned: ", bp(obj.flags.aligned), file=output) | |
418 print("contiguous: ", bp(obj.flags.contiguous), file=output) | |
419 print("fortran: ", obj.flags.fortran, file=output) | |
420 print( | |
421 "data pointer: %s%s" % (hex(obj.ctypes._as_parameter_.value), extra), | |
422 file=output | |
423 ) | |
424 print("byteorder: ", end=' ', file=output) | |
425 if endian in ['|', '=']: | |
426 print("%s%s%s" % (tic, sys.byteorder, tic), file=output) | |
427 byteswap = False | |
428 elif endian == '>': | |
429 print("%sbig%s" % (tic, tic), file=output) | |
430 byteswap = sys.byteorder != "big" | |
431 else: | |
432 print("%slittle%s" % (tic, tic), file=output) | |
433 byteswap = sys.byteorder != "little" | |
434 print("byteswap: ", bp(byteswap), file=output) | |
435 print("type: %s" % obj.dtype, file=output) | |
436 | |
437 | |
438 def info(object=None, maxwidth=76, output=sys.stdout, toplevel='numpy'): | |
439 """ | |
440 Get help information for a function, class, or module. | |
441 | |
442 Parameters | |
443 ---------- | |
444 object : object or str, optional | |
445 Input object or name to get information about. If `object` is a | |
446 numpy object, its docstring is given. If it is a string, available | |
447 modules are searched for matching objects. If None, information | |
448 about `info` itself is returned. | |
449 maxwidth : int, optional | |
450 Printing width. | |
451 output : file like object, optional | |
452 File like object that the output is written to, default is | |
453 ``stdout``. The object has to be opened in 'w' or 'a' mode. | |
454 toplevel : str, optional | |
455 Start search at this level. | |
456 | |
457 See Also | |
458 -------- | |
459 source, lookfor | |
460 | |
461 Notes | |
462 ----- | |
463 When used interactively with an object, ``np.info(obj)`` is equivalent | |
464 to ``help(obj)`` on the Python prompt or ``obj?`` on the IPython | |
465 prompt. | |
466 | |
467 Examples | |
468 -------- | |
469 >>> np.info(np.polyval) # doctest: +SKIP | |
470 polyval(p, x) | |
471 Evaluate the polynomial p at x. | |
472 ... | |
473 | |
474 When using a string for `object` it is possible to get multiple results. | |
475 | |
476 >>> np.info('fft') # doctest: +SKIP | |
477 *** Found in numpy *** | |
478 Core FFT routines | |
479 ... | |
480 *** Found in numpy.fft *** | |
481 fft(a, n=None, axis=-1) | |
482 ... | |
483 *** Repeat reference found in numpy.fft.fftpack *** | |
484 *** Total of 3 references found. *** | |
485 | |
486 """ | |
487 global _namedict, _dictlist | |
488 # Local import to speed up numpy's import time. | |
489 import pydoc | |
490 import inspect | |
491 | |
492 if (hasattr(object, '_ppimport_importer') or | |
493 hasattr(object, '_ppimport_module')): | |
494 object = object._ppimport_module | |
495 elif hasattr(object, '_ppimport_attr'): | |
496 object = object._ppimport_attr | |
497 | |
498 if object is None: | |
499 info(info) | |
500 elif isinstance(object, ndarray): | |
501 _info(object, output=output) | |
502 elif isinstance(object, str): | |
503 if _namedict is None: | |
504 _namedict, _dictlist = _makenamedict(toplevel) | |
505 numfound = 0 | |
506 objlist = [] | |
507 for namestr in _dictlist: | |
508 try: | |
509 obj = _namedict[namestr][object] | |
510 if id(obj) in objlist: | |
511 print("\n " | |
512 "*** Repeat reference found in %s *** " % namestr, | |
513 file=output | |
514 ) | |
515 else: | |
516 objlist.append(id(obj)) | |
517 print(" *** Found in %s ***" % namestr, file=output) | |
518 info(obj) | |
519 print("-"*maxwidth, file=output) | |
520 numfound += 1 | |
521 except KeyError: | |
522 pass | |
523 if numfound == 0: | |
524 print("Help for %s not found." % object, file=output) | |
525 else: | |
526 print("\n " | |
527 "*** Total of %d references found. ***" % numfound, | |
528 file=output | |
529 ) | |
530 | |
531 elif inspect.isfunction(object): | |
532 name = object.__name__ | |
533 arguments = inspect.formatargspec(*inspect.getargspec(object)) | |
534 | |
535 if len(name+arguments) > maxwidth: | |
536 argstr = _split_line(name, arguments, maxwidth) | |
537 else: | |
538 argstr = name + arguments | |
539 | |
540 print(" " + argstr + "\n", file=output) | |
541 print(inspect.getdoc(object), file=output) | |
542 | |
543 elif inspect.isclass(object): | |
544 name = object.__name__ | |
545 arguments = "()" | |
546 try: | |
547 if hasattr(object, '__init__'): | |
548 arguments = inspect.formatargspec( | |
549 *inspect.getargspec(object.__init__.__func__) | |
550 ) | |
551 arglist = arguments.split(', ') | |
552 if len(arglist) > 1: | |
553 arglist[1] = "("+arglist[1] | |
554 arguments = ", ".join(arglist[1:]) | |
555 except: | |
556 pass | |
557 | |
558 if len(name+arguments) > maxwidth: | |
559 argstr = _split_line(name, arguments, maxwidth) | |
560 else: | |
561 argstr = name + arguments | |
562 | |
563 print(" " + argstr + "\n", file=output) | |
564 doc1 = inspect.getdoc(object) | |
565 if doc1 is None: | |
566 if hasattr(object, '__init__'): | |
567 print(inspect.getdoc(object.__init__), file=output) | |
568 else: | |
569 print(inspect.getdoc(object), file=output) | |
570 | |
571 methods = pydoc.allmethods(object) | |
572 if methods != []: | |
573 print("\n\nMethods:\n", file=output) | |
574 for meth in methods: | |
575 if meth[0] == '_': | |
576 continue | |
577 thisobj = getattr(object, meth, None) | |
578 if thisobj is not None: | |
579 methstr, other = pydoc.splitdoc( | |
580 inspect.getdoc(thisobj) or "None" | |
581 ) | |
582 print(" %s -- %s" % (meth, methstr), file=output) | |
583 | |
584 elif (sys.version_info[0] < 3 | |
585 and isinstance(object, types.InstanceType)): | |
586 # check for __call__ method | |
587 # types.InstanceType is the type of the instances of oldstyle classes | |
588 print("Instance of class: ", object.__class__.__name__, file=output) | |
589 print(file=output) | |
590 if hasattr(object, '__call__'): | |
591 arguments = inspect.formatargspec( | |
592 *inspect.getargspec(object.__call__.__func__) | |
593 ) | |
594 arglist = arguments.split(', ') | |
595 if len(arglist) > 1: | |
596 arglist[1] = "("+arglist[1] | |
597 arguments = ", ".join(arglist[1:]) | |
598 else: | |
599 arguments = "()" | |
600 | |
601 if hasattr(object, 'name'): | |
602 name = "%s" % object.name | |
603 else: | |
604 name = "<name>" | |
605 if len(name+arguments) > maxwidth: | |
606 argstr = _split_line(name, arguments, maxwidth) | |
607 else: | |
608 argstr = name + arguments | |
609 | |
610 print(" " + argstr + "\n", file=output) | |
611 doc = inspect.getdoc(object.__call__) | |
612 if doc is not None: | |
613 print(inspect.getdoc(object.__call__), file=output) | |
614 print(inspect.getdoc(object), file=output) | |
615 | |
616 else: | |
617 print(inspect.getdoc(object), file=output) | |
618 | |
619 elif inspect.ismethod(object): | |
620 name = object.__name__ | |
621 arguments = inspect.formatargspec( | |
622 *inspect.getargspec(object.__func__) | |
623 ) | |
624 arglist = arguments.split(', ') | |
625 if len(arglist) > 1: | |
626 arglist[1] = "("+arglist[1] | |
627 arguments = ", ".join(arglist[1:]) | |
628 else: | |
629 arguments = "()" | |
630 | |
631 if len(name+arguments) > maxwidth: | |
632 argstr = _split_line(name, arguments, maxwidth) | |
633 else: | |
634 argstr = name + arguments | |
635 | |
636 print(" " + argstr + "\n", file=output) | |
637 print(inspect.getdoc(object), file=output) | |
638 | |
639 elif hasattr(object, '__doc__'): | |
640 print(inspect.getdoc(object), file=output) | |
641 | |
642 | |
643 def source(object, output=sys.stdout): | |
644 """ | |
645 Print or write to a file the source code for a Numpy object. | |
646 | |
647 The source code is only returned for objects written in Python. Many | |
648 functions and classes are defined in C and will therefore not return | |
649 useful information. | |
650 | |
651 Parameters | |
652 ---------- | |
653 object : numpy object | |
654 Input object. This can be any object (function, class, module, | |
655 ...). | |
656 output : file object, optional | |
657 If `output` not supplied then source code is printed to screen | |
658 (sys.stdout). File object must be created with either write 'w' or | |
659 append 'a' modes. | |
660 | |
661 See Also | |
662 -------- | |
663 lookfor, info | |
664 | |
665 Examples | |
666 -------- | |
667 >>> np.source(np.interp) #doctest: +SKIP | |
668 In file: /usr/lib/python2.6/dist-packages/numpy/lib/function_base.py | |
669 def interp(x, xp, fp, left=None, right=None): | |
670 \"\"\".... (full docstring printed)\"\"\" | |
671 if isinstance(x, (float, int, number)): | |
672 return compiled_interp([x], xp, fp, left, right).item() | |
673 else: | |
674 return compiled_interp(x, xp, fp, left, right) | |
675 | |
676 The source code is only returned for objects written in Python. | |
677 | |
678 >>> np.source(np.array) #doctest: +SKIP | |
679 Not available for this object. | |
680 | |
681 """ | |
682 # Local import to speed up numpy's import time. | |
683 import inspect | |
684 try: | |
685 print("In file: %s\n" % inspect.getsourcefile(object), file=output) | |
686 print(inspect.getsource(object), file=output) | |
687 except: | |
688 print("Not available for this object.", file=output) | |
689 | |
690 | |
691 # Cache for lookfor: {id(module): {name: (docstring, kind, index), ...}...} | |
692 # where kind: "func", "class", "module", "object" | |
693 # and index: index in breadth-first namespace traversal | |
694 _lookfor_caches = {} | |
695 | |
696 # regexp whose match indicates that the string may contain a function | |
697 # signature | |
698 _function_signature_re = re.compile(r"[a-z0-9_]+\(.*[,=].*\)", re.I) | |
699 | |
700 def lookfor(what, module=None, import_modules=True, regenerate=False, | |
701 output=None): | |
702 """ | |
703 Do a keyword search on docstrings. | |
704 | |
705 A list of of objects that matched the search is displayed, | |
706 sorted by relevance. All given keywords need to be found in the | |
707 docstring for it to be returned as a result, but the order does | |
708 not matter. | |
709 | |
710 Parameters | |
711 ---------- | |
712 what : str | |
713 String containing words to look for. | |
714 module : str or list, optional | |
715 Name of module(s) whose docstrings to go through. | |
716 import_modules : bool, optional | |
717 Whether to import sub-modules in packages. Default is True. | |
718 regenerate : bool, optional | |
719 Whether to re-generate the docstring cache. Default is False. | |
720 output : file-like, optional | |
721 File-like object to write the output to. If omitted, use a pager. | |
722 | |
723 See Also | |
724 -------- | |
725 source, info | |
726 | |
727 Notes | |
728 ----- | |
729 Relevance is determined only roughly, by checking if the keywords occur | |
730 in the function name, at the start of a docstring, etc. | |
731 | |
732 Examples | |
733 -------- | |
734 >>> np.lookfor('binary representation') | |
735 Search results for 'binary representation' | |
736 ------------------------------------------ | |
737 numpy.binary_repr | |
738 Return the binary representation of the input number as a string. | |
739 numpy.core.setup_common.long_double_representation | |
740 Given a binary dump as given by GNU od -b, look for long double | |
741 numpy.base_repr | |
742 Return a string representation of a number in the given base system. | |
743 ... | |
744 | |
745 """ | |
746 import pydoc | |
747 | |
748 # Cache | |
749 cache = _lookfor_generate_cache(module, import_modules, regenerate) | |
750 | |
751 # Search | |
752 # XXX: maybe using a real stemming search engine would be better? | |
753 found = [] | |
754 whats = str(what).lower().split() | |
755 if not whats: | |
756 return | |
757 | |
758 for name, (docstring, kind, index) in cache.items(): | |
759 if kind in ('module', 'object'): | |
760 # don't show modules or objects | |
761 continue | |
762 ok = True | |
763 doc = docstring.lower() | |
764 for w in whats: | |
765 if w not in doc: | |
766 ok = False | |
767 break | |
768 if ok: | |
769 found.append(name) | |
770 | |
771 # Relevance sort | |
772 # XXX: this is full Harrison-Stetson heuristics now, | |
773 # XXX: it probably could be improved | |
774 | |
775 kind_relevance = {'func': 1000, 'class': 1000, | |
776 'module': -1000, 'object': -1000} | |
777 | |
778 def relevance(name, docstr, kind, index): | |
779 r = 0 | |
780 # do the keywords occur within the start of the docstring? | |
781 first_doc = "\n".join(docstr.lower().strip().split("\n")[:3]) | |
782 r += sum([200 for w in whats if w in first_doc]) | |
783 # do the keywords occur in the function name? | |
784 r += sum([30 for w in whats if w in name]) | |
785 # is the full name long? | |
786 r += -len(name) * 5 | |
787 # is the object of bad type? | |
788 r += kind_relevance.get(kind, -1000) | |
789 # is the object deep in namespace hierarchy? | |
790 r += -name.count('.') * 10 | |
791 r += max(-index / 100, -100) | |
792 return r | |
793 | |
794 def relevance_value(a): | |
795 return relevance(a, *cache[a]) | |
796 found.sort(key=relevance_value) | |
797 | |
798 # Pretty-print | |
799 s = "Search results for '%s'" % (' '.join(whats)) | |
800 help_text = [s, "-"*len(s)] | |
801 for name in found[::-1]: | |
802 doc, kind, ix = cache[name] | |
803 | |
804 doclines = [line.strip() for line in doc.strip().split("\n") | |
805 if line.strip()] | |
806 | |
807 # find a suitable short description | |
808 try: | |
809 first_doc = doclines[0].strip() | |
810 if _function_signature_re.search(first_doc): | |
811 first_doc = doclines[1].strip() | |
812 except IndexError: | |
813 first_doc = "" | |
814 help_text.append("%s\n %s" % (name, first_doc)) | |
815 | |
816 if not found: | |
817 help_text.append("Nothing found.") | |
818 | |
819 # Output | |
820 if output is not None: | |
821 output.write("\n".join(help_text)) | |
822 elif len(help_text) > 10: | |
823 pager = pydoc.getpager() | |
824 pager("\n".join(help_text)) | |
825 else: | |
826 print("\n".join(help_text)) | |
827 | |
828 def _lookfor_generate_cache(module, import_modules, regenerate): | |
829 """ | |
830 Generate docstring cache for given module. | |
831 | |
832 Parameters | |
833 ---------- | |
834 module : str, None, module | |
835 Module for which to generate docstring cache | |
836 import_modules : bool | |
837 Whether to import sub-modules in packages. | |
838 regenerate : bool | |
839 Re-generate the docstring cache | |
840 | |
841 Returns | |
842 ------- | |
843 cache : dict {obj_full_name: (docstring, kind, index), ...} | |
844 Docstring cache for the module, either cached one (regenerate=False) | |
845 or newly generated. | |
846 | |
847 """ | |
848 global _lookfor_caches | |
849 # Local import to speed up numpy's import time. | |
850 import inspect | |
851 | |
852 if sys.version_info[0] >= 3: | |
853 # In Python3 stderr, stdout are text files. | |
854 from io import StringIO | |
855 else: | |
856 from StringIO import StringIO | |
857 | |
858 if module is None: | |
859 module = "numpy" | |
860 | |
861 if isinstance(module, str): | |
862 try: | |
863 __import__(module) | |
864 except ImportError: | |
865 return {} | |
866 module = sys.modules[module] | |
867 elif isinstance(module, list) or isinstance(module, tuple): | |
868 cache = {} | |
869 for mod in module: | |
870 cache.update(_lookfor_generate_cache(mod, import_modules, | |
871 regenerate)) | |
872 return cache | |
873 | |
874 if id(module) in _lookfor_caches and not regenerate: | |
875 return _lookfor_caches[id(module)] | |
876 | |
877 # walk items and collect docstrings | |
878 cache = {} | |
879 _lookfor_caches[id(module)] = cache | |
880 seen = {} | |
881 index = 0 | |
882 stack = [(module.__name__, module)] | |
883 while stack: | |
884 name, item = stack.pop(0) | |
885 if id(item) in seen: | |
886 continue | |
887 seen[id(item)] = True | |
888 | |
889 index += 1 | |
890 kind = "object" | |
891 | |
892 if inspect.ismodule(item): | |
893 kind = "module" | |
894 try: | |
895 _all = item.__all__ | |
896 except AttributeError: | |
897 _all = None | |
898 | |
899 # import sub-packages | |
900 if import_modules and hasattr(item, '__path__'): | |
901 for pth in item.__path__: | |
902 for mod_path in os.listdir(pth): | |
903 this_py = os.path.join(pth, mod_path) | |
904 init_py = os.path.join(pth, mod_path, '__init__.py') | |
905 if (os.path.isfile(this_py) and | |
906 mod_path.endswith('.py')): | |
907 to_import = mod_path[:-3] | |
908 elif os.path.isfile(init_py): | |
909 to_import = mod_path | |
910 else: | |
911 continue | |
912 if to_import == '__init__': | |
913 continue | |
914 | |
915 try: | |
916 # Catch SystemExit, too | |
917 base_exc = BaseException | |
918 except NameError: | |
919 # Python 2.4 doesn't have BaseException | |
920 base_exc = Exception | |
921 | |
922 try: | |
923 old_stdout = sys.stdout | |
924 old_stderr = sys.stderr | |
925 try: | |
926 sys.stdout = StringIO() | |
927 sys.stderr = StringIO() | |
928 __import__("%s.%s" % (name, to_import)) | |
929 finally: | |
930 sys.stdout = old_stdout | |
931 sys.stderr = old_stderr | |
932 except base_exc: | |
933 continue | |
934 | |
935 for n, v in _getmembers(item): | |
936 try: | |
937 item_name = getattr(v, '__name__', "%s.%s" % (name, n)) | |
938 mod_name = getattr(v, '__module__', None) | |
939 except NameError: | |
940 # ref. SWIG's global cvars | |
941 # NameError: Unknown C global variable | |
942 item_name = "%s.%s" % (name, n) | |
943 mod_name = None | |
944 if '.' not in item_name and mod_name: | |
945 item_name = "%s.%s" % (mod_name, item_name) | |
946 | |
947 if not item_name.startswith(name + '.'): | |
948 # don't crawl "foreign" objects | |
949 if isinstance(v, ufunc): | |
950 # ... unless they are ufuncs | |
951 pass | |
952 else: | |
953 continue | |
954 elif not (inspect.ismodule(v) or _all is None or n in _all): | |
955 continue | |
956 stack.append(("%s.%s" % (name, n), v)) | |
957 elif inspect.isclass(item): | |
958 kind = "class" | |
959 for n, v in _getmembers(item): | |
960 stack.append(("%s.%s" % (name, n), v)) | |
961 elif hasattr(item, "__call__"): | |
962 kind = "func" | |
963 | |
964 try: | |
965 doc = inspect.getdoc(item) | |
966 except NameError: | |
967 # ref SWIG's NameError: Unknown C global variable | |
968 doc = None | |
969 if doc is not None: | |
970 cache[name] = (doc, kind, index) | |
971 | |
972 return cache | |
973 | |
974 def _getmembers(item): | |
975 import inspect | |
976 try: | |
977 members = inspect.getmembers(item) | |
978 except AttributeError: | |
979 members = [(x, getattr(item, x)) for x in dir(item) | |
980 if hasattr(item, x)] | |
981 return members | |
982 | |
983 #----------------------------------------------------------------------------- | |
984 | |
985 # The following SafeEval class and company are adapted from Michael Spencer's | |
986 # ASPN Python Cookbook recipe: | |
987 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/364469 | |
988 # Accordingly it is mostly Copyright 2006 by Michael Spencer. | |
989 # The recipe, like most of the other ASPN Python Cookbook recipes was made | |
990 # available under the Python license. | |
991 # http://www.python.org/license | |
992 | |
993 # It has been modified to: | |
994 # * handle unary -/+ | |
995 # * support True/False/None | |
996 # * raise SyntaxError instead of a custom exception. | |
997 | |
998 class SafeEval(object): | |
999 """ | |
1000 Object to evaluate constant string expressions. | |
1001 | |
1002 This includes strings with lists, dicts and tuples using the abstract | |
1003 syntax tree created by ``compiler.parse``. | |
1004 | |
1005 For an example of usage, see `safe_eval`. | |
1006 | |
1007 See Also | |
1008 -------- | |
1009 safe_eval | |
1010 | |
1011 """ | |
1012 | |
1013 if sys.version_info[0] < 3: | |
1014 def visit(self, node, **kw): | |
1015 cls = node.__class__ | |
1016 meth = getattr(self, 'visit'+cls.__name__, self.default) | |
1017 return meth(node, **kw) | |
1018 | |
1019 def default(self, node, **kw): | |
1020 raise SyntaxError("Unsupported source construct: %s" | |
1021 % node.__class__) | |
1022 | |
1023 def visitExpression(self, node, **kw): | |
1024 for child in node.getChildNodes(): | |
1025 return self.visit(child, **kw) | |
1026 | |
1027 def visitConst(self, node, **kw): | |
1028 return node.value | |
1029 | |
1030 def visitDict(self, node,**kw): | |
1031 return dict( | |
1032 [(self.visit(k), self.visit(v)) for k, v in node.items] | |
1033 ) | |
1034 | |
1035 def visitTuple(self, node, **kw): | |
1036 return tuple([self.visit(i) for i in node.nodes]) | |
1037 | |
1038 def visitList(self, node, **kw): | |
1039 return [self.visit(i) for i in node.nodes] | |
1040 | |
1041 def visitUnaryAdd(self, node, **kw): | |
1042 return +self.visit(node.getChildNodes()[0]) | |
1043 | |
1044 def visitUnarySub(self, node, **kw): | |
1045 return -self.visit(node.getChildNodes()[0]) | |
1046 | |
1047 def visitName(self, node, **kw): | |
1048 if node.name == 'False': | |
1049 return False | |
1050 elif node.name == 'True': | |
1051 return True | |
1052 elif node.name == 'None': | |
1053 return None | |
1054 else: | |
1055 raise SyntaxError("Unknown name: %s" % node.name) | |
1056 else: | |
1057 | |
1058 def visit(self, node): | |
1059 cls = node.__class__ | |
1060 meth = getattr(self, 'visit' + cls.__name__, self.default) | |
1061 return meth(node) | |
1062 | |
1063 def default(self, node): | |
1064 raise SyntaxError("Unsupported source construct: %s" | |
1065 % node.__class__) | |
1066 | |
1067 def visitExpression(self, node): | |
1068 return self.visit(node.body) | |
1069 | |
1070 def visitNum(self, node): | |
1071 return node.n | |
1072 | |
1073 def visitStr(self, node): | |
1074 return node.s | |
1075 | |
1076 def visitBytes(self, node): | |
1077 return node.s | |
1078 | |
1079 def visitDict(self, node,**kw): | |
1080 return dict([(self.visit(k), self.visit(v)) | |
1081 for k, v in zip(node.keys, node.values)]) | |
1082 | |
1083 def visitTuple(self, node): | |
1084 return tuple([self.visit(i) for i in node.elts]) | |
1085 | |
1086 def visitList(self, node): | |
1087 return [self.visit(i) for i in node.elts] | |
1088 | |
1089 def visitUnaryOp(self, node): | |
1090 import ast | |
1091 if isinstance(node.op, ast.UAdd): | |
1092 return +self.visit(node.operand) | |
1093 elif isinstance(node.op, ast.USub): | |
1094 return -self.visit(node.operand) | |
1095 else: | |
1096 raise SyntaxError("Unknown unary op: %r" % node.op) | |
1097 | |
1098 def visitName(self, node): | |
1099 if node.id == 'False': | |
1100 return False | |
1101 elif node.id == 'True': | |
1102 return True | |
1103 elif node.id == 'None': | |
1104 return None | |
1105 else: | |
1106 raise SyntaxError("Unknown name: %s" % node.id) | |
1107 | |
1108 def visitNameConstant(self, node): | |
1109 return node.value | |
1110 | |
1111 def safe_eval(source): | |
1112 """ | |
1113 Protected string evaluation. | |
1114 | |
1115 Evaluate a string containing a Python literal expression without | |
1116 allowing the execution of arbitrary non-literal code. | |
1117 | |
1118 Parameters | |
1119 ---------- | |
1120 source : str | |
1121 The string to evaluate. | |
1122 | |
1123 Returns | |
1124 ------- | |
1125 obj : object | |
1126 The result of evaluating `source`. | |
1127 | |
1128 Raises | |
1129 ------ | |
1130 SyntaxError | |
1131 If the code has invalid Python syntax, or if it contains | |
1132 non-literal code. | |
1133 | |
1134 Examples | |
1135 -------- | |
1136 >>> np.safe_eval('1') | |
1137 1 | |
1138 >>> np.safe_eval('[1, 2, 3]') | |
1139 [1, 2, 3] | |
1140 >>> np.safe_eval('{"foo": ("bar", 10.0)}') | |
1141 {'foo': ('bar', 10.0)} | |
1142 | |
1143 >>> np.safe_eval('import os') | |
1144 Traceback (most recent call last): | |
1145 ... | |
1146 SyntaxError: invalid syntax | |
1147 | |
1148 >>> np.safe_eval('open("/home/user/.ssh/id_dsa").read()') | |
1149 Traceback (most recent call last): | |
1150 ... | |
1151 SyntaxError: Unsupported source construct: compiler.ast.CallFunc | |
1152 | |
1153 """ | |
1154 # Local imports to speed up numpy's import time. | |
1155 import warnings | |
1156 | |
1157 with warnings.catch_warnings(): | |
1158 # compiler package is deprecated for 3.x, which is already solved | |
1159 # here | |
1160 warnings.simplefilter('ignore', DeprecationWarning) | |
1161 try: | |
1162 import compiler | |
1163 except ImportError: | |
1164 import ast as compiler | |
1165 | |
1166 walker = SafeEval() | |
1167 try: | |
1168 ast = compiler.parse(source, mode="eval") | |
1169 except SyntaxError: | |
1170 raise | |
1171 try: | |
1172 return walker.visit(ast) | |
1173 except SyntaxError: | |
1174 raise | |
1175 | |
1176 #----------------------------------------------------------------------------- |