From b179002ae494538d950394f5fa4c8b664839bcf1 Mon Sep 17 00:00:00 2001 From: Janosh Riebesell Date: Tue, 31 Aug 2021 13:22:42 +0100 Subject: [PATCH 01/12] add Series.str.remove(pre|suf)fix (new in Python 3.9) (pandas-dev#36944) --- doc/source/whatsnew/v1.4.0.rst | 1 + pandas/core/strings/accessor.py | 59 ++++++++++++++++++++++++++++ pandas/core/strings/base.py | 8 ++++ pandas/core/strings/object_array.py | 26 +++++++++++- pandas/tests/strings/conftest.py | 2 + pandas/tests/strings/test_strings.py | 20 ++++++++++ 6 files changed, 115 insertions(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.4.0.rst b/doc/source/whatsnew/v1.4.0.rst index 7b1f44d25d5ae..c57da15f2e7bb 100644 --- a/doc/source/whatsnew/v1.4.0.rst +++ b/doc/source/whatsnew/v1.4.0.rst @@ -96,6 +96,7 @@ Other enhancements - :meth:`Series.ewm`, :meth:`DataFrame.ewm`, now support a ``method`` argument with a ``'table'`` option that performs the windowing operation over an entire :class:`DataFrame`. See :ref:`Window Overview ` for performance and functional benefits (:issue:`42273`) - :meth:`.GroupBy.cummin` and :meth:`.GroupBy.cummax` now support the argument ``skipna`` (:issue:`34047`) - :meth:`read_table` now supports the argument ``storage_options`` (:issue:`39167`) +- Add :meth:`Series.str.removeprefix` and :meth:`Series.str.removesuffix` introduced in Python 3.9 to remove pre-/suffixes from string-type :class:`Series`. .. --------------------------------------------------------------------------- diff --git a/pandas/core/strings/accessor.py b/pandas/core/strings/accessor.py index 55a55d0111397..b1ac57e1dead3 100644 --- a/pandas/core/strings/accessor.py +++ b/pandas/core/strings/accessor.py @@ -1907,6 +1907,65 @@ def rstrip(self, to_strip=None): result = self._data.array._str_rstrip(to_strip) return self._wrap_result(result) + _shared_docs[ + "str_remove" + ] = r""" + Remove a %(side)s from an object series. If the %(side)s is not present, + the original string will be returned. + + Parameters + ---------- + %(side)s: str + %(side)s to remove. + + Returns + ------- + Series/Index: object + The Series or Index with given %(side)s removed. + + See also + -------- + Series.str.remove%(other_side)s : Remove a %(other_side)s from an object series. + + Examples + -------- + >>> s = pd.Series(["str_foo", "str_bar", "no_prefix"]) + >>> s + 0 str_foo + 1 str_bar + 2 no_prefix + dtype: object + >>> s.str.removeprefix("str_") + 0 foo + 1 bar + 2 no_prefix + dtype: object + + >>> s = pd.Series(["foo_str", "bar_str", "no_suffix"]) + >>> s + 0 foo_str + 1 bar_str + 2 no_prefix + dtype: object + >>> s.str.removesuffix("_str") + 0 foo + 1 bar + 2 no_prefix + dtype: object + """ + + @Appender(_shared_docs["str_remove"] % {"side": "prefix", "other_side": "suffix"}) + @forbid_nonstring_types(["bytes"]) + def removeprefix(self, prefix): + result = self._data.array._str_removeprefix(prefix) + return self._wrap_result(result) + + @Appender(_shared_docs["str_remove"] % {"side": "suffix", "other_side": "prefix"}) + @forbid_nonstring_types(["bytes"]) + def removesuffix(self, suffix): + result = self._data.array._str_removesuffix(suffix) + return self._wrap_result(result) + @forbid_nonstring_types(["bytes"]) def wrap(self, width, **kwargs): r""" diff --git a/pandas/core/strings/base.py b/pandas/core/strings/base.py index cd71844d3b527..8551e4fa590b5 100644 --- a/pandas/core/strings/base.py +++ b/pandas/core/strings/base.py @@ -223,6 +223,14 @@ def _str_lstrip(self, to_strip=None): def _str_rstrip(self, to_strip=None): pass + @abc.abstractmethod + def _str_removeprefix(self, prefix): + pass + + @abc.abstractmethod + def _str_removesuffix(self, suffix): + pass + @abc.abstractmethod def _str_split(self, pat=None, n=-1, expand=False): pass diff --git a/pandas/core/strings/object_array.py b/pandas/core/strings/object_array.py index 02bdb7f181583..ce51d9b2203e8 100644 --- a/pandas/core/strings/object_array.py +++ b/pandas/core/strings/object_array.py @@ -36,7 +36,7 @@ def _str_map( self, f, na_value=None, dtype: Dtype | None = None, convert: bool = True ): """ - Map a callable over valid element of the array. + Map a callable over valid elements of the array. Parameters ---------- @@ -414,6 +414,30 @@ def _str_lstrip(self, to_strip=None): def _str_rstrip(self, to_strip=None): return self._str_map(lambda x: x.rstrip(to_strip)) + def _str_removeprefix(self, prefix): + # outstanding question on whether to use native methods for users + # on Python 3.9+ https://git.io/JE9QK, in which case we could do + # return self._str_map(str.removeprefix) + + def removeprefix(text: str) -> str: + if text.startswith(prefix): + return text[len(prefix) :] + return text + + return self._str_map(removeprefix) + + def _str_removesuffix(self, suffix): + # this could be used on Python 3.9+ + # f = lambda x: x.removesuffix(suffix) + # return self._str_map(str.removesuffix) + + def removesuffix(text: str) -> str: + if text.endswith(suffix): + return text[: len(suffix)] + return text + + return self._str_map(removesuffix) + def _str_extract(self, pat: str, flags: int = 0, expand: bool = True): regex = re.compile(pat, flags=flags) na_value = self._str_na_value diff --git a/pandas/tests/strings/conftest.py b/pandas/tests/strings/conftest.py index 4fedbee91f649..ab277e87e8f81 100644 --- a/pandas/tests/strings/conftest.py +++ b/pandas/tests/strings/conftest.py @@ -46,6 +46,8 @@ ("startswith", ("a",), {}), ("startswith", ("a",), {"na": True}), ("startswith", ("a",), {"na": False}), + ("removeprefix", ("a",)), + ("removesuffix", ("a",)), # translating unicode points of "a" to "d" ("translate", ({97: 100},), {}), ("wrap", (2,), {}), diff --git a/pandas/tests/strings/test_strings.py b/pandas/tests/strings/test_strings.py index 98f3fc859976e..2a945140c2fcf 100644 --- a/pandas/tests/strings/test_strings.py +++ b/pandas/tests/strings/test_strings.py @@ -535,6 +535,26 @@ def test_strip_lstrip_rstrip_args(any_string_dtype): tm.assert_series_equal(result, expected) +def test_remove_suffix_prefix(any_string_dtype): + ser = Series(["xxABCxx", "xx BNSD", "LDFJH xx"], dtype=any_string_dtype) + + result = ser.str.removeprefix("x") + expected = Series(["xABCxx", "x BNSD", "LDFJH xx"], dtype=any_string_dtype) + tm.assert_series_equal(result, expected) + + result = ser.str.removeprefix("xx ") + expected = Series(["xxABCxx", "BNSD", "LDFJH xx"], dtype=any_string_dtype) + tm.assert_series_equal(result, expected) + + result = ser.str.removesuffix("x") + expected = Series(["xxABCx", "xx BNSD", "LDFJH x"], dtype=any_string_dtype) + tm.assert_series_equal(result, expected) + + result = ser.str.removesuffix(" xx") + expected = Series(["xxABCxx", "xx BNSD", "LDFJH"], dtype=any_string_dtype) + tm.assert_series_equal(result, expected) + + def test_string_slice_get_syntax(any_string_dtype): ser = Series( ["YYY", "B", "C", "YYYYYYbYYY", "BYYYcYYY", np.nan, "CYYYBYYY", "dog", "cYYYt"], From 39d5f2a864f2ca17facd5e9e11ecf25a8738490d Mon Sep 17 00:00:00 2001 From: Janosh Riebesell Date: Tue, 31 Aug 2021 14:23:28 +0100 Subject: [PATCH 02/12] add arg type hints --- pandas/core/strings/base.py | 5 +++-- pandas/core/strings/object_array.py | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pandas/core/strings/base.py b/pandas/core/strings/base.py index 8551e4fa590b5..7915f19c3c65a 100644 --- a/pandas/core/strings/base.py +++ b/pandas/core/strings/base.py @@ -5,6 +5,7 @@ import re import numpy as np +import numpy.typing as npt from pandas._typing import Scalar @@ -224,11 +225,11 @@ def _str_rstrip(self, to_strip=None): pass @abc.abstractmethod - def _str_removeprefix(self, prefix): + def _str_removeprefix(self, prefix: str) -> npt.NDArray[np.str_]: pass @abc.abstractmethod - def _str_removesuffix(self, suffix): + def _str_removesuffix(self, suffix: str) -> npt.NDArray[np.str_]: pass @abc.abstractmethod diff --git a/pandas/core/strings/object_array.py b/pandas/core/strings/object_array.py index ce51d9b2203e8..7cc1124f58960 100644 --- a/pandas/core/strings/object_array.py +++ b/pandas/core/strings/object_array.py @@ -6,6 +6,7 @@ import unicodedata import numpy as np +import numpy.typing as npt import pandas._libs.lib as lib import pandas._libs.missing as libmissing @@ -414,7 +415,7 @@ def _str_lstrip(self, to_strip=None): def _str_rstrip(self, to_strip=None): return self._str_map(lambda x: x.rstrip(to_strip)) - def _str_removeprefix(self, prefix): + def _str_removeprefix(self, prefix: str) -> npt.NDArray[np.str_]: # outstanding question on whether to use native methods for users # on Python 3.9+ https://git.io/JE9QK, in which case we could do # return self._str_map(str.removeprefix) @@ -426,7 +427,7 @@ def removeprefix(text: str) -> str: return self._str_map(removeprefix) - def _str_removesuffix(self, suffix): + def _str_removesuffix(self, suffix: str) -> npt.NDArray[np.str_]: # this could be used on Python 3.9+ # f = lambda x: x.removesuffix(suffix) # return self._str_map(str.removesuffix) From 422bc143f418647ac8774583254dd903d14c91cd Mon Sep 17 00:00:00 2001 From: Janosh Riebesell Date: Tue, 31 Aug 2021 14:24:35 +0100 Subject: [PATCH 03/12] parametrize test cases --- pandas/tests/strings/test_strings.py | 32 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/pandas/tests/strings/test_strings.py b/pandas/tests/strings/test_strings.py index 2a945140c2fcf..ba942d740ac8b 100644 --- a/pandas/tests/strings/test_strings.py +++ b/pandas/tests/strings/test_strings.py @@ -535,24 +535,24 @@ def test_strip_lstrip_rstrip_args(any_string_dtype): tm.assert_series_equal(result, expected) -def test_remove_suffix_prefix(any_string_dtype): - ser = Series(["xxABCxx", "xx BNSD", "LDFJH xx"], dtype=any_string_dtype) - - result = ser.str.removeprefix("x") - expected = Series(["xABCxx", "x BNSD", "LDFJH xx"], dtype=any_string_dtype) - tm.assert_series_equal(result, expected) - - result = ser.str.removeprefix("xx ") - expected = Series(["xxABCxx", "BNSD", "LDFJH xx"], dtype=any_string_dtype) - tm.assert_series_equal(result, expected) +@pytest.mark.parametrize( + "prefix, expected", [("a", ["b", " b c", "bc"]), ("ab", ["", "a b c", "bc"])] +) +def test_removeprefix(any_string_dtype, prefix, expected): + ser = Series(["ab", "a b c", "bc"], dtype=any_string_dtype) + result = ser.str.removeprefix(prefix) + ser_expected = Series(expected, dtype=any_string_dtype) + tm.assert_series_equal(result, ser_expected) - result = ser.str.removesuffix("x") - expected = Series(["xxABCx", "xx BNSD", "LDFJH x"], dtype=any_string_dtype) - tm.assert_series_equal(result, expected) - result = ser.str.removesuffix(" xx") - expected = Series(["xxABCxx", "xx BNSD", "LDFJH"], dtype=any_string_dtype) - tm.assert_series_equal(result, expected) +@pytest.mark.parametrize( + "suffix, expected", [("c", ["ab", "a b ", "b"]), ("bc", ["ab", "a b c", ""])] +) +def test_removesuffix(any_string_dtype, suffix, expected): + ser = Series(["ab", "a b c", "bc"], dtype=any_string_dtype) + result = ser.str.removesuffix(suffix) + ser_expected = Series(expected, dtype=any_string_dtype) + tm.assert_series_equal(result, ser_expected) def test_string_slice_get_syntax(any_string_dtype): From afd46828d3b3360c10f2ad2373e74f0c6ba61570 Mon Sep 17 00:00:00 2001 From: Janosh Riebesell Date: Sat, 4 Sep 2021 07:48:07 +0100 Subject: [PATCH 04/12] change type annotations from np.typing to Series --- pandas/core/strings/base.py | 7 ++++--- pandas/core/strings/object_array.py | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/pandas/core/strings/base.py b/pandas/core/strings/base.py index 7915f19c3c65a..cd1ff358a1848 100644 --- a/pandas/core/strings/base.py +++ b/pandas/core/strings/base.py @@ -5,10 +5,11 @@ import re import numpy as np -import numpy.typing as npt from pandas._typing import Scalar +from pandas.core.series import Series + class BaseStringArrayMethods(abc.ABC): """ @@ -225,11 +226,11 @@ def _str_rstrip(self, to_strip=None): pass @abc.abstractmethod - def _str_removeprefix(self, prefix: str) -> npt.NDArray[np.str_]: + def _str_removeprefix(self, prefix: str) -> Series: pass @abc.abstractmethod - def _str_removesuffix(self, suffix: str) -> npt.NDArray[np.str_]: + def _str_removesuffix(self, suffix: str) -> Series: pass @abc.abstractmethod diff --git a/pandas/core/strings/object_array.py b/pandas/core/strings/object_array.py index 7cc1124f58960..3bb33915caa0e 100644 --- a/pandas/core/strings/object_array.py +++ b/pandas/core/strings/object_array.py @@ -6,7 +6,6 @@ import unicodedata import numpy as np -import numpy.typing as npt import pandas._libs.lib as lib import pandas._libs.missing as libmissing @@ -19,6 +18,7 @@ from pandas.core.dtypes.common import is_scalar from pandas.core.dtypes.missing import isna +from pandas.core.series import Series from pandas.core.strings.base import BaseStringArrayMethods @@ -415,7 +415,7 @@ def _str_lstrip(self, to_strip=None): def _str_rstrip(self, to_strip=None): return self._str_map(lambda x: x.rstrip(to_strip)) - def _str_removeprefix(self, prefix: str) -> npt.NDArray[np.str_]: + def _str_removeprefix(self, prefix: str) -> Series: # outstanding question on whether to use native methods for users # on Python 3.9+ https://git.io/JE9QK, in which case we could do # return self._str_map(str.removeprefix) @@ -427,7 +427,7 @@ def removeprefix(text: str) -> str: return self._str_map(removeprefix) - def _str_removesuffix(self, suffix: str) -> npt.NDArray[np.str_]: + def _str_removesuffix(self, suffix: str) -> Series: # this could be used on Python 3.9+ # f = lambda x: x.removesuffix(suffix) # return self._str_map(str.removesuffix) From 9583c1f8c9de53506b807131a3a2b36d0030e5d3 Mon Sep 17 00:00:00 2001 From: Janosh Riebesell Date: Sat, 4 Sep 2021 12:05:57 +0100 Subject: [PATCH 05/12] defer Series type import to type-check time --- pandas/core/strings/base.py | 4 +++- pandas/core/strings/object_array.py | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/pandas/core/strings/base.py b/pandas/core/strings/base.py index cd1ff358a1848..ef0c3f8c2321d 100644 --- a/pandas/core/strings/base.py +++ b/pandas/core/strings/base.py @@ -3,12 +3,14 @@ import abc from collections.abc import Callable # noqa: PDF001 import re +from typing import TYPE_CHECKING import numpy as np from pandas._typing import Scalar -from pandas.core.series import Series +if TYPE_CHECKING: + from pandas import Series class BaseStringArrayMethods(abc.ABC): diff --git a/pandas/core/strings/object_array.py b/pandas/core/strings/object_array.py index 3bb33915caa0e..dbd8a108664cf 100644 --- a/pandas/core/strings/object_array.py +++ b/pandas/core/strings/object_array.py @@ -3,6 +3,7 @@ from collections.abc import Callable # noqa: PDF001 import re import textwrap +from typing import TYPE_CHECKING import unicodedata import numpy as np @@ -18,9 +19,11 @@ from pandas.core.dtypes.common import is_scalar from pandas.core.dtypes.missing import isna -from pandas.core.series import Series from pandas.core.strings.base import BaseStringArrayMethods +if TYPE_CHECKING: + from pandas import Series + class ObjectStringArrayMixin(BaseStringArrayMethods): """ From d3e6d88225afe44fcc7d844ea534cfd8c019c97f Mon Sep 17 00:00:00 2001 From: Janosh Riebesell Date: Sat, 4 Sep 2021 18:28:01 +0100 Subject: [PATCH 06/12] fix pandas/tests/strings/conftest.py ValueError: not enough values to unpack (expected 3, got 2) --- pandas/tests/strings/conftest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/tests/strings/conftest.py b/pandas/tests/strings/conftest.py index ab277e87e8f81..15cc5af97a2d6 100644 --- a/pandas/tests/strings/conftest.py +++ b/pandas/tests/strings/conftest.py @@ -46,8 +46,8 @@ ("startswith", ("a",), {}), ("startswith", ("a",), {"na": True}), ("startswith", ("a",), {"na": False}), - ("removeprefix", ("a",)), - ("removesuffix", ("a",)), + ("removeprefix", ("a",), {}), + ("removesuffix", ("a",), {}), # translating unicode points of "a" to "d" ("translate", ({97: 100},), {}), ("wrap", (2,), {}), From 1c20c477aa3550f206e968f5a308de0b074e7d15 Mon Sep 17 00:00:00 2001 From: Janosh Riebesell Date: Sun, 5 Sep 2021 09:01:43 +0100 Subject: [PATCH 07/12] add docs in reference/series.rst, user_guide/text.rst --- doc/source/reference/series.rst | 2 ++ doc/source/user_guide/text.rst | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/doc/source/reference/series.rst b/doc/source/reference/series.rst index 3ff3b2bb53fda..a60dab549e66d 100644 --- a/doc/source/reference/series.rst +++ b/doc/source/reference/series.rst @@ -427,6 +427,8 @@ strings and apply several methods to it. These can be accessed like Series.str.normalize Series.str.pad Series.str.partition + Series.str.removeprefix + Series.str.removesuffix Series.str.repeat Series.str.replace Series.str.rfind diff --git a/doc/source/user_guide/text.rst b/doc/source/user_guide/text.rst index db9485f3f2348..ad9b6e569e5eb 100644 --- a/doc/source/user_guide/text.rst +++ b/doc/source/user_guide/text.rst @@ -335,6 +335,19 @@ regular expression object will raise a ``ValueError``. --------------------------------------------------------------------------- ValueError: case and flags cannot be set when pat is a compiled regex +``removeprefix`` and ``removesuffix`` have the same effect as ``str.removeprefix`` and ``str.removesuffix`` added in Python 3.9 +`__: + +.. ipython:: python + + s = pd.Series(["str_foo", "str_bar", "no_prefix"]) + s.str.removeprefix("str_") + + s = pd.Series(["foo_str", "bar_str", "no_suffix"]) + s.str.removesuffix("_str") + +.. versionchanged:: 1.4.0 + .. _text.concatenate: Concatenation @@ -742,6 +755,8 @@ Method summary :meth:`~Series.str.get_dummies`;Split strings on the delimiter returning DataFrame of dummy variables :meth:`~Series.str.contains`;Return boolean array if each string contains pattern/regex :meth:`~Series.str.replace`;Replace occurrences of pattern/regex/string with some other string or the return value of a callable given the occurrence + :meth:`~Series.str.removeprefix`;Remove prefix from string, i.e. only remove if string starts with prefix. + :meth:`~Series.str.removesuffix`;Remove suffix from string, i.e. only remove if string ends with suffix. :meth:`~Series.str.repeat`;Duplicate values (``s.str.repeat(3)`` equivalent to ``x * 3``) :meth:`~Series.str.pad`;"Add whitespace to left, right, or both sides of strings" :meth:`~Series.str.center`;Equivalent to ``str.center`` From 107d7296b82aaa825e1ab538d3c805e8e9d652e5 Mon Sep 17 00:00:00 2001 From: Janosh Riebesell Date: Sun, 5 Sep 2021 14:58:46 +0100 Subject: [PATCH 08/12] add issue # to whatsnew/v1.4.0.rst Co-authored-by: Simon Hawkins --- doc/source/whatsnew/v1.4.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.4.0.rst b/doc/source/whatsnew/v1.4.0.rst index 2874c24bb998b..8807e831913c7 100644 --- a/doc/source/whatsnew/v1.4.0.rst +++ b/doc/source/whatsnew/v1.4.0.rst @@ -104,7 +104,7 @@ Other enhancements - :meth:`.GroupBy.cummin` and :meth:`.GroupBy.cummax` now support the argument ``skipna`` (:issue:`34047`) - :meth:`read_table` now supports the argument ``storage_options`` (:issue:`39167`) - Methods that relied on hashmap based algos such as :meth:`DataFrameGroupBy.value_counts`, :meth:`DataFrameGroupBy.count` and :func:`factorize` ignored imaginary component for complex numbers (:issue:`17927`) -- Add :meth:`Series.str.removeprefix` and :meth:`Series.str.removesuffix` introduced in Python 3.9 to remove pre-/suffixes from string-type :class:`Series`. +- Add :meth:`Series.str.removeprefix` and :meth:`Series.str.removesuffix` introduced in Python 3.9 to remove pre-/suffixes from string-type :class:`Series` (:issue:`36944`) .. --------------------------------------------------------------------------- From 5352adf669b6f2a5ed08a69db0c5b01fda979412 Mon Sep 17 00:00:00 2001 From: Janosh Riebesell Date: Sun, 5 Sep 2021 15:08:48 +0100 Subject: [PATCH 09/12] fix _str_removesuffix --- pandas/core/strings/object_array.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/strings/object_array.py b/pandas/core/strings/object_array.py index dbd8a108664cf..76ee55ef5f9ad 100644 --- a/pandas/core/strings/object_array.py +++ b/pandas/core/strings/object_array.py @@ -437,7 +437,7 @@ def _str_removesuffix(self, suffix: str) -> Series: def removesuffix(text: str) -> str: if text.endswith(suffix): - return text[: len(suffix)] + return text[: -len(suffix)] return text return self._str_map(removesuffix) From f9f5c147fb67f44f450487b2bd9777d7f7643b98 Mon Sep 17 00:00:00 2001 From: Janosh Riebesell Date: Sun, 5 Sep 2021 18:19:28 +0100 Subject: [PATCH 10/12] fix string accessor docs: unknown section "See also", "prefix" requires a space before the colon separating the parameter name and type --- pandas/core/strings/accessor.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/pandas/core/strings/accessor.py b/pandas/core/strings/accessor.py index b1ac57e1dead3..b1b96b6977fb7 100644 --- a/pandas/core/strings/accessor.py +++ b/pandas/core/strings/accessor.py @@ -1908,14 +1908,14 @@ def rstrip(self, to_strip=None): return self._wrap_result(result) _shared_docs[ - "str_remove" + "str_removefix" ] = r""" Remove a %(side)s from an object series. If the %(side)s is not present, the original string will be returned. Parameters ---------- - %(side)s: str + %(side)s : str %(side)s to remove. Returns @@ -1923,7 +1923,7 @@ def rstrip(self, to_strip=None): Series/Index: object The Series or Index with given %(side)s removed. - See also + See Also -------- Series.str.remove%(other_side)s : Remove a %(other_side)s from an object series. @@ -1954,13 +1954,17 @@ def rstrip(self, to_strip=None): dtype: object """ - @Appender(_shared_docs["str_remove"] % {"side": "prefix", "other_side": "suffix"}) + @Appender( + _shared_docs["str_removefix"] % {"side": "prefix", "other_side": "suffix"} + ) @forbid_nonstring_types(["bytes"]) def removeprefix(self, prefix): result = self._data.array._str_removeprefix(prefix) return self._wrap_result(result) - @Appender(_shared_docs["str_remove"] % {"side": "suffix", "other_side": "prefix"}) + @Appender( + _shared_docs["str_removefix"] % {"side": "suffix", "other_side": "prefix"} + ) @forbid_nonstring_types(["bytes"]) def removesuffix(self, suffix): result = self._data.array._str_removesuffix(suffix) From 58ad4600bcfb6da342d62610f1729df9b2b0864b Mon Sep 17 00:00:00 2001 From: Janosh Riebesell Date: Mon, 6 Sep 2021 10:56:43 +0100 Subject: [PATCH 11/12] fix doc test --- pandas/core/strings/accessor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/core/strings/accessor.py b/pandas/core/strings/accessor.py index b1b96b6977fb7..4ea29edb7d41b 100644 --- a/pandas/core/strings/accessor.py +++ b/pandas/core/strings/accessor.py @@ -1945,12 +1945,12 @@ def rstrip(self, to_strip=None): >>> s 0 foo_str 1 bar_str - 2 no_prefix + 2 no_suffix dtype: object >>> s.str.removesuffix("_str") 0 foo 1 bar - 2 no_prefix + 2 no_suffix dtype: object """ From eb618ea1661f71b3d3b9ce3098a2d0d9ac1d574b Mon Sep 17 00:00:00 2001 From: Janosh Riebesell Date: Mon, 6 Sep 2021 17:02:32 +0100 Subject: [PATCH 12/12] fix docs versionchange to versionadded --- doc/source/user_guide/text.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/user_guide/text.rst b/doc/source/user_guide/text.rst index ad9b6e569e5eb..d350351075cb6 100644 --- a/doc/source/user_guide/text.rst +++ b/doc/source/user_guide/text.rst @@ -338,6 +338,8 @@ regular expression object will raise a ``ValueError``. ``removeprefix`` and ``removesuffix`` have the same effect as ``str.removeprefix`` and ``str.removesuffix`` added in Python 3.9 `__: +.. versionadded:: 1.4.0 + .. ipython:: python s = pd.Series(["str_foo", "str_bar", "no_prefix"]) @@ -346,8 +348,6 @@ regular expression object will raise a ``ValueError``. s = pd.Series(["foo_str", "bar_str", "no_suffix"]) s.str.removesuffix("_str") -.. versionchanged:: 1.4.0 - .. _text.concatenate: Concatenation