Skip to content
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

BUG: clear only attribute errors in get_attr_string.h::maybe_get_attr #14745

Merged
merged 11 commits into from
Oct 30, 2019
12 changes: 10 additions & 2 deletions numpy/core/src/common/get_attr_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ _is_basic_python_type(PyTypeObject *tp)
);
}

static NPY_INLINE void
clear_exception(PyObject *exception)
{
if (PyErr_Occurred() && PyErr_ExceptionMatches(exception)) {
keewis marked this conversation as resolved.
Show resolved Hide resolved
PyErr_Clear();
}
}

/*
* Stripped down version of PyObject_GetAttrString,
* avoids lookups for None, tuple, and List objects,
Expand All @@ -63,7 +71,7 @@ maybe_get_attr(PyObject *obj, char *name)
if (tp->tp_getattr != NULL) {
res = (*tp->tp_getattr)(obj, name);
if (res == NULL) {
keewis marked this conversation as resolved.
Show resolved Hide resolved
PyErr_Clear();
clear_exception(PyExc_AttributeError);
}
}
/* Attribute referenced by (PyObject *)name */
Expand All @@ -79,7 +87,7 @@ maybe_get_attr(PyObject *obj, char *name)
res = (*tp->tp_getattro)(obj, w);
Py_DECREF(w);
if (res == NULL) {
PyErr_Clear();
clear_exception(PyExc_AttributeError);
}
}
return res;
Expand Down
6 changes: 5 additions & 1 deletion numpy/core/src/multiarray/ctors.c
Original file line number Diff line number Diff line change
Expand Up @@ -2351,7 +2351,11 @@ PyArray_FromStructInterface(PyObject *input)

attr = PyArray_LookupSpecial_OnInstance(input, "__array_struct__");
if (attr == NULL) {
return Py_NotImplemented;
if (PyErr_Occurred()) {
return NULL;
} else {
return Py_NotImplemented;
}
eric-wieser marked this conversation as resolved.
Show resolved Hide resolved
}
if (!NpyCapsule_Check(attr)) {
goto fail;
Expand Down
51 changes: 51 additions & 0 deletions numpy/core/tests/test_issue14735.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import pytest
import warnings
import numpy as np


class Wrapper:
def __init__(self, array):
self.array = array

def __len__(self):
return len(self.array)

def __getitem__(self, item):
return type(self)(self.array[item])

def __getattr__(self, name):
if name.startswith("__array_"):
warnings.warn("object got converted", UserWarning)

return getattr(self.array, name)

def __repr__(self):
return f"<Wrapper({self.array})>"

@pytest.mark.filterwarnings("error")
def test_pint_replica_warning():
array = Wrapper(np.arange(10))
with pytest.raises(UserWarning, match="object got converted"):
np.asarray(array)

def test_pint_replica():
print(np.__version__)

array = Wrapper(np.arange(10))
with warnings.catch_warnings():
warnings.filterwarnings("ignore")
expected = np.asarray(array)

with warnings.catch_warnings():
warnings.filterwarnings("error")
try:
actual = np.asarray(array)
except UserWarning:
print("user warning caught")
actual = expected

assert (
type(expected) == type(actual)
and expected.dtype == actual.dtype
and np.allclose(expected, actual)
)