Skip to content

MAINT: Use ValueError for duplicate field names in lookup (backport) #10435

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

Merged
Merged
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
4 changes: 4 additions & 0 deletions numpy/core/include/numpy/npy_3kcompat.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ static NPY_INLINE int PyInt_Check(PyObject *op) {
#define PyUString_InternFromString PyUnicode_InternFromString
#define PyUString_Format PyUnicode_Format

#define PyBaseString_Check(obj) (PyUnicode_Check(obj))

#else

#define PyBytes_Type PyString_Type
Expand Down Expand Up @@ -123,6 +125,8 @@ static NPY_INLINE int PyInt_Check(PyObject *op) {
#define PyUString_InternFromString PyString_InternFromString
#define PyUString_Format PyString_Format

#define PyBaseString_Check(obj) (PyBytes_Check(obj) || PyUnicode_Check(obj))

#endif /* NPY_PY3K */


Expand Down
30 changes: 5 additions & 25 deletions numpy/core/src/multiarray/descriptor.c
Original file line number Diff line number Diff line change
Expand Up @@ -512,11 +512,7 @@ _convert_from_array_descr(PyObject *obj, int align)
}
if ((PyDict_GetItem(fields, name) != NULL)
|| (title
#if defined(NPY_PY3K)
&& PyUString_Check(title)
#else
&& (PyUString_Check(title) || PyUnicode_Check(title))
#endif
&& PyBaseString_Check(title)
&& (PyDict_GetItem(fields, title) != NULL))) {
#if defined(NPY_PY3K)
name = PyUnicode_AsUTF8String(name);
Expand Down Expand Up @@ -551,11 +547,7 @@ _convert_from_array_descr(PyObject *obj, int align)
Py_INCREF(title);
PyTuple_SET_ITEM(tup, 2, title);
PyDict_SetItem(fields, name, tup);
#if defined(NPY_PY3K)
if (PyUString_Check(title)) {
#else
if (PyUString_Check(title) || PyUnicode_Check(title)) {
#endif
if (PyBaseString_Check(title)) {
if (PyDict_GetItem(fields, title) != NULL) {
PyErr_SetString(PyExc_ValueError,
"title already used as a name or title.");
Expand Down Expand Up @@ -1181,11 +1173,7 @@ _convert_from_dict(PyObject *obj, int align)
Py_DECREF(tup);
goto fail;
}
#if defined(NPY_PY3K)
if (!PyUString_Check(name)) {
#else
if (!(PyUString_Check(name) || PyUnicode_Check(name))) {
#endif
if (!PyBaseString_Check(name)) {
PyErr_SetString(PyExc_ValueError,
"field names must be strings");
Py_DECREF(tup);
Expand All @@ -1202,11 +1190,7 @@ _convert_from_dict(PyObject *obj, int align)
PyDict_SetItem(fields, name, tup);
Py_DECREF(name);
if (len == 3) {
#if defined(NPY_PY3K)
if (PyUString_Check(title)) {
#else
if (PyUString_Check(title) || PyUnicode_Check(title)) {
#endif
if (PyBaseString_Check(title)) {
if (PyDict_GetItem(fields, title) != NULL) {
PyErr_SetString(PyExc_ValueError,
"title already used as a name or title.");
Expand Down Expand Up @@ -3821,11 +3805,7 @@ descr_subscript(PyArray_Descr *self, PyObject *op)
return NULL;
}

#if defined(NPY_PY3K)
if (PyUString_Check(op)) {
#else
if (PyUString_Check(op) || PyUnicode_Check(op)) {
#endif
if (PyBaseString_Check(op)) {
return _subscript_by_name(self, op);
}
else {
Expand Down
14 changes: 3 additions & 11 deletions numpy/core/src/multiarray/mapping.c
Original file line number Diff line number Diff line change
Expand Up @@ -1396,11 +1396,7 @@ _get_field_view(PyArrayObject *arr, PyObject *ind, PyArrayObject **view)
*view = NULL;

/* first check for a single field name */
#if defined(NPY_PY3K)
if (PyUnicode_Check(ind)) {
#else
if (PyString_Check(ind) || PyUnicode_Check(ind)) {
#endif
if (PyBaseString_Check(ind)) {
PyObject *tup;
PyArray_Descr *fieldtype;
npy_intp offset;
Expand Down Expand Up @@ -1477,11 +1473,7 @@ _get_field_view(PyArrayObject *arr, PyObject *ind, PyArrayObject **view)
return -1;
}

#if defined(NPY_PY3K)
if (!PyUnicode_Check(name)) {
#else
if (!PyString_Check(name) && !PyUnicode_Check(name)) {
#endif
if (!PyBaseString_Check(name)) {
Py_DECREF(name);
Py_DECREF(fields);
Py_DECREF(names);
Expand Down Expand Up @@ -1521,7 +1513,7 @@ _get_field_view(PyArrayObject *arr, PyObject *ind, PyArrayObject **view)
PyObject *errmsg = PyUString_FromString(
"duplicate field of name ");
PyUString_ConcatAndDel(&errmsg, name);
PyErr_SetObject(PyExc_KeyError, errmsg);
PyErr_SetObject(PyExc_ValueError, errmsg);
Py_DECREF(errmsg);
Py_DECREF(fields);
Py_DECREF(names);
Expand Down
6 changes: 1 addition & 5 deletions numpy/core/src/multiarray/scalartypes.c.src
Original file line number Diff line number Diff line change
Expand Up @@ -2376,11 +2376,7 @@ voidtype_ass_subscript(PyVoidScalarObject *self, PyObject *ind, PyObject *val)
return -1;
}

#if defined(NPY_PY3K)
if (PyUString_Check(ind)) {
#else
if (PyBytes_Check(ind) || PyUnicode_Check(ind)) {
#endif
if (PyBaseString_Check(ind)) {
/*
* Much like in voidtype_setfield, we cannot simply use ndarray's
* __setitem__ since assignment to void scalars should not broadcast
Expand Down
4 changes: 3 additions & 1 deletion numpy/core/tests/test_multiarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -1157,9 +1157,11 @@ def test_structuredscalar_indexing(self):
def test_multiindex_titles(self):
a = np.zeros(4, dtype=[(('a', 'b'), 'i'), ('c', 'i'), ('d', 'i')])
assert_raises(KeyError, lambda : a[['a','c']])
assert_raises(KeyError, lambda : a[['b','b']])
assert_raises(KeyError, lambda : a[['a','a']])
assert_raises(ValueError, lambda : a[['b','b']]) # field exists, but repeated
a[['b','c']] # no exception


class TestBool(object):
def test_test_interning(self):
a0 = np.bool_(0)
Expand Down