Thanks to visit codestin.com
Credit goes to github.com

Skip to content

DEP: deprecate empty field names #12375

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions doc/release/1.16.0-notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ As part of `NEP 15`, they have been deprecated along with the C-API functions
the inner loop functions in built-in ufuncs should use
:c:func:`PyUFunc_ReplaceLoopBySignature`.

Empty names in dtypes have been deprecated
------------------------------------------
It has been possible to create a record array with an empty field name, i.e.
``np.dtype({'names': ['a', '', 'b'], 'formats': ['i4']*3})``. This conflicts
with internal usage of empty field names for padding, and unnamed fields cannot
be accessed by name. Such use has been deprecated.

Future Changes
==============

Expand Down
16 changes: 14 additions & 2 deletions numpy/core/src/multiarray/descriptor.c
Original file line number Diff line number Diff line change
Expand Up @@ -1059,7 +1059,7 @@ _convert_from_dict(PyObject *obj, int align)
totalsize = 0;
for (i = 0; i < n; i++) {
PyObject *tup, *descr, *ind, *title, *name, *off;
int len, ret, _align = 1;
int len, ret, tmp, _align = 1;
PyArray_Descr *newdescr;

/* Build item to insert (descr, offset, [title])*/
Expand Down Expand Up @@ -1169,7 +1169,19 @@ _convert_from_dict(PyObject *obj, int align)
Py_DECREF(tup);
goto fail;
}

tmp = PyObject_IsTrue(name);
if (tmp < 0) {
Py_DECREF(tup);
goto fail;
}
else if (tmp == 0) {
/* 2018-11-12 1.16 */
if (DEPRECATE("Blank field names are deprecated and will result in "
"an error in the future.") < 0) {
Py_DECREF(tup);
goto fail;
}
}
/* Insert into dictionary */
if (PyDict_GetItem(fields, name) != NULL) {
PyErr_SetString(PyExc_ValueError,
Expand Down
10 changes: 10 additions & 0 deletions numpy/core/tests/test_deprecations.py
Original file line number Diff line number Diff line change
Expand Up @@ -519,11 +519,13 @@ class TestPositiveOnNonNumerical(_DeprecationTestCase):
def test_positive_on_non_number(self):
self.assert_deprecated(operator.pos, args=(np.array('foo'),))


class TestFromstring(_DeprecationTestCase):
# 2017-10-19, 1.14
def test_fromstring(self):
self.assert_deprecated(np.fromstring, args=('\x00'*80,))


class Test_GetSet_NumericOps(_DeprecationTestCase):
# 2018-09-20, 1.16.0
def test_get_numeric_ops(self):
Expand All @@ -534,3 +536,11 @@ def test_get_numeric_ops(self):
# other tests.
self.assert_deprecated(np.set_numeric_ops, kwargs={})
assert_raises(ValueError, np.set_numeric_ops, add='abc')


class TestDtypeEmptyFieldName(_DeprecationTestCase):
# 2018-11-12, 1.16
def test_empty_fieldname(self):
d = {'names': ['a', '', 'b'], 'formats': ['i4']*3}
self.assert_deprecated(np.dtype, args=(d,))

31 changes: 16 additions & 15 deletions numpy/lib/tests/test_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@
import numpy as np
from numpy.testing import (
assert_, assert_array_equal, assert_raises, assert_raises_regex,
raises
raises, suppress_warnings
)
from numpy.lib import format

Expand Down Expand Up @@ -525,27 +525,28 @@ def test_compressed_roundtrip():


# aligned
dt1 = np.dtype('i1, i4, i1', align=True)
dt1 = {'names': ['a', 'b', 'c'], 'formats': ['i1', 'i4', 'i1'], 'align': True}
# non-aligned, explicit offsets
dt2 = np.dtype({'names': ['a', 'b'], 'formats': ['i4', 'i4'],
'offsets': [1, 6]})
dt2 = {'names': ['a', 'b'], 'formats': ['i4', 'i4'], 'offsets': [1, 6]}
# nested struct-in-struct
dt3 = np.dtype({'names': ['c', 'd'], 'formats': ['i4', dt2]})
dt3 = {'names': ['c', 'd'], 'formats': ['i4', dt2]}
# field with '' name
dt4 = np.dtype({'names': ['a', '', 'b'], 'formats': ['i4']*3})
dt4 = {'names': ['a', '', 'b'], 'formats': ['i4']*3}
# titles
dt5 = np.dtype({'names': ['a', 'b'], 'formats': ['i4', 'i4'],
'offsets': [1, 6], 'titles': ['aa', 'bb']})
dt5 = {'names': ['a', 'b'], 'formats': ['i4', 'i4'],
'offsets': [1, 6], 'titles': ['aa', 'bb']}

@pytest.mark.parametrize("dt", [dt1, dt2, dt3, dt4, dt5])
def test_load_padded_dtype(dt):
arr = np.zeros(3, dt)
for i in range(3):
arr[i] = i + 5
npz_file = os.path.join(tempdir, 'aligned.npz')
np.savez(npz_file, arr=arr)
arr1 = np.load(npz_file)['arr']
assert_array_equal(arr, arr1)
with suppress_warnings('always') as sup:
sup.filter(DeprecationWarning)
arr = np.zeros(3, dtype=dt)
for i in range(3):
arr[i] = i + 5
npz_file = os.path.join(tempdir, 'aligned.npz')
np.savez(npz_file, arr=arr)
arr1 = np.load(npz_file)['arr']
assert_array_equal(arr, arr1)


def test_python2_python3_interoperability():
Expand Down
6 changes: 4 additions & 2 deletions numpy/lib/tests/test_stride_tricks.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from numpy.core._rational_tests import rational
from numpy.testing import (
assert_equal, assert_array_equal, assert_raises, assert_,
assert_raises_regex
assert_raises_regex, suppress_warnings
)
from numpy.lib.stride_tricks import (
as_strided, broadcast_arrays, _broadcast_shape, broadcast_to
Expand Down Expand Up @@ -324,7 +324,9 @@ def test_as_strided():
assert_equal(a.dtype, a_view.dtype)

# Make sure that the only type that could fail is properly handled
dt = np.dtype({'names': [''], 'formats': ['V4']})
with suppress_warnings() as sup:
sup.filter(DeprecationWarning, '')
dt = np.dtype({'names': [''], 'formats': ['V4']})
a = np.empty((4,), dtype=dt)
a_view = as_strided(a, shape=(3, 4), strides=(0, a.itemsize))
assert_equal(a.dtype, a_view.dtype)
Expand Down