Repository: pandas-dev/pandas
Pull request #60715 (2025-01-13 09:52:33)

[backport 2.3.x] String dtype: disallow specifying the 'str' dtype with storage in [..] in string alias (#60661)
(cherry picked from commit 7415aca37159a99f8f99d93a1908070ddf36178c)

Backport of https://github.com/pandas-dev/pandas/pull/60661


Patch:
diff --git a/pandas/core/dtypes/dtypes.py b/pandas/core/dtypes/dtypes.py
index e7efb8598e..542bc85110 100644
--- a/pandas/core/dtypes/dtypes.py
+++ b/pandas/core/dtypes/dtypes.py
@@ -2242,7 +2242,7 @@ class ArrowDtype(StorageExtensionDtype):
             )
         if not string.endswith("[pyarrow]"):
             raise TypeError(f"'{string}' must end with '[pyarrow]'")
-        if string == "string[pyarrow]":
+        if string in ("string[pyarrow]", "str[pyarrow]"):
             # Ensure Registry.find skips ArrowDtype to use StringDtype instead
             raise TypeError("string[pyarrow] should be constructed by StringDtype")
 


Test patch:
diff --git a/pandas/tests/dtypes/test_common.py b/pandas/tests/dtypes/test_common.py
index f7442cf5d6..ceebfb1920 100644
--- a/pandas/tests/dtypes/test_common.py
+++ b/pandas/tests/dtypes/test_common.py
@@ -835,3 +835,23 @@ def test_pandas_dtype_string_dtypes(string_storage):
     with pd.option_context("string_storage", string_storage):
         result = pandas_dtype("string")
     assert result == pd.StringDtype(string_storage, na_value=pd.NA)
+
+
+def test_pandas_dtype_string_dtype_alias_with_storage():
+    with pytest.raises(TypeError, match="not understood"):
+        pandas_dtype("str[python]")
+
+    with pytest.raises(TypeError, match="not understood"):
+        pandas_dtype("str[pyarrow]")
+
+    result = pandas_dtype("string[python]")
+    assert result == pd.StringDtype("python", na_value=pd.NA)
+
+    if HAS_PYARROW:
+        result = pandas_dtype("string[pyarrow]")
+        assert result == pd.StringDtype("pyarrow", na_value=pd.NA)
+    else:
+        with pytest.raises(
+            ImportError, match="required for PyArrow backed StringArray"
+        ):
+            pandas_dtype("string[pyarrow]")
diff --git a/pandas/tests/groupby/test_groupby.py b/pandas/tests/groupby/test_groupby.py
index b5588898d4..07ddbc36b5 100644
--- a/pandas/tests/groupby/test_groupby.py
+++ b/pandas/tests/groupby/test_groupby.py
@@ -6,8 +6,6 @@ import re
 import numpy as np
 import pytest
 
-from pandas._config import using_string_dtype
-
 from pandas.errors import (
     PerformanceWarning,
     SpecificationError,
@@ -2876,12 +2874,13 @@ def test_groupby_none_in_first_mi_level():
     tm.assert_series_equal(result, expected)
 
 
-@pytest.mark.xfail(using_string_dtype(), reason="TODO(infer_string)")
-def test_groupby_none_column_name():
+def test_groupby_none_column_name(using_infer_string):
     # GH#47348
     df = DataFrame({None: [1, 1, 2, 2], "b": [1, 1, 2, 3], "c": [4, 5, 6, 7]})
-    result = df.groupby(by=[None]).sum()
-    expected = DataFrame({"b": [2, 5], "c": [9, 13]}, index=Index([1, 2], name=None))
+    by = [np.nan] if using_infer_string else [None]
+    gb = df.groupby(by=by)
+    result = gb.sum()
+    expected = DataFrame({"b": [2, 5], "c": [9, 13]}, index=Index([1, 2], name=by[0]))
     tm.assert_frame_equal(result, expected)