diff options
Diffstat (limited to 'numpy')
-rw-r--r-- | numpy/core/arrayprint.py | 48 | ||||
-rw-r--r-- | numpy/core/tests/test_arrayprint.py | 18 |
2 files changed, 64 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: diff --git a/numpy/core/tests/test_arrayprint.py b/numpy/core/tests/test_arrayprint.py index 62effc425..b228527da 100644 --- a/numpy/core/tests/test_arrayprint.py +++ b/numpy/core/tests/test_arrayprint.py @@ -34,6 +34,24 @@ class TestArrayRepr(object): " dtype=[('a', '<i4')])" ) + def test_self_containing(self): + arr0d = np.array(None) + arr0d[()] = arr0d + assert_equal(repr(arr0d), + 'array(array(..., dtype=object), dtype=object)') + + arr1d = np.array([None, None]) + arr1d[1] = arr1d + assert_equal(repr(arr1d), + 'array([None, array(..., dtype=object)], dtype=object)') + + first = np.array(None) + second = np.array(None) + first[()] = second + second[()] = first + assert_equal(repr(first), + 'array(array(array(..., dtype=object), dtype=object), dtype=object)') + class TestComplexArray(TestCase): def test_str(self): |