diff --git a/python/pyarrow/array.pxi b/python/pyarrow/array.pxi index 0dc79aeb6f1cf..5961498924b71 100644 --- a/python/pyarrow/array.pxi +++ b/python/pyarrow/array.pxi @@ -1530,10 +1530,15 @@ cdef class Array(_PandasConvertible): # values is already a numpy array at this point, but calling np.array(..) # again to handle the `dtype` keyword with a no-copy guarantee return np.array(values, dtype=dtype, copy=False) + values = self.to_numpy(zero_copy_only=False) + if copy is True and is_primitive(self.type.id) and self.null_count == 0: + # to_numpy did not yet make a copy + return np.array(values, dtype=dtype, copy=True) + if dtype is None: return values - return values.astype(dtype) + return np.asarray(values, dtype=dtype) def to_numpy(self, zero_copy_only=True, writable=False): """ diff --git a/python/pyarrow/includes/libarrow.pxd b/python/pyarrow/includes/libarrow.pxd index a35919579541a..6dae45ab80b1c 100644 --- a/python/pyarrow/includes/libarrow.pxd +++ b/python/pyarrow/includes/libarrow.pxd @@ -173,6 +173,7 @@ cdef extern from "arrow/api.h" namespace "arrow" nogil: c_string ToString() c_bool is_primitive(Type type) + c_bool is_numeric(Type type) cdef cppclass CArrayData" arrow::ArrayData": shared_ptr[CDataType] type diff --git a/python/pyarrow/tests/test_array.py b/python/pyarrow/tests/test_array.py index 654a362795238..dbe62a12dea99 100644 --- a/python/pyarrow/tests/test_array.py +++ b/python/pyarrow/tests/test_array.py @@ -3339,6 +3339,15 @@ def test_numpy_array_protocol(): with pytest.raises(ValueError): np.array(arr, dtype="float64", copy=False) + # copy=True -> not yet passed by numpy, so we have to call this directly to test + arr = pa.array([1, 2, 3]) + result = arr.__array__(copy=True) + assert result.flags.writeable + + arr = pa.array([1, 2, 3]) + result = arr.__array__(dtype=np.dtype("float64"), copy=True) + assert result.dtype == "float64" + def test_array_protocol():