diff options
author | Matti Picus <matti.picus@gmail.com> | 2019-12-23 23:08:24 +0200 |
---|---|---|
committer | Sebastian Berg <sebastian@sipsolutions.net> | 2019-12-23 15:08:24 -0600 |
commit | 42bd6db6ecfdb0b91e5d08ff587ad9af6d5f42d4 (patch) | |
tree | 8a4d33e46f7c18fa9cbdcbe8f0362a0023de025d | |
parent | 4f972297277e09f41f315fd75510cb313926fe67 (diff) | |
download | numpy-42bd6db6ecfdb0b91e5d08ff587ad9af6d5f42d4.tar.gz |
BUG: test, fix flexible dtype conversion on class with __array__ (#15076)
Fixes issue gh-12256 where
import numpy as np
class MyArray:
def __array__(self, result=None):
return np.array(['0'*70], dtype=object)
np.array(MyArray(), dtype=str)
# has dtype U64, not U70
The problem was the result of obj.__array__ was not used when filling out a flexible dtype "by-value".
I also renamed a test file, over time we should move the tests related to array protocol into it.
* BUG: test, fix flexible dtype conversion on class with __array__
* Update numpy/core/_add_newdocs.py
Thanks for the correction
Co-Authored-By: Eric Wieser <wieser.eric@gmail.com>
Co-authored-by: Eric Wieser <wieser.eric@gmail.com>
-rw-r--r-- | numpy/core/_add_newdocs.py | 3 | ||||
-rw-r--r-- | numpy/core/src/multiarray/ctors.c | 2 | ||||
-rw-r--r-- | numpy/core/tests/test_issue14735.py | 29 | ||||
-rw-r--r-- | numpy/core/tests/test_protocols.py | 44 |
4 files changed, 46 insertions, 32 deletions
diff --git a/numpy/core/_add_newdocs.py b/numpy/core/_add_newdocs.py index 2f1273904..d552348d0 100644 --- a/numpy/core/_add_newdocs.py +++ b/numpy/core/_add_newdocs.py @@ -2507,7 +2507,7 @@ add_newdoc('numpy.core.multiarray', 'ndarray', ('T', add_newdoc('numpy.core.multiarray', 'ndarray', ('__array__', - """ a.__array__(|dtype) -> reference if type unchanged, copy otherwise. + """ a.__array__([dtype], /) -> reference if type unchanged, copy otherwise. Returns either a new reference to self if dtype is not given or a new array of provided data type if dtype is different from the current dtype of the @@ -6871,4 +6871,3 @@ for float_name in ('half', 'single', 'double', 'longdouble'): >>> np.{ftype}(-.25).as_integer_ratio() (-1, 4) """.format(ftype=float_name))) - diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index 7276add75..6921427ce 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -1909,7 +1909,7 @@ PyArray_FromAny(PyObject *op, PyArray_Descr *newtype, int min_depth, /* If the requested dtype is flexible, adapt it */ if (newtype != NULL) { - newtype = PyArray_AdaptFlexibleDType(op, + newtype = PyArray_AdaptFlexibleDType((arr == NULL) ? op : (PyObject *)arr, (dtype == NULL) ? PyArray_DESCR(arr) : dtype, newtype); if (newtype == NULL) { diff --git a/numpy/core/tests/test_issue14735.py b/numpy/core/tests/test_issue14735.py deleted file mode 100644 index 6105c8e6a..000000000 --- a/numpy/core/tests/test_issue14735.py +++ /dev/null @@ -1,29 +0,0 @@ -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, stacklevel=1) - - return getattr(self.array, name) - - def __repr__(self): - return "<Wrapper({self.array})>".format(self=self) - -@pytest.mark.filterwarnings("error") -def test_getattr_warning(): - array = Wrapper(np.arange(10)) - with pytest.raises(UserWarning, match="object got converted"): - np.asarray(array) diff --git a/numpy/core/tests/test_protocols.py b/numpy/core/tests/test_protocols.py new file mode 100644 index 000000000..55a2bcf72 --- /dev/null +++ b/numpy/core/tests/test_protocols.py @@ -0,0 +1,44 @@ +import pytest +import warnings +import numpy as np + + +@pytest.mark.filterwarnings("error") +def test_getattr_warning(): + # issue gh-14735: make sure we clear only getattr errors, and let warnings + # through + 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, stacklevel=1) + + return getattr(self.array, name) + + def __repr__(self): + return "<Wrapper({self.array})>".format(self=self) + + array = Wrapper(np.arange(10)) + with pytest.raises(UserWarning, match="object got converted"): + np.asarray(array) + + +def test_array_called(): + class Wrapper: + val = '0' * 100 + def __array__(self, result=None): + return np.array([self.val], dtype=object) + + + wrapped = Wrapper() + arr = np.array(wrapped, dtype=str) + assert arr.dtype == 'U100' + assert arr[0] == Wrapper.val |