8000 Merge pull request #10612 from charris/backport-10381 · ahaldane/numpy@eaac472 · GitHub
[go: up one dir, main page]

Skip to content

Commit eaac472

Browse files
authored
Merge pull request numpy#10612 from charris/backport-10381
BUG/ENH: Improve output for structured non-void types
2 parents 94eb8ea + cf4151d commit eaac472

File tree

3 files changed

+48
-15
lines changed

3 files changed

+48
-15
lines changed

numpy/core/arrayprint.py

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -369,9 +369,6 @@ def _get_format_function(data, **options):
369369
find the right formatting function for the dtype_
370370
"""
371371
dtype_ = data.dtype
372-
if dtype_.fields is not None:
373-
return StructureFormat.from_data(data, **options)
374-
375372
dtypeobj = dtype_.type
376373
formatdict = _get_formatdict(data, **options)
377374
if issubclass(dtypeobj, _nt.bool_):
@@ -398,7 +395,10 @@ def _get_format_function(data, **options):
398395
elif issubclass(dtypeobj, _nt.object_):
399396
return formatdict['object']()
400397
elif issubclass(dtypeobj, _nt.void):
401-
return formatdict['void']()
398+
if dtype_.names is not None:
399+
return StructuredVoidFormat.from_data(data, **options)
400+
else:
401+
return formatdict['void']()
402402
else:
403403
return formatdict['numpystr']()
404404

@@ -1200,14 +1200,21 @@ def __call__(self, arr):
12001200
return "[" + ", ".join(self.__call__(a) for a in arr) + "]"
12011201

12021202

1203-
class StructureFormat(object):
1203+
class StructuredVoidFormat(object):
1204+
"""
1205+
Formatter for structured np.void objects.
1206+
1207+
This does not work on structured alias types like np.dtype(('i4', 'i2,i2')),
1208+
as alias scalars lose their field information, and the implementation
1209+
relies upon np.void.__getitem__.
1210+
"""
12041211
def __init__(self, format_functions):
12051212
self.format_functions = format_functions
12061213

12071214
@classmethod
12081215
def from_data(cls, data, **options):
12091216
"""
1210-
This is a second way to initialize StructureFormat, using the raw data
1217+
This is a second way to initialize StructuredVoidFormat, using the raw data
12111218
as input. Added to avoid changing the signature of __init__.
12121219
"""
12131220
format_functions = []
@@ -1228,13 +1235,24 @@ def __call__(self, x):
12281235
else:
12291236
return "({})".format(", ".join(str_fields))
12301237

1238+
1239+
# for backwards compatibility
1240+
class StructureFormat(StructuredVoidFormat):
1241+
def __init__(self, *args, **kwargs):
1242+
# NumPy 1.14, 2018-02-14
1243+
warnings.warn(
1244+
"StructureFormat has been replaced by StructuredVoidFormat",
1245+
DeprecationWarning, stacklevel=2)
1246+
super(StructureFormat, self).__init__(*args, **kwargs)
1247+
1248+
12311249
def _void_scalar_repr(x):
12321250
"""
12331251
Implements the repr for structured-void scalars. It is called from the
12341252
scalartypes.c.src code, and is placed here because it uses the elementwise
12351253
formatters defined above.
12361254
"""
1237-
return StructureFormat.from_data(array(x), **_format_options)(x)
1255+
return StructuredVoidFormat.from_data(array(x), **_format_options)(x)
12381256

12391257

12401258
_typelessdata = [int_, float_, complex_, bool_]
@@ -1272,6 +1290,11 @@ def dtype_is_implied(dtype):
12721290
dtype = np.dtype(dtype)
12731291
if _format_options['legacy'] == '1.13' and dtype.type == bool_:
12741292
return False
1293+
1294+
# not just void types can be structured, and names are not part of the repr
1295+
if dtype.names is not None:
1296+
return False
1297+
12751298
return dtype.type in _typelessdata
12761299

12771300

@@ -1284,12 +1307,12 @@ def dtype_short_repr(dtype):
12841307
>>> from numpy import *
12851308
>>> assert eval(dtype_short_repr(dt)) == dt
12861309
"""
1287-
# handle these separately so they don't give garbage like str256
1288-
if issubclass(dtype.type, flexible):
1289-
if dtype.names is not None:
1290-
return "%s" % str(dtype)
1291-
else:
1292-
return "'%s'" % str(dtype)
1310+
if dtype.names is not None:
1311+
# structured dtypes give a list or tuple repr
1312+
return str(dtype)
1313+
elif issubclass(dtype.type, flexible):
1314+
# handle these separately so they don't give garbage like str256
1315+
return "'%s'" % str(dtype)
12931316

12941317
typename = dtype.name
12951318
# quote typenames which can't be represented as python variable names

numpy/core/src/multiarray/descriptor.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3340,8 +3340,8 @@ arraydescr_struct_str(PyArray_Descr *dtype, int includealignflag)
33403340
sub = arraydescr_struct_dict_str(dtype, includealignflag);
33413341
}
33423342

3343-
/* If the data type has a non-void (subclassed) type, show it */
3344-
if (dtype->type_num == NPY_VOID && dtype->typeobj != &PyVoidArrType_Type) {
3343+
/* If the data type isn't the default, void, show it */
3344+
if (dtype->typeobj != &PyVoidArrType_Type) {
33453345
/*
33463346
* Note: We cannot get the type name from dtype->typeobj->tp_name
33473347
* because its value depends on whether the type is dynamically or

numpy/core/tests/test_multiarray.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,16 @@ def test_byteorders(self):
478478
assert_(np.dtype('<i4') != np.dtype('>i4'))
479479
assert_(np.dtype([('a', '<i4')]) != np.dtype([('a', '>i4')]))
480480

481+
def test_structured_non_void(self):
482+
fields = [('a', '<i2'), ('b', '<i2')]
483+
dt_int = np.dtype(('i4', fields))
484+
assert_equal(str(dt_int), "(numpy.int32, [('a', '<i2'), ('b', '<i2')])")
485+
486+
# gh-9821
487+
arr_int = np.zeros(4, dt_int)
488+
assert_equal(repr(arr_int),
489+
"array([0, 0, 0, 0], dtype=(numpy.int32, [('a', '<i2'), ('b', '<i2')]))")
490+
481491

482492
class TestZeroRank(object):
483493
def setup(self):

0 commit comments

Comments
 (0)
0