From 8c2d429dc3787a22d279c12d7db47586257c7f87 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sun, 16 Oct 2022 13:45:58 +0100 Subject: [PATCH 01/12] ENH: Improve typing for Timestamp --- pandas-stubs/_libs/tslibs/timestamps.pyi | 91 +++++-- tests/test_scalars.py | 307 +++++++++++++++++++++++ 2 files changed, 374 insertions(+), 24 deletions(-) create mode 100644 tests/test_scalars.py diff --git a/pandas-stubs/_libs/tslibs/timestamps.pyi b/pandas-stubs/_libs/tslibs/timestamps.pyi index 17ed5f211..948c4ac0a 100644 --- a/pandas-stubs/_libs/tslibs/timestamps.pyi +++ b/pandas-stubs/_libs/tslibs/timestamps.pyi @@ -8,14 +8,20 @@ from datetime import ( from time import struct_time from typing import ( ClassVar, + Literal, TypeVar, overload, ) import numpy as np -from pandas import Index +from pandas import ( + DatetimeIndex, + Index, + TimedeltaIndex, +) from pandas.core.series import ( Series, + TimedeltaSeries, TimestampSeries, ) @@ -25,21 +31,24 @@ from pandas._libs.tslibs import ( Tick, Timedelta, ) -from pandas._typing import np_ndarray_bool +from pandas._typing import ( + np_ndarray_bool, + npt, +) _DatetimeT = TypeVar("_DatetimeT", bound=datetime) -def integer_op_not_supported(obj: object) -> TypeError: ... - class Timestamp(datetime): min: ClassVar[Timestamp] max: ClassVar[Timestamp] resolution: ClassVar[Timedelta] - value: int # np.int64 + value: int def __new__( cls: type[_DatetimeT], ts_input: np.integer | float | str | _date | datetime | np.datetime64 = ..., + # Freq is deprecated but is left in to allow code like Timestamp(2000,1,1) + # Removing it would make the other arguments position only freq: int | str | BaseOffset | None = ..., tz: str | _tzinfo | int | None = ..., unit: str | int | None = ..., @@ -52,8 +61,7 @@ class Timestamp(datetime): microsecond: int | None = ..., nanosecond: int | None = ..., tzinfo: _tzinfo | None = ..., - *, - fold: int | None = ..., + fold: Literal[0, 1] | None = ..., ) -> _DatetimeT: ... # GH 46171 # While Timestamp can return pd.NaT, having the constructor return @@ -73,6 +81,8 @@ class Timestamp(datetime): @property def microsecond(self) -> int: ... @property + def nanosecond(self) -> int: ... + @property def tzinfo(self) -> _tzinfo | None: ... @property def tz(self) -> _tzinfo | None: ... @@ -113,15 +123,15 @@ class Timestamp(datetime): def timetz(self) -> _time: ... def replace( self, - year: int = ..., - month: int = ..., - day: int = ..., - hour: int = ..., - minute: int = ..., - second: int = ..., - microsecond: int = ..., + year: int | None = ..., + month: int | None = ..., + day: int | None = ..., + hour: int | None = ..., + minute: int | None = ..., + second: int | None = ..., + microsecond: int | None = ..., tzinfo: _tzinfo | None = ..., - fold: int = ..., + fold: int | None = ..., ) -> Timestamp: ... def astimezone(self: _DatetimeT, tz: _tzinfo | None = ...) -> _DatetimeT: ... def ctime(self) -> str: ... @@ -131,44 +141,75 @@ class Timestamp(datetime): def utcoffset(self) -> timedelta | None: ... def tzname(self) -> str | None: ... def dst(self) -> timedelta | None: ... + # Mypy complains Forward operator "" is not callable, so ignore misc + # for le, lt ge and gt @overload # type: ignore[override] - def __le__(self, other: datetime) -> bool: ... + def __le__(self, other: datetime | np.datetime64) -> bool: ... # type: ignore[misc] @overload - def __le__(self, other: Index) -> np_ndarray_bool: ... + def __le__(self, other: Index | npt.NDArray[np.datetime64]) -> np_ndarray_bool: ... @overload def __le__(self, other: TimestampSeries) -> Series[bool]: ... @overload # type: ignore[override] - def __lt__(self, other: datetime) -> bool: ... + def __lt__(self, other: datetime | np.datetime64) -> bool: ... # type: ignore[misc] @overload - def __lt__(self, other: Index) -> np_ndarray_bool: ... + def __lt__(self, other: Index | npt.NDArray[np.datetime64]) -> np_ndarray_bool: ... @overload def __lt__(self, other: TimestampSeries) -> Series[bool]: ... @overload # type: ignore[override] - def __ge__(self, other: datetime) -> bool: ... + def __ge__(self, other: datetime | np.datetime64) -> bool: ... # type: ignore[misc] @overload - def __ge__(self, other: Index) -> np_ndarray_bool: ... + def __ge__(self, other: Index | npt.NDArray[np.datetime64]) -> np_ndarray_bool: ... @overload def __ge__(self, other: TimestampSeries) -> Series[bool]: ... @overload # type: ignore[override] - def __gt__(self, other: datetime) -> bool: ... + def __gt__(self, other: datetime | np.datetime64) -> bool: ... # type: ignore[misc] @overload - def __gt__(self, other: Index) -> np_ndarray_bool: ... + def __gt__(self, other: Index | npt.NDArray[np.datetime64]) -> np_ndarray_bool: ... @overload def __gt__(self, other: TimestampSeries) -> Series[bool]: ... # error: Signature of "__add__" incompatible with supertype "date"/"datetime" @overload # type: ignore[override] - def __add__(self, other: np.ndarray) -> np.ndarray: ... + def __add__( + self, other: npt.NDArray[np.timedelta64] + ) -> npt.NDArray[np.datetime64]: ... @overload def __add__( self: _DatetimeT, other: timedelta | np.timedelta64 | Tick ) -> _DatetimeT: ... + @overload + def __add__(self, other: Series) -> TimestampSeries: ... + @overload + def __add__(self, other: TimedeltaIndex) -> DatetimeIndex: ... + @overload def __radd__(self: _DatetimeT, other: timedelta) -> _DatetimeT: ... + @overload + def __radd__(self, other: TimedeltaIndex) -> DatetimeIndex: ... @overload # type: ignore[override] def __sub__(self, other: datetime) -> Timedelta: ... @overload def __sub__( self: _DatetimeT, other: timedelta | np.timedelta64 | Tick ) -> _DatetimeT: ... + @overload + def __sub__(self, other: TimedeltaIndex) -> DatetimeIndex: ... + @overload + def __sub__(self, other: TimedeltaSeries) -> TimestampSeries: ... + @overload + def __sub__( + self, other: npt.NDArray[np.timedelta64] + ) -> npt.NDArray[np.datetime64]: ... + @overload # type: ignore[override] + def __eq__(self, other: Timestamp | np.datetime64 | datetime) -> bool: ... + @overload + def __eq__(self, other: TimestampSeries) -> Series[bool]: ... + @overload + def __eq__(self, other: npt.NDArray[np.datetime64] | Index) -> np_ndarray_bool: ... + @overload # type: ignore[override] + def __ne__(self, other: Timestamp | np.datetime64 | datetime) -> bool: ... + @overload + def __ne__(self, other: TimestampSeries) -> Series[bool]: ... + @overload + def __ne__(self, other: npt.NDArray[np.datetime64] | Index) -> np_ndarray_bool: ... def __hash__(self) -> int: ... def weekday(self) -> int: ... def isoweekday(self) -> int: ... @@ -223,6 +264,8 @@ class Timestamp(datetime): @property def dayofyear(self) -> int: ... @property + def weekofyear(self) -> int: ... + @property def quarter(self) -> int: ... @property def week(self) -> int: ... diff --git a/tests/test_scalars.py b/tests/test_scalars.py new file mode 100644 index 000000000..fb4737fb1 --- /dev/null +++ b/tests/test_scalars.py @@ -0,0 +1,307 @@ +from __future__ import annotations + +import datetime as dt +from typing import ( + TYPE_CHECKING, + Any, + Optional, + cast, +) + +import dateutil.tz +import numpy as np +from numpy import typing as npt +import pandas as pd +import pytz +from typing_extensions import assert_type + +if TYPE_CHECKING: + from pandas.core.series import TimedeltaSeries # noqa: F401 + from pandas.core.series import TimestampSeries # noqa: F401 + + from pandas._typing import np_ndarray_bool +else: + np_ndarray_bool = Any + +from tests import check + +from pandas.tseries.offsets import Day + + +def test_timestamp() -> None: + + pd.Timestamp("2000-1-1") + pd.Timestamp("2000-1-1", tz="US/Pacific") + pd.Timestamp("2000-1-1", tz=pytz.timezone("US/Eastern")) + pd.Timestamp("2000-1-1", tz=dateutil.tz.UTC) + pd.Timestamp( + year=2000, + month=1, + day=1, + hour=1, + minute=1, + second=1, + microsecond=1, + nanosecond=1, + ) + pd.Timestamp(1, unit="D") + pd.Timestamp(1, unit="h") + pd.Timestamp(1, unit="m") + pd.Timestamp(1, unit="s") + pd.Timestamp(1, unit="ms") + pd.Timestamp(1, unit="us") + pd.Timestamp(year=2000, month=3, day=24, hour=12, minute=27, fold=0) + pd.Timestamp(year=2000, month=3, day=24, hour=12, minute=27, fold=1) + pd.Timestamp( + year=2000, + month=1, + day=1, + hour=1, + minute=1, + second=1, + microsecond=1, + nanosecond=1, + tzinfo=dt.timezone(offset=dt.timedelta(hours=6), name="EST"), + ) + ts = pd.Timestamp(year=2000, month=3, day=24, hour=12, minute=27) + check(assert_type(ts.asm8, np.datetime64), np.datetime64) + check(assert_type(ts.day_of_week, int), int) + check(assert_type(ts.day_of_year, int), int) + check(assert_type(ts.dayofweek, int), int) + check(assert_type(ts.dayofyear, int), int) + check(assert_type(ts.days_in_month, int), int) + check(assert_type(ts.daysinmonth, int), int) + check(assert_type(ts.is_leap_year, bool), bool) + check(assert_type(ts.is_month_end, bool), bool) + check(assert_type(ts.is_month_start, bool), bool) + check(assert_type(ts.is_quarter_end, bool), bool) + check(assert_type(ts.is_quarter_start, bool), bool) + check(assert_type(ts.is_year_end, bool), bool) + check(assert_type(ts.is_year_start, bool), bool) + check(assert_type(ts.quarter, int), int) + check(assert_type(ts.tz, Optional[dt.tzinfo]), type(None)) + check(assert_type(ts.week, int), int) + check(assert_type(ts.weekofyear, int), int) + check(assert_type(ts.day, int), int) + check(assert_type(ts.fold, int), int) + check(assert_type(ts.hour, int), int) + check(assert_type(ts.microsecond, int), int) + check(assert_type(ts.minute, int), int) + check(assert_type(ts.month, int), int) + check(assert_type(ts.nanosecond, int), int) + check(assert_type(ts.second, int), int) + check(assert_type(ts.tzinfo, Optional[dt.tzinfo]), type(None)) + check(assert_type(ts.value, int), int) + check(assert_type(ts.year, int), int) + + ts = pd.Timestamp("2000-1-1") + check(assert_type(ts + pd.Timedelta(days=1), pd.Timestamp), pd.Timestamp) + check(assert_type(ts + dt.timedelta(days=1), pd.Timestamp), pd.Timestamp) + check(assert_type(pd.Timedelta(days=1) + ts, pd.Timestamp), pd.Timestamp) + check(assert_type(dt.timedelta(days=1) + ts, pd.Timestamp), pd.Timestamp) + check(assert_type(ts + 3 * Day(), pd.Timestamp), pd.Timestamp) + check(assert_type(3 * Day() + ts, pd.Timestamp), pd.Timestamp) + check( + assert_type(ts + pd.TimedeltaIndex([1, 2, 3], "D"), pd.DatetimeIndex), + pd.DatetimeIndex, + ) + check( + assert_type(ts + pd.Series([1, 2], dtype="timedelta64[ns]"), "TimestampSeries"), + pd.Series, + ) + np_td64_arr: npt.NDArray[np.timedelta64] = np.array([1, 2], dtype="timedelta64[ns]") + np_dt64_arr: npt.NDArray[np.datetime64] = np.array( + [1, 2, 3], dtype="datetime64[ns]" + ) + check( + assert_type(ts + np_td64_arr, npt.NDArray[np.datetime64]), + np.ndarray, + ) + check( + assert_type(pd.TimedeltaIndex([1, 2, 3], "D") + ts, pd.DatetimeIndex), + pd.DatetimeIndex, + ) + check( + assert_type(pd.Series([1, 2], dtype="timedelta64[ns]") + ts, "TimestampSeries"), + pd.Series, + ) + + check(assert_type(ts - pd.Timedelta(days=1), pd.Timestamp), pd.Timestamp) + check(assert_type(ts - dt.timedelta(days=1), pd.Timestamp), pd.Timestamp) + check(assert_type(ts - 3 * Day(), pd.Timestamp), pd.Timestamp) + check( + assert_type(ts - pd.TimedeltaIndex([1, 2, 3], "D"), pd.DatetimeIndex), + pd.DatetimeIndex, + ) + ts_series = cast("TimedeltaSeries", pd.Series([1, 2], dtype="timedelta64[ns]")) + check( + assert_type(ts - ts_series, "TimestampSeries"), + pd.Series, + ) + check(assert_type(ts - np_td64_arr, npt.NDArray[np.datetime64]), np.ndarray) + + check(assert_type(ts > ts, bool), bool) + check(assert_type(ts > np.datetime64(1, "ns"), bool), bool) + check(assert_type(ts > dt.datetime(year=2000, month=1, day=1), bool), bool) + check(assert_type(ts > pd.DatetimeIndex(["2000-1-1"]), np_ndarray_bool), np.ndarray) + check(assert_type(ts > np_dt64_arr, np_ndarray_bool), np.ndarray) + check( + assert_type( + ts > pd.Series([1, 2, 3], dtype="datetime64[ns]"), "pd.Series[bool]" + ), + pd.Series, + ) + + check(assert_type(dt.datetime(year=2000, month=1, day=1) > ts, bool), bool) + check(assert_type(pd.DatetimeIndex(["2000-1-1"]) > ts, np_ndarray_bool), np.ndarray) + check(assert_type(np_dt64_arr > ts, np_ndarray_bool), np.ndarray) + check( + assert_type( + pd.Series([1, 2, 3], dtype="datetime64[ns]") > ts, "pd.Series[bool]" + ), + pd.Series, + ) + + check(assert_type(ts >= ts, bool), bool) + check(assert_type(ts >= np.datetime64(1, "ns"), bool), bool) + check(assert_type(ts >= dt.datetime(year=2000, month=1, day=1), bool), bool) + check( + assert_type(ts >= pd.DatetimeIndex(["2000-1-1"]), np_ndarray_bool), np.ndarray + ) + check(assert_type(ts >= np_dt64_arr, np_ndarray_bool), np.ndarray) + check( + assert_type( + ts >= pd.Series([1, 2, 3], dtype="datetime64[ns]"), "pd.Series[bool]" + ), + pd.Series, + ) + + check(assert_type(dt.datetime(year=2000, month=1, day=1) >= ts, bool), bool) + check( + assert_type(pd.DatetimeIndex(["2000-1-1"]) >= ts, np_ndarray_bool), np.ndarray + ) + check(assert_type(np_dt64_arr >= ts, np_ndarray_bool), np.ndarray) + check( + assert_type( + pd.Series([1, 2, 3], dtype="datetime64[ns]") >= ts, "pd.Series[bool]" + ), + pd.Series, + ) + + check(assert_type(ts < ts, bool), bool) + check(assert_type(ts < np.datetime64(1, "ns"), bool), bool) + check(assert_type(ts < dt.datetime(year=2000, month=1, day=1), bool), bool) + check(assert_type(ts < pd.DatetimeIndex(["2000-1-1"]), np_ndarray_bool), np.ndarray) + check(assert_type(ts < np_dt64_arr, np_ndarray_bool), np.ndarray) + check( + assert_type( + ts < pd.Series([1, 2, 3], dtype="datetime64[ns]"), "pd.Series[bool]" + ), + pd.Series, + ) + + check(assert_type(dt.datetime(year=2000, month=1, day=1) < ts, bool), bool) + check(assert_type(pd.DatetimeIndex(["2000-1-1"]) < ts, np_ndarray_bool), np.ndarray) + check(assert_type(np_dt64_arr < ts, np_ndarray_bool), np.ndarray) + check( + assert_type( + pd.Series([1, 2, 3], dtype="datetime64[ns]") < ts, "pd.Series[bool]" + ), + pd.Series, + ) + + check(assert_type(ts <= ts, bool), bool) + check(assert_type(ts <= np.datetime64(1, "ns"), bool), bool) + check(assert_type(ts <= dt.datetime(year=2000, month=1, day=1), bool), bool) + check( + assert_type(ts <= pd.DatetimeIndex(["2000-1-1"]), np_ndarray_bool), np.ndarray + ) + check(assert_type(ts <= np_dt64_arr, np_ndarray_bool), np.ndarray) + check( + assert_type( + ts <= pd.Series([1, 2, 3], dtype="datetime64[ns]"), "pd.Series[bool]" + ), + pd.Series, + ) + + check(assert_type(dt.datetime(year=2000, month=1, day=1) <= ts, bool), bool) + check( + assert_type(pd.DatetimeIndex(["2000-1-1"]) <= ts, np_ndarray_bool), np.ndarray + ) + check(assert_type(np_dt64_arr <= ts, np_ndarray_bool), np.ndarray) + check( + assert_type( + pd.Series([1, 2, 3], dtype="datetime64[ns]") <= ts, "pd.Series[bool]" + ), + pd.Series, + ) + + check(assert_type(ts == ts, bool), bool) + check(assert_type(ts == np.datetime64(1, "ns"), bool), bool) + check(assert_type(ts == dt.datetime(year=2000, month=1, day=1), bool), bool) + check( + assert_type(ts == pd.DatetimeIndex(["2000-1-1"]), np_ndarray_bool), np.ndarray + ) + check( + assert_type(ts == np_dt64_arr, np_ndarray_bool), + np.ndarray, + ) + check( + assert_type( + ts == pd.Series([1, 2, 3], dtype="datetime64[ns]"), "pd.Series[bool]" + ), + pd.Series, + ) + + check(assert_type(dt.datetime(year=2000, month=1, day=1) == ts, bool), bool) + check( + assert_type(pd.DatetimeIndex(["2000-1-1"]) == ts, np_ndarray_bool), np.ndarray + ) + + check( + assert_type( + pd.Series([1, 2, 3], dtype="datetime64[ns]") == ts, "pd.Series[bool]" + ), + pd.Series, + ) + + check(assert_type(ts != ts, bool), bool) + check(assert_type(ts != np.datetime64(1, "ns"), bool), bool) + check(assert_type(ts != dt.datetime(year=2000, month=1, day=1), bool), bool) + check( + assert_type(ts != pd.DatetimeIndex(["2000-1-1"]), np_ndarray_bool), np.ndarray + ) + check(assert_type(ts != np_dt64_arr, np_ndarray_bool), np.ndarray) + check( + assert_type( + ts != pd.Series([1, 2, 3], dtype="datetime64[ns]"), "pd.Series[bool]" + ), + pd.Series, + ) + + check(assert_type(dt.datetime(year=2000, month=1, day=1) != ts, bool), bool) + check( + assert_type(pd.DatetimeIndex(["2000-1-1"]) != ts, np_ndarray_bool), np.ndarray + ) + check( + assert_type( + pd.Series([1, 2, 3], dtype="datetime64[ns]") != ts, "pd.Series[bool]" + ), + pd.Series, + ) + + # Failures due to NumPy ops returning Any + check( + assert_type( # type: ignore[assert-type] + np_td64_arr + ts, npt.NDArray[np.datetime64] # type: ignore[operator] + ), + np.ndarray, + ) + check(assert_type(np.datetime64(1, "ns") > ts, np.bool_), np.bool_) # type: ignore[assert-type] + check(assert_type(np.datetime64(1, "ns") >= ts, np.bool_), np.bool_) # type: ignore[assert-type] + check(assert_type(np.datetime64(1, "ns") < ts, np.bool_), np.bool_) # type: ignore[assert-type] + check(assert_type(np.datetime64(1, "ns") <= ts, np.bool_), np.bool_) # type: ignore[assert-type] + check(assert_type(np.datetime64(1, "ns") == ts, np.bool_), np.bool_) # type: ignore[assert-type] + check(assert_type(np_dt64_arr == ts, np_ndarray_bool), np.ndarray) # type: ignore[assert-type] + check(assert_type(np.datetime64(1, "ns") != ts, np.bool_), np.bool_) # type: ignore[assert-type] + check(assert_type(np_dt64_arr != ts, np_ndarray_bool), np.ndarray) # type: ignore[assert-type] From 3fc101d940661b6e41217eb2fcd9ba9072cf2870 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sun, 16 Oct 2022 13:50:49 +0100 Subject: [PATCH 02/12] MAINT: Add dep for testing --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index f310eaa49..d8eae891d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,6 +59,7 @@ tabulate = ">=0.8.10" jinja2 = "^3.1" scipy = ">=1.9.1" SQLAlchemy = "^1.4.41" +types-python-dateutil = ">=2.8.19" [build-system] requires = ["poetry-core>=1.0.0"] From b08505720e8f5706917b431c9551e6c130d6a67e Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sun, 16 Oct 2022 14:03:17 +0100 Subject: [PATCH 03/12] ENH: Improve fold --- pandas-stubs/_libs/tslibs/timestamps.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas-stubs/_libs/tslibs/timestamps.pyi b/pandas-stubs/_libs/tslibs/timestamps.pyi index 948c4ac0a..9b9446101 100644 --- a/pandas-stubs/_libs/tslibs/timestamps.pyi +++ b/pandas-stubs/_libs/tslibs/timestamps.pyi @@ -131,7 +131,7 @@ class Timestamp(datetime): second: int | None = ..., microsecond: int | None = ..., tzinfo: _tzinfo | None = ..., - fold: int | None = ..., + fold: Literal[0, 1] | None = ..., ) -> Timestamp: ... def astimezone(self: _DatetimeT, tz: _tzinfo | None = ...) -> _DatetimeT: ... def ctime(self) -> str: ... From e9065cb6b118282a2f6826abc94e793c2d176a5f Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sun, 16 Oct 2022 17:15:04 +0100 Subject: [PATCH 04/12] REV: Revert Literal due to violation of Liskov subst. princip. --- pandas-stubs/_libs/tslibs/timestamps.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas-stubs/_libs/tslibs/timestamps.pyi b/pandas-stubs/_libs/tslibs/timestamps.pyi index 9b9446101..948c4ac0a 100644 --- a/pandas-stubs/_libs/tslibs/timestamps.pyi +++ b/pandas-stubs/_libs/tslibs/timestamps.pyi @@ -131,7 +131,7 @@ class Timestamp(datetime): second: int | None = ..., microsecond: int | None = ..., tzinfo: _tzinfo | None = ..., - fold: Literal[0, 1] | None = ..., + fold: int | None = ..., ) -> Timestamp: ... def astimezone(self: _DatetimeT, tz: _tzinfo | None = ...) -> _DatetimeT: ... def ctime(self) -> str: ... From 9b935dfff61f94742472313c1a537a4a8266ac3f Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sun, 16 Oct 2022 14:03:17 +0100 Subject: [PATCH 05/12] TST: Add type tests for series --- tests/test_scalars.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/test_scalars.py b/tests/test_scalars.py index fb4737fb1..b3de46862 100644 --- a/tests/test_scalars.py +++ b/tests/test_scalars.py @@ -150,6 +150,7 @@ def test_timestamp() -> None: ts > pd.Series([1, 2, 3], dtype="datetime64[ns]"), "pd.Series[bool]" ), pd.Series, + bool, ) check(assert_type(dt.datetime(year=2000, month=1, day=1) > ts, bool), bool) @@ -160,6 +161,7 @@ def test_timestamp() -> None: pd.Series([1, 2, 3], dtype="datetime64[ns]") > ts, "pd.Series[bool]" ), pd.Series, + bool, ) check(assert_type(ts >= ts, bool), bool) @@ -174,6 +176,7 @@ def test_timestamp() -> None: ts >= pd.Series([1, 2, 3], dtype="datetime64[ns]"), "pd.Series[bool]" ), pd.Series, + bool, ) check(assert_type(dt.datetime(year=2000, month=1, day=1) >= ts, bool), bool) @@ -186,6 +189,7 @@ def test_timestamp() -> None: pd.Series([1, 2, 3], dtype="datetime64[ns]") >= ts, "pd.Series[bool]" ), pd.Series, + bool, ) check(assert_type(ts < ts, bool), bool) @@ -198,6 +202,7 @@ def test_timestamp() -> None: ts < pd.Series([1, 2, 3], dtype="datetime64[ns]"), "pd.Series[bool]" ), pd.Series, + bool, ) check(assert_type(dt.datetime(year=2000, month=1, day=1) < ts, bool), bool) @@ -208,6 +213,7 @@ def test_timestamp() -> None: pd.Series([1, 2, 3], dtype="datetime64[ns]") < ts, "pd.Series[bool]" ), pd.Series, + bool, ) check(assert_type(ts <= ts, bool), bool) @@ -222,6 +228,7 @@ def test_timestamp() -> None: ts <= pd.Series([1, 2, 3], dtype="datetime64[ns]"), "pd.Series[bool]" ), pd.Series, + bool, ) check(assert_type(dt.datetime(year=2000, month=1, day=1) <= ts, bool), bool) @@ -234,6 +241,7 @@ def test_timestamp() -> None: pd.Series([1, 2, 3], dtype="datetime64[ns]") <= ts, "pd.Series[bool]" ), pd.Series, + bool, ) check(assert_type(ts == ts, bool), bool) @@ -251,6 +259,7 @@ def test_timestamp() -> None: ts == pd.Series([1, 2, 3], dtype="datetime64[ns]"), "pd.Series[bool]" ), pd.Series, + bool, ) check(assert_type(dt.datetime(year=2000, month=1, day=1) == ts, bool), bool) @@ -263,6 +272,7 @@ def test_timestamp() -> None: pd.Series([1, 2, 3], dtype="datetime64[ns]") == ts, "pd.Series[bool]" ), pd.Series, + bool, ) check(assert_type(ts != ts, bool), bool) @@ -277,6 +287,7 @@ def test_timestamp() -> None: ts != pd.Series([1, 2, 3], dtype="datetime64[ns]"), "pd.Series[bool]" ), pd.Series, + bool, ) check(assert_type(dt.datetime(year=2000, month=1, day=1) != ts, bool), bool) @@ -288,6 +299,7 @@ def test_timestamp() -> None: pd.Series([1, 2, 3], dtype="datetime64[ns]") != ts, "pd.Series[bool]" ), pd.Series, + bool, ) # Failures due to NumPy ops returning Any From 1666a67800e38dd3fd3d5ca098d1eb357b706135 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 17 Oct 2022 08:23:01 +0100 Subject: [PATCH 06/12] CLN: Clean testing code --- pandas-stubs/_libs/tslibs/timestamps.pyi | 10 +- tests/test_scalars.py | 454 +++++++++++------------ 2 files changed, 228 insertions(+), 236 deletions(-) diff --git a/pandas-stubs/_libs/tslibs/timestamps.pyi b/pandas-stubs/_libs/tslibs/timestamps.pyi index 948c4ac0a..9a941ea96 100644 --- a/pandas-stubs/_libs/tslibs/timestamps.pyi +++ b/pandas-stubs/_libs/tslibs/timestamps.pyi @@ -121,7 +121,9 @@ class Timestamp(datetime): def date(self) -> _date: ... def time(self) -> _time: ... def timetz(self) -> _time: ... - def replace( + # Override since fold is more precise than datetime.replace(fold:int) + # Violation of Liskov substitution principle + def replace( # type:ignore[override] self, year: int | None = ..., month: int | None = ..., @@ -131,7 +133,7 @@ class Timestamp(datetime): second: int | None = ..., microsecond: int | None = ..., tzinfo: _tzinfo | None = ..., - fold: int | None = ..., + fold: Literal[0, 1] | None = ..., ) -> Timestamp: ... def astimezone(self: _DatetimeT, tz: _tzinfo | None = ...) -> _DatetimeT: ... def ctime(self) -> str: ... @@ -184,6 +186,10 @@ class Timestamp(datetime): def __radd__(self: _DatetimeT, other: timedelta) -> _DatetimeT: ... @overload def __radd__(self, other: TimedeltaIndex) -> DatetimeIndex: ... + @overload + def __radd__( + self, other: npt.NDArray[np.timedelta64] + ) -> npt.NDArray[np.datetime64]: ... @overload # type: ignore[override] def __sub__(self, other: datetime) -> Timedelta: ... @overload diff --git a/tests/test_scalars.py b/tests/test_scalars.py index b3de46862..8985ccf30 100644 --- a/tests/test_scalars.py +++ b/tests/test_scalars.py @@ -28,42 +28,82 @@ from pandas.tseries.offsets import Day -def test_timestamp() -> None: - - pd.Timestamp("2000-1-1") - pd.Timestamp("2000-1-1", tz="US/Pacific") - pd.Timestamp("2000-1-1", tz=pytz.timezone("US/Eastern")) - pd.Timestamp("2000-1-1", tz=dateutil.tz.UTC) - pd.Timestamp( - year=2000, - month=1, - day=1, - hour=1, - minute=1, - second=1, - microsecond=1, - nanosecond=1, +def test_timestamp_construction() -> None: + + check(assert_type(pd.Timestamp("2000-1-1"), pd.Timestamp), pd.Timestamp) + check( + assert_type(pd.Timestamp("2000-1-1", tz="US/Pacific"), pd.Timestamp), + pd.Timestamp, + ) + check( + assert_type( + pd.Timestamp("2000-1-1", tz=pytz.timezone("US/Eastern")), pd.Timestamp + ), + pd.Timestamp, + ) + check( + assert_type(pd.Timestamp("2000-1-1", tz=dateutil.tz.UTC), pd.Timestamp), + pd.Timestamp, + ) + check( + assert_type( + pd.Timestamp( + year=2000, + month=1, + day=1, + hour=1, + minute=1, + second=1, + microsecond=1, + nanosecond=1, + ), + pd.Timestamp, + ), + pd.Timestamp, + ) + check(assert_type(pd.Timestamp(1, unit="D"), pd.Timestamp), pd.Timestamp) + check(assert_type(pd.Timestamp(1, unit="h"), pd.Timestamp), pd.Timestamp) + check(assert_type(pd.Timestamp(1, unit="m"), pd.Timestamp), pd.Timestamp) + check(assert_type(pd.Timestamp(1, unit="s"), pd.Timestamp), pd.Timestamp) + check(assert_type(pd.Timestamp(1, unit="ms"), pd.Timestamp), pd.Timestamp) + check(assert_type(pd.Timestamp(1, unit="us"), pd.Timestamp), pd.Timestamp) + check( + assert_type( + pd.Timestamp(year=2000, month=3, day=24, hour=12, minute=27, fold=0), + pd.Timestamp, + ), + pd.Timestamp, + ) + check( + assert_type( + pd.Timestamp(year=2000, month=3, day=24, hour=12, minute=27, fold=1), + pd.Timestamp, + ), + pd.Timestamp, ) - pd.Timestamp(1, unit="D") - pd.Timestamp(1, unit="h") - pd.Timestamp(1, unit="m") - pd.Timestamp(1, unit="s") - pd.Timestamp(1, unit="ms") - pd.Timestamp(1, unit="us") - pd.Timestamp(year=2000, month=3, day=24, hour=12, minute=27, fold=0) - pd.Timestamp(year=2000, month=3, day=24, hour=12, minute=27, fold=1) - pd.Timestamp( - year=2000, - month=1, - day=1, - hour=1, - minute=1, - second=1, - microsecond=1, - nanosecond=1, - tzinfo=dt.timezone(offset=dt.timedelta(hours=6), name="EST"), + check( + assert_type( + pd.Timestamp( + year=2000, + month=1, + day=1, + hour=1, + minute=1, + second=1, + microsecond=1, + nanosecond=1, + tzinfo=dt.timezone(offset=dt.timedelta(hours=6), name="EST"), + ), + pd.Timestamp, + ), + pd.Timestamp, ) + + +def test_timestamp_properties() -> None: ts = pd.Timestamp(year=2000, month=3, day=24, hour=12, minute=27) + + check(assert_type(ts, pd.Timestamp), pd.Timestamp) check(assert_type(ts.asm8, np.datetime64), np.datetime64) check(assert_type(ts.day_of_week, int), int) check(assert_type(ts.day_of_year, int), int) @@ -94,226 +134,172 @@ def test_timestamp() -> None: check(assert_type(ts.value, int), int) check(assert_type(ts.year, int), int) + +def test_timestamp_add_sub() -> None: ts = pd.Timestamp("2000-1-1") - check(assert_type(ts + pd.Timedelta(days=1), pd.Timestamp), pd.Timestamp) - check(assert_type(ts + dt.timedelta(days=1), pd.Timestamp), pd.Timestamp) - check(assert_type(pd.Timedelta(days=1) + ts, pd.Timestamp), pd.Timestamp) - check(assert_type(dt.timedelta(days=1) + ts, pd.Timestamp), pd.Timestamp) - check(assert_type(ts + 3 * Day(), pd.Timestamp), pd.Timestamp) - check(assert_type(3 * Day() + ts, pd.Timestamp), pd.Timestamp) - check( - assert_type(ts + pd.TimedeltaIndex([1, 2, 3], "D"), pd.DatetimeIndex), - pd.DatetimeIndex, - ) - check( - assert_type(ts + pd.Series([1, 2], dtype="timedelta64[ns]"), "TimestampSeries"), - pd.Series, - ) + ts_series = cast("TimedeltaSeries", pd.Series([1, 2], dtype="timedelta64[ns]")) np_td64_arr: npt.NDArray[np.timedelta64] = np.array([1, 2], dtype="timedelta64[ns]") - np_dt64_arr: npt.NDArray[np.datetime64] = np.array( - [1, 2, 3], dtype="datetime64[ns]" - ) - check( - assert_type(ts + np_td64_arr, npt.NDArray[np.datetime64]), - np.ndarray, - ) - check( - assert_type(pd.TimedeltaIndex([1, 2, 3], "D") + ts, pd.DatetimeIndex), - pd.DatetimeIndex, - ) - check( - assert_type(pd.Series([1, 2], dtype="timedelta64[ns]") + ts, "TimestampSeries"), - pd.Series, - ) - check(assert_type(ts - pd.Timedelta(days=1), pd.Timestamp), pd.Timestamp) - check(assert_type(ts - dt.timedelta(days=1), pd.Timestamp), pd.Timestamp) - check(assert_type(ts - 3 * Day(), pd.Timestamp), pd.Timestamp) - check( - assert_type(ts - pd.TimedeltaIndex([1, 2, 3], "D"), pd.DatetimeIndex), - pd.DatetimeIndex, - ) - ts_series = cast("TimedeltaSeries", pd.Series([1, 2], dtype="timedelta64[ns]")) - check( - assert_type(ts - ts_series, "TimestampSeries"), - pd.Series, - ) - check(assert_type(ts - np_td64_arr, npt.NDArray[np.datetime64]), np.ndarray) + as1 = pd.Timedelta(days=1) + as2 = dt.timedelta(days=1) + as3 = 3 * Day() + as4 = pd.TimedeltaIndex([1, 2, 3], "D") + as5 = ts_series + as6 = np_td64_arr - check(assert_type(ts > ts, bool), bool) - check(assert_type(ts > np.datetime64(1, "ns"), bool), bool) - check(assert_type(ts > dt.datetime(year=2000, month=1, day=1), bool), bool) - check(assert_type(ts > pd.DatetimeIndex(["2000-1-1"]), np_ndarray_bool), np.ndarray) - check(assert_type(ts > np_dt64_arr, np_ndarray_bool), np.ndarray) - check( - assert_type( - ts > pd.Series([1, 2, 3], dtype="datetime64[ns]"), "pd.Series[bool]" - ), - pd.Series, - bool, - ) + check(assert_type(ts + as1, pd.Timestamp), pd.Timestamp) + check(assert_type(ts + as2, pd.Timestamp), pd.Timestamp) + check(assert_type(ts + as3, pd.Timestamp), pd.Timestamp) + check(assert_type(ts + as4, pd.DatetimeIndex), pd.DatetimeIndex) + check(assert_type(ts + as5, "TimestampSeries"), pd.Series) + check(assert_type(ts + as6, npt.NDArray[np.datetime64]), np.ndarray) - check(assert_type(dt.datetime(year=2000, month=1, day=1) > ts, bool), bool) - check(assert_type(pd.DatetimeIndex(["2000-1-1"]) > ts, np_ndarray_bool), np.ndarray) - check(assert_type(np_dt64_arr > ts, np_ndarray_bool), np.ndarray) + check(assert_type(as1 + ts, pd.Timestamp), pd.Timestamp) + check(assert_type(as2 + ts, pd.Timestamp), pd.Timestamp) + check(assert_type(as3 + ts, pd.Timestamp), pd.Timestamp) + check(assert_type(as4 + ts, pd.DatetimeIndex), pd.DatetimeIndex) + check(assert_type(as5 + ts, "TimestampSeries"), pd.Series) + # pyright and mypy disagree on the type of this expression + # pyright: Any, mypy: npt.NDArray[np.datetime64] check( assert_type( - pd.Series([1, 2, 3], dtype="datetime64[ns]") > ts, "pd.Series[bool]" + as6 + ts, # pyright: ignore [reportGeneralTypeIssues] + npt.NDArray[np.datetime64], ), - pd.Series, - bool, + np.ndarray, ) - check(assert_type(ts >= ts, bool), bool) - check(assert_type(ts >= np.datetime64(1, "ns"), bool), bool) - check(assert_type(ts >= dt.datetime(year=2000, month=1, day=1), bool), bool) - check( - assert_type(ts >= pd.DatetimeIndex(["2000-1-1"]), np_ndarray_bool), np.ndarray - ) - check(assert_type(ts >= np_dt64_arr, np_ndarray_bool), np.ndarray) - check( - assert_type( - ts >= pd.Series([1, 2, 3], dtype="datetime64[ns]"), "pd.Series[bool]" - ), - pd.Series, - bool, - ) + check(assert_type(ts - as1, pd.Timestamp), pd.Timestamp) + check(assert_type(ts - as2, pd.Timestamp), pd.Timestamp) + check(assert_type(ts - as3, pd.Timestamp), pd.Timestamp) + check(assert_type(ts - as4, pd.DatetimeIndex), pd.DatetimeIndex) + check(assert_type(ts - as5, "TimestampSeries"), pd.Series) + check(assert_type(ts - as6, npt.NDArray[np.datetime64]), np.ndarray) - check(assert_type(dt.datetime(year=2000, month=1, day=1) >= ts, bool), bool) - check( - assert_type(pd.DatetimeIndex(["2000-1-1"]) >= ts, np_ndarray_bool), np.ndarray - ) - check(assert_type(np_dt64_arr >= ts, np_ndarray_bool), np.ndarray) - check( - assert_type( - pd.Series([1, 2, 3], dtype="datetime64[ns]") >= ts, "pd.Series[bool]" - ), - pd.Series, - bool, - ) - check(assert_type(ts < ts, bool), bool) - check(assert_type(ts < np.datetime64(1, "ns"), bool), bool) - check(assert_type(ts < dt.datetime(year=2000, month=1, day=1), bool), bool) - check(assert_type(ts < pd.DatetimeIndex(["2000-1-1"]), np_ndarray_bool), np.ndarray) - check(assert_type(ts < np_dt64_arr, np_ndarray_bool), np.ndarray) - check( - assert_type( - ts < pd.Series([1, 2, 3], dtype="datetime64[ns]"), "pd.Series[bool]" - ), - pd.Series, - bool, - ) +def test_timestamp_cmp() -> None: + ts = pd.Timestamp(year=2000, month=3, day=24, hour=12, minute=27) - check(assert_type(dt.datetime(year=2000, month=1, day=1) < ts, bool), bool) - check(assert_type(pd.DatetimeIndex(["2000-1-1"]) < ts, np_ndarray_bool), np.ndarray) - check(assert_type(np_dt64_arr < ts, np_ndarray_bool), np.ndarray) - check( - assert_type( - pd.Series([1, 2, 3], dtype="datetime64[ns]") < ts, "pd.Series[bool]" - ), - pd.Series, - bool, + np_dt64_arr: npt.NDArray[np.datetime64] = np.array( + [1, 2, 3], dtype="datetime64[ns]" ) - check(assert_type(ts <= ts, bool), bool) - check(assert_type(ts <= np.datetime64(1, "ns"), bool), bool) - check(assert_type(ts <= dt.datetime(year=2000, month=1, day=1), bool), bool) - check( - assert_type(ts <= pd.DatetimeIndex(["2000-1-1"]), np_ndarray_bool), np.ndarray - ) - check(assert_type(ts <= np_dt64_arr, np_ndarray_bool), np.ndarray) - check( - assert_type( - ts <= pd.Series([1, 2, 3], dtype="datetime64[ns]"), "pd.Series[bool]" - ), - pd.Series, - bool, - ) + c1 = ts + c2 = np.datetime64(1, "ns") + c3 = dt.datetime(year=2000, month=1, day=1) + c4 = pd.DatetimeIndex(["2000-1-1"]) + c5 = np_dt64_arr + c6 = pd.Series([1, 2, 3], dtype="datetime64[ns]") - check(assert_type(dt.datetime(year=2000, month=1, day=1) <= ts, bool), bool) - check( - assert_type(pd.DatetimeIndex(["2000-1-1"]) <= ts, np_ndarray_bool), np.ndarray - ) - check(assert_type(np_dt64_arr <= ts, np_ndarray_bool), np.ndarray) - check( - assert_type( - pd.Series([1, 2, 3], dtype="datetime64[ns]") <= ts, "pd.Series[bool]" - ), - pd.Series, - bool, - ) + # Use xor to ensure one is True and the other is False + # Correctness ensures since tested to be bools + gt = check(assert_type(ts > c1, bool), bool) + lte = check(assert_type(ts <= c1, bool), bool) + assert gt != lte - check(assert_type(ts == ts, bool), bool) - check(assert_type(ts == np.datetime64(1, "ns"), bool), bool) - check(assert_type(ts == dt.datetime(year=2000, month=1, day=1), bool), bool) - check( - assert_type(ts == pd.DatetimeIndex(["2000-1-1"]), np_ndarray_bool), np.ndarray - ) - check( - assert_type(ts == np_dt64_arr, np_ndarray_bool), - np.ndarray, - ) - check( - assert_type( - ts == pd.Series([1, 2, 3], dtype="datetime64[ns]"), "pd.Series[bool]" - ), - pd.Series, - bool, - ) + gt = check(assert_type(ts > c2, bool), bool) + lte = check(assert_type(ts <= c2, bool), bool) + assert gt != lte - check(assert_type(dt.datetime(year=2000, month=1, day=1) == ts, bool), bool) - check( - assert_type(pd.DatetimeIndex(["2000-1-1"]) == ts, np_ndarray_bool), np.ndarray - ) + gt = check(assert_type(ts > c3, bool), bool) + lte = check(assert_type(ts <= c3, bool), bool) + assert gt != lte - check( - assert_type( - pd.Series([1, 2, 3], dtype="datetime64[ns]") == ts, "pd.Series[bool]" - ), - pd.Series, - bool, - ) + check(assert_type(ts > c4, np_ndarray_bool), np.ndarray) + check(assert_type(ts <= c4, np_ndarray_bool), np.ndarray) - check(assert_type(ts != ts, bool), bool) - check(assert_type(ts != np.datetime64(1, "ns"), bool), bool) - check(assert_type(ts != dt.datetime(year=2000, month=1, day=1), bool), bool) - check( - assert_type(ts != pd.DatetimeIndex(["2000-1-1"]), np_ndarray_bool), np.ndarray - ) - check(assert_type(ts != np_dt64_arr, np_ndarray_bool), np.ndarray) - check( - assert_type( - ts != pd.Series([1, 2, 3], dtype="datetime64[ns]"), "pd.Series[bool]" - ), - pd.Series, - bool, - ) + check(assert_type(ts > c5, np_ndarray_bool), np.ndarray) + check(assert_type(ts <= c5, np_ndarray_bool), np.ndarray) - check(assert_type(dt.datetime(year=2000, month=1, day=1) != ts, bool), bool) - check( - assert_type(pd.DatetimeIndex(["2000-1-1"]) != ts, np_ndarray_bool), np.ndarray - ) - check( - assert_type( - pd.Series([1, 2, 3], dtype="datetime64[ns]") != ts, "pd.Series[bool]" - ), - pd.Series, - bool, - ) + check(assert_type(ts > c6, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(ts <= c6, "pd.Series[bool]"), pd.Series, bool) - # Failures due to NumPy ops returning Any - check( - assert_type( # type: ignore[assert-type] - np_td64_arr + ts, npt.NDArray[np.datetime64] # type: ignore[operator] - ), - np.ndarray, - ) - check(assert_type(np.datetime64(1, "ns") > ts, np.bool_), np.bool_) # type: ignore[assert-type] - check(assert_type(np.datetime64(1, "ns") >= ts, np.bool_), np.bool_) # type: ignore[assert-type] - check(assert_type(np.datetime64(1, "ns") < ts, np.bool_), np.bool_) # type: ignore[assert-type] - check(assert_type(np.datetime64(1, "ns") <= ts, np.bool_), np.bool_) # type: ignore[assert-type] - check(assert_type(np.datetime64(1, "ns") == ts, np.bool_), np.bool_) # type: ignore[assert-type] - check(assert_type(np_dt64_arr == ts, np_ndarray_bool), np.ndarray) # type: ignore[assert-type] - check(assert_type(np.datetime64(1, "ns") != ts, np.bool_), np.bool_) # type: ignore[assert-type] - check(assert_type(np_dt64_arr != ts, np_ndarray_bool), np.ndarray) # type: ignore[assert-type] + check(assert_type(c2 > ts, Any), np.bool_) + check(assert_type(c2 <= ts, Any), np.bool_) + + gt = check(assert_type(c3 > ts, bool), bool) + lte = check(assert_type(c3 <= ts, bool), bool) + assert gt != lte + + check(assert_type(c4 > ts, np_ndarray_bool), np.ndarray) + check(assert_type(c4 <= ts, np_ndarray_bool), np.ndarray) + + check(assert_type(c5 > ts, np_ndarray_bool), np.ndarray) + check(assert_type(c5 <= ts, np_ndarray_bool), np.ndarray) + + check(assert_type(c6 > ts, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(c6 <= ts, "pd.Series[bool]"), pd.Series, bool) + + gte = check(assert_type(ts >= c1, bool), bool) + lt = check(assert_type(ts < c1, bool), bool) + assert gte != lt + + gte = check(assert_type(ts >= c2, bool), bool) + lt = check(assert_type(ts < c2, bool), bool) + assert gte != lt + + gte = check(assert_type(ts >= c3, bool), bool) + lt = check(assert_type(ts < c3, bool), bool) + assert gte != lt + + check(assert_type(ts >= c4, np_ndarray_bool), np.ndarray) + check(assert_type(ts < c4, np_ndarray_bool), np.ndarray) + + check(assert_type(ts >= c5, np_ndarray_bool), np.ndarray) + check(assert_type(ts < c5, np_ndarray_bool), np.ndarray) + + check(assert_type(ts >= c6, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(ts < c6, "pd.Series[bool]"), pd.Series, bool) + + gte = check(assert_type(c3 >= ts, bool), bool) + lt = check(assert_type(c3 < ts, bool), bool) + assert gte != lt + + check(assert_type(c2 >= ts, Any), np.bool_) + check(assert_type(c2 < ts, Any), np.bool_) + + check(assert_type(c4 >= ts, np_ndarray_bool), np.ndarray) + check(assert_type(c4 < ts, np_ndarray_bool), np.ndarray) + + check(assert_type(c5 >= ts, np_ndarray_bool), np.ndarray) + check(assert_type(c5 < ts, np_ndarray_bool), np.ndarray) + + check(assert_type(c6 >= ts, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(c6 < ts, "pd.Series[bool]"), pd.Series, bool) + + eq = check(assert_type(ts == c1, bool), bool) + ne = check(assert_type(ts != c1, bool), bool) + assert eq != ne + + eq = check(assert_type(ts == c2, bool), bool) + ne = check(assert_type(ts != c2, bool), bool) + assert eq != ne + + eq = check(assert_type(ts == c3, bool), bool) + ne = check(assert_type(ts != c3, bool), bool) + assert eq != ne + + check(assert_type(ts == c4, np_ndarray_bool), np.ndarray) + check(assert_type(ts != c4, np_ndarray_bool), np.ndarray) + + check(assert_type(ts == c5, np_ndarray_bool), np.ndarray) + check(assert_type(ts != c5, np_ndarray_bool), np.ndarray) + + check(assert_type(ts == c6, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(ts != c6, "pd.Series[bool]"), pd.Series, bool) + + check(assert_type(c2 == ts, Any), np.bool_) + check(assert_type(c2 != ts, Any), np.bool_) + + eq = check(assert_type(c3 == ts, bool), bool) + ne = check(assert_type(c3 != ts, bool), bool) + assert eq != ne + + check(assert_type(c4 == ts, np_ndarray_bool), np.ndarray) + check(assert_type(c4 != ts, np_ndarray_bool), np.ndarray) + + check(assert_type(c5 != ts, Any), np.ndarray) + check(assert_type(c5 == ts, Any), np.ndarray) + + check(assert_type(c6 == ts, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(c6 != ts, "pd.Series[bool]"), pd.Series, bool) From dacff37896201406a3487454e1acb2951d54cd28 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Fri, 21 Oct 2022 18:09:25 +0100 Subject: [PATCH 07/12] ENH: Further refinements of timestamp and tests --- pandas-stubs/core/series.pyi | 10 ++ tests/test_scalars.py | 227 +++++++++++++++++++---------------- 2 files changed, 133 insertions(+), 104 deletions(-) diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 0a12a9a1b..d54d91bb5 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -186,6 +186,16 @@ class Series(IndexOpsMixin, NDFrame, Generic[S1]): fastpath: bool = ..., ) -> TimestampSeries: ... @overload + def __new__( + cls, + data: TimedeltaIndex, + index: Axes | None = ..., + dtype=..., + name: Hashable | None = ..., + copy: bool = ..., + fastpath: bool = ..., + ) -> TimedeltaSeries: ... + @overload def __new__( cls, data: PeriodIndex, diff --git a/tests/test_scalars.py b/tests/test_scalars.py index 8985ccf30..8b2f3c677 100644 --- a/tests/test_scalars.py +++ b/tests/test_scalars.py @@ -5,7 +5,6 @@ TYPE_CHECKING, Any, Optional, - cast, ) import dateutil.tz @@ -16,12 +15,17 @@ from typing_extensions import assert_type if TYPE_CHECKING: - from pandas.core.series import TimedeltaSeries # noqa: F401 - from pandas.core.series import TimestampSeries # noqa: F401 + from pandas.core.series import ( + TimedeltaSeries, + TimestampSeries, + ) from pandas._typing import np_ndarray_bool else: - np_ndarray_bool = Any + np_ndarray_bool = npt.NDArray[np.bool_] + TimedeltaSeries = pd.Series + TimestampSeries = pd.Series + from tests import check @@ -137,44 +141,49 @@ def test_timestamp_properties() -> None: def test_timestamp_add_sub() -> None: ts = pd.Timestamp("2000-1-1") - ts_series = cast("TimedeltaSeries", pd.Series([1, 2], dtype="timedelta64[ns]")) np_td64_arr: npt.NDArray[np.timedelta64] = np.array([1, 2], dtype="timedelta64[ns]") - as1 = pd.Timedelta(days=1) - as2 = dt.timedelta(days=1) - as3 = 3 * Day() - as4 = pd.TimedeltaIndex([1, 2, 3], "D") - as5 = ts_series - as6 = np_td64_arr - - check(assert_type(ts + as1, pd.Timestamp), pd.Timestamp) - check(assert_type(ts + as2, pd.Timestamp), pd.Timestamp) - check(assert_type(ts + as3, pd.Timestamp), pd.Timestamp) - check(assert_type(ts + as4, pd.DatetimeIndex), pd.DatetimeIndex) - check(assert_type(ts + as5, "TimestampSeries"), pd.Series) - check(assert_type(ts + as6, npt.NDArray[np.datetime64]), np.ndarray) - - check(assert_type(as1 + ts, pd.Timestamp), pd.Timestamp) - check(assert_type(as2 + ts, pd.Timestamp), pd.Timestamp) - check(assert_type(as3 + ts, pd.Timestamp), pd.Timestamp) - check(assert_type(as4 + ts, pd.DatetimeIndex), pd.DatetimeIndex) - check(assert_type(as5 + ts, "TimestampSeries"), pd.Series) + as_pd_timedelta = pd.Timedelta(days=1) + as_dt_timedelta = dt.timedelta(days=1) + as_offset = 3 * Day() + as_timedelta_index = pd.TimedeltaIndex([1, 2, 3], "D") + as_timedelta_series = pd.Series(as_timedelta_index) + check(assert_type(as_timedelta_series, TimedeltaSeries), pd.Series) + as_np_ndarray_td64 = np_td64_arr + + check(assert_type(ts + as_pd_timedelta, pd.Timestamp), pd.Timestamp) + check(assert_type(as_pd_timedelta + ts, pd.Timestamp), pd.Timestamp) + + check(assert_type(ts + as_dt_timedelta, pd.Timestamp), pd.Timestamp) + check(assert_type(as_dt_timedelta + ts, pd.Timestamp), pd.Timestamp) + + check(assert_type(ts + as_offset, pd.Timestamp), pd.Timestamp) + check(assert_type(as_offset + ts, pd.Timestamp), pd.Timestamp) + + check(assert_type(ts + as_timedelta_index, pd.DatetimeIndex), pd.DatetimeIndex) + check(assert_type(as_timedelta_index + ts, pd.DatetimeIndex), pd.DatetimeIndex) + + check(assert_type(ts + as_timedelta_series, "TimestampSeries"), pd.Series) + check(assert_type(as_timedelta_series + ts, "TimestampSeries"), pd.Series) + + check(assert_type(ts + as_np_ndarray_td64, npt.NDArray[np.datetime64]), np.ndarray) # pyright and mypy disagree on the type of this expression # pyright: Any, mypy: npt.NDArray[np.datetime64] check( assert_type( - as6 + ts, # pyright: ignore [reportGeneralTypeIssues] + as_np_ndarray_td64 + ts, # pyright: ignore [reportGeneralTypeIssues] npt.NDArray[np.datetime64], ), np.ndarray, ) - check(assert_type(ts - as1, pd.Timestamp), pd.Timestamp) - check(assert_type(ts - as2, pd.Timestamp), pd.Timestamp) - check(assert_type(ts - as3, pd.Timestamp), pd.Timestamp) - check(assert_type(ts - as4, pd.DatetimeIndex), pd.DatetimeIndex) - check(assert_type(ts - as5, "TimestampSeries"), pd.Series) - check(assert_type(ts - as6, npt.NDArray[np.datetime64]), np.ndarray) + # Reverse order is not possible for all of these + check(assert_type(ts - as_pd_timedelta, pd.Timestamp), pd.Timestamp) + check(assert_type(ts - as_dt_timedelta, pd.Timestamp), pd.Timestamp) + check(assert_type(ts - as_offset, pd.Timestamp), pd.Timestamp) + check(assert_type(ts - as_timedelta_index, pd.DatetimeIndex), pd.DatetimeIndex) + check(assert_type(ts - as_timedelta_series, "TimestampSeries"), pd.Series) + check(assert_type(ts - as_np_ndarray_td64, npt.NDArray[np.datetime64]), np.ndarray) def test_timestamp_cmp() -> None: @@ -184,122 +193,132 @@ def test_timestamp_cmp() -> None: [1, 2, 3], dtype="datetime64[ns]" ) - c1 = ts - c2 = np.datetime64(1, "ns") - c3 = dt.datetime(year=2000, month=1, day=1) - c4 = pd.DatetimeIndex(["2000-1-1"]) - c5 = np_dt64_arr - c6 = pd.Series([1, 2, 3], dtype="datetime64[ns]") - + c_timestamp = ts + c_np_dt64 = np.datetime64(1, "ns") + c_dt_datetime = dt.datetime(year=2000, month=1, day=1) + c_datetimeindex = pd.DatetimeIndex(["2000-1-1"]) + c_np_ndarray_dt64 = np_dt64_arr + c_series_dt64 = pd.Series([1, 2, 3], dtype="datetime64[ns]") + c_series_timestamp = pd.Series(pd.DatetimeIndex(["2000-1-1"])) + check(assert_type(c_series_timestamp, TimestampSeries), pd.Series) # Use xor to ensure one is True and the other is False # Correctness ensures since tested to be bools - gt = check(assert_type(ts > c1, bool), bool) - lte = check(assert_type(ts <= c1, bool), bool) + gt = check(assert_type(ts > c_timestamp, bool), bool) + lte = check(assert_type(ts <= c_timestamp, bool), bool) assert gt != lte - gt = check(assert_type(ts > c2, bool), bool) - lte = check(assert_type(ts <= c2, bool), bool) + gt = check(assert_type(ts > c_np_dt64, bool), bool) + lte = check(assert_type(ts <= c_np_dt64, bool), bool) assert gt != lte - gt = check(assert_type(ts > c3, bool), bool) - lte = check(assert_type(ts <= c3, bool), bool) + gt = check(assert_type(ts > c_dt_datetime, bool), bool) + lte = check(assert_type(ts <= c_dt_datetime, bool), bool) assert gt != lte - check(assert_type(ts > c4, np_ndarray_bool), np.ndarray) - check(assert_type(ts <= c4, np_ndarray_bool), np.ndarray) + check(assert_type(ts > c_datetimeindex, np_ndarray_bool), np.ndarray) + check(assert_type(ts <= c_datetimeindex, np_ndarray_bool), np.ndarray) - check(assert_type(ts > c5, np_ndarray_bool), np.ndarray) - check(assert_type(ts <= c5, np_ndarray_bool), np.ndarray) + check(assert_type(ts > c_np_ndarray_dt64, np_ndarray_bool), np.ndarray) + check(assert_type(ts <= c_np_ndarray_dt64, np_ndarray_bool), np.ndarray) - check(assert_type(ts > c6, "pd.Series[bool]"), pd.Series, bool) - check(assert_type(ts <= c6, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(ts > c_series_timestamp, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(ts <= c_series_timestamp, "pd.Series[bool]"), pd.Series, bool) - check(assert_type(c2 > ts, Any), np.bool_) - check(assert_type(c2 <= ts, Any), np.bool_) + check(assert_type(ts > c_series_dt64, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(ts <= c_series_dt64, "pd.Series[bool]"), pd.Series, bool) - gt = check(assert_type(c3 > ts, bool), bool) - lte = check(assert_type(c3 <= ts, bool), bool) + check(assert_type(c_np_dt64 > ts, Any), np.bool_) + check(assert_type(c_np_dt64 <= ts, Any), np.bool_) + + gt = check(assert_type(c_dt_datetime > ts, bool), bool) + lte = check(assert_type(c_dt_datetime <= ts, bool), bool) assert gt != lte - check(assert_type(c4 > ts, np_ndarray_bool), np.ndarray) - check(assert_type(c4 <= ts, np_ndarray_bool), np.ndarray) + check(assert_type(c_datetimeindex > ts, np_ndarray_bool), np.ndarray) + check(assert_type(c_datetimeindex <= ts, np_ndarray_bool), np.ndarray) - check(assert_type(c5 > ts, np_ndarray_bool), np.ndarray) - check(assert_type(c5 <= ts, np_ndarray_bool), np.ndarray) + check(assert_type(c_np_ndarray_dt64 > ts, np_ndarray_bool), np.ndarray) + check(assert_type(c_np_ndarray_dt64 <= ts, np_ndarray_bool), np.ndarray) - check(assert_type(c6 > ts, "pd.Series[bool]"), pd.Series, bool) - check(assert_type(c6 <= ts, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(c_series_dt64 > ts, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(c_series_dt64 <= ts, "pd.Series[bool]"), pd.Series, bool) - gte = check(assert_type(ts >= c1, bool), bool) - lt = check(assert_type(ts < c1, bool), bool) + gte = check(assert_type(ts >= c_timestamp, bool), bool) + lt = check(assert_type(ts < c_timestamp, bool), bool) assert gte != lt - gte = check(assert_type(ts >= c2, bool), bool) - lt = check(assert_type(ts < c2, bool), bool) + gte = check(assert_type(ts >= c_np_dt64, bool), bool) + lt = check(assert_type(ts < c_np_dt64, bool), bool) assert gte != lt - gte = check(assert_type(ts >= c3, bool), bool) - lt = check(assert_type(ts < c3, bool), bool) + gte = check(assert_type(ts >= c_dt_datetime, bool), bool) + lt = check(assert_type(ts < c_dt_datetime, bool), bool) assert gte != lt - check(assert_type(ts >= c4, np_ndarray_bool), np.ndarray) - check(assert_type(ts < c4, np_ndarray_bool), np.ndarray) + check(assert_type(ts >= c_datetimeindex, np_ndarray_bool), np.ndarray) + check(assert_type(ts < c_datetimeindex, np_ndarray_bool), np.ndarray) + + check(assert_type(ts >= c_np_ndarray_dt64, np_ndarray_bool), np.ndarray) + check(assert_type(ts < c_np_ndarray_dt64, np_ndarray_bool), np.ndarray) - check(assert_type(ts >= c5, np_ndarray_bool), np.ndarray) - check(assert_type(ts < c5, np_ndarray_bool), np.ndarray) + check(assert_type(ts >= c_series_timestamp, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(ts < c_series_timestamp, "pd.Series[bool]"), pd.Series, bool) - check(assert_type(ts >= c6, "pd.Series[bool]"), pd.Series, bool) - check(assert_type(ts < c6, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(ts >= c_series_dt64, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(ts < c_series_dt64, "pd.Series[bool]"), pd.Series, bool) - gte = check(assert_type(c3 >= ts, bool), bool) - lt = check(assert_type(c3 < ts, bool), bool) + gte = check(assert_type(c_dt_datetime >= ts, bool), bool) + lt = check(assert_type(c_dt_datetime < ts, bool), bool) assert gte != lt - check(assert_type(c2 >= ts, Any), np.bool_) - check(assert_type(c2 < ts, Any), np.bool_) + check(assert_type(c_np_dt64 >= ts, Any), np.bool_) + check(assert_type(c_np_dt64 < ts, Any), np.bool_) - check(assert_type(c4 >= ts, np_ndarray_bool), np.ndarray) - check(assert_type(c4 < ts, np_ndarray_bool), np.ndarray) + check(assert_type(c_datetimeindex >= ts, np_ndarray_bool), np.ndarray) + check(assert_type(c_datetimeindex < ts, np_ndarray_bool), np.ndarray) - check(assert_type(c5 >= ts, np_ndarray_bool), np.ndarray) - check(assert_type(c5 < ts, np_ndarray_bool), np.ndarray) + check(assert_type(c_np_ndarray_dt64 >= ts, np_ndarray_bool), np.ndarray) + check(assert_type(c_np_ndarray_dt64 < ts, np_ndarray_bool), np.ndarray) - check(assert_type(c6 >= ts, "pd.Series[bool]"), pd.Series, bool) - check(assert_type(c6 < ts, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(c_series_dt64 >= ts, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(c_series_dt64 < ts, "pd.Series[bool]"), pd.Series, bool) - eq = check(assert_type(ts == c1, bool), bool) - ne = check(assert_type(ts != c1, bool), bool) + eq = check(assert_type(ts == c_timestamp, bool), bool) + ne = check(assert_type(ts != c_timestamp, bool), bool) assert eq != ne - eq = check(assert_type(ts == c2, bool), bool) - ne = check(assert_type(ts != c2, bool), bool) + eq = check(assert_type(ts == c_np_dt64, bool), bool) + ne = check(assert_type(ts != c_np_dt64, bool), bool) assert eq != ne - eq = check(assert_type(ts == c3, bool), bool) - ne = check(assert_type(ts != c3, bool), bool) + eq = check(assert_type(ts == c_dt_datetime, bool), bool) + ne = check(assert_type(ts != c_dt_datetime, bool), bool) assert eq != ne - check(assert_type(ts == c4, np_ndarray_bool), np.ndarray) - check(assert_type(ts != c4, np_ndarray_bool), np.ndarray) + check(assert_type(ts == c_datetimeindex, np_ndarray_bool), np.ndarray) + check(assert_type(ts != c_datetimeindex, np_ndarray_bool), np.ndarray) + + check(assert_type(ts == c_np_ndarray_dt64, np_ndarray_bool), np.ndarray) + check(assert_type(ts != c_np_ndarray_dt64, np_ndarray_bool), np.ndarray) - check(assert_type(ts == c5, np_ndarray_bool), np.ndarray) - check(assert_type(ts != c5, np_ndarray_bool), np.ndarray) + check(assert_type(ts == c_series_timestamp, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(ts != c_series_timestamp, "pd.Series[bool]"), pd.Series, bool) - check(assert_type(ts == c6, "pd.Series[bool]"), pd.Series, bool) - check(assert_type(ts != c6, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(ts == c_series_dt64, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(ts != c_series_dt64, "pd.Series[bool]"), pd.Series, bool) - check(assert_type(c2 == ts, Any), np.bool_) - check(assert_type(c2 != ts, Any), np.bool_) + check(assert_type(c_np_dt64 == ts, Any), np.bool_) + check(assert_type(c_np_dt64 != ts, Any), np.bool_) - eq = check(assert_type(c3 == ts, bool), bool) - ne = check(assert_type(c3 != ts, bool), bool) + eq = check(assert_type(c_dt_datetime == ts, bool), bool) + ne = check(assert_type(c_dt_datetime != ts, bool), bool) assert eq != ne - check(assert_type(c4 == ts, np_ndarray_bool), np.ndarray) - check(assert_type(c4 != ts, np_ndarray_bool), np.ndarray) + check(assert_type(c_datetimeindex == ts, np_ndarray_bool), np.ndarray) + check(assert_type(c_datetimeindex != ts, np_ndarray_bool), np.ndarray) - check(assert_type(c5 != ts, Any), np.ndarray) - check(assert_type(c5 == ts, Any), np.ndarray) + check(assert_type(c_np_ndarray_dt64 != ts, Any), np.ndarray) + check(assert_type(c_np_ndarray_dt64 == ts, Any), np.ndarray) - check(assert_type(c6 == ts, "pd.Series[bool]"), pd.Series, bool) - check(assert_type(c6 != ts, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(c_series_dt64 == ts, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(c_series_dt64 != ts, "pd.Series[bool]"), pd.Series, bool) From bc529f278ffb951f29e52f60b5596c72b196a4ac Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 24 Oct 2022 18:53:53 +0100 Subject: [PATCH 08/12] BUG: Correct new --- pandas-stubs/core/series.pyi | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 0574cf1a3..521c81418 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -206,16 +206,6 @@ class Series(IndexOpsMixin, NDFrame, Generic[S1]): fastpath: bool = ..., ) -> PeriodSeries: ... @overload - def __new__( - cls, - data: TimedeltaIndex, - index: Axes | None = ..., - dtype=..., - name: Hashable | None = ..., - copy: bool = ..., - fastpath: bool = ..., - ) -> TimedeltaSeries: ... - @overload def __new__( cls, data: object | _ListLike | Series[S1] | dict[int, S1] | dict[_str, S1] | None, From 81b6183e613490cfd50e9acc16953dfe45e265da Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 25 Oct 2022 10:52:32 +0100 Subject: [PATCH 09/12] Final types and tests for timestamp --- pandas-stubs/_libs/tslibs/timestamps.pyi | 77 +++++++---- pyproject.toml | 4 + scripts/test/__init__.py | 5 + scripts/test/_step.py | 5 + scripts/test/run.py | 12 ++ tests/test_scalars.py | 157 ++++++++++++++++++++++- 6 files changed, 231 insertions(+), 29 deletions(-) diff --git a/pandas-stubs/_libs/tslibs/timestamps.pyi b/pandas-stubs/_libs/tslibs/timestamps.pyi index 9a941ea96..ca53072e4 100644 --- a/pandas-stubs/_libs/tslibs/timestamps.pyi +++ b/pandas-stubs/_libs/tslibs/timestamps.pyi @@ -10,6 +10,7 @@ from typing import ( ClassVar, Literal, TypeVar, + Union, overload, ) @@ -24,6 +25,7 @@ from pandas.core.series import ( TimedeltaSeries, TimestampSeries, ) +from typing_extensions import TypeAlias from pandas._libs.tslibs import ( BaseOffset, @@ -37,6 +39,10 @@ from pandas._typing import ( ) _DatetimeT = TypeVar("_DatetimeT", bound=datetime) +_Ambiguous: TypeAlias = Union[bool, Literal["raise", "NaT"]] +_Nonexistent: TypeAlias = Union[ + Literal["raise", "NaT", "shift_backward", "shift_forward"], Timedelta, timedelta +] class Timestamp(datetime): min: ClassVar[Timestamp] @@ -61,6 +67,7 @@ class Timestamp(datetime): microsecond: int | None = ..., nanosecond: int | None = ..., tzinfo: _tzinfo | None = ..., + *, fold: Literal[0, 1] | None = ..., ) -> _DatetimeT: ... # GH 46171 @@ -90,7 +97,7 @@ class Timestamp(datetime): def fold(self) -> int: ... @classmethod def fromtimestamp( - cls: type[_DatetimeT], t: float, tz: _tzinfo | None = ... + cls: type[_DatetimeT], t: float, tz: _tzinfo | str | None = ... ) -> _DatetimeT: ... @classmethod def utcfromtimestamp(cls: type[_DatetimeT], ts: float) -> _DatetimeT: ... @@ -100,7 +107,7 @@ class Timestamp(datetime): def fromordinal( cls: type[_DatetimeT], ordinal: int, - freq: str | BaseOffset | None = ..., + *, tz: _tzinfo | str | None = ..., ) -> _DatetimeT: ... @classmethod @@ -146,29 +153,29 @@ class Timestamp(datetime): # Mypy complains Forward operator "" is not callable, so ignore misc # for le, lt ge and gt @overload # type: ignore[override] - def __le__(self, other: datetime | np.datetime64) -> bool: ... # type: ignore[misc] + def __le__(self, other: Timestamp | datetime | np.datetime64) -> bool: ... # type: ignore[misc] @overload def __le__(self, other: Index | npt.NDArray[np.datetime64]) -> np_ndarray_bool: ... @overload - def __le__(self, other: TimestampSeries) -> Series[bool]: ... + def __le__(self, other: TimestampSeries | Series[Timestamp]) -> Series[bool]: ... @overload # type: ignore[override] - def __lt__(self, other: datetime | np.datetime64) -> bool: ... # type: ignore[misc] + def __lt__(self, other: Timestamp | datetime | np.datetime64) -> bool: ... # type: ignore[misc] @overload def __lt__(self, other: Index | npt.NDArray[np.datetime64]) -> np_ndarray_bool: ... @overload - def __lt__(self, other: TimestampSeries) -> Series[bool]: ... + def __lt__(self, other: TimestampSeries | Series[Timestamp]) -> Series[bool]: ... @overload # type: ignore[override] - def __ge__(self, other: datetime | np.datetime64) -> bool: ... # type: ignore[misc] + def __ge__(self, other: Timestamp | datetime | np.datetime64) -> bool: ... # type: ignore[misc] @overload def __ge__(self, other: Index | npt.NDArray[np.datetime64]) -> np_ndarray_bool: ... @overload - def __ge__(self, other: TimestampSeries) -> Series[bool]: ... + def __ge__(self, other: TimestampSeries | Series[Timestamp]) -> Series[bool]: ... @overload # type: ignore[override] - def __gt__(self, other: datetime | np.datetime64) -> bool: ... # type: ignore[misc] + def __gt__(self, other: Timestamp | datetime | np.datetime64) -> bool: ... # type: ignore[misc] @overload def __gt__(self, other: Index | npt.NDArray[np.datetime64]) -> np_ndarray_bool: ... @overload - def __gt__(self, other: TimestampSeries) -> Series[bool]: ... + def __gt__(self, other: TimestampSeries | Series[Timestamp]) -> Series[bool]: ... # error: Signature of "__add__" incompatible with supertype "date"/"datetime" @overload # type: ignore[override] def __add__( @@ -179,7 +186,9 @@ class Timestamp(datetime): self: _DatetimeT, other: timedelta | np.timedelta64 | Tick ) -> _DatetimeT: ... @overload - def __add__(self, other: Series) -> TimestampSeries: ... + def __add__( + self, other: TimedeltaSeries | Series[Timedelta] + ) -> TimestampSeries: ... @overload def __add__(self, other: TimedeltaIndex) -> DatetimeIndex: ... @overload @@ -190,8 +199,9 @@ class Timestamp(datetime): def __radd__( self, other: npt.NDArray[np.timedelta64] ) -> npt.NDArray[np.datetime64]: ... + # TODO: test dt64 @overload # type: ignore[override] - def __sub__(self, other: datetime) -> Timedelta: ... + def __sub__(self, other: Timestamp | datetime | np.datetime64) -> Timedelta: ... @overload def __sub__( self: _DatetimeT, other: timedelta | np.timedelta64 | Tick @@ -204,18 +214,22 @@ class Timestamp(datetime): def __sub__( self, other: npt.NDArray[np.timedelta64] ) -> npt.NDArray[np.datetime64]: ... - @overload # type: ignore[override] - def __eq__(self, other: Timestamp | np.datetime64 | datetime) -> bool: ... @overload - def __eq__(self, other: TimestampSeries) -> Series[bool]: ... + def __eq__(self, other: Timestamp | datetime | np.datetime64) -> bool: ... # type: ignore[misc] @overload - def __eq__(self, other: npt.NDArray[np.datetime64] | Index) -> np_ndarray_bool: ... - @overload # type: ignore[override] - def __ne__(self, other: Timestamp | np.datetime64 | datetime) -> bool: ... + def __eq__(self, other: TimestampSeries | Series[Timestamp]) -> Series[bool]: ... # type: ignore[misc] + @overload + def __eq__(self, other: npt.NDArray[np.datetime64] | Index) -> np_ndarray_bool: ... # type: ignore[misc] + @overload + def __eq__(self, other: object) -> Literal[False]: ... @overload - def __ne__(self, other: TimestampSeries) -> Series[bool]: ... + def __ne__(self, other: Timestamp | datetime | np.datetime64) -> bool: ... # type: ignore[misc] @overload - def __ne__(self, other: npt.NDArray[np.datetime64] | Index) -> np_ndarray_bool: ... + def __ne__(self, other: TimestampSeries | Series[Timestamp]) -> Series[bool]: ... # type: ignore[misc] + @overload + def __ne__(self, other: npt.NDArray[np.datetime64] | Index) -> np_ndarray_bool: ... # type: ignore[misc] + @overload + def __ne__(self, other: object) -> Literal[True]: ... def __hash__(self) -> int: ... def weekday(self) -> int: ... def isoweekday(self) -> int: ... @@ -245,19 +259,28 @@ class Timestamp(datetime): def tz_localize( self: _DatetimeT, tz: _tzinfo | str | None, - ambiguous: str = ..., - nonexistent: str = ..., + ambiguous: _Ambiguous = ..., + nonexistent: _Nonexistent = ..., ) -> _DatetimeT: ... def normalize(self: _DatetimeT) -> _DatetimeT: ... # TODO: round/floor/ceil could return NaT? def round( - self: _DatetimeT, freq: str, ambiguous: bool | str = ..., nonexistent: str = ... + self: _DatetimeT, + freq: str, + ambiguous: _Ambiguous = ..., + nonexistent: _Nonexistent = ..., ) -> _DatetimeT: ... def floor( - self: _DatetimeT, freq: str, ambiguous: bool | str = ..., nonexistent: str = ... + self: _DatetimeT, + freq: str, + ambiguous: _Ambiguous = ..., + nonexistent: _Nonexistent = ..., ) -> _DatetimeT: ... def ceil( - self: _DatetimeT, freq: str, ambiguous: bool | str = ..., nonexistent: str = ... + self: _DatetimeT, + freq: str, + ambiguous: _Ambiguous = ..., + nonexistent: _Nonexistent = ..., ) -> _DatetimeT: ... def day_name(self, locale: str | None = ...) -> str: ... def month_name(self, locale: str | None = ...) -> str: ... @@ -275,9 +298,7 @@ class Timestamp(datetime): def quarter(self) -> int: ... @property def week(self) -> int: ... - def to_numpy( - self, dtype: np.dtype | None = ..., copy: bool = ... - ) -> np.datetime64: ... + def to_numpy(self) -> np.datetime64: ... @property def days_in_month(self) -> int: ... @property diff --git a/pyproject.toml b/pyproject.toml index c6ddd37ca..2dbda913d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -94,6 +94,10 @@ script = "scripts.test.run:mypy_src" help = "Run mypy on 'tests' using the installed stubs" script = "scripts.test:test(dist=True, type_checker='mypy')" +[tool.poe.tasks.mypy_coverage] +help = "Run mypy on 'tests' using the local stubs and report HTML coverage" +script = "scripts.test:test(coverage=True, type_checker='mypy')" + [tool.poe.tasks.pyright] help = "Run pyright on 'tests' (using the local stubs) and on the local stubs" script = "scripts.test.run:pyright_src" diff --git a/scripts/test/__init__.py b/scripts/test/__init__.py index 02d053947..68f1a84db 100644 --- a/scripts/test/__init__.py +++ b/scripts/test/__init__.py @@ -13,11 +13,13 @@ _step.mypy_dist, _step.pyright_dist, ] +_COVERAGE_STEPS = [_step.mypy_coverage] def test( src: bool = False, dist: bool = False, + coverage: bool = False, type_checker: Literal["", "mypy", "pyright"] = "", ): steps = [] @@ -27,6 +29,9 @@ def test( if dist: steps.extend(_DIST_STEPS) + if coverage: + steps.extend(_COVERAGE_STEPS) + if type_checker: # either pyright or mypy remove = "mypy" if type_checker == "pyright" else "pyright" diff --git a/scripts/test/_step.py b/scripts/test/_step.py index 56b4d4a02..d4fbf6553 100644 --- a/scripts/test/_step.py +++ b/scripts/test/_step.py @@ -23,6 +23,11 @@ mypy_dist = Step( name="Run mypy on 'tests' using the installed stubs", run=run.mypy_dist ) +mypy_coverage = Step( + name="Run mypy on 'tests' (using the local stubs) and on the local stubs, reporting coverage as HTML", + run=run.mypy_coverage, +) + pyright_dist = Step( name="Run pyright on 'tests' using the installed stubs", run=run.pyright_dist ) diff --git a/scripts/test/run.py b/scripts/test/run.py index 145e4b2b2..86ad2e32e 100644 --- a/scripts/test/run.py +++ b/scripts/test/run.py @@ -8,6 +8,18 @@ def mypy_src(): subprocess.run(cmd, check=True) +def mypy_coverage(): + cmd = [ + "mypy", + "pandas-stubs", + "tests", + "--no-incremental", + "--html-report", + "./coverage", + ] + subprocess.run(cmd, check=True) + + def pyright_src(): cmd = ["pyright"] subprocess.run(cmd, check=True) diff --git a/tests/test_scalars.py b/tests/test_scalars.py index 3306e2e30..428c20d35 100644 --- a/tests/test_scalars.py +++ b/tests/test_scalars.py @@ -210,7 +210,11 @@ def test_timestamp_cmp() -> None: c_dt_datetime = dt.datetime(year=2000, month=1, day=1) c_datetimeindex = pd.DatetimeIndex(["2000-1-1"]) c_np_ndarray_dt64 = np_dt64_arr - c_series_dt64 = pd.Series([1, 2, 3], dtype="datetime64[ns]") + # Typing provided since there is no way to get a Series[Timestamp], + # which is a different type from a TimestampSeries + c_series_dt64: pd.Series[pd.Timestamp] = pd.Series( + [1, 2, 3], dtype="datetime64[ns]" + ) c_series_timestamp = pd.Series(pd.DatetimeIndex(["2000-1-1"])) check(assert_type(c_series_timestamp, TimestampSeries), pd.Series) # Use xor to ensure one is True and the other is False @@ -371,6 +375,145 @@ def test_timestamp_types_init() -> None: ) +def test_timestamp_misc_methods() -> None: + ts = pd.Timestamp("2021-03-01T12") + check(assert_type(ts, pd.Timestamp), pd.Timestamp) + + check(assert_type(ts.to_numpy(), np.datetime64), np.datetime64) + + check(assert_type(pd.Timestamp.fromtimestamp(432.54), pd.Timestamp), pd.Timestamp) + check( + assert_type(pd.Timestamp.fromtimestamp(432.54, tz="US/Pacific"), pd.Timestamp), + pd.Timestamp, + ) + check(assert_type(pd.Timestamp.fromordinal(700000), pd.Timestamp), pd.Timestamp) + check( + assert_type(pd.Timestamp.fromordinal(700000, tz="US/Pacific"), pd.Timestamp), + pd.Timestamp, + ) + + ts2 = ts.replace( + year=2020, + month=2, + day=2, + hour=12, + minute=21, + second=21, + microsecond=12, + tzinfo=dateutil.tz.UTC, + fold=0, + ) + check(assert_type(ts2, pd.Timestamp), pd.Timestamp) + check(assert_type(ts.tz_localize("US/Pacific", False), pd.Timestamp), pd.Timestamp) + check(assert_type(ts.tz_localize("US/Pacific", True), pd.Timestamp), pd.Timestamp) + check(assert_type(ts.tz_localize("US/Pacific", "NaT"), pd.Timestamp), pd.Timestamp) + check( + assert_type(ts.tz_localize("US/Pacific", "raise"), pd.Timestamp), pd.Timestamp + ) + + check( + assert_type( + ts.tz_localize("US/Pacific", nonexistent="shift_forward"), pd.Timestamp + ), + pd.Timestamp, + ) + check( + assert_type( + ts.tz_localize("US/Pacific", nonexistent="shift_backward"), pd.Timestamp + ), + pd.Timestamp, + ) + check( + assert_type(ts.tz_localize("US/Pacific", nonexistent="NaT"), pd.Timestamp), + pd.Timestamp, + ) + check( + assert_type(ts.tz_localize("US/Pacific", nonexistent="raise"), pd.Timestamp), + pd.Timestamp, + ) + check( + assert_type( + ts.tz_localize("US/Pacific", nonexistent=pd.Timedelta("1D")), pd.Timestamp + ), + pd.Timestamp, + ) + + check(assert_type(ts2.round("1S"), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.round("1S", ambiguous="raise"), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.round("1S", ambiguous=True), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.round("1S", ambiguous=False), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.round("1S", ambiguous="NaT"), pd.Timestamp), pd.Timestamp) + + check( + assert_type(ts2.round("2H", nonexistent="shift_forward"), pd.Timestamp), + pd.Timestamp, + ) + check( + assert_type(ts2.round("2H", nonexistent="shift_backward"), pd.Timestamp), + pd.Timestamp, + ) + check(assert_type(ts2.round("2H", nonexistent="NaT"), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.round("2H", nonexistent="raise"), pd.Timestamp), pd.Timestamp) + check( + assert_type(ts2.round("2H", nonexistent=pd.Timedelta(24, "H")), pd.Timestamp), + pd.Timestamp, + ) + check( + assert_type(ts2.round("2H", nonexistent=dt.timedelta(hours=24)), pd.Timestamp), + pd.Timestamp, + ) + + check(assert_type(ts2.ceil("1S"), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.ceil("1S", ambiguous="raise"), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.ceil("1S", ambiguous=True), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.ceil("1S", ambiguous=False), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.ceil("1S", ambiguous="NaT"), pd.Timestamp), pd.Timestamp) + + check( + assert_type(ts2.ceil("2H", nonexistent="shift_forward"), pd.Timestamp), + pd.Timestamp, + ) + check( + assert_type(ts2.ceil("2H", nonexistent="shift_backward"), pd.Timestamp), + pd.Timestamp, + ) + check(assert_type(ts2.ceil("2H", nonexistent="NaT"), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.ceil("2H", nonexistent="raise"), pd.Timestamp), pd.Timestamp) + check( + assert_type(ts2.ceil("2H", nonexistent=pd.Timedelta(24, "H")), pd.Timestamp), + pd.Timestamp, + ) + check( + assert_type(ts2.ceil("2H", nonexistent=dt.timedelta(hours=24)), pd.Timestamp), + pd.Timestamp, + ) + + check(assert_type(ts2.floor("1S"), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.floor("1S", ambiguous="raise"), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.floor("1S", ambiguous=True), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.floor("1S", ambiguous=False), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.floor("1S", ambiguous="NaT"), pd.Timestamp), pd.Timestamp) + + check( + assert_type(ts2.floor("2H", nonexistent="shift_forward"), pd.Timestamp), + pd.Timestamp, + ) + check( + assert_type(ts2.floor("2H", nonexistent="shift_backward"), pd.Timestamp), + pd.Timestamp, + ) + check(assert_type(ts2.floor("2H", nonexistent="NaT"), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.floor("2H", nonexistent="raise"), pd.Timestamp), pd.Timestamp) + check( + assert_type(ts2.floor("2H", nonexistent=pd.Timedelta(24, "H")), pd.Timestamp), + pd.Timestamp, + ) + check( + assert_type(ts2.floor("2H", nonexistent=dt.timedelta(hours=24)), pd.Timestamp), + pd.Timestamp, + ) + + def test_timestamp_types_arithmetic() -> None: ts: pd.Timestamp = pd.to_datetime("2021-03-01") ts2: pd.Timestamp = pd.to_datetime("2021-01-01") @@ -431,6 +574,18 @@ def test_todatetime_fromnumpy() -> None: check(assert_type(pd.to_datetime(t1), pd.Timestamp), pd.Timestamp) +def test_timestamp_combine() -> None: + ts = pd.Timestamp("2022-03-18") + # mypy and pyright disagree from actual type due to inheritance. + # Same issue with some timedelta ops + check( + assert_type( + ts.combine(dt.date(2000, 1, 1), dt.time(12, 21, 21, 12)), dt.datetime + ), + pd.Timestamp, + ) + + def test_period_construction() -> None: p = pd.Period("2012-1-1", freq="D") check(assert_type(p, pd.Period), pd.Period) From 9c677efc82f69f763500d29b700adeacecb1f000 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 25 Oct 2022 10:56:04 +0100 Subject: [PATCH 10/12] REV: Remove mypy coverage changes --- pandas-stubs/core/series.pyi | 8 ++++---- pyproject.toml | 4 ---- scripts/test/__init__.py | 5 ----- scripts/test/_step.py | 5 ----- scripts/test/run.py | 12 ------------ 5 files changed, 4 insertions(+), 30 deletions(-) diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 521c81418..189054673 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -188,23 +188,23 @@ class Series(IndexOpsMixin, NDFrame, Generic[S1]): @overload def __new__( cls, - data: TimedeltaIndex, + data: PeriodIndex, index: Axes | None = ..., dtype=..., name: Hashable | None = ..., copy: bool = ..., fastpath: bool = ..., - ) -> TimedeltaSeries: ... + ) -> PeriodSeries: ... @overload def __new__( cls, - data: PeriodIndex, + data: TimedeltaIndex, index: Axes | None = ..., dtype=..., name: Hashable | None = ..., copy: bool = ..., fastpath: bool = ..., - ) -> PeriodSeries: ... + ) -> TimedeltaSeries: ... @overload def __new__( cls, diff --git a/pyproject.toml b/pyproject.toml index 2dbda913d..c6ddd37ca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -94,10 +94,6 @@ script = "scripts.test.run:mypy_src" help = "Run mypy on 'tests' using the installed stubs" script = "scripts.test:test(dist=True, type_checker='mypy')" -[tool.poe.tasks.mypy_coverage] -help = "Run mypy on 'tests' using the local stubs and report HTML coverage" -script = "scripts.test:test(coverage=True, type_checker='mypy')" - [tool.poe.tasks.pyright] help = "Run pyright on 'tests' (using the local stubs) and on the local stubs" script = "scripts.test.run:pyright_src" diff --git a/scripts/test/__init__.py b/scripts/test/__init__.py index 68f1a84db..02d053947 100644 --- a/scripts/test/__init__.py +++ b/scripts/test/__init__.py @@ -13,13 +13,11 @@ _step.mypy_dist, _step.pyright_dist, ] -_COVERAGE_STEPS = [_step.mypy_coverage] def test( src: bool = False, dist: bool = False, - coverage: bool = False, type_checker: Literal["", "mypy", "pyright"] = "", ): steps = [] @@ -29,9 +27,6 @@ def test( if dist: steps.extend(_DIST_STEPS) - if coverage: - steps.extend(_COVERAGE_STEPS) - if type_checker: # either pyright or mypy remove = "mypy" if type_checker == "pyright" else "pyright" diff --git a/scripts/test/_step.py b/scripts/test/_step.py index d4fbf6553..56b4d4a02 100644 --- a/scripts/test/_step.py +++ b/scripts/test/_step.py @@ -23,11 +23,6 @@ mypy_dist = Step( name="Run mypy on 'tests' using the installed stubs", run=run.mypy_dist ) -mypy_coverage = Step( - name="Run mypy on 'tests' (using the local stubs) and on the local stubs, reporting coverage as HTML", - run=run.mypy_coverage, -) - pyright_dist = Step( name="Run pyright on 'tests' using the installed stubs", run=run.pyright_dist ) diff --git a/scripts/test/run.py b/scripts/test/run.py index 86ad2e32e..145e4b2b2 100644 --- a/scripts/test/run.py +++ b/scripts/test/run.py @@ -8,18 +8,6 @@ def mypy_src(): subprocess.run(cmd, check=True) -def mypy_coverage(): - cmd = [ - "mypy", - "pandas-stubs", - "tests", - "--no-incremental", - "--html-report", - "./coverage", - ] - subprocess.run(cmd, check=True) - - def pyright_src(): cmd = ["pyright"] subprocess.run(cmd, check=True) From 396a02371c2b8c073e9e4f4f41a4a97e83a9760f Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 3 Nov 2022 16:55:47 +0000 Subject: [PATCH 11/12] CLN: Final clean --- pandas-stubs/_libs/tslibs/timestamps.pyi | 6 +- pandas-stubs/core/algorithms.pyi | 1 - pandas-stubs/core/arrays/arrow/dtype.pyi | 1 - pandas-stubs/core/arrays/numpy_.pyi | 1 - pandas-stubs/core/dtypes/common.pyi | 1 - pandas-stubs/core/frame.pyi | 1 - pandas-stubs/core/groupby/generic.pyi | 1 - pandas-stubs/core/indexes/interval.pyi | 1 - pandas-stubs/core/indexes/numeric.pyi | 1 - pandas-stubs/core/ops/dispatch.pyi | 2 - pandas-stubs/core/tools/datetimes.pyi | 1 - pandas-stubs/core/tools/timedeltas.pyi | 1 - pandas-stubs/core/window/expanding.pyi | 1 - pandas-stubs/core/window/rolling.pyi | 1 - pandas-stubs/io/clipboards.pyi | 1 - pandas-stubs/io/formats/format.pyi | 2 - pandas-stubs/io/parsers/readers.pyi | 1 - pandas-stubs/io/pytables.pyi | 1 - pandas-stubs/io/sas/sas7bdat.pyi | 2 - pandas-stubs/io/stata.pyi | 3 - pyproject.toml | 2 +- tests/test_scalars.py | 75 ++++++++++++++---------- 22 files changed, 49 insertions(+), 58 deletions(-) diff --git a/pandas-stubs/_libs/tslibs/timestamps.pyi b/pandas-stubs/_libs/tslibs/timestamps.pyi index ca53072e4..c9e6d9986 100644 --- a/pandas-stubs/_libs/tslibs/timestamps.pyi +++ b/pandas-stubs/_libs/tslibs/timestamps.pyi @@ -107,7 +107,8 @@ class Timestamp(datetime): def fromordinal( cls: type[_DatetimeT], ordinal: int, - *, + # freq produces a FutureWarning about being deprecated in a future version + freq: None = ..., tz: _tzinfo | str | None = ..., ) -> _DatetimeT: ... @classmethod @@ -129,6 +130,7 @@ class Timestamp(datetime): def time(self) -> _time: ... def timetz(self) -> _time: ... # Override since fold is more precise than datetime.replace(fold:int) + # Here it is restricted to be 0 or 1 using a Literal # Violation of Liskov substitution principle def replace( # type:ignore[override] self, @@ -140,6 +142,7 @@ class Timestamp(datetime): second: int | None = ..., microsecond: int | None = ..., tzinfo: _tzinfo | None = ..., + *, fold: Literal[0, 1] | None = ..., ) -> Timestamp: ... def astimezone(self: _DatetimeT, tz: _tzinfo | None = ...) -> _DatetimeT: ... @@ -230,7 +233,6 @@ class Timestamp(datetime): def __ne__(self, other: npt.NDArray[np.datetime64] | Index) -> np_ndarray_bool: ... # type: ignore[misc] @overload def __ne__(self, other: object) -> Literal[True]: ... - def __hash__(self) -> int: ... def weekday(self) -> int: ... def isoweekday(self) -> int: ... def isocalendar(self) -> tuple[int, int, int]: ... diff --git a/pandas-stubs/core/algorithms.pyi b/pandas-stubs/core/algorithms.pyi index 4ac2621a1..4582c3184 100644 --- a/pandas-stubs/core/algorithms.pyi +++ b/pandas-stubs/core/algorithms.pyi @@ -4,7 +4,6 @@ from typing import ( ) import numpy as np -import pandas as pd from pandas import ( Categorical, CategoricalIndex, diff --git a/pandas-stubs/core/arrays/arrow/dtype.pyi b/pandas-stubs/core/arrays/arrow/dtype.pyi index dc27fff7c..041012a7a 100644 --- a/pandas-stubs/core/arrays/arrow/dtype.pyi +++ b/pandas-stubs/core/arrays/arrow/dtype.pyi @@ -1,4 +1,3 @@ -import numpy as np import pyarrow as pa from pandas.core.dtypes.base import StorageExtensionDtype diff --git a/pandas-stubs/core/arrays/numpy_.pyi b/pandas-stubs/core/arrays/numpy_.pyi index f44e5a6af..535b1905d 100644 --- a/pandas-stubs/core/arrays/numpy_.pyi +++ b/pandas-stubs/core/arrays/numpy_.pyi @@ -1,4 +1,3 @@ -import numpy as np from numpy.lib.mixins import NDArrayOperatorsMixin from pandas.core.arrays.base import ( ExtensionArray, diff --git a/pandas-stubs/core/dtypes/common.pyi b/pandas-stubs/core/dtypes/common.pyi index 3da5a0091..3156f1508 100644 --- a/pandas-stubs/core/dtypes/common.pyi +++ b/pandas-stubs/core/dtypes/common.pyi @@ -1,6 +1,5 @@ from typing import Union -import numpy as np import pandas as pd from typing_extensions import TypeAlias diff --git a/pandas-stubs/core/frame.pyi b/pandas-stubs/core/frame.pyi index 7d49cf35b..d82f70c33 100644 --- a/pandas-stubs/core/frame.pyi +++ b/pandas-stubs/core/frame.pyi @@ -110,7 +110,6 @@ from pandas._typing import ( num, ) -from pandas.io.formats import format as fmt from pandas.io.formats.style import Styler from pandas.plotting import PlotAccessor diff --git a/pandas-stubs/core/groupby/generic.pyi b/pandas-stubs/core/groupby/generic.pyi index 0cc15a2b9..3dff35b2c 100644 --- a/pandas-stubs/core/groupby/generic.pyi +++ b/pandas-stubs/core/groupby/generic.pyi @@ -15,7 +15,6 @@ from matplotlib.axes import ( Axes as PlotAxes, SubplotBase as AxesSubplot, ) -import numpy as np from pandas.core.frame import DataFrame from pandas.core.generic import NDFrame from pandas.core.groupby.groupby import ( # , get_groupby as get_groupby diff --git a/pandas-stubs/core/indexes/interval.pyi b/pandas-stubs/core/indexes/interval.pyi index 339f99053..dd5ef8510 100644 --- a/pandas-stubs/core/indexes/interval.pyi +++ b/pandas-stubs/core/indexes/interval.pyi @@ -1,4 +1,3 @@ -import datetime as dt from typing import ( Any, Hashable, diff --git a/pandas-stubs/core/indexes/numeric.pyi b/pandas-stubs/core/indexes/numeric.pyi index 5e927327e..95715a83a 100644 --- a/pandas-stubs/core/indexes/numeric.pyi +++ b/pandas-stubs/core/indexes/numeric.pyi @@ -1,6 +1,5 @@ from typing import Iterable -import numpy as np from pandas.core.indexes.base import Index from pandas._typing import np_ndarray_int64 diff --git a/pandas-stubs/core/ops/dispatch.pyi b/pandas-stubs/core/ops/dispatch.pyi index 0a69d985a..b283ba29e 100644 --- a/pandas-stubs/core/ops/dispatch.pyi +++ b/pandas-stubs/core/ops/dispatch.pyi @@ -1,5 +1,3 @@ -import numpy as np - from pandas.core.dtypes.generic import ABCSeries def should_extension_dispatch(left: ABCSeries, right) -> bool: ... diff --git a/pandas-stubs/core/tools/datetimes.pyi b/pandas-stubs/core/tools/datetimes.pyi index fa32eceff..6cc504f7d 100644 --- a/pandas-stubs/core/tools/datetimes.pyi +++ b/pandas-stubs/core/tools/datetimes.pyi @@ -10,7 +10,6 @@ from typing import ( ) import numpy as np -import pandas as pd from pandas import ( Index, Timestamp, diff --git a/pandas-stubs/core/tools/timedeltas.pyi b/pandas-stubs/core/tools/timedeltas.pyi index 5f6817b8f..ed1818348 100644 --- a/pandas-stubs/core/tools/timedeltas.pyi +++ b/pandas-stubs/core/tools/timedeltas.pyi @@ -4,7 +4,6 @@ from typing import ( overload, ) -import pandas as pd from pandas import Index from pandas.core.indexes.timedeltas import TimedeltaIndex from pandas.core.series import ( diff --git a/pandas-stubs/core/window/expanding.pyi b/pandas-stubs/core/window/expanding.pyi index 1c3b164ff..04df37896 100644 --- a/pandas-stubs/core/window/expanding.pyi +++ b/pandas-stubs/core/window/expanding.pyi @@ -4,7 +4,6 @@ from typing import ( overload, ) -import numpy as np from pandas import ( DataFrame, Series, diff --git a/pandas-stubs/core/window/rolling.pyi b/pandas-stubs/core/window/rolling.pyi index de3eb8357..9830b01d3 100644 --- a/pandas-stubs/core/window/rolling.pyi +++ b/pandas-stubs/core/window/rolling.pyi @@ -5,7 +5,6 @@ from typing import ( overload, ) -import numpy as np from pandas import ( DataFrame, Series, diff --git a/pandas-stubs/io/clipboards.pyi b/pandas-stubs/io/clipboards.pyi index a57c5ecab..cb8449902 100644 --- a/pandas-stubs/io/clipboards.pyi +++ b/pandas-stubs/io/clipboards.pyi @@ -8,7 +8,6 @@ from typing import ( overload, ) -import numpy as np from pandas.core.frame import DataFrame from pandas.core.indexes.base import Index from pandas.core.series import Series diff --git a/pandas-stubs/io/formats/format.pyi b/pandas-stubs/io/formats/format.pyi index 0305a2886..c26fbcf2f 100644 --- a/pandas-stubs/io/formats/format.pyi +++ b/pandas-stubs/io/formats/format.pyi @@ -1,5 +1,3 @@ -import numpy as np - class EngFormatter: ENG_PREFIXES = ... accuracy = ... diff --git a/pandas-stubs/io/parsers/readers.pyi b/pandas-stubs/io/parsers/readers.pyi index 14db44693..cf2d7d3f1 100644 --- a/pandas-stubs/io/parsers/readers.pyi +++ b/pandas-stubs/io/parsers/readers.pyi @@ -16,7 +16,6 @@ from pandas.core.frame import DataFrame from pandas.core.indexes.base import Index from pandas.core.series import Series -import pandas._libs.lib as lib from pandas._typing import ( CompressionOptions, CSVEngine, diff --git a/pandas-stubs/io/pytables.pyi b/pandas-stubs/io/pytables.pyi index 4dcaea325..41719e389 100644 --- a/pandas-stubs/io/pytables.pyi +++ b/pandas-stubs/io/pytables.pyi @@ -7,7 +7,6 @@ from typing import ( overload, ) -import numpy as np from pandas import ( DataFrame, Series, diff --git a/pandas-stubs/io/sas/sas7bdat.pyi b/pandas-stubs/io/sas/sas7bdat.pyi index fdb0a556a..1db480959 100644 --- a/pandas-stubs/io/sas/sas7bdat.pyi +++ b/pandas-stubs/io/sas/sas7bdat.pyi @@ -1,5 +1,3 @@ -import numpy as np -import pandas as pd from pandas import DataFrame from pandas.io.sas.sasreader import ReaderBase diff --git a/pandas-stubs/io/stata.pyi b/pandas-stubs/io/stata.pyi index 86c8b0825..aca173e87 100644 --- a/pandas-stubs/io/stata.pyi +++ b/pandas-stubs/io/stata.pyi @@ -8,9 +8,6 @@ from typing import ( overload, ) -import numpy as np -import numpy.typing as npt -import pandas as pd from pandas.core.frame import DataFrame from pandas._typing import ( diff --git a/pyproject.toml b/pyproject.toml index 801d5899c..db5eb825d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,7 @@ types-pytz = ">= 2022.1.1" mypy = "==0.971" pyarrow = ">=9.0.0" pytest = ">=7.1.2" -pyright = ">=1.1.266" +pyright = ">=1.1.278" poethepoet = "0.16.0" loguru = ">=0.6.0" pandas = "1.5.1" diff --git a/tests/test_scalars.py b/tests/test_scalars.py index 428c20d35..ac85a2b64 100644 --- a/tests/test_scalars.py +++ b/tests/test_scalars.py @@ -175,18 +175,25 @@ def test_timestamp_add_sub() -> None: check(assert_type(ts + as_timedelta_index, pd.DatetimeIndex), pd.DatetimeIndex) check(assert_type(as_timedelta_index + ts, pd.DatetimeIndex), pd.DatetimeIndex) - check(assert_type(ts + as_timedelta_series, "TimestampSeries"), pd.Series) - check(assert_type(as_timedelta_series + ts, "TimestampSeries"), pd.Series) + check( + assert_type(ts + as_timedelta_series, TimestampSeries), pd.Series, pd.Timestamp + ) + check( + assert_type(as_timedelta_series + ts, TimestampSeries), pd.Series, pd.Timestamp + ) - check(assert_type(ts + as_np_ndarray_td64, npt.NDArray[np.datetime64]), np.ndarray) - # pyright and mypy disagree on the type of this expression - # pyright: Any, mypy: npt.NDArray[np.datetime64] + check( + assert_type(ts + as_np_ndarray_td64, npt.NDArray[np.datetime64]), + np.ndarray, + np.datetime64, + ) check( assert_type( - as_np_ndarray_td64 + ts, # pyright: ignore [reportGeneralTypeIssues] + as_np_ndarray_td64 + ts, npt.NDArray[np.datetime64], ), np.ndarray, + np.datetime64, ) # Reverse order is not possible for all of these @@ -194,8 +201,14 @@ def test_timestamp_add_sub() -> None: check(assert_type(ts - as_dt_timedelta, pd.Timestamp), pd.Timestamp) check(assert_type(ts - as_offset, pd.Timestamp), pd.Timestamp) check(assert_type(ts - as_timedelta_index, pd.DatetimeIndex), pd.DatetimeIndex) - check(assert_type(ts - as_timedelta_series, "TimestampSeries"), pd.Series) - check(assert_type(ts - as_np_ndarray_td64, npt.NDArray[np.datetime64]), np.ndarray) + check( + assert_type(ts - as_timedelta_series, TimestampSeries), pd.Series, pd.Timestamp + ) + check( + assert_type(ts - as_np_ndarray_td64, npt.NDArray[np.datetime64]), + np.ndarray, + np.datetime64, + ) def test_timestamp_cmp() -> None: @@ -216,7 +229,7 @@ def test_timestamp_cmp() -> None: [1, 2, 3], dtype="datetime64[ns]" ) c_series_timestamp = pd.Series(pd.DatetimeIndex(["2000-1-1"])) - check(assert_type(c_series_timestamp, TimestampSeries), pd.Series) + check(assert_type(c_series_timestamp, TimestampSeries), pd.Series, pd.Timestamp) # Use xor to ensure one is True and the other is False # Correctness ensures since tested to be bools gt = check(assert_type(ts > c_timestamp, bool), bool) @@ -231,11 +244,11 @@ def test_timestamp_cmp() -> None: lte = check(assert_type(ts <= c_dt_datetime, bool), bool) assert gt != lte - check(assert_type(ts > c_datetimeindex, np_ndarray_bool), np.ndarray) - check(assert_type(ts <= c_datetimeindex, np_ndarray_bool), np.ndarray) + check(assert_type(ts > c_datetimeindex, np_ndarray_bool), np.ndarray, np.bool_) + check(assert_type(ts <= c_datetimeindex, np_ndarray_bool), np.ndarray, np.bool_) - check(assert_type(ts > c_np_ndarray_dt64, np_ndarray_bool), np.ndarray) - check(assert_type(ts <= c_np_ndarray_dt64, np_ndarray_bool), np.ndarray) + check(assert_type(ts > c_np_ndarray_dt64, np_ndarray_bool), np.ndarray, np.bool_) + check(assert_type(ts <= c_np_ndarray_dt64, np_ndarray_bool), np.ndarray, np.bool_) check(assert_type(ts > c_series_timestamp, "pd.Series[bool]"), pd.Series, bool) check(assert_type(ts <= c_series_timestamp, "pd.Series[bool]"), pd.Series, bool) @@ -250,11 +263,11 @@ def test_timestamp_cmp() -> None: lte = check(assert_type(c_dt_datetime <= ts, bool), bool) assert gt != lte - check(assert_type(c_datetimeindex > ts, np_ndarray_bool), np.ndarray) - check(assert_type(c_datetimeindex <= ts, np_ndarray_bool), np.ndarray) + check(assert_type(c_datetimeindex > ts, np_ndarray_bool), np.ndarray, np.bool_) + check(assert_type(c_datetimeindex <= ts, np_ndarray_bool), np.ndarray, np.bool_) - check(assert_type(c_np_ndarray_dt64 > ts, np_ndarray_bool), np.ndarray) - check(assert_type(c_np_ndarray_dt64 <= ts, np_ndarray_bool), np.ndarray) + check(assert_type(c_np_ndarray_dt64 > ts, np_ndarray_bool), np.ndarray, np.bool_) + check(assert_type(c_np_ndarray_dt64 <= ts, np_ndarray_bool), np.ndarray, np.bool_) check(assert_type(c_series_dt64 > ts, "pd.Series[bool]"), pd.Series, bool) check(assert_type(c_series_dt64 <= ts, "pd.Series[bool]"), pd.Series, bool) @@ -271,11 +284,11 @@ def test_timestamp_cmp() -> None: lt = check(assert_type(ts < c_dt_datetime, bool), bool) assert gte != lt - check(assert_type(ts >= c_datetimeindex, np_ndarray_bool), np.ndarray) - check(assert_type(ts < c_datetimeindex, np_ndarray_bool), np.ndarray) + check(assert_type(ts >= c_datetimeindex, np_ndarray_bool), np.ndarray, np.bool_) + check(assert_type(ts < c_datetimeindex, np_ndarray_bool), np.ndarray, np.bool_) - check(assert_type(ts >= c_np_ndarray_dt64, np_ndarray_bool), np.ndarray) - check(assert_type(ts < c_np_ndarray_dt64, np_ndarray_bool), np.ndarray) + check(assert_type(ts >= c_np_ndarray_dt64, np_ndarray_bool), np.ndarray, np.bool_) + check(assert_type(ts < c_np_ndarray_dt64, np_ndarray_bool), np.ndarray, np.bool_) check(assert_type(ts >= c_series_timestamp, "pd.Series[bool]"), pd.Series, bool) check(assert_type(ts < c_series_timestamp, "pd.Series[bool]"), pd.Series, bool) @@ -290,11 +303,11 @@ def test_timestamp_cmp() -> None: check(assert_type(c_np_dt64 >= ts, Any), np.bool_) check(assert_type(c_np_dt64 < ts, Any), np.bool_) - check(assert_type(c_datetimeindex >= ts, np_ndarray_bool), np.ndarray) - check(assert_type(c_datetimeindex < ts, np_ndarray_bool), np.ndarray) + check(assert_type(c_datetimeindex >= ts, np_ndarray_bool), np.ndarray, np.bool_) + check(assert_type(c_datetimeindex < ts, np_ndarray_bool), np.ndarray, np.bool_) - check(assert_type(c_np_ndarray_dt64 >= ts, np_ndarray_bool), np.ndarray) - check(assert_type(c_np_ndarray_dt64 < ts, np_ndarray_bool), np.ndarray) + check(assert_type(c_np_ndarray_dt64 >= ts, np_ndarray_bool), np.ndarray, np.bool_) + check(assert_type(c_np_ndarray_dt64 < ts, np_ndarray_bool), np.ndarray, np.bool_) check(assert_type(c_series_dt64 >= ts, "pd.Series[bool]"), pd.Series, bool) check(assert_type(c_series_dt64 < ts, "pd.Series[bool]"), pd.Series, bool) @@ -311,11 +324,11 @@ def test_timestamp_cmp() -> None: ne = check(assert_type(ts != c_dt_datetime, bool), bool) assert eq != ne - check(assert_type(ts == c_datetimeindex, np_ndarray_bool), np.ndarray) - check(assert_type(ts != c_datetimeindex, np_ndarray_bool), np.ndarray) + check(assert_type(ts == c_datetimeindex, np_ndarray_bool), np.ndarray, np.bool_) + check(assert_type(ts != c_datetimeindex, np_ndarray_bool), np.ndarray, np.bool_) - check(assert_type(ts == c_np_ndarray_dt64, np_ndarray_bool), np.ndarray) - check(assert_type(ts != c_np_ndarray_dt64, np_ndarray_bool), np.ndarray) + check(assert_type(ts == c_np_ndarray_dt64, np_ndarray_bool), np.ndarray, np.bool_) + check(assert_type(ts != c_np_ndarray_dt64, np_ndarray_bool), np.ndarray, np.bool_) check(assert_type(ts == c_series_timestamp, "pd.Series[bool]"), pd.Series, bool) check(assert_type(ts != c_series_timestamp, "pd.Series[bool]"), pd.Series, bool) @@ -330,8 +343,8 @@ def test_timestamp_cmp() -> None: ne = check(assert_type(c_dt_datetime != ts, bool), bool) assert eq != ne - check(assert_type(c_datetimeindex == ts, np_ndarray_bool), np.ndarray) - check(assert_type(c_datetimeindex != ts, np_ndarray_bool), np.ndarray) + check(assert_type(c_datetimeindex == ts, np_ndarray_bool), np.ndarray, np.bool_) + check(assert_type(c_datetimeindex != ts, np_ndarray_bool), np.ndarray, np.bool_) check(assert_type(c_np_ndarray_dt64 != ts, Any), np.ndarray) check(assert_type(c_np_ndarray_dt64 == ts, Any), np.ndarray) From 1bcba6df16cabe61e4a8b0cee2ff8bf38e55df68 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 3 Nov 2022 18:01:46 +0000 Subject: [PATCH 12/12] CLN: Final clean --- tests/test_scalars.py | 74 +++++++++++++++++++++++++++++++++---------- 1 file changed, 58 insertions(+), 16 deletions(-) diff --git a/tests/test_scalars.py b/tests/test_scalars.py index ac85a2b64..799277d0c 100644 --- a/tests/test_scalars.py +++ b/tests/test_scalars.py @@ -324,33 +324,75 @@ def test_timestamp_cmp() -> None: ne = check(assert_type(ts != c_dt_datetime, bool), bool) assert eq != ne - check(assert_type(ts == c_datetimeindex, np_ndarray_bool), np.ndarray, np.bool_) - check(assert_type(ts != c_datetimeindex, np_ndarray_bool), np.ndarray, np.bool_) + eq_arr = check( + assert_type(ts == c_datetimeindex, np_ndarray_bool), np.ndarray, np.bool_ + ) + ne_arr = check( + assert_type(ts != c_datetimeindex, np_ndarray_bool), np.ndarray, np.bool_ + ) + assert (eq_arr != ne_arr).all() + + eq_arr = check( + assert_type(ts == c_np_ndarray_dt64, np_ndarray_bool), np.ndarray, np.bool_ + ) + ne_arr = check( + assert_type(ts != c_np_ndarray_dt64, np_ndarray_bool), np.ndarray, np.bool_ + ) + assert (eq_arr != ne_arr).all() + + eq_s = check( + assert_type(ts == c_series_timestamp, "pd.Series[bool]"), pd.Series, bool + ) + ne_s = check( + assert_type(ts != c_series_timestamp, "pd.Series[bool]"), pd.Series, bool + ) + assert (eq_s != ne_s).all() - check(assert_type(ts == c_np_ndarray_dt64, np_ndarray_bool), np.ndarray, np.bool_) - check(assert_type(ts != c_np_ndarray_dt64, np_ndarray_bool), np.ndarray, np.bool_) + eq_s = check(assert_type(ts == c_series_dt64, "pd.Series[bool]"), pd.Series, bool) + ne_s = check(assert_type(ts != c_series_dt64, "pd.Series[bool]"), pd.Series, bool) + assert (eq_s != ne_s).all() - check(assert_type(ts == c_series_timestamp, "pd.Series[bool]"), pd.Series, bool) - check(assert_type(ts != c_series_timestamp, "pd.Series[bool]"), pd.Series, bool) - check(assert_type(ts == c_series_dt64, "pd.Series[bool]"), pd.Series, bool) - check(assert_type(ts != c_series_dt64, "pd.Series[bool]"), pd.Series, bool) +def test_timestamp_eq_ne_rhs() -> None: + # These test equality using the LHS objects __eq__ and __ne__ methods + # The tests are retained for completeness, but are not strictly necessary + ts = pd.Timestamp(year=2000, month=3, day=24, hour=12, minute=27) - check(assert_type(c_np_dt64 == ts, Any), np.bool_) - check(assert_type(c_np_dt64 != ts, Any), np.bool_) + np_dt64_arr: npt.NDArray[np.datetime64] = np.array( + [1, 2, 3], dtype="datetime64[ns]" + ) + + c_np_dt64 = np.datetime64(1, "ns") + c_dt_datetime = dt.datetime(year=2000, month=1, day=1) + c_datetimeindex = pd.DatetimeIndex(["2000-1-1"]) + c_np_ndarray_dt64 = np_dt64_arr + c_series_dt64: pd.Series[pd.Timestamp] = pd.Series( + [1, 2, 3], dtype="datetime64[ns]" + ) + + eq_a = check(assert_type(c_np_dt64 == ts, Any), np.bool_) + ne_a = check(assert_type(c_np_dt64 != ts, Any), np.bool_) + assert eq_a != ne_a eq = check(assert_type(c_dt_datetime == ts, bool), bool) ne = check(assert_type(c_dt_datetime != ts, bool), bool) assert eq != ne - check(assert_type(c_datetimeindex == ts, np_ndarray_bool), np.ndarray, np.bool_) - check(assert_type(c_datetimeindex != ts, np_ndarray_bool), np.ndarray, np.bool_) + eq_arr = check( + assert_type(c_datetimeindex == ts, np_ndarray_bool), np.ndarray, np.bool_ + ) + ne_arr = check( + assert_type(c_datetimeindex != ts, np_ndarray_bool), np.ndarray, np.bool_ + ) + assert (eq_arr != ne_arr).all() - check(assert_type(c_np_ndarray_dt64 != ts, Any), np.ndarray) - check(assert_type(c_np_ndarray_dt64 == ts, Any), np.ndarray) + eq_a = check(assert_type(c_np_ndarray_dt64 != ts, Any), np.ndarray, np.bool_) + ne_a = check(assert_type(c_np_ndarray_dt64 == ts, Any), np.ndarray, np.bool_) + assert (eq_a != ne_a).all() - check(assert_type(c_series_dt64 == ts, "pd.Series[bool]"), pd.Series, bool) - check(assert_type(c_series_dt64 != ts, "pd.Series[bool]"), pd.Series, bool) + eq_s = check(assert_type(c_series_dt64 == ts, "pd.Series[bool]"), pd.Series, bool) + ne_s = check(assert_type(c_series_dt64 != ts, "pd.Series[bool]"), pd.Series, bool) + assert (eq_s != ne_s).all() def test_timestamp_types_init() -> None: