diff options
author | Eric Wieser <wieser.eric@gmail.com> | 2020-01-27 22:52:48 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-01-27 22:52:48 +0000 |
commit | 6d889e7eca0f7ae6d640c380bd0b604e6530f049 (patch) | |
tree | 70909ea235d77703909f65fcb9da0775037e9745 | |
parent | 7b7197517f31bdfdf6fb1d99944002c90568d705 (diff) | |
parent | cf688edd6777881aae5af233aa538b7fd9b6c361 (diff) | |
download | numpy-6d889e7eca0f7ae6d640c380bd0b604e6530f049.tar.gz |
Merge pull request #15446 from eric-wieser/reject-garbage-arguments
BUG: Reject nonsense arguments to scalar constructors
-rw-r--r-- | numpy/core/src/multiarray/multiarraymodule.c | 6 | ||||
-rw-r--r-- | numpy/core/src/multiarray/scalartypes.c.src | 28 | ||||
-rw-r--r-- | numpy/core/tests/test_scalar_ctors.py | 35 |
3 files changed, 53 insertions, 16 deletions
diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c index 11e0bc44d..c2e597385 100644 --- a/numpy/core/src/multiarray/multiarraymodule.c +++ b/numpy/core/src/multiarray/multiarraymodule.c @@ -3287,12 +3287,14 @@ array_datetime_data(PyObject *NPY_UNUSED(dummy), PyObject *args) } meta = get_datetime_metadata_from_dtype(dtype); - Py_DECREF(dtype); if (meta == NULL) { + Py_DECREF(dtype); return NULL; } - return convert_datetime_metadata_to_tuple(meta); + PyObject *res = convert_datetime_metadata_to_tuple(meta); + Py_DECREF(dtype); + return res; } /* diff --git a/numpy/core/src/multiarray/scalartypes.c.src b/numpy/core/src/multiarray/scalartypes.c.src index 9b53fea6f..67c268a9b 100644 --- a/numpy/core/src/multiarray/scalartypes.c.src +++ b/numpy/core/src/multiarray/scalartypes.c.src @@ -2537,7 +2537,9 @@ object_arrtype_dealloc(PyObject *v) PyTypeObject *sup = (PyTypeObject *)PyTuple_GET_ITEM(cls.tp_bases, num); \ robj = sup->tp_new(type, args, kwds); \ if (robj != NULL) goto finish; \ - if (PyTuple_GET_SIZE(args) != 1) return NULL; \ + if (PyTuple_GET_SIZE(args) != 1 || (kwds && PyDict_Size(kwds) != 0)) { \ + return NULL; \ + } \ PyErr_Clear(); \ /* now do default conversion */ @@ -2558,17 +2560,12 @@ object_arrtype_dealloc(PyObject *v) #if defined(_@TYPE@_IS_OBJECT) #define _NPY_UNUSED_TYPE NPY_UNUSED - #define _NPY_UNUSED_KWDS NPY_UNUSED -#elif defined(_@TYPE@_IS_UNICODE) || defined(_@TYPE@_IS_STRING) || defined(_@TYPE@_IS_DOUBLE) - #define _NPY_UNUSED_TYPE - #define _NPY_UNUSED_KWDS #else #define _NPY_UNUSED_TYPE - #define _NPY_UNUSED_KWDS NPY_UNUSED #endif static PyObject * -@name@_arrtype_new(PyTypeObject *_NPY_UNUSED_TYPE(type), PyObject *args, PyObject *_NPY_UNUSED_KWDS(kwds)) +@name@_arrtype_new(PyTypeObject *_NPY_UNUSED_TYPE(type), PyObject *args, PyObject *kwds) { PyObject *obj = NULL; PyObject *robj; @@ -2586,7 +2583,8 @@ static PyObject * #endif /* TODO: include type name in error message, which is not @name@ */ - if (!PyArg_ParseTuple(args, "|O", &obj)) { + char *kwnames[] = {"", NULL}; /* positional-only */ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwnames, &obj)) { return NULL; } typecode = PyArray_DescrFromType(NPY_@TYPE@); @@ -2699,8 +2697,8 @@ static PyObject * PyObject *obj = NULL, *meta_obj = NULL; Py@Name@ScalarObject *ret; - /* TODO: include type name in error message, which is not @name@ */ - if (!PyArg_ParseTuple(args, "|OO", &obj, &meta_obj)) { + char *kwnames[] = {"", "", NULL}; /* positional-only */ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwnames, &obj, &meta_obj)) { return NULL; } @@ -2753,12 +2751,13 @@ static PyObject * /* bool->tp_new only returns Py_True or Py_False */ static PyObject * -bool_arrtype_new(PyTypeObject *NPY_UNUSED(type), PyObject *args, PyObject *NPY_UNUSED(kwds)) +bool_arrtype_new(PyTypeObject *NPY_UNUSED(type), PyObject *args, PyObject *kwds) { PyObject *obj = NULL; PyArrayObject *arr; - if (!PyArg_ParseTuple(args, "|O:bool_", &obj)) { + char *kwnames[] = {"", NULL}; /* positional-only */ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:bool_", kwnames, &obj)) { return NULL; } if (obj == NULL) { @@ -2897,12 +2896,13 @@ NPY_NO_EXPORT PyNumberMethods bool_arrtype_as_number = { }; static PyObject * -void_arrtype_new(PyTypeObject *type, PyObject *args, PyObject *NPY_UNUSED(kwds)) +void_arrtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *obj, *arr; PyObject *new = NULL; - if (!PyArg_ParseTuple(args, "O:void", &obj)) { + char *kwnames[] = {"", NULL}; /* positional-only */ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:void", kwnames, &obj)) { return NULL; } /* diff --git a/numpy/core/tests/test_scalar_ctors.py b/numpy/core/tests/test_scalar_ctors.py index 2de5084b6..7645a0853 100644 --- a/numpy/core/tests/test_scalar_ctors.py +++ b/numpy/core/tests/test_scalar_ctors.py @@ -1,6 +1,8 @@ """ Test the scalar constructors, which also do type-coercion """ +import pytest + import numpy as np from numpy.testing import ( assert_equal, assert_almost_equal, assert_warns, @@ -37,6 +39,39 @@ class TestFromString: assert_equal(flongdouble, -np.inf) +class TestExtraArgs: + def test_superclass(self): + # try both positional and keyword arguments + s = np.str_(b'\\x61', encoding='unicode-escape') + assert s == 'a' + s = np.str_(b'\\x61', 'unicode-escape') + assert s == 'a' + + # previously this would return '\\xx' + with pytest.raises(UnicodeDecodeError): + np.str_(b'\\xx', encoding='unicode-escape') + with pytest.raises(UnicodeDecodeError): + np.str_(b'\\xx', 'unicode-escape') + + # superclass fails, but numpy succeeds + assert np.bytes_(-2) == b'-2' + + def test_datetime(self): + dt = np.datetime64('2000-01', ('M', 2)) + assert np.datetime_data(dt) == ('M', 2) + + with pytest.raises(TypeError): + np.datetime64('2000', garbage=True) + + def test_bool(self): + with pytest.raises(TypeError): + np.bool(False, garbage=True) + + def test_void(self): + with pytest.raises(TypeError): + np.void(b'test', garbage=True) + + class TestFromInt: def test_intp(self): # Ticket #99 |