diff options
| author | Allan Haldane <ealloc@gmail.com> | 2018-02-15 16:27:51 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-02-15 16:27:51 +0100 |
| commit | 69fa37f422c845655492220440735e7c800306b8 (patch) | |
| tree | 48b423d4b58e6e0dffe8af8c8a6d50bdaf2019f3 /numpy | |
| parent | 921b42a194190345eafba0286b8f528e57526e81 (diff) | |
| parent | fed44d7c309d0c2fd7c193efa39ba59652a43c44 (diff) | |
| download | numpy-69fa37f422c845655492220440735e7c800306b8.tar.gz | |
Merge pull request #10381 from eric-wieser/fix-segfault
BUG/ENH: Improve output for structured non-void types
Diffstat (limited to 'numpy')
| -rw-r--r-- | numpy/core/arrayprint.py | 49 | ||||
| -rw-r--r-- | numpy/core/src/multiarray/descriptor.c | 4 | ||||
| -rw-r--r-- | numpy/core/tests/test_multiarray.py | 10 |
3 files changed, 48 insertions, 15 deletions
diff --git a/numpy/core/arrayprint.py b/numpy/core/arrayprint.py index 0fdd6fc7f..84943cafc 100644 --- a/numpy/core/arrayprint.py +++ b/numpy/core/arrayprint.py @@ -402,9 +402,6 @@ def _get_format_function(data, **options): find the right formatting function for the dtype_ """ dtype_ = data.dtype - if dtype_.fields is not None: - return StructureFormat.from_data(data, **options) - dtypeobj = dtype_.type formatdict = _get_formatdict(data, **options) if issubclass(dtypeobj, _nt.bool_): @@ -431,7 +428,10 @@ def _get_format_function(data, **options): elif issubclass(dtypeobj, _nt.object_): return formatdict['object']() elif issubclass(dtypeobj, _nt.void): - return formatdict['void']() + if dtype_.names is not None: + return StructuredVoidFormat.from_data(data, **options) + else: + return formatdict['void']() else: return formatdict['numpystr']() @@ -1233,14 +1233,21 @@ class SubArrayFormat(object): return "[" + ", ".join(self.__call__(a) for a in arr) + "]" -class StructureFormat(object): +class StructuredVoidFormat(object): + """ + Formatter for structured np.void objects. + + This does not work on structured alias types like np.dtype(('i4', 'i2,i2')), + as alias scalars lose their field information, and the implementation + relies upon np.void.__getitem__. + """ def __init__(self, format_functions): self.format_functions = format_functions @classmethod def from_data(cls, data, **options): """ - This is a second way to initialize StructureFormat, using the raw data + This is a second way to initialize StructuredVoidFormat, using the raw data as input. Added to avoid changing the signature of __init__. """ format_functions = [] @@ -1261,13 +1268,24 @@ class StructureFormat(object): else: return "({})".format(", ".join(str_fields)) + +# for backwards compatibility +class StructureFormat(StructuredVoidFormat): + def __init__(self, *args, **kwargs): + # NumPy 1.14, 2018-02-14 + warnings.warn( + "StructureFormat has been replaced by StructuredVoidFormat", + DeprecationWarning, stacklevel=2) + super(StructureFormat, self).__init__(*args, **kwargs) + + def _void_scalar_repr(x): """ Implements the repr for structured-void scalars. It is called from the scalartypes.c.src code, and is placed here because it uses the elementwise formatters defined above. """ - return StructureFormat.from_data(array(x), **_format_options)(x) + return StructuredVoidFormat.from_data(array(x), **_format_options)(x) _typelessdata = [int_, float_, complex_, bool_] @@ -1305,6 +1323,11 @@ def dtype_is_implied(dtype): dtype = np.dtype(dtype) if _format_options['legacy'] == '1.13' and dtype.type == bool_: return False + + # not just void types can be structured, and names are not part of the repr + if dtype.names is not None: + return False + return dtype.type in _typelessdata @@ -1317,12 +1340,12 @@ def dtype_short_repr(dtype): >>> from numpy import * >>> assert eval(dtype_short_repr(dt)) == dt """ - # handle these separately so they don't give garbage like str256 - if issubclass(dtype.type, flexible): - if dtype.names is not None: - return "%s" % str(dtype) - else: - return "'%s'" % str(dtype) + if dtype.names is not None: + # structured dtypes give a list or tuple repr + return str(dtype) + elif issubclass(dtype.type, flexible): + # handle these separately so they don't give garbage like str256 + return "'%s'" % str(dtype) typename = dtype.name # quote typenames which can't be represented as python variable names diff --git a/numpy/core/src/multiarray/descriptor.c b/numpy/core/src/multiarray/descriptor.c index 80161b71c..897155238 100644 --- a/numpy/core/src/multiarray/descriptor.c +++ b/numpy/core/src/multiarray/descriptor.c @@ -3340,8 +3340,8 @@ arraydescr_struct_str(PyArray_Descr *dtype, int includealignflag) sub = arraydescr_struct_dict_str(dtype, includealignflag); } - /* If the data type has a non-void (subclassed) type, show it */ - if (dtype->type_num == NPY_VOID && dtype->typeobj != &PyVoidArrType_Type) { + /* If the data type isn't the default, void, show it */ + if (dtype->typeobj != &PyVoidArrType_Type) { /* * Note: We cannot get the type name from dtype->typeobj->tp_name * because its value depends on whether the type is dynamically or diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index e1fcf947e..3b92a0610 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -478,6 +478,16 @@ class TestDtypedescr(object): assert_(np.dtype('<i4') != np.dtype('>i4')) assert_(np.dtype([('a', '<i4')]) != np.dtype([('a', '>i4')])) + def test_structured_non_void(self): + fields = [('a', '<i2'), ('b', '<i2')] + dt_int = np.dtype(('i4', fields)) + assert_equal(str(dt_int), "(numpy.int32, [('a', '<i2'), ('b', '<i2')])") + + # gh-9821 + arr_int = np.zeros(4, dt_int) + assert_equal(repr(arr_int), + "array([0, 0, 0, 0], dtype=(numpy.int32, [('a', '<i2'), ('b', '<i2')]))") + class TestZeroRank(object): def setup(self): |
