diff --git a/pandas-stubs/core/frame.pyi b/pandas-stubs/core/frame.pyi index f872ad2f..2af25a20 100644 --- a/pandas-stubs/core/frame.pyi +++ b/pandas-stubs/core/frame.pyi @@ -256,9 +256,9 @@ class _LocIndexerFrame(_LocIndexer, Generic[_T]): ] | None ), - ) -> Series: ... + ) -> UnknownSeries: ... @overload - def __getitem__(self, idx: tuple[Scalar, slice]) -> Series | _T: ... + def __getitem__(self, idx: tuple[Scalar, slice]) -> UnknownSeries | _T: ... @overload def __setitem__( self, @@ -288,13 +288,13 @@ class _LocIndexerFrame(_LocIndexer, Generic[_T]): if sys.version_info >= (3, 12): class _GetItemHack: @overload - def __getitem__(self, key: Scalar | tuple[Hashable, ...]) -> Series: ... # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + def __getitem__(self, key: Scalar | tuple[Hashable, ...]) -> UnknownSeries: ... # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @overload def __getitem__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] self, key: Iterable[Hashable] | slice ) -> Self: ... @overload - def __getitem__(self, key: Hashable) -> Series: ... + def __getitem__(self, key: Hashable) -> UnknownSeries: ... else: class _GetItemHack: diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 9552d407..dbd5016f 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -245,6 +245,54 @@ _ListLike: TypeAlias = ( ArrayLike | dict[_str, np.ndarray] | Sequence[S1] | IndexOpsMixin[S1] ) +class _StrMethods: + @overload + def __get__(self, instance: Series[str], owner: Any) -> StringMethods[ + Series[str], + DataFrame, + Series[bool], + Series[list[str]], + Series[int], + Series[bytes], + Series[str], + Series[type[object]], + ]: ... + @overload + def __get__(self, instance: Series[bytes], owner: Any) -> StringMethods[ + Series[bytes], + DataFrame, + Series[bool], + Series[list[str]], + Series[int], + Series[bytes], + Series[str], + Series[type[object]], + ]: ... + @overload + def __get__(self, instance: Series[list[str]], owner: Any) -> StringMethods[ + Series[list[str]], + DataFrame, + Series[bool], + Series[list[str]], + Series[int], + Series[bytes], + Series[str], + Series[type[object]], + ]: ... + @overload + def __get__(self, instance: Series[S1], owner: Any) -> NoReturn: ... + @overload + def __get__(self, instance: UnknownSeries, owner: Any) -> StringMethods[ + Series, + DataFrame, + Series[bool], + Series[list[str]], + Series[int], + Series[bytes], + Series[str], + Series[type[object]], + ]: ... + class Series(IndexOpsMixin[S1], NDFrame): __hash__: ClassVar[None] @@ -1170,19 +1218,7 @@ class Series(IndexOpsMixin[S1], NDFrame): copy: _bool = ..., ) -> Series[S1]: ... def to_period(self, freq: _str | None = ..., copy: _bool = ...) -> DataFrame: ... - @property - def str( - self, - ) -> StringMethods[ - Self, - DataFrame, - Series[bool], - Series[list[str]], - Series[int], - Series[bytes], - Series[str], - Series[type[object]], - ]: ... + str: _StrMethods @property def dt(self) -> CombinedDatetimelikeProperties: ... @property diff --git a/pyproject.toml b/pyproject.toml index 4a155c1b..9779b232 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,7 +35,7 @@ types-pytz = ">= 2022.1.1" numpy = ">= 1.23.5" [tool.poetry.group.dev.dependencies] -mypy = "1.15.0" +mypy = "1.16.0" pandas = "2.2.3" pyarrow = ">=10.0.1" pytest = ">=7.1.2" diff --git a/tests/test_frame.py b/tests/test_frame.py index e133a046..05a62b52 100644 --- a/tests/test_frame.py +++ b/tests/test_frame.py @@ -3073,15 +3073,15 @@ def test_set_columns() -> None: # https://github.com/python/mypy/issues/3004 # pyright accepts this, so we only type check for pyright, # and also test the code with pytest - df.columns = ["c", "d"] # type: ignore[assignment] - df.columns = [1, 2] # type: ignore[assignment] - df.columns = [1, "a"] # type: ignore[assignment] - df.columns = np.array([1, 2]) # type: ignore[assignment] - df.columns = pd.Series([1, 2]) # type: ignore[assignment] - df.columns = np.array([1, "a"]) # type: ignore[assignment] - df.columns = pd.Series([1, "a"]) # type: ignore[assignment] - df.columns = (1, 2) # type: ignore[assignment] - df.columns = (1, "a") # type: ignore[assignment] + df.columns = ["c", "d"] + df.columns = [1, 2] + df.columns = [1, "a"] + df.columns = np.array([1, 2]) + df.columns = pd.Series([1, 2]) + df.columns = np.array([1, "a"]) + df.columns = pd.Series([1, "a"]) + df.columns = (1, 2) + df.columns = (1, "a") if TYPE_CHECKING_INVALID_USAGE: df.columns = "abc" # type: ignore[assignment] # pyright: ignore[reportAttributeAccessIssue] @@ -4373,8 +4373,8 @@ def test_hashable_args() -> None: # https://github.com/python/mypy/issues/3004 # pyright accepts this, so we only type check for pyright, # and also test the code with pytest - df.columns = test # type: ignore[assignment] - df.columns = ["test"] # type: ignore[assignment] + df.columns = test + df.columns = ["test"] testDict = {"test": 1} with ensure_clean() as path: diff --git a/tests/test_string_accessors.py b/tests/test_string_accessors.py index 649dae78..94519379 100644 --- a/tests/test_string_accessors.py +++ b/tests/test_string_accessors.py @@ -6,6 +6,7 @@ from typing_extensions import assert_type from tests import ( + TYPE_CHECKING_INVALID_USAGE, check, np_ndarray_bool, ) @@ -411,3 +412,10 @@ def test_index_overloads_extract(): pd.Index, object, ) + + +def test_series_unknown(): + if TYPE_CHECKING_INVALID_USAGE: + s = pd.Series([1, 2, 3]) + s.str.startswith("a") # type:ignore[attr-defined] + s.str.slice(2, 4) # type:ignore[attr-defined]