Skip to content

Commit 0eef0a3

Browse files
committed
refactor
1 parent 9cb9a46 commit 0eef0a3

2 files changed

Lines changed: 67 additions & 76 deletions

File tree

python/pyarrow/array.pxi

Lines changed: 45 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -4705,17 +4705,7 @@ cdef class FixedShapeTensorArray(ExtensionArray):
47054705
"Cannot convert 1D array or scalar to fixed shape tensor array")
47064706
if np.prod(obj.shape) == 0:
47074707
raise ValueError("Expected a non-empty ndarray")
4708-
if dim_names is not None:
4709-
if not isinstance(dim_names, Sequence):
4710-
raise TypeError("dim_names must be a tuple or list")
4711-
if len(dim_names) != len(obj.shape[1:]):
4712-
raise ValueError(
4713-
(f"The length of dim_names ({len(dim_names)}) does not match"
4714-
f"the number of tensor dimensions ({len(obj.shape[1:])})."
4715-
)
4716-
)
4717-
if not all(isinstance(name, str) for name in dim_names):
4718-
raise TypeError("Each element of dim_names must be a string")
4708+
_validate_dim_names(dim_names, len(obj.shape[1:]))
47194709

47204710
permutation = (-np.array(obj.strides)).argsort(kind='stable')
47214711
if permutation[0] != 0:
@@ -4874,6 +4864,44 @@ cdef class Bool8Array(ExtensionArray):
48744864
return Bool8Array.from_storage(storage_arr)
48754865

48764866

4867+
def _check_sequence_param(value, ndim, name):
4868+
if value is None:
4869+
return False
4870+
if not isinstance(value, Sequence):
4871+
raise TypeError(f"{name} must be a tuple or list")
4872+
if len(value) != ndim:
4873+
raise ValueError(
4874+
(f"The length of {name} ({len(value)}) does not match"
4875+
f" the number of tensor dimensions ({ndim})."))
4876+
return True
4877+
4878+
4879+
def _validate_dim_names(dim_names, ndim):
4880+
if not _check_sequence_param(dim_names, ndim, "dim_names"):
4881+
return
4882+
if not all(isinstance(name, str) for name in dim_names):
4883+
raise TypeError("Each element of dim_names must be a string")
4884+
4885+
4886+
def _validate_permutation(permutation, ndim):
4887+
if not _check_sequence_param(permutation, ndim, "permutation"):
4888+
return None
4889+
normalized = [int(x) for x in permutation]
4890+
if sorted(normalized) != list(range(ndim)):
4891+
raise ValueError(
4892+
"permutation must contain each dimension index exactly once")
4893+
return normalized
4894+
4895+
4896+
def _validate_uniform_shape(uniform_shape, ndim):
4897+
if not _check_sequence_param(uniform_shape, ndim, "uniform_shape"):
4898+
return
4899+
for value in uniform_shape:
4900+
if value is not None and value < 0:
4901+
raise ValueError(
4902+
"uniform_shape must contain non-negative values")
4903+
4904+
48774905
cdef class VariableShapeTensorArray(ExtensionArray):
48784906
"""
48794907
Concrete class for variable shape tensor extension arrays.
@@ -4981,39 +5009,9 @@ cdef class VariableShapeTensorArray(ExtensionArray):
49815009
if ndim < 0:
49825010
raise ValueError("ndim must be non-negative")
49835011

4984-
if dim_names is not None:
4985-
if not isinstance(dim_names, Sequence):
4986-
raise TypeError("dim_names must be a tuple or list")
4987-
if len(dim_names) != ndim:
4988-
raise ValueError(
4989-
(f"The length of dim_names ({len(dim_names)}) does not match"
4990-
f" the number of tensor dimensions ({ndim})."))
4991-
if not all(isinstance(name, str) for name in dim_names):
4992-
raise TypeError("Each element of dim_names must be a string")
4993-
4994-
if permutation is not None:
4995-
if not isinstance(permutation, Sequence):
4996-
raise TypeError("permutation must be a tuple or list")
4997-
permutation = [int(x) for x in permutation]
4998-
if len(permutation) != ndim:
4999-
raise ValueError(
5000-
(f"The length of permutation ({len(permutation)}) does not match"
5001-
f" the number of tensor dimensions ({ndim})."))
5002-
if sorted(permutation) != list(range(ndim)):
5003-
raise ValueError(
5004-
"permutation must contain each dimension index exactly once")
5005-
5006-
if uniform_shape is not None:
5007-
if not isinstance(uniform_shape, Sequence):
5008-
raise TypeError("uniform_shape must be a tuple or list")
5009-
if len(uniform_shape) != ndim:
5010-
raise ValueError(
5011-
(f"The length of uniform_shape ({len(uniform_shape)}) does not match"
5012-
f" the number of tensor dimensions ({ndim})."))
5013-
for value in uniform_shape:
5014-
if value is not None and value < 0:
5015-
raise ValueError(
5016-
"uniform_shape must contain non-negative values")
5012+
_validate_dim_names(dim_names, ndim)
5013+
permutation = _validate_permutation(permutation, ndim)
5014+
_validate_uniform_shape(uniform_shape, ndim)
50175015

50185016
shape_type = list_(int32(), list_size=ndim)
50195017
values = array([], list_(value_type))
@@ -5055,29 +5053,8 @@ cdef class VariableShapeTensorArray(ExtensionArray):
50555053
if arr.ndim != ndim:
50565054
raise ValueError(f"obj[{i}] has ndim {arr.ndim}; expected {ndim}")
50575055

5058-
if dim_names is not None:
5059-
if not isinstance(dim_names, Sequence):
5060-
raise TypeError("dim_names must be a tuple or list")
5061-
if len(dim_names) != ndim:
5062-
raise ValueError(
5063-
(f"The length of dim_names ({len(dim_names)}) does not match"
5064-
f" the number of tensor dimensions ({ndim})."))
5065-
if not all(isinstance(name, str) for name in dim_names):
5066-
raise TypeError("Each element of dim_names must be a string")
5067-
5068-
if permutation is not None:
5069-
if not isinstance(permutation, Sequence):
5070-
raise TypeError("permutation must be a tuple or list")
5071-
normalized_permutation = [int(x) for x in permutation]
5072-
if len(normalized_permutation) != ndim:
5073-
raise ValueError(
5074-
(f"The length of permutation ({len(normalized_permutation)}) does not match"
5075-
f" the number of tensor dimensions ({ndim})."))
5076-
if sorted(normalized_permutation) != list(range(ndim)):
5077-
raise ValueError(
5078-
"permutation must contain each dimension index exactly once")
5079-
else:
5080-
normalized_permutation = None
5056+
_validate_dim_names(dim_names, ndim)
5057+
normalized_permutation = _validate_permutation(permutation, ndim)
50815058

50825059
for i, arr in enumerate(arrays):
50835060
ndarray_permutation = (-np.array(arr.strides)).argsort(kind="stable")
@@ -5099,17 +5076,9 @@ cdef class VariableShapeTensorArray(ExtensionArray):
50995076
]
51005077

51015078
if uniform_shape is not None:
5102-
if not isinstance(uniform_shape, Sequence):
5103-
raise TypeError("uniform_shape must be a tuple or list")
5104-
if len(uniform_shape) != ndim:
5105-
raise ValueError(
5106-
(f"The length of uniform_shape ({len(uniform_shape)}) does not match"
5107-
f" the number of tensor dimensions ({ndim})."))
5079+
_validate_uniform_shape(uniform_shape, ndim)
51085080
for i, value in enumerate(uniform_shape):
51095081
if value is not None:
5110-
if value < 0:
5111-
raise ValueError(
5112-
"uniform_shape must contain non-negative values")
51135082
if any(shape[i] != value for shape in shape_rows):
51145083
raise ValueError(
51155084
(f"uniform_shape[{i}]={value} does not match input shape "

python/pyarrow/tests/test_extension_type.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1903,6 +1903,28 @@ def test_variable_shape_tensor_row_split_adapters():
19031903
ndarray_list[1], np.array([[7], [8]], dtype=np.int32))
19041904

19051905

1906+
@pytest.mark.numpy
1907+
def test_variable_shape_tensor_to_numpy_ndarray_list_with_nulls():
1908+
tensor_type = pa.variable_shape_tensor(pa.int32(), 2)
1909+
1910+
data = pa.array([[1, 2, 3, 4, 5, 6], [10, 20], [7, 8]], pa.list_(pa.int32()))
1911+
shapes = pa.array([[2, 3], [1, 2], [2, 1]],
1912+
pa.list_(pa.int32(), 2))
1913+
mask = pa.array([False, True, False])
1914+
1915+
storage = pa.StructArray.from_arrays(
1916+
[data, shapes], names=["data", "shape"], mask=mask)
1917+
arr = pa.ExtensionArray.from_storage(tensor_type, storage)
1918+
1919+
result = arr.to_numpy_ndarray_list()
1920+
assert len(result) == 3
1921+
np.testing.assert_array_equal(
1922+
result[0], np.array([[1, 2, 3], [4, 5, 6]], dtype=np.int32))
1923+
assert result[1] is None
1924+
np.testing.assert_array_equal(
1925+
result[2], np.array([[7], [8]], dtype=np.int32))
1926+
1927+
19061928
@pytest.mark.numpy
19071929
def test_variable_shape_tensor_metadata_roundtrip_from_numpy():
19081930
ndarray_list = [

0 commit comments

Comments
 (0)