Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/numpy/lib/_utils_impl.py: 12%
284 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-09 06:12 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-09 06:12 +0000
1import os
2import sys
3import textwrap
4import types
5import re
6import warnings
7import functools
8import platform
10from numpy._core import ndarray
11from numpy._utils import set_module
12import numpy as np
14__all__ = [
15 'get_include', 'info', 'show_runtime'
16]
19@set_module('numpy')
20def show_runtime():
21 """
22 Print information about various resources in the system
23 including available intrinsic support and BLAS/LAPACK library
24 in use
26 .. versionadded:: 1.24.0
28 See Also
29 --------
30 show_config : Show libraries in the system on which NumPy was built.
32 Notes
33 -----
34 1. Information is derived with the help of `threadpoolctl <https://pypi.org/project/threadpoolctl/>`_
35 library if available.
36 2. SIMD related information is derived from ``__cpu_features__``,
37 ``__cpu_baseline__`` and ``__cpu_dispatch__``
39 """
40 from numpy._core._multiarray_umath import (
41 __cpu_features__, __cpu_baseline__, __cpu_dispatch__
42 )
43 from pprint import pprint
44 config_found = [{
45 "numpy_version": np.__version__,
46 "python": sys.version,
47 "uname": platform.uname(),
48 }]
49 features_found, features_not_found = [], []
50 for feature in __cpu_dispatch__:
51 if __cpu_features__[feature]:
52 features_found.append(feature)
53 else:
54 features_not_found.append(feature)
55 config_found.append({
56 "simd_extensions": {
57 "baseline": __cpu_baseline__,
58 "found": features_found,
59 "not_found": features_not_found
60 }
61 })
62 try:
63 from threadpoolctl import threadpool_info
64 config_found.extend(threadpool_info())
65 except ImportError:
66 print("WARNING: `threadpoolctl` not found in system!"
67 " Install it by `pip install threadpoolctl`."
68 " Once installed, try `np.show_runtime` again"
69 " for more detailed build information")
70 pprint(config_found)
73@set_module('numpy')
74def get_include():
75 """
76 Return the directory that contains the NumPy \\*.h header files.
78 Extension modules that need to compile against NumPy may need to use this
79 function to locate the appropriate include directory.
81 Notes
82 -----
83 When using ``setuptools``, for example in ``setup.py``::
85 import numpy as np
86 ...
87 Extension('extension_name', ...
88 include_dirs=[np.get_include()])
89 ...
91 Note that a CLI tool ``numpy-config`` was introduced in NumPy 2.0, using
92 that is likely preferred for build systems other than ``setuptools``::
94 $ numpy-config --cflags
95 -I/path/to/site-packages/numpy/_core/include
97 # Or rely on pkg-config:
98 $ export PKG_CONFIG_PATH=$(numpy-config --pkgconfigdir)
99 $ pkg-config --cflags
100 -I/path/to/site-packages/numpy/_core/include
102 """
103 import numpy
104 if numpy.show_config is None:
105 # running from numpy source directory
106 d = os.path.join(os.path.dirname(numpy.__file__), '_core', 'include')
107 else:
108 # using installed numpy core headers
109 import numpy._core as _core
110 d = os.path.join(os.path.dirname(_core.__file__), 'include')
111 return d
114class _Deprecate:
115 """
116 Decorator class to deprecate old functions.
118 Refer to `deprecate` for details.
120 See Also
121 --------
122 deprecate
124 """
126 def __init__(self, old_name=None, new_name=None, message=None):
127 self.old_name = old_name
128 self.new_name = new_name
129 self.message = message
131 def __call__(self, func, *args, **kwargs):
132 """
133 Decorator call. Refer to ``decorate``.
135 """
136 old_name = self.old_name
137 new_name = self.new_name
138 message = self.message
140 if old_name is None:
141 old_name = func.__name__
142 if new_name is None:
143 depdoc = "`%s` is deprecated!" % old_name
144 else:
145 depdoc = "`%s` is deprecated, use `%s` instead!" % \
146 (old_name, new_name)
148 if message is not None:
149 depdoc += "\n" + message
151 @functools.wraps(func)
152 def newfunc(*args, **kwds):
153 warnings.warn(depdoc, DeprecationWarning, stacklevel=2)
154 return func(*args, **kwds)
156 newfunc.__name__ = old_name
157 doc = func.__doc__
158 if doc is None:
159 doc = depdoc
160 else:
161 lines = doc.expandtabs().split('\n')
162 indent = _get_indent(lines[1:])
163 if lines[0].lstrip():
164 # Indent the original first line to let inspect.cleandoc()
165 # dedent the docstring despite the deprecation notice.
166 doc = indent * ' ' + doc
167 else:
168 # Remove the same leading blank lines as cleandoc() would.
169 skip = len(lines[0]) + 1
170 for line in lines[1:]:
171 if len(line) > indent:
172 break
173 skip += len(line) + 1
174 doc = doc[skip:]
175 depdoc = textwrap.indent(depdoc, ' ' * indent)
176 doc = '\n\n'.join([depdoc, doc])
177 newfunc.__doc__ = doc
179 return newfunc
182def _get_indent(lines):
183 """
184 Determines the leading whitespace that could be removed from all the lines.
185 """
186 indent = sys.maxsize
187 for line in lines:
188 content = len(line.lstrip())
189 if content:
190 indent = min(indent, len(line) - content)
191 if indent == sys.maxsize:
192 indent = 0
193 return indent
196def deprecate(*args, **kwargs):
197 """
198 Issues a DeprecationWarning, adds warning to `old_name`'s
199 docstring, rebinds ``old_name.__name__`` and returns the new
200 function object.
202 This function may also be used as a decorator.
204 .. deprecated:: 2.0
205 Use `~warnings.warn` with :exc:`DeprecationWarning` instead.
207 Parameters
208 ----------
209 func : function
210 The function to be deprecated.
211 old_name : str, optional
212 The name of the function to be deprecated. Default is None, in
213 which case the name of `func` is used.
214 new_name : str, optional
215 The new name for the function. Default is None, in which case the
216 deprecation message is that `old_name` is deprecated. If given, the
217 deprecation message is that `old_name` is deprecated and `new_name`
218 should be used instead.
219 message : str, optional
220 Additional explanation of the deprecation. Displayed in the
221 docstring after the warning.
223 Returns
224 -------
225 old_func : function
226 The deprecated function.
228 Examples
229 --------
230 Note that ``olduint`` returns a value after printing Deprecation
231 Warning:
233 >>> olduint = np.lib.utils.deprecate(np.uint)
234 DeprecationWarning: `uint64` is deprecated! # may vary
235 >>> olduint(6)
236 6
238 """
239 # Deprecate may be run as a function or as a decorator
240 # If run as a function, we initialise the decorator class
241 # and execute its __call__ method.
243 # Deprecated in NumPy 2.0, 2023-07-11
244 warnings.warn(
245 "`deprecate` is deprecated, "
246 "use `warn` with `DeprecationWarning` instead. "
247 "(deprecated in NumPy 2.0)",
248 DeprecationWarning,
249 stacklevel=2
250 )
252 if args:
253 fn = args[0]
254 args = args[1:]
256 return _Deprecate(*args, **kwargs)(fn)
257 else:
258 return _Deprecate(*args, **kwargs)
261def deprecate_with_doc(msg):
262 """
263 Deprecates a function and includes the deprecation in its docstring.
265 .. deprecated:: 2.0
266 Use `~warnings.warn` with :exc:`DeprecationWarning` instead.
268 This function is used as a decorator. It returns an object that can be
269 used to issue a DeprecationWarning, by passing the to-be decorated
270 function as argument, this adds warning to the to-be decorated function's
271 docstring and returns the new function object.
273 See Also
274 --------
275 deprecate : Decorate a function such that it issues a
276 :exc:`DeprecationWarning`
278 Parameters
279 ----------
280 msg : str
281 Additional explanation of the deprecation. Displayed in the
282 docstring after the warning.
284 Returns
285 -------
286 obj : object
288 """
290 # Deprecated in NumPy 2.0, 2023-07-11
291 warnings.warn(
292 "`deprecate` is deprecated, "
293 "use `warn` with `DeprecationWarning` instead. "
294 "(deprecated in NumPy 2.0)",
295 DeprecationWarning,
296 stacklevel=2
297 )
299 return _Deprecate(message=msg)
302#-----------------------------------------------------------------------------
305# NOTE: pydoc defines a help function which works similarly to this
306# except it uses a pager to take over the screen.
308# combine name and arguments and split to multiple lines of width
309# characters. End lines on a comma and begin argument list indented with
310# the rest of the arguments.
311def _split_line(name, arguments, width):
312 firstwidth = len(name)
313 k = firstwidth
314 newstr = name
315 sepstr = ", "
316 arglist = arguments.split(sepstr)
317 for argument in arglist:
318 if k == firstwidth:
319 addstr = ""
320 else:
321 addstr = sepstr
322 k = k + len(argument) + len(addstr)
323 if k > width:
324 k = firstwidth + 1 + len(argument)
325 newstr = newstr + ",\n" + " "*(firstwidth+2) + argument
326 else:
327 newstr = newstr + addstr + argument
328 return newstr
330_namedict = None
331_dictlist = None
333# Traverse all module directories underneath globals
334# to see if something is defined
335def _makenamedict(module='numpy'):
336 module = __import__(module, globals(), locals(), [])
337 thedict = {module.__name__:module.__dict__}
338 dictlist = [module.__name__]
339 totraverse = [module.__dict__]
340 while True:
341 if len(totraverse) == 0:
342 break
343 thisdict = totraverse.pop(0)
344 for x in thisdict.keys():
345 if isinstance(thisdict[x], types.ModuleType):
346 modname = thisdict[x].__name__
347 if modname not in dictlist:
348 moddict = thisdict[x].__dict__
349 dictlist.append(modname)
350 totraverse.append(moddict)
351 thedict[modname] = moddict
352 return thedict, dictlist
355def _info(obj, output=None):
356 """Provide information about ndarray obj.
358 Parameters
359 ----------
360 obj : ndarray
361 Must be ndarray, not checked.
362 output
363 Where printed output goes.
365 Notes
366 -----
367 Copied over from the numarray module prior to its removal.
368 Adapted somewhat as only numpy is an option now.
370 Called by info.
372 """
373 extra = ""
374 tic = ""
375 bp = lambda x: x
376 cls = getattr(obj, '__class__', type(obj))
377 nm = getattr(cls, '__name__', cls)
378 strides = obj.strides
379 endian = obj.dtype.byteorder
381 if output is None:
382 output = sys.stdout
384 print("class: ", nm, file=output)
385 print("shape: ", obj.shape, file=output)
386 print("strides: ", strides, file=output)
387 print("itemsize: ", obj.itemsize, file=output)
388 print("aligned: ", bp(obj.flags.aligned), file=output)
389 print("contiguous: ", bp(obj.flags.contiguous), file=output)
390 print("fortran: ", obj.flags.fortran, file=output)
391 print(
392 "data pointer: %s%s" % (hex(obj.ctypes._as_parameter_.value), extra),
393 file=output
394 )
395 print("byteorder: ", end=' ', file=output)
396 if endian in ['|', '=']:
397 print("%s%s%s" % (tic, sys.byteorder, tic), file=output)
398 byteswap = False
399 elif endian == '>':
400 print("%sbig%s" % (tic, tic), file=output)
401 byteswap = sys.byteorder != "big"
402 else:
403 print("%slittle%s" % (tic, tic), file=output)
404 byteswap = sys.byteorder != "little"
405 print("byteswap: ", bp(byteswap), file=output)
406 print("type: %s" % obj.dtype, file=output)
409@set_module('numpy')
410def info(object=None, maxwidth=76, output=None, toplevel='numpy'):
411 """
412 Get help information for an array, function, class, or module.
414 Parameters
415 ----------
416 object : object or str, optional
417 Input object or name to get information about. If `object` is
418 an `ndarray` instance, information about the array is printed.
419 If `object` is a numpy object, its docstring is given. If it is
420 a string, available modules are searched for matching objects.
421 If None, information about `info` itself is returned.
422 maxwidth : int, optional
423 Printing width.
424 output : file like object, optional
425 File like object that the output is written to, default is
426 ``None``, in which case ``sys.stdout`` will be used.
427 The object has to be opened in 'w' or 'a' mode.
428 toplevel : str, optional
429 Start search at this level.
431 Notes
432 -----
433 When used interactively with an object, ``np.info(obj)`` is equivalent
434 to ``help(obj)`` on the Python prompt or ``obj?`` on the IPython
435 prompt.
437 Examples
438 --------
439 >>> np.info(np.polyval) # doctest: +SKIP
440 polyval(p, x)
441 Evaluate the polynomial p at x.
442 ...
444 When using a string for `object` it is possible to get multiple results.
446 >>> np.info('fft') # doctest: +SKIP
447 *** Found in numpy ***
448 Core FFT routines
449 ...
450 *** Found in numpy.fft ***
451 fft(a, n=None, axis=-1)
452 ...
453 *** Repeat reference found in numpy.fft.fftpack ***
454 *** Total of 3 references found. ***
456 When the argument is an array, information about the array is printed.
458 >>> a = np.array([[1 + 2j, 3, -4], [-5j, 6, 0]], dtype=np.complex64)
459 >>> np.info(a)
460 class: ndarray
461 shape: (2, 3)
462 strides: (24, 8)
463 itemsize: 8
464 aligned: True
465 contiguous: True
466 fortran: False
467 data pointer: 0x562b6e0d2860 # may vary
468 byteorder: little
469 byteswap: False
470 type: complex64
472 """
473 global _namedict, _dictlist
474 # Local import to speed up numpy's import time.
475 import pydoc
476 import inspect
478 if (hasattr(object, '_ppimport_importer') or
479 hasattr(object, '_ppimport_module')):
480 object = object._ppimport_module
481 elif hasattr(object, '_ppimport_attr'):
482 object = object._ppimport_attr
484 if output is None:
485 output = sys.stdout
487 if object is None:
488 info(info)
489 elif isinstance(object, ndarray):
490 _info(object, output=output)
491 elif isinstance(object, str):
492 if _namedict is None:
493 _namedict, _dictlist = _makenamedict(toplevel)
494 numfound = 0
495 objlist = []
496 for namestr in _dictlist:
497 try:
498 obj = _namedict[namestr][object]
499 if id(obj) in objlist:
500 print("\n "
501 "*** Repeat reference found in %s *** " % namestr,
502 file=output
503 )
504 else:
505 objlist.append(id(obj))
506 print(" *** Found in %s ***" % namestr, file=output)
507 info(obj)
508 print("-"*maxwidth, file=output)
509 numfound += 1
510 except KeyError:
511 pass
512 if numfound == 0:
513 print("Help for %s not found." % object, file=output)
514 else:
515 print("\n "
516 "*** Total of %d references found. ***" % numfound,
517 file=output
518 )
520 elif inspect.isfunction(object) or inspect.ismethod(object):
521 name = object.__name__
522 try:
523 arguments = str(inspect.signature(object))
524 except Exception:
525 arguments = "()"
527 if len(name+arguments) > maxwidth:
528 argstr = _split_line(name, arguments, maxwidth)
529 else:
530 argstr = name + arguments
532 print(" " + argstr + "\n", file=output)
533 print(inspect.getdoc(object), file=output)
535 elif inspect.isclass(object):
536 name = object.__name__
537 try:
538 arguments = str(inspect.signature(object))
539 except Exception:
540 arguments = "()"
542 if len(name+arguments) > maxwidth:
543 argstr = _split_line(name, arguments, maxwidth)
544 else:
545 argstr = name + arguments
547 print(" " + argstr + "\n", file=output)
548 doc1 = inspect.getdoc(object)
549 if doc1 is None:
550 if hasattr(object, '__init__'):
551 print(inspect.getdoc(object.__init__), file=output)
552 else:
553 print(inspect.getdoc(object), file=output)
555 methods = pydoc.allmethods(object)
557 public_methods = [meth for meth in methods if meth[0] != '_']
558 if public_methods:
559 print("\n\nMethods:\n", file=output)
560 for meth in public_methods:
561 thisobj = getattr(object, meth, None)
562 if thisobj is not None:
563 methstr, other = pydoc.splitdoc(
564 inspect.getdoc(thisobj) or "None"
565 )
566 print(" %s -- %s" % (meth, methstr), file=output)
568 elif hasattr(object, '__doc__'):
569 print(inspect.getdoc(object), file=output)
572def safe_eval(source):
573 """
574 Protected string evaluation.
576 .. deprecated:: 2.0
577 Use `ast.literal_eval` instead.
579 Evaluate a string containing a Python literal expression without
580 allowing the execution of arbitrary non-literal code.
582 .. warning::
584 This function is identical to :py:meth:`ast.literal_eval` and
585 has the same security implications. It may not always be safe
586 to evaluate large input strings.
588 Parameters
589 ----------
590 source : str
591 The string to evaluate.
593 Returns
594 -------
595 obj : object
596 The result of evaluating `source`.
598 Raises
599 ------
600 SyntaxError
601 If the code has invalid Python syntax, or if it contains
602 non-literal code.
604 Examples
605 --------
606 >>> np.safe_eval('1')
607 1
608 >>> np.safe_eval('[1, 2, 3]')
609 [1, 2, 3]
610 >>> np.safe_eval('{"foo": ("bar", 10.0)}')
611 {'foo': ('bar', 10.0)}
613 >>> np.safe_eval('import os')
614 Traceback (most recent call last):
615 ...
616 SyntaxError: invalid syntax
618 >>> np.safe_eval('open("/home/user/.ssh/id_dsa").read()')
619 Traceback (most recent call last):
620 ...
621 ValueError: malformed node or string: <_ast.Call object at 0x...>
623 """
625 # Deprecated in NumPy 2.0, 2023-07-11
626 warnings.warn(
627 "`safe_eval` is deprecated. Use `ast.literal_eval` instead. "
628 "Be aware of security implications, such as memory exhaustion "
629 "based attacks (deprecated in NumPy 2.0)",
630 DeprecationWarning,
631 stacklevel=2
632 )
634 # Local import to speed up numpy's import time.
635 import ast
636 return ast.literal_eval(source)
639def _median_nancheck(data, result, axis):
640 """
641 Utility function to check median result from data for NaN values at the end
642 and return NaN in that case. Input result can also be a MaskedArray.
644 Parameters
645 ----------
646 data : array
647 Sorted input data to median function
648 result : Array or MaskedArray
649 Result of median function.
650 axis : int
651 Axis along which the median was computed.
653 Returns
654 -------
655 result : scalar or ndarray
656 Median or NaN in axes which contained NaN in the input. If the input
657 was an array, NaN will be inserted in-place. If a scalar, either the
658 input itself or a scalar NaN.
659 """
660 if data.size == 0:
661 return result
662 potential_nans = data.take(-1, axis=axis)
663 n = np.isnan(potential_nans)
664 # masked NaN values are ok, although for masked the copyto may fail for
665 # unmasked ones (this was always broken) when the result is a scalar.
666 if np.ma.isMaskedArray(n):
667 n = n.filled(False)
669 if not n.any():
670 return result
672 # Without given output, it is possible that the current result is a
673 # numpy scalar, which is not writeable. If so, just return nan.
674 if isinstance(result, np.generic):
675 return potential_nans
677 # Otherwise copy NaNs (if there are any)
678 np.copyto(result, potential_nans, where=n)
679 return result
681def _opt_info():
682 """
683 Returns a string containing the CPU features supported
684 by the current build.
686 The format of the string can be explained as follows:
687 - Dispatched features supported by the running machine end with `*`.
688 - Dispatched features not supported by the running machine
689 end with `?`.
690 - Remaining features represent the baseline.
692 Returns:
693 str: A formatted string indicating the supported CPU features.
694 """
695 from numpy._core._multiarray_umath import (
696 __cpu_features__, __cpu_baseline__, __cpu_dispatch__
697 )
699 if len(__cpu_baseline__) == 0 and len(__cpu_dispatch__) == 0:
700 return ''
702 enabled_features = ' '.join(__cpu_baseline__)
703 for feature in __cpu_dispatch__:
704 if __cpu_features__[feature]:
705 enabled_features += f" {feature}*"
706 else:
707 enabled_features += f" {feature}?"
709 return enabled_features
711def drop_metadata(dtype, /):
712 """
713 Returns the dtype unchanged if it contained no metadata or a copy of the
714 dtype if it (or any of its structure dtypes) contained metadata.
716 This utility is used by `np.save` and `np.savez` to drop metadata before
717 saving.
719 .. note::
721 Due to its limitation this function may move to a more appropriate
722 home or change in the future and is considered semi-public API only.
724 .. warning::
726 This function does not preserve more strange things like record dtypes
727 and user dtypes may simply return the wrong thing. If you need to be
728 sure about the latter, check the result with:
729 ``np.can_cast(new_dtype, dtype, casting="no")``.
731 """
732 if dtype.fields is not None:
733 found_metadata = dtype.metadata is not None
735 names = []
736 formats = []
737 offsets = []
738 titles = []
739 for name, field in dtype.fields.items():
740 field_dt = drop_metadata(field[0])
741 if field_dt is not field[0]:
742 found_metadata = True
744 names.append(name)
745 formats.append(field_dt)
746 offsets.append(field[1])
747 titles.append(None if len(field) < 3 else field[2])
749 if not found_metadata:
750 return dtype
752 structure = dict(
753 names=names, formats=formats, offsets=offsets, titles=titles,
754 itemsize=dtype.itemsize)
756 # NOTE: Could pass (dtype.type, structure) to preserve record dtypes...
757 return np.dtype(structure, align=dtype.isalignedstruct)
758 elif dtype.subdtype is not None:
759 # subarray dtype
760 subdtype, shape = dtype.subdtype
761 new_subdtype = drop_metadata(subdtype)
762 if dtype.metadata is None and new_subdtype is subdtype:
763 return dtype
765 return np.dtype((new_subdtype, shape))
766 else:
767 # Normal unstructured dtype
768 if dtype.metadata is None:
769 return dtype
770 # Note that `dt.str` doesn't round-trip e.g. for user-dtypes.
771 return np.dtype(dtype.str)