Skip to content

Commit 911e19b

Browse files
authored
[#33770] bug fix to prevent ExtensionArrays from crashing Series.__repr__() (#33771)
1 parent 29c820f commit 911e19b

File tree

3 files changed

+64
-3
lines changed

3 files changed

+64
-3
lines changed

doc/source/whatsnew/v1.1.0.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -749,8 +749,8 @@ Sparse
749749
ExtensionArray
750750
^^^^^^^^^^^^^^
751751

752-
- Fixed bug where :meth:`Series.value_counts` would raise on empty input of ``Int64`` dtype (:issue:`33317`)
753-
-
752+
- Fixed bug where :meth:`Serires.value_counts` would raise on empty input of ``Int64`` dtype (:issue:`33317`)
753+
- Fixed bug that caused :meth:`Series.__repr__()` to crash for extension types whose elements are multidimensional arrays (:issue:`33770`).
754754

755755

756756
Other

pandas/io/formats/format.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -1228,7 +1228,11 @@ def _format(x):
12281228

12291229
vals = extract_array(self.values, extract_numpy=True)
12301230

1231-
is_float_type = lib.map_infer(vals, is_float) & notna(vals)
1231+
is_float_type = (
1232+
lib.map_infer(vals, is_float)
1233+
# vals may have 2 or more dimensions
1234+
& np.all(notna(vals), axis=tuple(range(1, len(vals.shape))))
1235+
)
12321236
leading_space = self.leading_space
12331237
if leading_space is None:
12341238
leading_space = is_float_type.any()

pandas/tests/io/formats/test_format.py

+57
Original file line numberDiff line numberDiff line change
@@ -2810,6 +2810,63 @@ def test_to_string_multindex_header(self):
28102810
assert res == exp
28112811

28122812

2813+
class TestGenericArrayFormatter:
2814+
def test_1d_array(self):
2815+
# GenericArrayFormatter is used on types for which there isn't a dedicated
2816+
# formatter. np.bool is one of those types.
2817+
obj = fmt.GenericArrayFormatter(np.array([True, False]))
2818+
res = obj.get_result()
2819+
assert len(res) == 2
2820+
# Results should be right-justified.
2821+
assert res[0] == " True"
2822+
assert res[1] == " False"
2823+
2824+
def test_2d_array(self):
2825+
obj = fmt.GenericArrayFormatter(np.array([[True, False], [False, True]]))
2826+
res = obj.get_result()
2827+
assert len(res) == 2
2828+
assert res[0] == " [True, False]"
2829+
assert res[1] == " [False, True]"
2830+
2831+
def test_3d_array(self):
2832+
obj = fmt.GenericArrayFormatter(
2833+
np.array([[[True, True], [False, False]], [[False, True], [True, False]]])
2834+
)
2835+
res = obj.get_result()
2836+
assert len(res) == 2
2837+
assert res[0] == " [[True, True], [False, False]]"
2838+
assert res[1] == " [[False, True], [True, False]]"
2839+
2840+
def test_2d_extension_type(self):
2841+
# GH 33770
2842+
2843+
# Define a stub extension type with just enough code to run Series.__repr__()
2844+
class DtypeStub(pd.api.extensions.ExtensionDtype):
2845+
@property
2846+
def type(self):
2847+
return np.ndarray
2848+
2849+
@property
2850+
def name(self):
2851+
return "DtypeStub"
2852+
2853+
class ExtTypeStub(pd.api.extensions.ExtensionArray):
2854+
def __len__(self):
2855+
return 2
2856+
2857+
def __getitem__(self, ix):
2858+
return [ix == 1, ix == 0]
2859+
2860+
@property
2861+
def dtype(self):
2862+
return DtypeStub()
2863+
2864+
series = pd.Series(ExtTypeStub())
2865+
res = repr(series) # This line crashed before #33770 was fixed.
2866+
expected = "0 [False True]\n" + "1 [ True False]\n" + "dtype: DtypeStub"
2867+
assert res == expected
2868+
2869+
28132870
def _three_digit_exp():
28142871
return f"{1.7e8:.4g}" == "1.7e+008"
28152872

0 commit comments

Comments
 (0)