diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 13016a4d6..9034303be 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -360,7 +360,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): copy: bool | None = None, ) -> Series[list[_str]]: ... @overload - def __new__( + def __new__( # type: ignore[overload-overlap] cls, data: Sequence[_str], index: AxesData | None = None, @@ -507,6 +507,26 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): name: Hashable = None, copy: bool | None = None, ) -> Self: ... + # the resolutions are not supported by pandas at creation, only in astype + @overload + def __new__( + cls, + data: ( + S1 + | ArrayLike + | dict[_str, np_ndarray] + | Sequence[S1] + | IndexOpsMixin[S1] + | dict[HashableT1, S1] + | KeysView[S1] + | ValuesView[S1] + ), + index: AxesData | None = None, + *, + dtype: PandasAstypeTimedeltaDtypeArg | PandasAstypeTimestampDtypeArg, + name: Hashable = None, + copy: bool | None = None, + ) -> Never: ... @overload def __new__( cls, diff --git a/pandas-stubs/core/strings/accessor.pyi b/pandas-stubs/core/strings/accessor.pyi index 41f4b6a00..c2b7cf0ae 100644 --- a/pandas-stubs/core/strings/accessor.pyi +++ b/pandas-stubs/core/strings/accessor.pyi @@ -9,6 +9,7 @@ import re from typing import ( Generic, Literal, + Never, TypeVar, overload, ) @@ -54,7 +55,7 @@ class StringMethods( ): def __init__(self, data: T) -> None: ... def __getitem__(self, key: _slice | int) -> _T_STR: ... - def __iter__(self) -> _T_STR: ... + def __iter__(self) -> Never: ... @overload def cat( self, diff --git a/tests/series/test_series.py b/tests/series/test_series.py index 7c06217e8..db7a200b9 100644 --- a/tests/series/test_series.py +++ b/tests/series/test_series.py @@ -3062,6 +3062,19 @@ def test_series_str_methods() -> None: check(assert_type(s_str.str.lower(), "pd.Series[str]"), pd.Series, str) +def test_series_str_methods_iter() -> None: + """Test that StringMethods are not iterable.""" + s_str = pd.Series(["a", "b"]) + if TYPE_CHECKING_INVALID_USAGE: + + def _sr_iter() -> None: # pyright: ignore[reportUnusedFunction] + assert_type(s_str.str.__iter__(), Never) + + # def _sr_iterator() -> None: + # for _ in s_str.str: + # pass + + def test_series_explode() -> None: """Test Series.explode method.""" s = pd.Series([[1, 2, 3], "foo", [], [3, 4]]) diff --git a/tests/series/timedelta/test_dtypes.py b/tests/series/timedelta/test_dtypes.py index b11c467f3..a0b147f78 100644 --- a/tests/series/timedelta/test_dtypes.py +++ b/tests/series/timedelta/test_dtypes.py @@ -1,18 +1,200 @@ from __future__ import annotations +import datetime from typing import ( TYPE_CHECKING, + Never, assert_type, ) import pandas as pd import pytest -from tests import check -from tests._typing import TimedeltaDtypeArg +from tests import ( + TYPE_CHECKING_INVALID_USAGE, + check, +) +from tests._typing import ( + TimedeltaDtypeArg, +) from tests.dtypes import ASTYPE_TIMEDELTA_ARGS +def test_series_construction_timedelta_dtype() -> None: + """ + Test allowable resolutions for pd.Series() construction with timedelta64 dtype. + + Only s, ms, us, ns resolutions are valid for Series construction. + Resolutions Y, M, W, D, h, m, μs, ps, fs, as are only valid for astype(). + """ + + # numpy timedelta64: only s, ms, us, ns are valid for construction + check( + assert_type( + pd.Series([datetime.timedelta(seconds=1)], dtype="timedelta64[s]"), + "pd.Series[pd.Timedelta]", + ), + pd.Series, + pd.Timedelta, + ) + check( + assert_type( + pd.Series([datetime.timedelta(seconds=1)], dtype="timedelta64[ms]"), + "pd.Series[pd.Timedelta]", + ), + pd.Series, + pd.Timedelta, + ) + check( + assert_type( + pd.Series([datetime.timedelta(seconds=1)], dtype="timedelta64[us]"), + "pd.Series[pd.Timedelta]", + ), + pd.Series, + pd.Timedelta, + ) + check( + assert_type( + pd.Series([datetime.timedelta(seconds=1)], dtype="timedelta64[ns]"), + "pd.Series[pd.Timedelta]", + ), + pd.Series, + pd.Timedelta, + ) + # numpy timedelta64 type codes + check( + assert_type( + pd.Series([datetime.timedelta(seconds=1)], dtype="m8[s]"), + "pd.Series[pd.Timedelta]", + ), + pd.Series, + pd.Timedelta, + ) + check( + assert_type( + pd.Series([datetime.timedelta(seconds=1)], dtype="m8[ms]"), + "pd.Series[pd.Timedelta]", + ), + pd.Series, + pd.Timedelta, + ) + check( + assert_type( + pd.Series([datetime.timedelta(seconds=1)], dtype="m8[us]"), + "pd.Series[pd.Timedelta]", + ), + pd.Series, + pd.Timedelta, + ) + check( + assert_type( + pd.Series([datetime.timedelta(seconds=1)], dtype="m8[ns]"), + "pd.Series[pd.Timedelta]", + ), + pd.Series, + pd.Timedelta, + ) + # little-endian numpy timedelta64 type codes + check( + assert_type( + pd.Series([datetime.timedelta(seconds=1)], dtype=" None: # pyright: ignore[reportUnusedFunction] + assert_type( + pd.Series([datetime.timedelta(seconds=1)], dtype="timedelta64[Y]"), + Never, + ) + + def _td_M() -> None: # pyright: ignore[reportUnusedFunction] + assert_type( + pd.Series([datetime.timedelta(seconds=1)], dtype="timedelta64[M]"), + Never, + ) + + def _td_W() -> None: # pyright: ignore[reportUnusedFunction] + assert_type( + pd.Series([datetime.timedelta(seconds=1)], dtype="timedelta64[W]"), + Never, + ) + + def _td_D() -> None: # pyright: ignore[reportUnusedFunction] + assert_type( + pd.Series([datetime.timedelta(seconds=1)], dtype="timedelta64[D]"), + Never, + ) + + def _td_h() -> None: # pyright: ignore[reportUnusedFunction] + assert_type( + pd.Series([datetime.timedelta(seconds=1)], dtype="timedelta64[h]"), + Never, + ) + + def _td_m() -> None: # pyright: ignore[reportUnusedFunction] + assert_type( + pd.Series([datetime.timedelta(seconds=1)], dtype="timedelta64[m]"), + Never, + ) + + def _td_mus() -> None: # pyright: ignore[reportUnusedFunction] + assert_type( + pd.Series([datetime.timedelta(seconds=1)], dtype="timedelta64[μs]"), + Never, + ) + + def _td_ps() -> None: # pyright: ignore[reportUnusedFunction] + assert_type( + pd.Series([datetime.timedelta(seconds=1)], dtype="timedelta64[ps]"), + Never, + ) + + def _td_fs() -> None: # pyright: ignore[reportUnusedFunction] + assert_type( + pd.Series([datetime.timedelta(seconds=1)], dtype="timedelta64[fs]"), + Never, + ) + + def _td_as() -> None: # pyright: ignore[reportUnusedFunction] + assert_type( + pd.Series([datetime.timedelta(seconds=1)], dtype="timedelta64[as]"), + Never, + ) + + @pytest.mark.parametrize( "cast_arg, target_type", ASTYPE_TIMEDELTA_ARGS.items(), ids=repr ) diff --git a/tests/series/timestamp/test_dtypes.py b/tests/series/timestamp/test_dtypes.py index 42218a650..69cb63c12 100644 --- a/tests/series/timestamp/test_dtypes.py +++ b/tests/series/timestamp/test_dtypes.py @@ -1,16 +1,191 @@ from __future__ import annotations +import datetime from typing import ( TYPE_CHECKING, + Never, assert_type, ) import pandas as pd import pytest -from tests import check +from tests import ( + TYPE_CHECKING_INVALID_USAGE, + check, +) from tests._typing import TimestampDtypeArg -from tests.dtypes import ASTYPE_TIMESTAMP_ARGS +from tests.dtypes import ( + ASTYPE_TIMESTAMP_ARGS, +) + + +def test_series_construction_timestamp_dtype() -> None: + """Test allowable resolutions for pd.Series() construction with datetime64 dtype. + + Only s, ms, us, ns resolutions are valid for Series construction. + Resolutions Y, M, W, D, h, m, μs, ps, fs, as are only valid for astype(). + """ + + # numpy datetime64: only s, ms, us, ns are valid for construction + check( + assert_type( + pd.Series([datetime.datetime(2020, 1, 1)], dtype="datetime64[s]"), + "pd.Series[pd.Timestamp]", + ), + pd.Series, + pd.Timestamp, + ) + check( + assert_type( + pd.Series([datetime.datetime(2020, 1, 1)], dtype="datetime64[ms]"), + "pd.Series[pd.Timestamp]", + ), + pd.Series, + pd.Timestamp, + ) + check( + assert_type( + pd.Series([datetime.datetime(2020, 1, 1)], dtype="datetime64[us]"), + "pd.Series[pd.Timestamp]", + ), + pd.Series, + pd.Timestamp, + ) + check( + assert_type( + pd.Series([datetime.datetime(2020, 1, 1)], dtype="datetime64[ns]"), + "pd.Series[pd.Timestamp]", + ), + pd.Series, + pd.Timestamp, + ) + # numpy datetime64 type codes + check( + assert_type( + pd.Series([datetime.datetime(2020, 1, 1)], dtype="M8[s]"), + "pd.Series[pd.Timestamp]", + ), + pd.Series, + pd.Timestamp, + ) + check( + assert_type( + pd.Series([datetime.datetime(2020, 1, 1)], dtype="M8[ms]"), + "pd.Series[pd.Timestamp]", + ), + pd.Series, + pd.Timestamp, + ) + check( + assert_type( + pd.Series([datetime.datetime(2020, 1, 1)], dtype="M8[us]"), + "pd.Series[pd.Timestamp]", + ), + pd.Series, + pd.Timestamp, + ) + check( + assert_type( + pd.Series([datetime.datetime(2020, 1, 1)], dtype="M8[ns]"), + "pd.Series[pd.Timestamp]", + ), + pd.Series, + pd.Timestamp, + ) + # little-endian numpy datetime64 type codes + check( + assert_type( + pd.Series([datetime.datetime(2020, 1, 1)], dtype=" None: # pyright: ignore[reportUnusedFunction] + assert_type( + pd.Series([datetime.datetime(2020, 1, 1)], dtype="datetime64[Y]"), Never + ) + + def _ts_M() -> None: # pyright: ignore[reportUnusedFunction] + assert_type( + pd.Series([datetime.datetime(2020, 1, 1)], dtype="datetime64[M]"), Never + ) + + def _ts_W() -> None: # pyright: ignore[reportUnusedFunction] + assert_type( + pd.Series([datetime.datetime(2020, 1, 1)], dtype="datetime64[W]"), Never + ) + + def _ts_D() -> None: # pyright: ignore[reportUnusedFunction] + assert_type( + pd.Series([datetime.datetime(2020, 1, 1)], dtype="datetime64[D]"), Never + ) + + def _ts_h() -> None: # pyright: ignore[reportUnusedFunction] + assert_type( + pd.Series([datetime.datetime(2020, 1, 1)], dtype="datetime64[h]"), Never + ) + + def _ts_m() -> None: # pyright: ignore[reportUnusedFunction] + assert_type( + pd.Series([datetime.datetime(2020, 1, 1)], dtype="datetime64[m]"), Never + ) + + def _ts_mus() -> None: # pyright: ignore[reportUnusedFunction] + assert_type( + pd.Series([datetime.datetime(2020, 1, 1)], dtype="datetime64[μs]"), + Never, + ) + + def _ts_ps() -> None: # pyright: ignore[reportUnusedFunction] + assert_type( + pd.Series([datetime.datetime(2020, 1, 1)], dtype="datetime64[ps]"), + Never, + ) + + def _ts_fs() -> None: # pyright: ignore[reportUnusedFunction] + assert_type( + pd.Series([datetime.datetime(2020, 1, 1)], dtype="datetime64[fs]"), + Never, + ) + + def _ts_as() -> None: # pyright: ignore[reportUnusedFunction] + assert_type( + pd.Series([datetime.datetime(2020, 1, 1)], dtype="datetime64[as]"), + Never, + ) @pytest.mark.parametrize(