Skip to content

Commit

Permalink
BUG: Fix small issues found with pytest-leaks
Browse files Browse the repository at this point in the history
None of these are particularly worrying as they either usually only
leak reference (and not memory) or appear in rare or almost impossible
error-paths, or are limited to the tests.

Unfortunately, this PR will not apply to 1.20.x, due to small changes
in the overrides.

Backport of gh-18670 (with two small differences)
  • Loading branch information
seberg committed Mar 23, 2021
1 parent c4fd82f commit afc861e
Show file tree
Hide file tree
Showing 7 changed files with 41 additions and 26 deletions.
31 changes: 20 additions & 11 deletions numpy/core/src/multiarray/arrayfunction_override.c
Expand Up @@ -341,18 +341,23 @@ array_implement_array_function(
return NULL;
}

/* Remove `like=` kwarg, which is NumPy-exclusive and thus not present
/*
* Remove `like=` kwarg, which is NumPy-exclusive and thus not present
* in downstream libraries. If `like=` is specified but doesn't
* implement `__array_function__`, raise a `TypeError`.
*/
if (kwargs != NULL && PyDict_Contains(kwargs, npy_ma_str_like)) {
PyObject *like_arg = PyDict_GetItem(kwargs, npy_ma_str_like);
if (like_arg && !get_array_function(like_arg)) {
return PyErr_Format(PyExc_TypeError,
"The `like` argument must be an array-like that implements "
"the `__array_function__` protocol.");
if (like_arg != NULL) {
PyObject *tmp_has_override = get_array_function(like_arg);
if (tmp_has_override == NULL) {
return PyErr_Format(PyExc_TypeError,
"The `like` argument must be an array-like that "
"implements the `__array_function__` protocol.");
}
Py_DECREF(tmp_has_override);
PyDict_DelItem(kwargs, npy_ma_str_like);
}
PyDict_DelItem(kwargs, npy_ma_str_like);
}

PyObject *res = array_implement_array_function_internal(
Expand Down Expand Up @@ -387,14 +392,18 @@ array_implement_c_array_function_creation(
return Py_NotImplemented;
}

PyObject *like_arg = PyDict_GetItem(kwargs, npy_ma_str_like);
PyObject *like_arg = PyDict_GetItemWithError(kwargs, npy_ma_str_like);
if (like_arg == NULL) {
return NULL;
}
else if (!get_array_function(like_arg)) {
return PyErr_Format(PyExc_TypeError,
"The `like` argument must be an array-like that implements "
"the `__array_function__` protocol.");
else {
PyObject *tmp_has_override = get_array_function(like_arg);
if (tmp_has_override == NULL) {
return PyErr_Format(PyExc_TypeError,
"The `like` argument must be an array-like that "
"implements the `__array_function__` protocol.");
}
Py_DECREF(tmp_has_override);
}
PyObject *relevant_args = PyTuple_Pack(1, like_arg);
PyDict_DelItem(kwargs, npy_ma_str_like);
Expand Down
3 changes: 1 addition & 2 deletions numpy/core/src/multiarray/convert_datatype.c
Expand Up @@ -902,8 +902,7 @@ PyArray_FindConcatenationDescriptor(
"The dtype `%R` is not a valid dtype for concatenation "
"since it is a subarray dtype (the subarray dimensions "
"would be added as array dimensions).", result);
Py_DECREF(result);
return NULL;
Py_SETREF(result, NULL);
}
goto finish;
}
Expand Down
1 change: 1 addition & 0 deletions numpy/core/src/multiarray/multiarraymodule.c
Expand Up @@ -2100,6 +2100,7 @@ array_fromstring(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *keywds
array_function_result = array_implement_c_array_function_creation(
"fromstring", args, keywds);
if (array_function_result != Py_NotImplemented) {
Py_XDECREF(descr);
return array_function_result;
}

Expand Down
1 change: 1 addition & 0 deletions numpy/core/src/umath/_umath_tests.c.src
Expand Up @@ -621,6 +621,7 @@ UMath_Tests_test_dispatch(PyObject *NPY_UNUSED(dummy), PyObject *NPY_UNUSED(dumm
goto err;
}
NPY_CPU_DISPATCH_CALL_ALL(_umath_tests_dispatch_attach, (item));
Py_SETREF(item, NULL);
if (PyErr_Occurred()) {
goto err;
}
Expand Down
1 change: 1 addition & 0 deletions numpy/core/src/umath/_umath_tests.dispatch.c
Expand Up @@ -29,5 +29,6 @@ void NPY_CPU_DISPATCH_CURFX(_umath_tests_dispatch_attach)(PyObject *list)
PyObject *item = PyUnicode_FromString(NPY_TOSTRING(NPY_CPU_DISPATCH_CURFX(func)));
if (item) {
PyList_Append(list, item);
Py_DECREF(item);
}
}
4 changes: 3 additions & 1 deletion numpy/core/src/umath/ufunc_object.c
Expand Up @@ -5495,6 +5495,7 @@ ufunc_outer(PyUFuncObject *ufunc, PyObject *args, PyObject *kwds)
/* DEPRECATED 2020-05-13, NumPy 1.20 */
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
matrix_deprecation_msg, ufunc->name, "first") < 0) {
Py_DECREF(tmp);
return NULL;
}
ap1 = (PyArrayObject *) PyArray_FromObject(tmp, NPY_NOTYPE, 0, 0);
Expand All @@ -5514,6 +5515,7 @@ ufunc_outer(PyUFuncObject *ufunc, PyObject *args, PyObject *kwds)
/* DEPRECATED 2020-05-13, NumPy 1.20 */
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
matrix_deprecation_msg, ufunc->name, "second") < 0) {
Py_DECREF(tmp);
Py_DECREF(ap1);
return NULL;
}
Expand All @@ -5538,7 +5540,7 @@ ufunc_outer(PyUFuncObject *ufunc, PyObject *args, PyObject *kwds)
"maximum supported dimension for an ndarray is %d, but "
"`%s.outer()` result would have %d.",
NPY_MAXDIMS, ufunc->name, newdims.len);
return NPY_FAIL;
goto fail;
}
if (newdims.ptr == NULL) {
goto fail;
Expand Down
26 changes: 14 additions & 12 deletions numpy/core/tests/test_overrides.py
@@ -1,5 +1,6 @@
import inspect
import sys
import os
import tempfile
from io import StringIO
from unittest import mock
Expand Down Expand Up @@ -558,18 +559,19 @@ def test_array_like_fromfile(self, numpy_ref):

data = np.random.random(5)

fname = tempfile.mkstemp()[1]
data.tofile(fname)

array_like = np.fromfile(fname, like=ref)
if numpy_ref is True:
assert type(array_like) is np.ndarray
np_res = np.fromfile(fname, like=ref)
assert_equal(np_res, data)
assert_equal(array_like, np_res)
else:
assert type(array_like) is self.MyArray
assert array_like.function is self.MyArray.fromfile
with tempfile.TemporaryDirectory() as tmpdir:
fname = os.path.join(tmpdir, "testfile")
data.tofile(fname)

array_like = np.fromfile(fname, like=ref)
if numpy_ref is True:
assert type(array_like) is np.ndarray
np_res = np.fromfile(fname, like=ref)
assert_equal(np_res, data)
assert_equal(array_like, np_res)
else:
assert type(array_like) is self.MyArray
assert array_like.function is self.MyArray.fromfile

@requires_array_function
def test_exception_handling(self):
Expand Down

0 comments on commit afc861e

Please sign in to comment.