Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions python/pyarrow/src/arrow/python/numpy_to_arrow.cc
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,8 @@ class NumPyConverter {

Status Visit(const FixedSizeBinaryType& type);

Status Visit(const DecimalType& type);

// Default case
Status Visit(const DataType& type) { return TypeNotImplemented(type.ToString()); }

Expand Down Expand Up @@ -638,6 +640,31 @@ Status NumPyConverter::Visit(const BinaryViewType& type) {
return PushArray(result->data());
}

Status NumPyConverter::Visit(const DecimalType& type) {
// Decimal types derive from FixedSizeBinaryType, so without this overload
// integer arrays would be reinterpreted as raw bytes.
if (!PyTypeNum_ISINTEGER(dtype_->type_num)) {
return TypeNotImplemented(type.ToString());
}
ARROW_ASSIGN_OR_RAISE(auto input_type, NumPyDtypeToArrow(dtype_));
NumPyConverter converter(pool_, reinterpret_cast<PyObject*>(arr_),
reinterpret_cast<PyObject*>(mask_), input_type, from_pandas_,
cast_options_);
RETURN_NOT_OK(converter.Convert());
// Go through decimal128(20, 0), which holds any 64-bit integer, so the
// final cast checks the values rather than the input type's range.
const auto wide_type = decimal128(20, 0);
compute::ExecContext context(pool_);
for (const auto& arr : converter.result()) {
ARROW_ASSIGN_OR_RAISE(auto wide,
compute::Cast(*arr, wide_type, cast_options_, &context));
ARROW_ASSIGN_OR_RAISE(auto casted,
compute::Cast(*wide, type_, cast_options_, &context));
out_arrays_.push_back(std::move(casted));
}
return Status::OK();
}

Status NumPyConverter::Visit(const FixedSizeBinaryType& type) {
auto byte_width = type.byte_width();

Expand Down
16 changes: 16 additions & 0 deletions python/pyarrow/tests/test_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -1882,6 +1882,22 @@ def test_half_float_array_from_python():
arr = pa.array(['a', 3, None], type=pa.float16())


@pytest.mark.numpy
@pytest.mark.parametrize('typ', [pa.decimal32(9, 2), pa.decimal64(18, 2),
pa.decimal128(38, 9), pa.decimal256(40, 2)])
def test_decimal_from_numpy_integers(typ):
# GH-44712
arr = np.array([1, -2, 3], dtype=np.int64)
expected = pa.array([1, -2, 3], type=typ)
assert pa.array(arr, type=typ).equals(expected)

result = pa.array(arr, type=typ, mask=np.array([False, True, False]))
assert result.equals(pa.array([1, None, 3], type=typ))

with pytest.raises(pa.ArrowInvalid):
pa.array(np.array([10**6], dtype=np.int64), type=pa.decimal32(5, 2))


def test_decimal_to_int_safe():
safe_cases = [
(
Expand Down
Loading