Skip to content

Commit 13145f5

Browse files
Merge remote-tracking branch 'upstream/2.3.x' into backport-61995
2 parents 54e6bd1 + 7981a43 commit 13145f5

File tree

6 files changed

+134
-3
lines changed

6 files changed

+134
-3
lines changed

doc/source/whatsnew/v2.3.2.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ Bug fixes
2626
"string" type in the JSON Table Schema for :class:`StringDtype` columns
2727
(:issue:`61889`)
2828
- Boolean operations (``|``, ``&``, ``^``) with bool-dtype objects on the left and :class:`StringDtype` objects on the right now cast the string to bool, with a deprecation warning (:issue:`60234`)
29-
- Fixed ``~Series.str.match`` and ``~Series.str.fullmatch`` with compiled regex
30-
for the Arrow-backed string dtype (:issue:`61964`)
29+
- Fixed ``~Series.str.match``, ``~Series.str.fullmatch`` and ``~Series.str.contains``
30+
with compiled regex for the Arrow-backed string dtype (:issue:`61964`, :issue:`61942`)
3131

3232
.. ---------------------------------------------------------------------------
3333
.. _whatsnew_232.contributors:

pandas/core/arrays/string_arrow.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,8 @@ def _str_contains(
355355
):
356356
if flags:
357357
return super()._str_contains(pat, case, flags, na, regex)
358+
if isinstance(pat, re.Pattern):
359+
pat = pat.pattern
358360

359361
return ArrowStringArrayMixin._str_contains(self, pat, case, flags, na, regex)
360362

pandas/core/indexing.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2575,6 +2575,22 @@ def __getitem__(self, key):
25752575
return super().__getitem__(key)
25762576

25772577
def __setitem__(self, key, value) -> None:
2578+
if not PYPY and using_copy_on_write():
2579+
if sys.getrefcount(self.obj) <= 2:
2580+
warnings.warn(
2581+
_chained_assignment_msg, ChainedAssignmentError, stacklevel=2
2582+
)
2583+
elif not PYPY and not using_copy_on_write():
2584+
ctr = sys.getrefcount(self.obj)
2585+
ref_count = 2
2586+
if not warn_copy_on_write() and _check_cacher(self.obj):
2587+
# see https://github.com/pandas-dev/pandas/pull/56060#discussion_r1399245221
2588+
ref_count += 1
2589+
if ctr <= ref_count:
2590+
warnings.warn(
2591+
_chained_assignment_warning_msg, FutureWarning, stacklevel=2
2592+
)
2593+
25782594
if self.ndim == 2 and not self._axes_are_unique:
25792595
# GH#33041 fall back to .loc
25802596
if not isinstance(key, tuple) or not all(is_scalar(x) for x in key):
@@ -2599,6 +2615,25 @@ def _convert_key(self, key):
25992615
raise ValueError("iAt based indexing can only have integer indexers")
26002616
return key
26012617

2618+
def __setitem__(self, key, value) -> None:
2619+
if not PYPY and using_copy_on_write():
2620+
if sys.getrefcount(self.obj) <= 2:
2621+
warnings.warn(
2622+
_chained_assignment_msg, ChainedAssignmentError, stacklevel=2
2623+
)
2624+
elif not PYPY and not using_copy_on_write():
2625+
ctr = sys.getrefcount(self.obj)
2626+
ref_count = 2
2627+
if not warn_copy_on_write() and _check_cacher(self.obj):
2628+
# see https://github.com/pandas-dev/pandas/pull/56060#discussion_r1399245221
2629+
ref_count += 1
2630+
if ctr <= ref_count:
2631+
warnings.warn(
2632+
_chained_assignment_warning_msg, FutureWarning, stacklevel=2
2633+
)
2634+
2635+
return super().__setitem__(key, value)
2636+
26022637

26032638
def _tuplify(ndim: int, loc: Hashable) -> tuple[Hashable | slice, ...]:
26042639
"""

pandas/tests/copy_view/test_chained_assignment_deprecation.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,3 +172,83 @@ def test_frame_setitem(indexer, using_copy_on_write):
172172
with option_context("chained_assignment", "warn"):
173173
with tm.raises_chained_assignment_error(extra_warnings=extra_warnings):
174174
df[0:3][indexer] = 10
175+
176+
177+
@pytest.mark.parametrize(
178+
"indexer", [0, [0, 1], slice(0, 2), np.array([True, False, True])]
179+
)
180+
def test_series_iloc_setitem(indexer):
181+
df = DataFrame({"a": [1, 2, 3], "b": 1})
182+
183+
with option_context("chained_assignment", "warn"):
184+
with tm.raises_chained_assignment_error():
185+
df["a"].iloc[indexer] = 0
186+
187+
188+
@pytest.mark.parametrize(
189+
"indexer", [0, [0, 1], slice(0, 2), np.array([True, False, True])]
190+
)
191+
def test_frame_iloc_setitem(indexer, using_copy_on_write):
192+
df = DataFrame({"a": [1, 2, 3, 4, 5], "b": 1})
193+
194+
extra_warnings = () if using_copy_on_write else (SettingWithCopyWarning,)
195+
196+
with option_context("chained_assignment", "warn"):
197+
with tm.raises_chained_assignment_error(extra_warnings=extra_warnings):
198+
df[0:3].iloc[indexer] = 10
199+
200+
201+
@pytest.mark.parametrize(
202+
"indexer", [0, [0, 1], slice(0, 2), np.array([True, False, True])]
203+
)
204+
def test_series_loc_setitem(indexer):
205+
df = DataFrame({"a": [1, 2, 3], "b": 1})
206+
207+
with option_context("chained_assignment", "warn"):
208+
with tm.raises_chained_assignment_error():
209+
df["a"].loc[indexer] = 0
210+
211+
212+
@pytest.mark.parametrize(
213+
"indexer", [0, [0, 1], (0, "a"), slice(0, 2), np.array([True, False, True])]
214+
)
215+
def test_frame_loc_setitem(indexer, using_copy_on_write):
216+
df = DataFrame({"a": [1, 2, 3, 4, 5], "b": 1})
217+
218+
extra_warnings = () if using_copy_on_write else (SettingWithCopyWarning,)
219+
220+
with option_context("chained_assignment", "warn"):
221+
with tm.raises_chained_assignment_error(extra_warnings=extra_warnings):
222+
df[0:3].loc[indexer] = 10
223+
224+
225+
def test_series_at_setitem():
226+
df = DataFrame({"a": [1, 2, 3], "b": 1})
227+
228+
with option_context("chained_assignment", "warn"):
229+
with tm.raises_chained_assignment_error():
230+
df["a"].at[0] = 0
231+
232+
233+
def test_frame_at_setitem():
234+
df = DataFrame({"a": [1, 2, 3, 4, 5], "b": 1})
235+
236+
with option_context("chained_assignment", "warn"):
237+
with tm.raises_chained_assignment_error():
238+
df[0:3].at[0, "a"] = 10
239+
240+
241+
def test_series_iat_setitem():
242+
df = DataFrame({"a": [1, 2, 3], "b": 1})
243+
244+
with option_context("chained_assignment", "warn"):
245+
with tm.raises_chained_assignment_error():
246+
df["a"].iat[0] = 0
247+
248+
249+
def test_frame_iat_setitem():
250+
df = DataFrame({"a": [1, 2, 3, 4, 5], "b": 1})
251+
252+
with option_context("chained_assignment", "warn"):
253+
with tm.raises_chained_assignment_error():
254+
df[0:3].iat[0, 0] = 10

pandas/tests/strings/test_find_replace.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,19 @@ def test_contains_nan(any_string_dtype):
290290
tm.assert_series_equal(result, expected)
291291

292292

293+
def test_contains_compiled_regex(any_string_dtype):
294+
# GH#61942
295+
ser = Series(["foo", "bar", "baz"], dtype=any_string_dtype)
296+
pat = re.compile("ba.")
297+
result = ser.str.contains(pat)
298+
299+
expected_dtype = (
300+
np.bool_ if is_object_or_nan_string_dtype(any_string_dtype) else "boolean"
301+
)
302+
expected = Series([False, True, True], dtype=expected_dtype)
303+
tm.assert_series_equal(result, expected)
304+
305+
293306
# --------------------------------------------------------------------------------------
294307
# str.startswith
295308
# --------------------------------------------------------------------------------------

pandas/tests/tslibs/test_parsing.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,8 @@ def test_hypothesis_delimited_date(
395395
request.applymarker(
396396
pytest.mark.xfail(
397397
reason="parse_datetime_string cannot reliably tell whether "
398-
"e.g. %m.%Y is a float or a date"
398+
"e.g. %m.%Y is a float or a date",
399+
strict=False,
399400
)
400401
)
401402
date_string = test_datetime.strftime(date_format.replace(" ", delimiter))

0 commit comments

Comments
 (0)