diff --git a/pandas-stubs/_libs/tslibs/period.pyi b/pandas-stubs/_libs/tslibs/period.pyi index e0f93e54c..b1f9bd0eb 100644 --- a/pandas-stubs/_libs/tslibs/period.pyi +++ b/pandas-stubs/_libs/tslibs/period.pyi @@ -1,34 +1,157 @@ -from typing import Any +import datetime +from typing import ( + Literal, + Union, + overload, +) + +import numpy as np +from pandas import ( + Index, + PeriodIndex, + Series, + Timedelta, + TimedeltaIndex, +) +from pandas.core.series import ( + OffsetSeries, + PeriodSeries, + TimedeltaSeries, +) +from typing_extensions import TypeAlias + +from pandas._libs.tslibs import NaTType +from pandas._typing import npt + +from .timestamps import Timestamp class IncompatibleFrequency(ValueError): ... -class Period: +from pandas._libs.tslibs.offsets import BaseOffset + +_PeriodAddSub: TypeAlias = Union[ + Timedelta, datetime.timedelta, np.timedelta64, np.int64, int, BaseOffset +] + +_PeriodFreqHow: TypeAlias = Literal[ + "S", + "E", + "start", + "end", +] + +_PeriodToTimestampHow: TypeAlias = Union[ + _PeriodFreqHow, + Literal[ + "Start", + "Finish", + "Begin", + "End", + "s", + "e", + "finish", + "begin", + ], +] + +class PeriodMixin: + @property + def end_time(self) -> Timestamp: ... + @property + def start_time(self) -> Timestamp: ... + +class Period(PeriodMixin): def __init__( self, - value: Any = ..., - freqstr: Any = ..., - ordinal: Any = ..., - year: Any = ..., - month: int = ..., - quarter: Any = ..., - day: int = ..., - hour: int = ..., - minute: int = ..., - second: int = ..., + value: Period | str | None = ..., + freq: str | BaseOffset | None = ..., + ordinal: int | None = ..., + year: int | None = ..., + month: int | None = ..., + quarter: int | None = ..., + day: int | None = ..., + hour: int | None = ..., + minute: int | None = ..., + second: int | None = ..., ) -> None: ... - def __add__(self, other) -> Period: ... - def __eq__(self, other) -> bool: ... - def __ge__(self, other) -> bool: ... - def __gt__(self, other) -> bool: ... - def __hash__(self) -> int: ... - def __le__(self, other) -> bool: ... - def __lt__(self, other) -> bool: ... - def __new__(cls, *args, **kwargs) -> Period: ... - def __ne__(self, other) -> bool: ... - def __radd__(self, other) -> Period: ... - def __reduce__(self, *args, **kwargs) -> Any: ... # what should this be? - def __rsub__(self, other) -> Period: ... - def __setstate__(self, *args, **kwargs) -> Any: ... # what should this be? + @overload + def __sub__(self, other: _PeriodAddSub) -> Period: ... + @overload + def __sub__(self, other: Period) -> BaseOffset: ... + @overload + def __sub__(self, other: NaTType) -> NaTType: ... + @overload + def __sub__(self, other: PeriodIndex) -> Index: ... + @overload + def __sub__(self, other: TimedeltaSeries) -> PeriodSeries: ... + @overload + def __sub__(self, other: TimedeltaIndex) -> PeriodIndex: ... + @overload + def __add__(self, other: _PeriodAddSub) -> Period: ... + @overload + def __add__(self, other: NaTType) -> NaTType: ... + @overload + def __add__(self, other: Index) -> PeriodIndex: ... + @overload + def __add__(self, other: OffsetSeries | TimedeltaSeries) -> PeriodSeries: ... + # ignore[misc] here because we know all other comparisons + # are False, so we use Literal[False] + @overload + def __eq__(self, other: Period) -> bool: ... # type: ignore[misc] + @overload + def __eq__(self, other: PeriodIndex) -> npt.NDArray[np.bool_]: ... # type: ignore[misc] + @overload + def __eq__(self, other: PeriodSeries | Series[Period]) -> Series[bool]: ... # type: ignore[misc] + @overload + def __eq__(self, other: object) -> Literal[False]: ... + @overload + def __ge__(self, other: Period) -> bool: ... + @overload + def __ge__(self, other: PeriodIndex) -> npt.NDArray[np.bool_]: ... + @overload + def __ge__(self, other: PeriodSeries | Series[Period]) -> Series[bool]: ... + @overload + def __gt__(self, other: Period) -> bool: ... + @overload + def __gt__(self, other: PeriodIndex) -> npt.NDArray[np.bool_]: ... + @overload + def __gt__(self, other: PeriodSeries | Series[Period]) -> Series[bool]: ... + @overload + def __le__(self, other: Period) -> bool: ... + @overload + def __le__(self, other: PeriodIndex) -> npt.NDArray[np.bool_]: ... + @overload + def __le__(self, other: PeriodSeries | Series[Period]) -> Series[bool]: ... + @overload + def __lt__(self, other: Period) -> bool: ... + @overload + def __lt__(self, other: PeriodIndex) -> npt.NDArray[np.bool_]: ... + @overload + def __lt__(self, other: PeriodSeries | Series[Period]) -> Series[bool]: ... + # ignore[misc] here because we know all other comparisons + # are False, so we use Literal[False] + @overload + def __ne__(self, other: Period) -> bool: ... # type: ignore[misc] + @overload + def __ne__(self, other: PeriodIndex) -> npt.NDArray[np.bool_]: ... # type: ignore[misc] + @overload + def __ne__(self, other: PeriodSeries | Series[Period]) -> Series[bool]: ... # type: ignore[misc] + @overload + def __ne__(self, other: object) -> Literal[True]: ... + # Ignored due to indecipherable error from mypy: + # Forward operator "__add__" is not callable [misc] + @overload + def __radd__(self, other: _PeriodAddSub) -> Period: ... # type: ignore[misc] + # Real signature is -> PeriodIndex, but conflicts with Index.__add__ + # Changing Index is very hard due to Index inheritance + # Signatures of "__radd__" of "Period" and "__add__" of "Index" + # are unsafely overlapping + @overload + def __radd__(self, other: Index) -> Index: ... + @overload + def __radd__(self, other: TimedeltaSeries) -> PeriodSeries: ... + @overload + def __radd__(self, other: NaTType) -> NaTType: ... @property def day(self) -> int: ... @property @@ -42,7 +165,7 @@ class Period: @property def end_time(self) -> Timestamp: ... @property - def freq(self) -> Any: ... + def freq(self) -> BaseOffset: ... @property def freqstr(self) -> str: ... @property @@ -71,12 +194,16 @@ class Period: def weekofyear(self) -> int: ... @property def year(self) -> int: ... - # Static methods + @property + def day_of_year(self) -> int: ... + @property + def day_of_week(self) -> int: ... + def asfreq(self, freq: str | BaseOffset, how: _PeriodFreqHow = ...) -> Period: ... @classmethod - def now(cls) -> Period: ... - # Methods - def asfreq(self, freq: str, how: str = ...) -> Period: ... + def now(cls, freq: str | BaseOffset = ...) -> Period: ... def strftime(self, fmt: str) -> str: ... - def to_timestamp(self, freq: str, how: str = ...) -> Timestamp: ... - -from .timestamps import Timestamp + def to_timestamp( + self, + freq: str | BaseOffset | None = ..., + how: _PeriodToTimestampHow = ..., + ) -> Timestamp: ... diff --git a/pandas-stubs/core/indexes/period.pyi b/pandas-stubs/core/indexes/period.pyi index 665bd28b3..53ce95277 100644 --- a/pandas-stubs/core/indexes/period.pyi +++ b/pandas-stubs/core/indexes/period.pyi @@ -1,13 +1,21 @@ -from typing import Hashable +from typing import ( + Hashable, + overload, +) import numpy as np import pandas as pd +from pandas import Index from pandas.core.indexes.datetimelike import ( DatetimeIndexOpsMixin as DatetimeIndexOpsMixin, ) from pandas.core.indexes.numeric import Int64Index +from pandas.core.series import OffsetSeries -from pandas._libs.tslibs import BaseOffset +from pandas._libs.tslibs import ( + BaseOffset, + Period, +) class PeriodIndex(DatetimeIndexOpsMixin, Int64Index): def __new__( @@ -24,6 +32,11 @@ class PeriodIndex(DatetimeIndexOpsMixin, Int64Index): @property def values(self): ... def __contains__(self, key) -> bool: ... + # Override due to supertype incompatibility which has it for NumericIndex or complex. + @overload # type: ignore[override] + def __sub__(self, other: Period) -> Index: ... + @overload + def __sub__(self, other: PeriodIndex) -> OffsetSeries: ... def __array__(self, dtype=...) -> np.ndarray: ... def __array_wrap__(self, result, context=...): ... def asof_locs(self, where, mask): ... diff --git a/pandas-stubs/core/indexes/timedeltas.pyi b/pandas-stubs/core/indexes/timedeltas.pyi index 9b06abfb6..f85145fc4 100644 --- a/pandas-stubs/core/indexes/timedeltas.pyi +++ b/pandas-stubs/core/indexes/timedeltas.pyi @@ -4,10 +4,14 @@ from typing import ( overload, ) -from pandas import DateOffset +from pandas import ( + DateOffset, + Period, +) from pandas.core.indexes.accessors import TimedeltaIndexProperties from pandas.core.indexes.datetimelike import DatetimeTimedeltaMixin from pandas.core.indexes.datetimes import DatetimeIndex +from pandas.core.indexes.period import PeriodIndex from pandas.core.series import TimedeltaSeries from pandas._libs import ( @@ -33,6 +37,8 @@ class TimedeltaIndex(DatetimeTimedeltaMixin, TimedeltaIndexProperties): # various ignores needed for mypy, as we do want to restrict what can be used in # arithmetic for these types @overload # type: ignore[override] + def __add__(self, other: Period) -> PeriodIndex: ... + @overload def __add__(self, other: DatetimeIndex) -> DatetimeIndex: ... @overload def __add__(self, other: Timedelta | TimedeltaIndex) -> TimedeltaIndex: ... diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 0a12a9a1b..189054673 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -194,7 +194,17 @@ class Series(IndexOpsMixin, NDFrame, Generic[S1]): name: Hashable | None = ..., copy: bool = ..., fastpath: bool = ..., - ) -> Series[Period]: ... + ) -> PeriodSeries: ... + @overload + def __new__( + cls, + data: TimedeltaIndex, + index: Axes | None = ..., + dtype=..., + name: Hashable | None = ..., + copy: bool = ..., + fastpath: bool = ..., + ) -> TimedeltaSeries: ... @overload def __new__( cls, @@ -1727,6 +1737,10 @@ class TimestampSeries(Series[Timestamp]): class TimedeltaSeries(Series[Timedelta]): # ignores needed because of mypy + @overload # type: ignore[override] + def __add__(self, other: Period) -> PeriodSeries: ... + @overload + def __add__(self, other: Timestamp | DatetimeIndex) -> TimestampSeries: ... def __radd__(self, pther: Timestamp | TimestampSeries) -> TimestampSeries: ... # type: ignore[override] def __mul__(self, other: num) -> TimedeltaSeries: ... # type: ignore[override] def __sub__( # type: ignore[override] @@ -1739,3 +1753,10 @@ class PeriodSeries(Series[Period]): # ignore needed because of mypy @property def dt(self) -> PeriodProperties: ... # type: ignore[override] + def __sub__(self, other: PeriodSeries) -> OffsetSeries: ... # type: ignore[override] + +class OffsetSeries(Series): + @overload # type: ignore[override] + def __radd__(self, other: Period) -> PeriodSeries: ... + @overload + def __radd__(self, other: BaseOffset) -> OffsetSeries: ... diff --git a/tests/test_scalars.py b/tests/test_scalars.py new file mode 100644 index 000000000..6139bb74f --- /dev/null +++ b/tests/test_scalars.py @@ -0,0 +1,296 @@ +from __future__ import annotations + +import datetime as dt +from typing import TYPE_CHECKING + +import numpy as np +import pandas as pd +from typing_extensions import ( + TypeAlias, + assert_type, +) + +from pandas._libs.tslibs import ( + BaseOffset, + NaTType, +) + +if TYPE_CHECKING: + from pandas.core.series import ( + OffsetSeries, + PeriodSeries, + TimedeltaSeries, + ) + + from pandas._typing import np_ndarray_bool +else: + import numpy.typing as npt + + np_ndarray_bool = npt.NDArray[np.bool_] + PeriodSeries: TypeAlias = pd.Series + TimedeltaSeries: TypeAlias = pd.Series + OffsetSeries: TypeAlias = pd.Series + + +from tests import check + +from pandas.tseries.offsets import Day + + +def test_period_construction() -> None: + p = pd.Period("2012-1-1", freq="D") + check(assert_type(p, pd.Period), pd.Period) + check(assert_type(pd.Period(p), pd.Period), pd.Period) + check(assert_type(pd.Period("2012-1-1", freq=Day()), pd.Period), pd.Period) + check( + assert_type(pd.Period(freq="D", year=2012, day=1, month=1), pd.Period), + pd.Period, + ) + check( + assert_type(pd.Period(None, "D", year=2012, day=1, month=1), pd.Period), + pd.Period, + ) + check( + assert_type(pd.Period(None, "D", 1, year=2012, day=1, month=1), pd.Period), + pd.Period, + ) + check( + assert_type( + pd.Period( + freq="s", year=2012, month=1, day=1, hour=12, minute=30, second=45 + ), + pd.Period, + ), + pd.Period, + ) + check(assert_type(pd.Period(freq="Q", year=2012, quarter=2), pd.Period), pd.Period) + + +def test_period_properties() -> None: + p = pd.Period("2012-1-1", freq="D") + + check(assert_type(p.day, int), int) + check(assert_type(p.day_of_week, int), int) + check(assert_type(p.day_of_year, int), int) + check(assert_type(p.dayofweek, int), int) + check(assert_type(p.dayofyear, int), int) + check(assert_type(p.days_in_month, int), int) + check(assert_type(p.daysinmonth, int), int) + check(assert_type(p.end_time, pd.Timestamp), pd.Timestamp) + check(assert_type(p.freqstr, str), str) + check(assert_type(p.hour, int), int) + check(assert_type(p.is_leap_year, bool), bool) + check(assert_type(p.minute, int), int) + check(assert_type(p.month, int), int) + check(assert_type(p.quarter, int), int) + check(assert_type(p.qyear, int), int) + check(assert_type(p.second, int), int) + check(assert_type(p.start_time, pd.Timestamp), pd.Timestamp) + check(assert_type(p.week, int), int) + check(assert_type(p.weekday, int), int) + check(assert_type(p.weekofyear, int), int) + check(assert_type(p.year, int), int) + check(assert_type(p.freq, BaseOffset), Day) + check(assert_type(p.ordinal, int), int) + + p2 = pd.Period("2012-1-1", freq="2D") + check(assert_type(p2.freq, BaseOffset), Day) + + +def test_period_add_subtract() -> None: + p = pd.Period("2012-1-1", freq="D") + + as_pd_td = pd.Timedelta(1, "D") + as_dt_td = dt.timedelta(days=1) + as_np_td = np.timedelta64(1, "D") + as_np_i64 = np.int64(1) + as_int = int(1) + as_period_index = pd.period_range("2012-1-1", periods=10, freq="D") + check(assert_type(as_period_index, pd.PeriodIndex), pd.PeriodIndex) + as_period = pd.Period("2012-1-1", freq="D") + scale = 24 * 60 * 60 * 10**9 + as_td_series = pd.Series(pd.timedelta_range(scale, scale, freq="D")) + check(assert_type(as_td_series, TimedeltaSeries), pd.Series) + as_period_series = pd.Series(as_period_index) + check(assert_type(as_period_series, PeriodSeries), pd.Series) + as_timedelta_idx = pd.timedelta_range(scale, scale, freq="D") + as_nat = pd.NaT + + check(assert_type(p + as_pd_td, pd.Period), pd.Period) + check(assert_type(p + as_dt_td, pd.Period), pd.Period) + check(assert_type(p + as_np_td, pd.Period), pd.Period) + check(assert_type(p + as_np_i64, pd.Period), pd.Period) + check(assert_type(p + as_int, pd.Period), pd.Period) + check(assert_type(p + p.freq, pd.Period), pd.Period) + # offset_index is tested below + offset_index = p - as_period_index + check(assert_type(p + offset_index, pd.PeriodIndex), pd.PeriodIndex) + check(assert_type(p + as_td_series, PeriodSeries), pd.Series, pd.Period) + check(assert_type(p + as_timedelta_idx, pd.PeriodIndex), pd.PeriodIndex) + check(assert_type(p + as_nat, NaTType), NaTType) + offset_series = as_period_series - as_period_series + check(assert_type(offset_series, OffsetSeries), pd.Series) + check(assert_type(p + offset_series, PeriodSeries), pd.Series, pd.Period) + check(assert_type(p - as_pd_td, pd.Period), pd.Period) + check(assert_type(p - as_dt_td, pd.Period), pd.Period) + check(assert_type(p - as_np_td, pd.Period), pd.Period) + check(assert_type(p - as_np_i64, pd.Period), pd.Period) + check(assert_type(p - as_int, pd.Period), pd.Period) + check(assert_type(offset_index, pd.Index), pd.Index) + check(assert_type(p - as_period, BaseOffset), Day) + check(assert_type(p - as_td_series, PeriodSeries), pd.Series, pd.Period) + check(assert_type(p - as_timedelta_idx, pd.PeriodIndex), pd.PeriodIndex) + check(assert_type(p - as_nat, NaTType), NaTType) + check(assert_type(p - p.freq, pd.Period), pd.Period) + + # The __radd__ and __rsub__ methods are included to + # establish the location of the concrete implementation + # Those missing are using the __add__ of the other class + check(assert_type(as_pd_td + p, pd.Period), pd.Period) + check(assert_type(p.__radd__(as_pd_td), pd.Period), pd.Period) + + check(assert_type(as_dt_td + p, pd.Period), pd.Period) + check(assert_type(p.__radd__(as_dt_td), pd.Period), pd.Period) + + check(assert_type(as_np_td + p, pd.Period), pd.Period) + check(assert_type(p.__radd__(as_np_td), pd.Period), pd.Period) + + check(assert_type(as_np_i64 + p, pd.Period), pd.Period) + check(assert_type(p.__radd__(as_np_i64), pd.Period), pd.Period) + + check(assert_type(as_int + p, pd.Period), pd.Period) + check(assert_type(p.__radd__(as_int), pd.Period), pd.Period) + + check(assert_type(as_td_series + p, PeriodSeries), pd.Series, pd.Period) + + check(assert_type(as_timedelta_idx + p, pd.PeriodIndex), pd.PeriodIndex) + + check(assert_type(as_nat + p, NaTType), NaTType) + check(assert_type(p.__radd__(as_nat), NaTType), NaTType) + + check(assert_type(p.freq + p, pd.Period), pd.Period) + check(assert_type(p.__radd__(p.freq), pd.Period), pd.Period) + + check(assert_type(as_period_index - p, pd.Index), pd.Index) + + +def test_period_cmp() -> None: + p = pd.Period("2012-1-1", freq="D") + + c_period = pd.Period("2012-1-1", freq="D") + c_period_index = pd.period_range("2012-1-1", periods=10, freq="D") + c_period_series = pd.Series(c_period_index) + + eq = check(assert_type(p == c_period, bool), bool) + ne = check(assert_type(p != c_period, bool), bool) + assert eq != ne + + eq_a = check( + assert_type(p == c_period_index, np_ndarray_bool), np.ndarray, np.bool_ + ) + ne_q = check( + assert_type(p != c_period_index, np_ndarray_bool), np.ndarray, np.bool_ + ) + assert (eq_a != ne_q).all() + + eq_s = check(assert_type(p == c_period_series, "pd.Series[bool]"), pd.Series, bool) + ne_s = check(assert_type(p != c_period_series, "pd.Series[bool]"), pd.Series, bool) + assert (eq_s != ne_s).all() + + eq = check(assert_type(c_period == p, bool), bool) + ne = check(assert_type(c_period != p, bool), bool) + assert eq != ne + + eq_a = check( + assert_type(c_period_index == p, np_ndarray_bool), np.ndarray, np.bool_ + ) + ne_a = check( + assert_type(c_period_index != p, np_ndarray_bool), np.ndarray, np.bool_ + ) + assert (eq_a != ne_a).all() + + eq_s = check(assert_type(c_period_series == p, "pd.Series[bool]"), pd.Series, bool) + ne_s = check(assert_type(c_period_series != p, "pd.Series[bool]"), pd.Series, bool) + assert (eq_s != ne_s).all() + + gt = check(assert_type(p > c_period, bool), bool) + le = check(assert_type(p <= c_period, bool), bool) + assert gt != le + + gt_a = check(assert_type(p > c_period_index, np_ndarray_bool), np.ndarray, np.bool_) + le_a = check( + assert_type(p <= c_period_index, np_ndarray_bool), np.ndarray, np.bool_ + ) + assert (gt_a != le_a).all() + + gt_s = check(assert_type(p > c_period_series, "pd.Series[bool]"), pd.Series, bool) + le_s = check(assert_type(p <= c_period_series, "pd.Series[bool]"), pd.Series, bool) + assert (gt_s != le_s).all() + + gt = check(assert_type(c_period > p, bool), bool) + le = check(assert_type(c_period <= p, bool), bool) + assert gt != le + + gt_a = check(assert_type(c_period_index > p, np_ndarray_bool), np.ndarray, np.bool_) + le_a = check( + assert_type(c_period_index <= p, np_ndarray_bool), np.ndarray, np.bool_ + ) + assert (gt_a != le_a).all() + + gt_s = check(assert_type(c_period_series > p, "pd.Series[bool]"), pd.Series, bool) + le_s = check(assert_type(c_period_series <= p, "pd.Series[bool]"), pd.Series, bool) + assert (gt_s != le_s).all() + + lt = check(assert_type(p < c_period, bool), bool) + ge = check(assert_type(p >= c_period, bool), bool) + assert lt != ge + + lt_a = check(assert_type(p < c_period_index, np_ndarray_bool), np.ndarray, np.bool_) + ge_a = check( + assert_type(p >= c_period_index, np_ndarray_bool), np.ndarray, np.bool_ + ) + assert (lt_a != ge_a).all() + + lt_s = check(assert_type(p < c_period_series, "pd.Series[bool]"), pd.Series, bool) + ge_s = check(assert_type(p >= c_period_series, "pd.Series[bool]"), pd.Series, bool) + assert (lt_s != ge_s).all() + + lt = check(assert_type(c_period < p, bool), bool) + ge = check(assert_type(c_period >= p, bool), bool) + assert lt != ge + + lt_a = check(assert_type(c_period_index < p, np_ndarray_bool), np.ndarray, np.bool_) + ge_a = check( + assert_type(c_period_index >= p, np_ndarray_bool), np.ndarray, np.bool_ + ) + assert (lt_a != ge_a).all() + + lt_s = check(assert_type(c_period_series < p, "pd.Series[bool]"), pd.Series, bool) + ge_s = check(assert_type(c_period_series >= p, "pd.Series[bool]"), pd.Series, bool) + assert (lt_s != ge_s).all() + + +def test_period_methods(): + p3 = pd.Period("2007-01", freq="M") + check(assert_type(p3.to_timestamp("D", "S"), pd.Timestamp), pd.Timestamp) + check(assert_type(p3.to_timestamp("D", "E"), pd.Timestamp), pd.Timestamp) + check(assert_type(p3.to_timestamp("D", "start"), pd.Timestamp), pd.Timestamp) + check(assert_type(p3.to_timestamp("D", "end"), pd.Timestamp), pd.Timestamp) + check(assert_type(p3.to_timestamp("D", "Finish"), pd.Timestamp), pd.Timestamp) + check(assert_type(p3.to_timestamp("D", "Begin"), pd.Timestamp), pd.Timestamp) + check(assert_type(p3.to_timestamp("D", "End"), pd.Timestamp), pd.Timestamp) + check(assert_type(p3.to_timestamp("D", "s"), pd.Timestamp), pd.Timestamp) + check(assert_type(p3.to_timestamp("D", "e"), pd.Timestamp), pd.Timestamp) + check(assert_type(p3.to_timestamp("D", "finish"), pd.Timestamp), pd.Timestamp) + check(assert_type(p3.to_timestamp("D", "begin"), pd.Timestamp), pd.Timestamp) + + check(assert_type(p3.asfreq("D", "S"), pd.Period), pd.Period) + check(assert_type(p3.asfreq(Day(), "E"), pd.Period), pd.Period) + check(assert_type(p3.asfreq(Day(), "end"), pd.Period), pd.Period) + check(assert_type(p3.asfreq(Day(), "start"), pd.Period), pd.Period) + + check(assert_type(pd.Period.now("D"), pd.Period), pd.Period) + check(assert_type(pd.Period.now(Day()), pd.Period), pd.Period) + + check(assert_type(p3.strftime("%Y-%m-%d"), str), str) + check(assert_type(hash(p3), int), int)