pitrou commented on code in PR #50929:
URL: https://github.com/apache/arrow/pull/50929#discussion_r3905730490


##########
cpp/src/arrow/array/array_list_test.cc:
##########
@@ -1821,4 +1822,109 @@ TEST_F(TestFixedSizeListArray, FlattenRecursively) {
                     *ArrayFromJSON(value_type_, "[0, 1, null, 3, 7, null, 2, 
5]"));
 }
 
+namespace {
+
+/// The innermost values of the nested fixed size lists.
+std::shared_ptr<Array> LeafValues(std::shared_ptr<Array> array) {
+  while (array->type_id() == Type::FIXED_SIZE_LIST) {
+    const auto& fsl = checked_cast<const FixedSizeListArray&>(*array);
+    array =
+        fsl.values()->Slice(fsl.value_offset(0), array->length() * 
fsl.value_length());
+  }
+  return array;
+}
+
+template <typename T>
+void CheckToTensor(const std::shared_ptr<Array>& array, const 
std::vector<int64_t>& shape,
+                   std::initializer_list<T> values) {
+  const auto value_type = CTypeTraits<T>::type_singleton();
+  ASSERT_OK_AND_ASSIGN(
+      auto expected,
+      Tensor::Make(value_type, Buffer::Wrap(values.begin(), values.size()), 
shape));
+
+  ASSERT_OK_AND_ASSIGN(auto tensor, array->ToTensor());
+  ASSERT_OK(tensor->Validate());
+
+  AssertTypeEqual(*value_type, *tensor->type());
+  ASSERT_EQ(shape, tensor->shape());
+  ASSERT_TRUE(tensor->is_row_major());
+  ASSERT_TRUE(tensor->Equals(*expected));
+
+  // The tensor shares the values buffer, it does not copy
+  const auto leaf = LeafValues(array);
+  ASSERT_EQ(leaf->data()->buffers[1]->data() + leaf->offset() * sizeof(T),
+            tensor->data()->data());
+}
+
+}  // namespace
+
+TEST_F(TestFixedSizeListArray, ToTensor) {
+  auto array = ArrayFromJSON(fixed_size_list(int32(), 3),
+                             "[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 
12]]");
+  CheckToTensor<int32_t>(array, {4, 3}, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 
12});
+
+  // Offset on the list array itself
+  CheckToTensor<int32_t>(array->Slice(2, 2), {2, 3}, {7, 8, 9, 10, 11, 12});
+
+  // Offset on the values array
+  auto values = ArrayFromJSON(int32(), "[1, 2, 3, 4, 5, 6, 7, 8, 
9]")->Slice(3);
+  ASSERT_OK_AND_ASSIGN(auto from_values, 
FixedSizeListArray::FromArrays(values, 3));
+  CheckToTensor<int32_t>(from_values, {2, 3}, {4, 5, 6, 7, 8, 9});
+
+  // Offsets on both the list array and its values
+  CheckToTensor<int32_t>(from_values->Slice(1), {1, 3}, {7, 8, 9});
+}
+
+TEST_F(TestFixedSizeListArray, ToTensorNested) {
+  auto array = ArrayFromJSON(fixed_size_list(fixed_size_list(float32(), 2), 
3), R"([
+    [[1, 2], [3, 4], [5, 6]],
+    [[7, 8], [9, 10], [11, 12]],
+    [[13, 14], [15, 16], [17, 18]]
+  ])");
+  CheckToTensor<float>(array, {3, 3, 2},
+                       {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 
17, 18});
+
+  CheckToTensor<float>(array->Slice(1, 2), {2, 3, 2},
+                       {7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18});
+
+  // Offsets accumulate at every level: the innermost values are offset by 2, 
the
+  // middle lists by 3 * 2 and the outer lists by 1 * 3 * 2.
+  auto values = ArrayFromJSON(float32(), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 
11, 12, 13]")
+                    ->Slice(2, 12);
+  ASSERT_OK_AND_ASSIGN(auto inner, FixedSizeListArray::FromArrays(values, 2));
+  ASSERT_OK_AND_ASSIGN(auto outer, FixedSizeListArray::FromArrays(inner, 3));
+  CheckToTensor<float>(outer, {2, 3, 2}, {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 
13});
+  CheckToTensor<float>(outer->Slice(1), {1, 3, 2}, {8, 9, 10, 11, 12, 13});
+}
+
+TEST_F(TestFixedSizeListArray, ToTensorNulls) {
+  auto array = ArrayFromJSON(fixed_size_list(int32(), 2), "[[1, 2], null, [5, 
null]]");
+
+  // Default behaviour is to not allow nulls
+  ASSERT_RAISES(NotImplemented, array->ToTensor());
+
+  // Nulls are ignored, leaving unspecified values in the output tensor.
+  ASSERT_OK_AND_ASSIGN(auto tensor, array->ToTensor(/* allow_nulls= */ true));
+  ASSERT_OK(tensor->Validate());
+  ASSERT_EQ(std::vector<int64_t>({3, 2}), tensor->shape());

Review Comment:
   We can probably check the 3 non-null tensor values?



##########
cpp/src/arrow/array/array_base.h:
##########
@@ -36,6 +36,8 @@
 
 namespace arrow {
 
+class Tensor;

Review Comment:
   Can include `arrow/type_fwd.h` to avoid adding declarations like this.



##########
cpp/src/arrow/array/array_test.cc:
##########
@@ -1218,6 +1219,56 @@ TEST(TestPrimitiveArray, CtorNoValidityBitmap) {
   ASSERT_EQ(arr.data()->null_count, 0);
 }
 
+TEST(TestPrimitiveArray, ToTensor) {
+  const std::vector<int64_t> shape = {5};
+  const std::vector<int64_t> strides = {sizeof(int32_t)};
+
+  auto array = ArrayFromJSON(int32(), "[1, 2, 3, 4, 5]");
+  ASSERT_OK_AND_ASSIGN(auto tensor, array->ToTensor());
+  ASSERT_OK(tensor->Validate());
+
+  EXPECT_EQ(int32(), tensor->type());
+  EXPECT_EQ(shape, tensor->shape());
+  EXPECT_EQ(strides, tensor->strides());
+  EXPECT_TRUE(tensor->is_contiguous());
+  EXPECT_TRUE(
+      TensorFromJSON(int32(), "[1, 2, 3, 4, 5]", shape, 
strides)->Equals(*tensor));
+}
+
+TEST(TestPrimitiveArray, ToTensorSliced) {
+  const std::vector<int64_t> shape = {3};
+  const std::vector<int64_t> strides = {sizeof(int64_t)};
+
+  auto array = ArrayFromJSON(int64(), "[1, 2, 3, 4, 5]")->Slice(2);
+  ASSERT_OK_AND_ASSIGN(auto tensor, array->ToTensor());
+  ASSERT_OK(tensor->Validate());
+
+  EXPECT_EQ(shape, tensor->shape());
+  EXPECT_TRUE(TensorFromJSON(int64(), "[3, 4, 5]", shape, 
strides)->Equals(*tensor));
+}
+
+TEST(TestPrimitiveArray, ToTensorNulls) {
+  // Nulls are ignored, leaving unspecified values in the output tensor.
+  const std::vector<int64_t> shape = {3};
+  auto array = ArrayFromJSON(int32(), "[1, null, 3]");
+
+  // Default behaviour is to not allow nulls
+  ASSERT_RAISES(NotImplemented, array->ToTensor());
+
+  // Nulls are ignored, leaving unspecified values in the output tensor.
+  ASSERT_OK_AND_ASSIGN(auto tensor, array->ToTensor(/* allow_nulls= */ true));
+  ASSERT_OK(tensor->Validate());
+
+  EXPECT_EQ(shape, tensor->shape());

Review Comment:
   We can also check the non-null values here?



##########
python/pyarrow/tests/test_dlpack.py:
##########
@@ -145,6 +145,68 @@ def test_tensor_dlpack(np_type):
     check_dlpack_export(t, expected)
 
 
+def multidim_arrays():
+    np_arr = np.arange(12, dtype=np.int32).reshape(3, 2, 2)
+    values = pa.array(np_arr.ravel(), type=pa.int32())
+    nested_list = pa.FixedSizeListArray.from_arrays(
+        pa.FixedSizeListArray.from_arrays(values, 2), 2)
+    return [
+        pytest.param(nested_list, np_arr, id="nested_fixed_size_list"),
+        pytest.param(
+            pa.FixedShapeTensorArray.from_numpy_ndarray(np_arr),
+            np_arr,
+            id="fixed_shape_tensor",
+        ),
+    ]
+
+
+@check_bytes_allocated
[email protected](('arr', 'expected'), multidim_arrays())
+def test_array_to_tensor_dlpack(arr, expected):
+    if Version(np.__version__) < Version("2.1.0"):
+        pytest.skip("Versioned DLPack capsules require numpy 2.1.0 or later")
+
+    tensor = arr.to_tensor()
+    # A Tensor sharing an Array buffer is immutable, so it can only be exported
+    # through the versioned DLPack protocol.
+    assert not tensor.is_mutable
+    result = np.from_dlpack(DLPackForwarder(tensor, max_version=(1, 0)))

Review Comment:
   Is it possible to also call `np.from_dlpack(arr)` or is that not possible 
yet?



##########
python/pyarrow/array.pxi:
##########
@@ -4949,7 +4974,7 @@ cdef class FixedShapeTensorArray(ExtensionArray):
 
         return self.to_tensor().to_numpy()
 
-    def to_tensor(self):
+    def to_tensor(self, allow_nulls=False):

Review Comment:
   Same here: make it keyword-only?
   
   ```suggestion
       def to_tensor(self, *, allow_nulls=False):
   ```



##########
cpp/src/arrow/array/array_list_test.cc:
##########
@@ -1821,4 +1822,109 @@ TEST_F(TestFixedSizeListArray, FlattenRecursively) {
                     *ArrayFromJSON(value_type_, "[0, 1, null, 3, 7, null, 2, 
5]"));
 }
 
+namespace {
+
+/// The innermost values of the nested fixed size lists.
+std::shared_ptr<Array> LeafValues(std::shared_ptr<Array> array) {
+  while (array->type_id() == Type::FIXED_SIZE_LIST) {
+    const auto& fsl = checked_cast<const FixedSizeListArray&>(*array);
+    array =
+        fsl.values()->Slice(fsl.value_offset(0), array->length() * 
fsl.value_length());
+  }
+  return array;
+}
+
+template <typename T>
+void CheckToTensor(const std::shared_ptr<Array>& array, const 
std::vector<int64_t>& shape,
+                   std::initializer_list<T> values) {
+  const auto value_type = CTypeTraits<T>::type_singleton();
+  ASSERT_OK_AND_ASSIGN(
+      auto expected,
+      Tensor::Make(value_type, Buffer::Wrap(values.begin(), values.size()), 
shape));
+
+  ASSERT_OK_AND_ASSIGN(auto tensor, array->ToTensor());
+  ASSERT_OK(tensor->Validate());
+
+  AssertTypeEqual(*value_type, *tensor->type());
+  ASSERT_EQ(shape, tensor->shape());
+  ASSERT_TRUE(tensor->is_row_major());
+  ASSERT_TRUE(tensor->Equals(*expected));
+
+  // The tensor shares the values buffer, it does not copy
+  const auto leaf = LeafValues(array);
+  ASSERT_EQ(leaf->data()->buffers[1]->data() + leaf->offset() * sizeof(T),
+            tensor->data()->data());
+}
+
+}  // namespace
+
+TEST_F(TestFixedSizeListArray, ToTensor) {
+  auto array = ArrayFromJSON(fixed_size_list(int32(), 3),
+                             "[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 
12]]");
+  CheckToTensor<int32_t>(array, {4, 3}, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 
12});
+
+  // Offset on the list array itself
+  CheckToTensor<int32_t>(array->Slice(2, 2), {2, 3}, {7, 8, 9, 10, 11, 12});
+
+  // Offset on the values array
+  auto values = ArrayFromJSON(int32(), "[1, 2, 3, 4, 5, 6, 7, 8, 
9]")->Slice(3);
+  ASSERT_OK_AND_ASSIGN(auto from_values, 
FixedSizeListArray::FromArrays(values, 3));
+  CheckToTensor<int32_t>(from_values, {2, 3}, {4, 5, 6, 7, 8, 9});
+
+  // Offsets on both the list array and its values
+  CheckToTensor<int32_t>(from_values->Slice(1), {1, 3}, {7, 8, 9});
+}
+
+TEST_F(TestFixedSizeListArray, ToTensorNested) {
+  auto array = ArrayFromJSON(fixed_size_list(fixed_size_list(float32(), 2), 
3), R"([
+    [[1, 2], [3, 4], [5, 6]],
+    [[7, 8], [9, 10], [11, 12]],
+    [[13, 14], [15, 16], [17, 18]]
+  ])");
+  CheckToTensor<float>(array, {3, 3, 2},
+                       {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 
17, 18});
+
+  CheckToTensor<float>(array->Slice(1, 2), {2, 3, 2},
+                       {7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18});
+
+  // Offsets accumulate at every level: the innermost values are offset by 2, 
the
+  // middle lists by 3 * 2 and the outer lists by 1 * 3 * 2.

Review Comment:
   The middle lists do not seem sliced below?



##########
cpp/src/arrow/array/array_test.cc:
##########
@@ -1218,6 +1219,56 @@ TEST(TestPrimitiveArray, CtorNoValidityBitmap) {
   ASSERT_EQ(arr.data()->null_count, 0);
 }
 
+TEST(TestPrimitiveArray, ToTensor) {
+  const std::vector<int64_t> shape = {5};
+  const std::vector<int64_t> strides = {sizeof(int32_t)};
+
+  auto array = ArrayFromJSON(int32(), "[1, 2, 3, 4, 5]");
+  ASSERT_OK_AND_ASSIGN(auto tensor, array->ToTensor());
+  ASSERT_OK(tensor->Validate());
+
+  EXPECT_EQ(int32(), tensor->type());
+  EXPECT_EQ(shape, tensor->shape());
+  EXPECT_EQ(strides, tensor->strides());
+  EXPECT_TRUE(tensor->is_contiguous());
+  EXPECT_TRUE(
+      TensorFromJSON(int32(), "[1, 2, 3, 4, 5]", shape, 
strides)->Equals(*tensor));
+}
+
+TEST(TestPrimitiveArray, ToTensorSliced) {
+  const std::vector<int64_t> shape = {3};
+  const std::vector<int64_t> strides = {sizeof(int64_t)};
+
+  auto array = ArrayFromJSON(int64(), "[1, 2, 3, 4, 5]")->Slice(2);
+  ASSERT_OK_AND_ASSIGN(auto tensor, array->ToTensor());
+  ASSERT_OK(tensor->Validate());
+
+  EXPECT_EQ(shape, tensor->shape());
+  EXPECT_TRUE(TensorFromJSON(int64(), "[3, 4, 5]", shape, 
strides)->Equals(*tensor));
+}
+
+TEST(TestPrimitiveArray, ToTensorNulls) {

Review Comment:
   Can you add a test with a zero-length array?



##########
cpp/src/arrow/array/array_list_test.cc:
##########
@@ -1821,4 +1822,109 @@ TEST_F(TestFixedSizeListArray, FlattenRecursively) {
                     *ArrayFromJSON(value_type_, "[0, 1, null, 3, 7, null, 2, 
5]"));
 }
 
+namespace {
+
+/// The innermost values of the nested fixed size lists.
+std::shared_ptr<Array> LeafValues(std::shared_ptr<Array> array) {
+  while (array->type_id() == Type::FIXED_SIZE_LIST) {
+    const auto& fsl = checked_cast<const FixedSizeListArray&>(*array);
+    array =
+        fsl.values()->Slice(fsl.value_offset(0), array->length() * 
fsl.value_length());
+  }
+  return array;
+}
+
+template <typename T>
+void CheckToTensor(const std::shared_ptr<Array>& array, const 
std::vector<int64_t>& shape,
+                   std::initializer_list<T> values) {
+  const auto value_type = CTypeTraits<T>::type_singleton();
+  ASSERT_OK_AND_ASSIGN(
+      auto expected,
+      Tensor::Make(value_type, Buffer::Wrap(values.begin(), values.size()), 
shape));
+
+  ASSERT_OK_AND_ASSIGN(auto tensor, array->ToTensor());
+  ASSERT_OK(tensor->Validate());
+
+  AssertTypeEqual(*value_type, *tensor->type());
+  ASSERT_EQ(shape, tensor->shape());
+  ASSERT_TRUE(tensor->is_row_major());
+  ASSERT_TRUE(tensor->Equals(*expected));
+
+  // The tensor shares the values buffer, it does not copy
+  const auto leaf = LeafValues(array);
+  ASSERT_EQ(leaf->data()->buffers[1]->data() + leaf->offset() * sizeof(T),
+            tensor->data()->data());
+}
+
+}  // namespace
+
+TEST_F(TestFixedSizeListArray, ToTensor) {
+  auto array = ArrayFromJSON(fixed_size_list(int32(), 3),
+                             "[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 
12]]");
+  CheckToTensor<int32_t>(array, {4, 3}, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 
12});
+
+  // Offset on the list array itself
+  CheckToTensor<int32_t>(array->Slice(2, 2), {2, 3}, {7, 8, 9, 10, 11, 12});
+
+  // Offset on the values array
+  auto values = ArrayFromJSON(int32(), "[1, 2, 3, 4, 5, 6, 7, 8, 
9]")->Slice(3);
+  ASSERT_OK_AND_ASSIGN(auto from_values, 
FixedSizeListArray::FromArrays(values, 3));
+  CheckToTensor<int32_t>(from_values, {2, 3}, {4, 5, 6, 7, 8, 9});
+
+  // Offsets on both the list array and its values
+  CheckToTensor<int32_t>(from_values->Slice(1), {1, 3}, {7, 8, 9});
+}
+
+TEST_F(TestFixedSizeListArray, ToTensorNested) {
+  auto array = ArrayFromJSON(fixed_size_list(fixed_size_list(float32(), 2), 
3), R"([
+    [[1, 2], [3, 4], [5, 6]],
+    [[7, 8], [9, 10], [11, 12]],
+    [[13, 14], [15, 16], [17, 18]]
+  ])");
+  CheckToTensor<float>(array, {3, 3, 2},
+                       {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 
17, 18});
+
+  CheckToTensor<float>(array->Slice(1, 2), {2, 3, 2},
+                       {7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18});
+
+  // Offsets accumulate at every level: the innermost values are offset by 2, 
the
+  // middle lists by 3 * 2 and the outer lists by 1 * 3 * 2.
+  auto values = ArrayFromJSON(float32(), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 
11, 12, 13]")
+                    ->Slice(2, 12);
+  ASSERT_OK_AND_ASSIGN(auto inner, FixedSizeListArray::FromArrays(values, 2));
+  ASSERT_OK_AND_ASSIGN(auto outer, FixedSizeListArray::FromArrays(inner, 3));
+  CheckToTensor<float>(outer, {2, 3, 2}, {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 
13});
+  CheckToTensor<float>(outer->Slice(1), {1, 3, 2}, {8, 9, 10, 11, 12, 13});
+}
+
+TEST_F(TestFixedSizeListArray, ToTensorNulls) {
+  auto array = ArrayFromJSON(fixed_size_list(int32(), 2), "[[1, 2], null, [5, 
null]]");
+
+  // Default behaviour is to not allow nulls
+  ASSERT_RAISES(NotImplemented, array->ToTensor());
+
+  // Nulls are ignored, leaving unspecified values in the output tensor.
+  ASSERT_OK_AND_ASSIGN(auto tensor, array->ToTensor(/* allow_nulls= */ true));
+  ASSERT_OK(tensor->Validate());
+  ASSERT_EQ(std::vector<int64_t>({3, 2}), tensor->shape());
+}
+
+TEST_F(TestFixedSizeListArray, ToTensorZeroLength) {
+  auto array = ArrayFromJSON(fixed_size_list(int64(), 2), "[]");
+  ASSERT_OK_AND_ASSIGN(auto tensor, array->ToTensor());
+  ASSERT_OK(tensor->Validate());
+  ASSERT_EQ(std::vector<int64_t>({0, 2}), tensor->shape());
+}
+
+TEST_F(TestFixedSizeListArray, ToTensorUnsupportedType) {
+  ASSERT_RAISES(
+      NotImplemented,
+      ArrayFromJSON(fixed_size_list(utf8(), 1), R"([["a"], 
["b"]])")->ToTensor());
+  ASSERT_RAISES(
+      Invalid,
+      ArrayFromJSON(fixed_size_list(boolean(), 2), "[[true, 
false]]")->ToTensor());

Review Comment:
   Why do we get `NotImplemented` and `Invalid`? Ideally this should return 
`TypeError`.



##########
cpp/src/arrow/tensor.h:
##########
@@ -33,6 +33,8 @@
 
 namespace arrow {
 
+class Array;

Review Comment:
   Same here: can include `arrow/type_fwd.h` instead.



##########
cpp/src/arrow/array/array_test.cc:
##########
@@ -1218,6 +1219,56 @@ TEST(TestPrimitiveArray, CtorNoValidityBitmap) {
   ASSERT_EQ(arr.data()->null_count, 0);
 }
 
+TEST(TestPrimitiveArray, ToTensor) {
+  const std::vector<int64_t> shape = {5};
+  const std::vector<int64_t> strides = {sizeof(int32_t)};
+
+  auto array = ArrayFromJSON(int32(), "[1, 2, 3, 4, 5]");
+  ASSERT_OK_AND_ASSIGN(auto tensor, array->ToTensor());
+  ASSERT_OK(tensor->Validate());
+
+  EXPECT_EQ(int32(), tensor->type());
+  EXPECT_EQ(shape, tensor->shape());
+  EXPECT_EQ(strides, tensor->strides());
+  EXPECT_TRUE(tensor->is_contiguous());
+  EXPECT_TRUE(
+      TensorFromJSON(int32(), "[1, 2, 3, 4, 5]", shape, 
strides)->Equals(*tensor));
+}
+
+TEST(TestPrimitiveArray, ToTensorSliced) {
+  const std::vector<int64_t> shape = {3};
+  const std::vector<int64_t> strides = {sizeof(int64_t)};
+
+  auto array = ArrayFromJSON(int64(), "[1, 2, 3, 4, 5]")->Slice(2);
+  ASSERT_OK_AND_ASSIGN(auto tensor, array->ToTensor());
+  ASSERT_OK(tensor->Validate());
+
+  EXPECT_EQ(shape, tensor->shape());
+  EXPECT_TRUE(TensorFromJSON(int64(), "[3, 4, 5]", shape, 
strides)->Equals(*tensor));
+}
+
+TEST(TestPrimitiveArray, ToTensorNulls) {
+  // Nulls are ignored, leaving unspecified values in the output tensor.
+  const std::vector<int64_t> shape = {3};
+  auto array = ArrayFromJSON(int32(), "[1, null, 3]");
+
+  // Default behaviour is to not allow nulls
+  ASSERT_RAISES(NotImplemented, array->ToTensor());
+
+  // Nulls are ignored, leaving unspecified values in the output tensor.
+  ASSERT_OK_AND_ASSIGN(auto tensor, array->ToTensor(/* allow_nulls= */ true));
+  ASSERT_OK(tensor->Validate());
+
+  EXPECT_EQ(shape, tensor->shape());
+}
+
+TEST(TestPrimitiveArray, ToTensorUnsupportedType) {
+  auto array = ArrayFromJSON(date32(), "[1, 2, 3]");
+  ASSERT_RAISES(Invalid, array->ToTensor());
+
+  ASSERT_RAISES(NotImplemented, ArrayFromJSON(utf8(), R"(["a"])")->ToTensor());

Review Comment:
   Would be nice to have `TypeError` in both cases too :)



##########
python/pyarrow/array.pxi:
##########
@@ -1841,6 +1841,34 @@ cdef class Array(_PandasConvertible):
             array = array.copy()
         return array
 
+    def to_tensor(self, allow_nulls=False):

Review Comment:
   We probably want to make the boolean flag `allow_nulls` keyword-only to 
discourage bad practices:
   
   ```suggestion
       def to_tensor(self, *, allow_nulls=False):
   ```



##########
python/pyarrow/array.pxi:
##########
@@ -4960,19 +4985,21 @@ cdef class FixedShapeTensorArray(ExtensionArray):
 
         The conversion is zero-copy.
 
+        Parameters
+        ----------
+        allow_nulls : bool, default `False`
+            When true, nulls are ignored, leaving the output tensor with
+            unspecified values where this array has null entries.
+            When false, nulls are rejected.
+
         Returns
         -------
         pyarrow.Tensor
             Tensor representing tensors in the fixed shape tensor array 
concatenated
             along the first dimension.
         """
 
-        cdef:
-            CFixedShapeTensorArray* ext_array = 
<CFixedShapeTensorArray*>(self.ap)
-            CResult[shared_ptr[CTensor]] ctensor
-        with nogil:
-            ctensor = ext_array.ToTensor()
-        return pyarrow_wrap_tensor(GetResultValue(ctensor))
+        return Array.to_tensor(self, allow_nulls=allow_nulls)

Review Comment:
   Can we just inherit this method or do you keep it for the more concrete 
docstring?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to