diff --git a/doc/source/whatsnew/v1.4.0.rst b/doc/source/whatsnew/v1.4.0.rst index cdc0bbb1dfd6a..ae3dbb6656451 100644 --- a/doc/source/whatsnew/v1.4.0.rst +++ b/doc/source/whatsnew/v1.4.0.rst @@ -670,6 +670,8 @@ Conversion - Bug in :meth:`DataFrame.convert_dtypes` not returning the correct type when a subclass does not overload :meth:`_constructor_sliced` (:issue:`43201`) - Bug in :meth:`DataFrame.astype` not propagating ``attrs`` from the original :class:`DataFrame` (:issue:`44414`) - Bug in :meth:`DataFrame.convert_dtypes` result losing ``columns.names`` (:issue:`41435`) +- Bug in constructing a ``IntegerArray`` from pyarrow data failing to validate dtypes (:issue:`44891`) +- Strings ^^^^^^^ diff --git a/pandas/core/arrays/numeric.py b/pandas/core/arrays/numeric.py index bdd7f8c0d3c8c..2ab95b4421814 100644 --- a/pandas/core/arrays/numeric.py +++ b/pandas/core/arrays/numeric.py @@ -21,6 +21,7 @@ is_integer, is_integer_dtype, is_list_like, + pandas_dtype, ) from pandas.core.arrays.masked import ( @@ -49,6 +50,16 @@ def __from_arrow__( pyarrow_type = pyarrow.from_numpy_dtype(self.type) if not array.type.equals(pyarrow_type): + # test_from_arrow_type_error raise for string, but allow + # through itemsize conversion GH#31896 + rt_dtype = pandas_dtype(array.type.to_pandas_dtype()) + if rt_dtype.kind not in ["i", "u", "f"]: + # Could allow "c" or potentially disallow float<->int conversion, + # but at the moment we specifically test that uint<->int works + raise TypeError( + f"Expected array of {self} type, got {array.type} instead" + ) + array = array.cast(pyarrow_type) if isinstance(array, pyarrow.Array): diff --git a/pandas/tests/arrays/masked/test_arrow_compat.py b/pandas/tests/arrays/masked/test_arrow_compat.py index 20eb055f14835..051762511a6ca 100644 --- a/pandas/tests/arrays/masked/test_arrow_compat.py +++ b/pandas/tests/arrays/masked/test_arrow_compat.py @@ -176,15 +176,9 @@ def test_pyarrow_array_to_numpy_and_mask(np_dtype_to_arrays): tm.assert_numpy_array_equal(mask, mask_expected_empty) -def test_from_arrow_type_error(request, data): +def test_from_arrow_type_error(data): # ensure that __from_arrow__ returns a TypeError when getting a wrong # array type - if data.dtype != "boolean": - # TODO numeric dtypes cast any incoming array to the correct dtype - # instead of erroring - request.node.add_marker( - pytest.mark.xfail(raises=None, reason="numeric dtypes don't error but cast") - ) arr = pa.array(data).cast("string") with pytest.raises(TypeError, match=None):