|
1 | 1 | from __future__ import annotations |
2 | 2 |
|
| 3 | +from functools import partial |
3 | 4 | from typing import ( |
4 | 5 | TYPE_CHECKING, |
5 | 6 | Literal, |
6 | 7 | ) |
7 | 8 |
|
8 | 9 | import numpy as np |
9 | 10 |
|
10 | | -from pandas.compat import pa_version_under10p1 |
| 11 | +from pandas.compat import ( |
| 12 | + pa_version_under10p1, |
| 13 | + pa_version_under17p0, |
| 14 | +) |
11 | 15 |
|
12 | 16 | from pandas.core.dtypes.missing import isna |
13 | 17 |
|
@@ -49,7 +53,19 @@ def _str_pad( |
49 | 53 | elif side == "right": |
50 | 54 | pa_pad = pc.utf8_rpad |
51 | 55 | elif side == "both": |
52 | | - pa_pad = pc.utf8_center |
| 56 | + if pa_version_under17p0: |
| 57 | + # GH#59624 fall back to object dtype |
| 58 | + from pandas import array |
| 59 | + |
| 60 | + obj_arr = self.astype(object, copy=False) # type: ignore[attr-defined] |
| 61 | + obj = array(obj_arr, dtype=object) |
| 62 | + result = obj._str_pad(width, side, fillchar) # type: ignore[attr-defined] |
| 63 | + return type(self)._from_sequence(result, dtype=self.dtype) # type: ignore[attr-defined] |
| 64 | + else: |
| 65 | + # GH#54792 |
| 66 | + # https://github.com/apache/arrow/issues/15053#issuecomment-2317032347 |
| 67 | + lean_left = (width % 2) == 0 |
| 68 | + pa_pad = partial(pc.utf8_center, lean_left_on_odd_padding=lean_left) |
53 | 69 | else: |
54 | 70 | raise ValueError( |
55 | 71 | f"Invalid side: {side}. Side must be one of 'left', 'right', 'both'" |
@@ -138,3 +154,54 @@ def _str_endswith(self, pat: str | tuple[str, ...], na: Scalar | None = None): |
138 | 154 | if not isna(na): # pyright: ignore [reportGeneralTypeIssues] |
139 | 155 | result = result.fill_null(na) |
140 | 156 | return self._convert_bool_result(result) |
| 157 | + |
| 158 | + def _str_isalnum(self): |
| 159 | + result = pc.utf8_is_alnum(self._pa_array) |
| 160 | + return self._convert_bool_result(result) |
| 161 | + |
| 162 | + def _str_isalpha(self): |
| 163 | + result = pc.utf8_is_alpha(self._pa_array) |
| 164 | + return self._convert_bool_result(result) |
| 165 | + |
| 166 | + def _str_isdecimal(self): |
| 167 | + result = pc.utf8_is_decimal(self._pa_array) |
| 168 | + return self._convert_bool_result(result) |
| 169 | + |
| 170 | + def _str_isdigit(self): |
| 171 | + result = pc.utf8_is_digit(self._pa_array) |
| 172 | + return self._convert_bool_result(result) |
| 173 | + |
| 174 | + def _str_islower(self): |
| 175 | + result = pc.utf8_is_lower(self._pa_array) |
| 176 | + return self._convert_bool_result(result) |
| 177 | + |
| 178 | + def _str_isnumeric(self): |
| 179 | + result = pc.utf8_is_numeric(self._pa_array) |
| 180 | + return self._convert_bool_result(result) |
| 181 | + |
| 182 | + def _str_isspace(self): |
| 183 | + result = pc.utf8_is_space(self._pa_array) |
| 184 | + return self._convert_bool_result(result) |
| 185 | + |
| 186 | + def _str_istitle(self): |
| 187 | + result = pc.utf8_is_title(self._pa_array) |
| 188 | + return self._convert_bool_result(result) |
| 189 | + |
| 190 | + def _str_isupper(self): |
| 191 | + result = pc.utf8_is_upper(self._pa_array) |
| 192 | + return self._convert_bool_result(result) |
| 193 | + |
| 194 | + def _str_contains( |
| 195 | + self, pat, case: bool = True, flags: int = 0, na=None, regex: bool = True |
| 196 | + ): |
| 197 | + if flags: |
| 198 | + raise NotImplementedError(f"contains not implemented with {flags=}") |
| 199 | + |
| 200 | + if regex: |
| 201 | + pa_contains = pc.match_substring_regex |
| 202 | + else: |
| 203 | + pa_contains = pc.match_substring |
| 204 | + result = pa_contains(self._pa_array, pat, ignore_case=not case) |
| 205 | + if not isna(na): # pyright: ignore [reportGeneralTypeIssues] |
| 206 | + result = result.fill_null(na) |
| 207 | + return self._convert_bool_result(result) |
0 commit comments