feat(python): function to inspect a single-chunk Array (#436)
diff --git a/python/src/nanoarrow/_repr_utils.py b/python/src/nanoarrow/_repr_utils.py
index 3209a34..bd090af 100644
--- a/python/src/nanoarrow/_repr_utils.py
+++ b/python/src/nanoarrow/_repr_utils.py
@@ -248,3 +248,46 @@
device_type = f"- device_type: {device.device_type.name} <{device.device_type_id}>"
device_id = f"- device_id: {device.device_id}"
return "\n".join([title_line, device_type, device_id])
+
+
+def array_inspect(array, indent=0, max_char_width=80):
+ array_view = array.view()
+
+ if max_char_width < 20:
+ max_char_width = 20
+
+ indent_str = " " * indent
+ class_label = "ArrowArray"
+ if array._addr() == 0:
+ return f"<{class_label} <NULL>>"
+ elif not array.is_valid():
+ return f"<{class_label} <released>>"
+
+ schema_string = array.schema._to_string(
+ max_chars=max_char_width - indent - 23, recursive=True
+ )
+ lines = [f"<{class_label} {schema_string}>"]
+ for attr in ("length", "offset", "null_count"):
+ attr_repr = repr(getattr(array, attr))
+ lines.append(f"{indent_str}- {attr}: {attr_repr}")
+
+ lines.append(f"{indent_str}- buffers[{array_view.n_buffers}]:")
+ for i, buffer in enumerate(array_view.buffers):
+ buffer_type = array_view.buffer_type(i)
+ lines.append(
+ f"{indent_str} - {buffer_type} "
+ f"<{buffer_view_repr(buffer, max_char_width - indent - 4 - len(buffer))}>"
+ )
+
+ if array.dictionary:
+ dictionary_repr = array_inspect(array.dictionary, indent=indent + 2)
+ lines.append(f"{indent_str}- dictionary: {dictionary_repr}")
+ else:
+ lines.append(f"{indent_str}- dictionary: NULL")
+
+ lines.append(f"{indent_str}- children[{array.n_children}]:")
+ for child in array.children:
+ child_repr = array_inspect(child, indent=indent + 4)
+ lines.append(f"{indent_str} {repr(child.schema.name)}: {child_repr}")
+
+ return "\n".join(lines)
diff --git a/python/src/nanoarrow/array.py b/python/src/nanoarrow/array.py
index af2e3cd..e38dc9c 100644
--- a/python/src/nanoarrow/array.py
+++ b/python/src/nanoarrow/array.py
@@ -490,3 +490,11 @@
def __repr__(self) -> str:
return self.to_string()
+
+ def inspect(self):
+ """
+ Print the details of the array (type, length, offset, buffers,
+ and children arrays).
+ """
+ self._assert_one_chunk("inspect")
+ print(_repr_utils.array_inspect(c_array(self)))
diff --git a/python/tests/test_array.py b/python/tests/test_array.py
index ee88d20..553a635 100644
--- a/python/tests/test_array.py
+++ b/python/tests/test_array.py
@@ -280,3 +280,22 @@
assert len(repr_lines) == 2
assert repr_lines[1].endswith("...")
assert len(repr_lines[1]) == 80
+
+
+def test_array_inspect(capsys):
+ array = na.Array(range(10), na.int32())
+ array.inspect()
+ captured = capsys.readouterr()
+ assert captured.out.startswith("<ArrowArray int32>")
+
+ # with children
+ c_array = na.c_array_from_buffers(
+ na.struct({f"col{i}": na.int32() for i in range(100)}),
+ length=1,
+ buffers=[None],
+ children=[na.c_array([123456], na.int32())] * 100,
+ )
+ array = na.Array(c_array)
+ array.inspect()
+ captured = capsys.readouterr()
+ assert captured.out.startswith("<ArrowArray struct<col0: int32")