BUG: displaying string dtypes not showing storage option
State: closed

- [x] closes #50099 (Replace xxxx with the GitHub issue number)
- [x] [Tests added and passed](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#writing-tests) if fixing a bug or adding a new feature
- [x] All [code checks passed](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#pre-commit).
- [x] Added [type annotations](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#type-hints) to new arguments/methods/functions.
- [x] Added an entry in the latest `doc/source/whatsnew/vX.X.X.rst` file if fixing a bug or adding a new feature.

cc @mroeschke not saying that this is a good fix, but this shows that we have to use repr for the string dtypes in some way. Is there a more general rule to accomplish this?

Labels:
name: Bug
name: Output-Formatting
description: __repr__ of pandas objects, to_string
name: Strings
description: String extension data type and string data

Comments:
Looks to be a doctest error

```
=================================== FAILURES ===================================
_____________ [doctest] pandas.core.generic.NDFrame.convert_dtypes _____________
6466         Convert the DataFrame to use best possible dtypes.
6467 
6468         >>> dfn = df.convert_dtypes()
6469         >>> dfn
6470            a  b      c     d     e      f
6471         0  1  x   True     h    10   <NA>
6472         1  2  y  False     i  <NA>  100.5
6473         2  3  z   <NA>  <NA>    20  200.0
6474 
6475         >>> dfn.dtypes
Differences (unified diff with -expected +actual):
    @@ -1,7 +1,7 @@
    -a      Int32
    -b     string
    -c    boolean
    -d     string
    -e      Int64
    -f    Float64
    +a             Int32
    +b    string[python]
    +c           boolean
    +d    string[python]
    +e             Int64
    +f           Float64
     dtype: object
```
> Is there a more general rule to accomplish this?

Yeah I don't think at the moment. Not sure why `StringDtype` (before `StorageDtype` was refactored away) has this str vs repr difference.

Looks like I actually hacked around this when creating `ArrowDtype` lol

```
class StorageExtensionDtype(ExtensionDtype):
    """ExtensionDtype that may be backed by more than one implementation."""

    name: str
    _metadata = ("storage",)

    def __init__(self, storage=None) -> None:
        self.storage = storage

    def __repr__(self) -> str:
        return f"{self.name}[{self.storage}]"

    def __str__(self) -> str:
        return self.name
``` 

```
class ArrowDtype(StorageExtensionDtype):
    def __repr__(self) -> str:
        return self.name

    @property
    def name(self) -> str:  # type: ignore[override]
        """
        A string identifying the data type.
        """
        return f"{str(self.pyarrow_dtype)}[{self.storage}]"
```
Thx, fixed the doctest.


Ok then can keep as is :)
> Not sure why StringDtype (before StorageDtype was refactored away) has this str vs repr difference.

As far as I remember, this was actually done intentionally. And I personally I would prefer to keep this. But let's discuss on the issue (will reopen that one).