diff options
author | Eric Wieser <wieser.eric@gmail.com> | 2017-04-20 12:06:45 +0100 |
---|---|---|
committer | Eric Wieser <wieser.eric@gmail.com> | 2017-04-25 10:28:30 +0100 |
commit | 1e65a2af062012ab4fd4f9954b45a608a915e56d (patch) | |
tree | dd31b17bc5d72c6a879cefea9d96bf6ffa10a597 /numpy/core/arrayprint.py | |
parent | a2aea7757aacaa140f22910de6b81f9196a4aecc (diff) | |
download | numpy-1e65a2af062012ab4fd4f9954b45a608a915e56d.tar.gz |
BUG: Prevent infinite recursion when printing self-containing arrays
Fixes #8960
Diffstat (limited to 'numpy/core/arrayprint.py')
-rw-r--r-- | numpy/core/arrayprint.py | 48 |
1 files changed, 46 insertions, 2 deletions
diff --git a/numpy/core/arrayprint.py b/numpy/core/arrayprint.py index 4e62a42fc..dba9dffb3 100644 --- a/numpy/core/arrayprint.py +++ b/numpy/core/arrayprint.py @@ -16,7 +16,18 @@ __docformat__ = 'restructuredtext' # and by Travis Oliphant 2005-8-22 for numpy import sys -from functools import reduce +import functools +if sys.version_info[0] >= 3: + try: + from _thread import get_ident + except ImportError: + from _dummy_thread import get_ident +else: + try: + from thread import get_ident + except ImportError: + from dummy_thread import get_ident + from . import numerictypes as _nt from .umath import maximum, minimum, absolute, not_equal, isnan, isinf from .multiarray import (array, format_longfloat, datetime_as_string, @@ -342,6 +353,39 @@ def _array2string(a, max_line_width, precision, suppress_small, separator=' ', _summaryEdgeItems, summary_insert)[:-1] return lst + +def _recursive_guard(fillvalue='...'): + """ + Like the python 3.2 reprlib.recursive_repr, but forwards *args and **kwargs + + Decorates a function such that if it calls itself with the same first + argument, it returns `fillvalue` instead of recursing. + + Largely copied from reprlib.recursive_repr + """ + + def decorating_function(f): + repr_running = set() + + @functools.wraps(f) + def wrapper(self, *args, **kwargs): + key = id(self), get_ident() + if key in repr_running: + return fillvalue + repr_running.add(key) + try: + return f(self, *args, **kwargs) + finally: + repr_running.discard(key) + + return wrapper + + return decorating_function + + +# gracefully handle recursive calls - this comes up when object arrays contain +# themselves +@_recursive_guard() def array2string(a, max_line_width=None, precision=None, suppress_small=None, separator=' ', prefix="", style=repr, formatter=None): @@ -460,7 +504,7 @@ def array2string(a, max_line_width=None, precision=None, lst = format_function(arr[0]) else: lst = style(x) - elif reduce(product, a.shape) == 0: + elif functools.reduce(product, a.shape) == 0: # treat as a null array if any of shape elements == 0 lst = "[]" else: |