From e7d5294792f6140fb2a8d64086d2e33c84fc5973 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 3 Oct 2022 07:16:33 +0100 Subject: [PATCH 01/14] TYP: Improve infer_freq --- pandas-stubs/tseries/frequencies.pyi | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pandas-stubs/tseries/frequencies.pyi b/pandas-stubs/tseries/frequencies.pyi index 70da435f2..199cb1443 100644 --- a/pandas-stubs/tseries/frequencies.pyi +++ b/pandas-stubs/tseries/frequencies.pyi @@ -1,6 +1,12 @@ +from pandas import ( + DatetimeIndex, + Series, + TimedeltaIndex, +) + from pandas.tseries.offsets import DateOffset as DateOffset def get_period_alias(offset_str: str) -> str | None: ... def to_offset(freq) -> DateOffset | None: ... def get_offset(name: str) -> DateOffset: ... -def infer_freq(index) -> str | None: ... +def infer_freq(index: Series | DatetimeIndex | TimedeltaIndex) -> str | None: ... From be6c87d5f87f3ac3ec73ad7aa4897eb083b6d107 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 3 Oct 2022 07:20:17 +0100 Subject: [PATCH 02/14] TYP: Imrprove timedelta_range --- pandas-stubs/core/indexes/timedeltas.pyi | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/pandas-stubs/core/indexes/timedeltas.pyi b/pandas-stubs/core/indexes/timedeltas.pyi index 962270e33..9b06abfb6 100644 --- a/pandas-stubs/core/indexes/timedeltas.pyi +++ b/pandas-stubs/core/indexes/timedeltas.pyi @@ -1,5 +1,10 @@ -from typing import overload +from typing import ( + Hashable, + Literal, + overload, +) +from pandas import DateOffset from pandas.core.indexes.accessors import TimedeltaIndexProperties from pandas.core.indexes.datetimelike import DatetimeTimedeltaMixin from pandas.core.indexes.datetimes import DatetimeIndex @@ -9,7 +14,10 @@ from pandas._libs import ( Timedelta, Timestamp, ) -from pandas._typing import num +from pandas._typing import ( + TimedeltaConvertibleTypes, + num, +) class TimedeltaIndex(DatetimeTimedeltaMixin, TimedeltaIndexProperties): def __new__( @@ -42,5 +50,10 @@ class TimedeltaIndex(DatetimeTimedeltaMixin, TimedeltaIndexProperties): def to_series(self, index=..., name=...) -> TimedeltaSeries: ... def timedelta_range( - start=..., end=..., periods=..., freq=..., name=..., closed=... + start: TimedeltaConvertibleTypes = ..., + end: TimedeltaConvertibleTypes = ..., + periods: int | None = ..., + freq: str | DateOffset | None = ..., + name: Hashable | None = ..., + closed: Literal["left", "right"] | None = ..., ) -> TimedeltaIndex: ... From 27fef79a18d4ca7c53e8ea1eb78f33f1c92e326a Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 3 Oct 2022 07:24:24 +0100 Subject: [PATCH 03/14] TYP: Imrprove period_range --- pandas-stubs/core/indexes/period.pyi | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pandas-stubs/core/indexes/period.pyi b/pandas-stubs/core/indexes/period.pyi index 520d53644..615fd5fee 100644 --- a/pandas-stubs/core/indexes/period.pyi +++ b/pandas-stubs/core/indexes/period.pyi @@ -1,4 +1,7 @@ +from typing import Hashable + import numpy as np +import pandas as pd from pandas.core.indexes.datetimelike import ( DatetimeIndexOpsMixin as DatetimeIndexOpsMixin, ) @@ -46,5 +49,9 @@ class PeriodIndex(DatetimeIndexOpsMixin, Int64Index): def memory_usage(self, deep: bool = ...): ... def period_range( - start=..., end=..., periods=..., freq=..., name=... + start: str | pd.Period | None = ..., + end: str | pd.Period | None = ..., + periods: int | None = ..., + freq: str | pd.DateOffset | None = ..., + name: Hashable | None = ..., ) -> PeriodIndex: ... From 68e41e1d3c3447d671c06ea740b0b2cb970af1e5 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 3 Oct 2022 07:28:31 +0100 Subject: [PATCH 04/14] TYP: Improve date_range and bdate_range --- pandas-stubs/core/indexes/datetimes.pyi | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/pandas-stubs/core/indexes/datetimes.pyi b/pandas-stubs/core/indexes/datetimes.pyi index 7bd4bbe5d..0c7be234e 100644 --- a/pandas-stubs/core/indexes/datetimes.pyi +++ b/pandas-stubs/core/indexes/datetimes.pyi @@ -2,7 +2,12 @@ from datetime import ( timedelta, tzinfo, ) -from typing import overload +from typing import ( + Hashable, + Literal, + Sequence, + overload, +) import numpy as np from pandas import ( @@ -87,23 +92,24 @@ def date_range( start: str | DatetimeLike | None = ..., end: str | DatetimeLike | None = ..., periods: int | None = ..., + # TODO: Test timedelta and Timedelta, update pandas docs freq: str | timedelta | Timedelta | BaseOffset = ..., tz: str | tzinfo = ..., normalize: bool = ..., - name: str | None = ..., - inclusive: IntervalClosedType = ..., - **kwargs, + name: Hashable | None = ..., + inclusive: Literal["left", "right"] | None = ..., ) -> DatetimeIndex: ... def bdate_range( start: str | DatetimeLike | None = ..., end: str | DatetimeLike | None = ..., periods: int | None = ..., + # TODO: Test timedelta and Timedelta, update pandas docs freq: str | timedelta | Timedelta | BaseOffset = ..., tz: str | tzinfo = ..., normalize: bool = ..., - name: str | None = ..., + name: Hashable | None = ..., weekmask: str | None = ..., - holidays: list | None = ..., - inclusive: IntervalClosedType = ..., - **kwargs, + # TODO: Check if dt.date is allowed + holidays: list[str | DatetimeLike] | None = ..., + inclusive: Literal["left", "right"] | None = ..., ) -> DatetimeIndex: ... From d360eb638b54b6851804ee3227e026116cf35aad Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 3 Oct 2022 07:39:33 +0100 Subject: [PATCH 05/14] TYP: Improve to_timedelta --- pandas-stubs/core/tools/timedeltas.pyi | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/pandas-stubs/core/tools/timedeltas.pyi b/pandas-stubs/core/tools/timedeltas.pyi index 8d84fa7c6..99bd239f5 100644 --- a/pandas-stubs/core/tools/timedeltas.pyi +++ b/pandas-stubs/core/tools/timedeltas.pyi @@ -1,6 +1,8 @@ -# def to_timedelta(arg, unit: str = ..., errors: str = ...): ... from datetime import timedelta -from typing import overload +from typing import ( + Sequence, + overload, +) from pandas import Index from pandas.core.indexes.timedeltas import TimedeltaIndex @@ -16,11 +18,10 @@ from pandas._typing import ( DateTimeErrorChoices, ) -# Copied from pandas/_libs/tslibs/timedeltas.pyx - @overload def to_timedelta( arg: str | float | timedelta, + # TODO: Check all UnitChoices are valid unit: UnitChoices | None = ..., errors: DateTimeErrorChoices = ..., ) -> Timedelta: ... @@ -32,7 +33,12 @@ def to_timedelta( ) -> TimedeltaSeries: ... @overload def to_timedelta( - arg: list | tuple | range | ArrayLike | Index, + arg: Sequence[float | timedelta] + | list[str | float | timedelta] + | tuple[str | float | timedelta, ...] + | range + | ArrayLike + | Index, unit: UnitChoices | None = ..., errors: DateTimeErrorChoices = ..., ) -> TimedeltaIndex: ... From 539c842fa329f32f5d9dd3b0b52e3a4b78e06714 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 3 Oct 2022 07:46:18 +0100 Subject: [PATCH 06/14] TYP: Improve to_datetime --- pandas-stubs/core/tools/datetimes.pyi | 29 ++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/pandas-stubs/core/tools/datetimes.pyi b/pandas-stubs/core/tools/datetimes.pyi index abd8dbebd..98d426aad 100644 --- a/pandas-stubs/core/tools/datetimes.pyi +++ b/pandas-stubs/core/tools/datetimes.pyi @@ -1,12 +1,14 @@ from datetime import datetime from typing import ( Literal, + Sequence, TypedDict, Union, overload, ) import numpy as np +import pandas as pd from pandas import ( Index, Timestamp, @@ -25,6 +27,7 @@ from pandas._typing import ( AnyArrayLike, DateTimeErrorChoices, IgnoreRaise, + npt, ) ArrayConvertible: TypeAlias = Union[list, tuple, AnyArrayLike] @@ -53,9 +56,6 @@ class FulldatetimeDict(YearMonthDayDict, total=False): DictConvertible: TypeAlias = Union[FulldatetimeDict, DataFrame] -def should_cache( - arg: ArrayConvertible, unique_share: float = ..., check_count: int | None = ... -) -> bool: ... @overload def to_datetime( arg: DatetimeScalar, @@ -67,7 +67,7 @@ def to_datetime( exact: bool = ..., unit: str | None = ..., infer_datetime_format: bool = ..., - origin=..., + origin: int | Literal["julian", "unix"] | pd.Timestamp = ..., cache: bool = ..., ) -> Timestamp: ... @overload @@ -81,11 +81,12 @@ def to_datetime( exact: bool = ..., unit: str | None = ..., infer_datetime_format: bool = ..., - origin=..., + origin: Literal["julian", "unix"] | pd.Timestamp = ..., cache: bool = ..., ) -> Timestamp | NaTType: ... @overload def to_datetime( + # TODO: Test dataframe return type arg: Series | DictConvertible, errors: DateTimeErrorChoices = ..., dayfirst: bool = ..., @@ -95,12 +96,23 @@ def to_datetime( exact: bool = ..., unit: str | None = ..., infer_datetime_format: bool = ..., - origin=..., + origin: int | Literal["julian", "unix"] | pd.Timestamp = ..., cache: bool = ..., ) -> TimestampSeries: ... @overload def to_datetime( - arg: list | tuple | np.ndarray | Index | ExtensionArray, + # TODO: Test other types + arg: list[str] + | list[int] + | list[float] + | list[datetime] + | tuple[int | float | str | datetime, ...] + | npt.NDArray[np.datetime64] + | npt.NDArray[np.str_] + | npt.NDArray[np.int_] + | npt.NDArray[np.float_] + | Index + | ExtensionArray, errors: DateTimeErrorChoices = ..., dayfirst: bool = ..., yearfirst: bool = ..., @@ -109,7 +121,6 @@ def to_datetime( exact: bool = ..., unit: str | None = ..., infer_datetime_format: bool = ..., - origin=..., + origin: int | Literal["julian", "unix"] | pd.Timestamp = ..., cache: bool = ..., ) -> DatetimeIndex: ... -def to_time(arg, format=..., infer_time_format: bool = ..., errors: str = ...): ... From 234fa44d0f27754a925b4a65fd10a8fab04a5aaa Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 3 Oct 2022 09:19:54 +0100 Subject: [PATCH 07/14] Small fixes --- pandas-stubs/core/indexes/datetimes.pyi | 2 -- pandas-stubs/core/tools/datetimes.pyi | 7 +++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/pandas-stubs/core/indexes/datetimes.pyi b/pandas-stubs/core/indexes/datetimes.pyi index 0c7be234e..84d71dea5 100644 --- a/pandas-stubs/core/indexes/datetimes.pyi +++ b/pandas-stubs/core/indexes/datetimes.pyi @@ -5,7 +5,6 @@ from datetime import ( from typing import ( Hashable, Literal, - Sequence, overload, ) @@ -28,7 +27,6 @@ from pandas._typing import ( AnyArrayLike, ArrayLike, DatetimeLike, - IntervalClosedType, ) from pandas.core.dtypes.dtypes import DatetimeTZDtype diff --git a/pandas-stubs/core/tools/datetimes.pyi b/pandas-stubs/core/tools/datetimes.pyi index 98d426aad..906f5cceb 100644 --- a/pandas-stubs/core/tools/datetimes.pyi +++ b/pandas-stubs/core/tools/datetimes.pyi @@ -102,10 +102,8 @@ def to_datetime( @overload def to_datetime( # TODO: Test other types - arg: list[str] - | list[int] - | list[float] - | list[datetime] + arg: Sequence[int | float | datetime] + | list[str] | tuple[int | float | str | datetime, ...] | npt.NDArray[np.datetime64] | npt.NDArray[np.str_] @@ -121,6 +119,7 @@ def to_datetime( exact: bool = ..., unit: str | None = ..., infer_datetime_format: bool = ..., + # TODO: Origin needs int in pandas docs origin: int | Literal["julian", "unix"] | pd.Timestamp = ..., cache: bool = ..., ) -> DatetimeIndex: ... From 47b9a6d1747db60265cab88228dbe5b46b1a16b5 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 3 Oct 2022 12:24:04 +0100 Subject: [PATCH 08/14] TST: Add tests for to_timedelta --- pandas-stubs/_libs/tslibs/timedeltas.pyi | 16 +++- pandas-stubs/core/tools/timedeltas.pyi | 10 +-- tests/test_timefuncs.py | 101 +++++++++++++++++++++++ 3 files changed, 118 insertions(+), 9 deletions(-) diff --git a/pandas-stubs/_libs/tslibs/timedeltas.pyi b/pandas-stubs/_libs/tslibs/timedeltas.pyi index 75ff28c87..aa09000ad 100644 --- a/pandas-stubs/_libs/tslibs/timedeltas.pyi +++ b/pandas-stubs/_libs/tslibs/timedeltas.pyi @@ -3,6 +3,7 @@ from typing import ( ClassVar, Literal, TypeVar, + Union, overload, ) @@ -17,10 +18,7 @@ from pandas._typing import npt # This should be kept consistent with the keys in the dict timedelta_abbrevs # in pandas/_libs/tslibs/timedeltas.pyx -UnitChoices: TypeAlias = Literal[ - "Y", - "y", - "M", +TimeDeltaUnitChoices: TypeAlias = Literal[ "W", "w", "D", @@ -60,6 +58,16 @@ UnitChoices: TypeAlias = Literal[ "nanosecond", "n", ] + +UnitChoices: TypeAlias = Union[ + TimeDeltaUnitChoices, + Literal[ + "Y", + "y", + "M", + ], +] + _S = TypeVar("_S", bound=timedelta) def ints_to_pytimedelta( diff --git a/pandas-stubs/core/tools/timedeltas.pyi b/pandas-stubs/core/tools/timedeltas.pyi index 99bd239f5..c2b881628 100644 --- a/pandas-stubs/core/tools/timedeltas.pyi +++ b/pandas-stubs/core/tools/timedeltas.pyi @@ -4,6 +4,7 @@ from typing import ( overload, ) +import pandas as pd from pandas import Index from pandas.core.indexes.timedeltas import TimedeltaIndex from pandas.core.series import ( @@ -12,7 +13,7 @@ from pandas.core.series import ( ) from pandas._libs.tslibs import Timedelta -from pandas._libs.tslibs.timedeltas import UnitChoices +from pandas._libs.tslibs.timedeltas import TimeDeltaUnitChoices from pandas._typing import ( ArrayLike, DateTimeErrorChoices, @@ -21,14 +22,13 @@ from pandas._typing import ( @overload def to_timedelta( arg: str | float | timedelta, - # TODO: Check all UnitChoices are valid - unit: UnitChoices | None = ..., + unit: TimeDeltaUnitChoices | None = ..., errors: DateTimeErrorChoices = ..., ) -> Timedelta: ... @overload def to_timedelta( arg: Series, - unit: UnitChoices | None = ..., + unit: TimeDeltaUnitChoices | None = ..., errors: DateTimeErrorChoices = ..., ) -> TimedeltaSeries: ... @overload @@ -39,6 +39,6 @@ def to_timedelta( | range | ArrayLike | Index, - unit: UnitChoices | None = ..., + unit: TimeDeltaUnitChoices | None = ..., errors: DateTimeErrorChoices = ..., ) -> TimedeltaIndex: ... diff --git a/tests/test_timefuncs.py b/tests/test_timefuncs.py index 24bd12dc4..7993defee 100644 --- a/tests/test_timefuncs.py +++ b/tests/test_timefuncs.py @@ -534,3 +534,104 @@ def test_types_to_numpy() -> None: check(assert_type(td_s.to_numpy(), np.ndarray), np.ndarray) check(assert_type(td_s.to_numpy(dtype="int", copy=True), np.ndarray), np.ndarray) check(assert_type(td_s.to_numpy(na_value=0), np.ndarray), np.ndarray) + + +def test_to_timdelta_units() -> None: + pd.to_timedelta(1, "W") + pd.to_timedelta(1, "w") + pd.to_timedelta(1, "D") + pd.to_timedelta(1, "d") + pd.to_timedelta(1, "days") + pd.to_timedelta(1, "day") + pd.to_timedelta(1, "hours") + pd.to_timedelta(1, "hour") + pd.to_timedelta(1, "hr") + pd.to_timedelta(1, "h") + pd.to_timedelta(1, "m") + pd.to_timedelta(1, "minute") + pd.to_timedelta(1, "min") + pd.to_timedelta(1, "minutes") + pd.to_timedelta(1, "t") + pd.to_timedelta(1, "s") + pd.to_timedelta(1, "seconds") + pd.to_timedelta(1, "sec") + pd.to_timedelta(1, "second") + pd.to_timedelta(1, "ms") + pd.to_timedelta(1, "milliseconds") + pd.to_timedelta(1, "millisecond") + pd.to_timedelta(1, "milli") + pd.to_timedelta(1, "millis") + pd.to_timedelta(1, "l") + pd.to_timedelta(1, "us") + pd.to_timedelta(1, "microseconds") + pd.to_timedelta(1, "microsecond") + pd.to_timedelta(1, "µs") + pd.to_timedelta(1, "micro") + pd.to_timedelta(1, "micros") + pd.to_timedelta(1, "u") + pd.to_timedelta(1, "ns") + pd.to_timedelta(1, "nanoseconds") + pd.to_timedelta(1, "nano") + pd.to_timedelta(1, "nanos") + pd.to_timedelta(1, "nanosecond") + pd.to_timedelta(1, "n") + + +def test_to_timedelta_scalar() -> None: + check( + assert_type(pd.to_timedelta(10, "ms", errors="raise"), pd.Timedelta), + pd.Timedelta, + ) + check( + assert_type(pd.to_timedelta("10ms", errors="ignore"), pd.Timedelta), + pd.Timedelta, + ) + check( + assert_type( + pd.to_timedelta(dt.timedelta(milliseconds=10), errors="coerce"), + pd.Timedelta, + ), + pd.Timedelta, + ) + + +def test_to_timedelta_series() -> None: + s = pd.Series([10, 20, 30, 40]) + s2 = pd.Series(["10ms", "20ms", "30ms"]) + check(assert_type(pd.to_timedelta(s, "ms"), "TimedeltaSeries"), pd.Series) + check(assert_type(pd.to_timedelta(s2), "TimedeltaSeries"), pd.Series) + + +def test_to_timedelta_index() -> None: + arg0 = [1.0, 2.0, 3.0] + arg1 = [ + dt.timedelta(milliseconds=1), + dt.timedelta(milliseconds=2), + dt.timedelta(milliseconds=3), + ] + arg2 = tuple(arg0) + arg3 = tuple(arg1) + arg4 = range(0, 10) + arg5 = np.arange(10) + arg6 = pd.Index(arg5) + check( + assert_type(pd.to_timedelta(arg0, "ms"), pd.TimedeltaIndex), pd.TimedeltaIndex + ) + check( + assert_type(pd.to_timedelta(arg1, "ms"), pd.TimedeltaIndex), pd.TimedeltaIndex + ) + check( + assert_type(pd.to_timedelta(arg2, "ms"), pd.TimedeltaIndex), pd.TimedeltaIndex + ) + check( + assert_type(pd.to_timedelta(arg3, "ms"), pd.TimedeltaIndex), pd.TimedeltaIndex + ) + check( + assert_type(pd.to_timedelta(arg4, "ms"), pd.TimedeltaIndex), pd.TimedeltaIndex + ) + check( + assert_type(pd.to_timedelta(arg5, "ms"), pd.TimedeltaIndex), pd.TimedeltaIndex + ) + check( + assert_type(pd.to_timedelta(arg6, "ms"), pd.TimedeltaIndex), pd.TimedeltaIndex + ) From 94b94e58a836498cd5e321a8c01226b0661ba508 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 3 Oct 2022 18:59:31 +0100 Subject: [PATCH 09/14] TST/ENH: Add tests and overload for bdate_range --- pandas-stubs/core/indexes/datetimes.pyi | 30 +++++++++++++++++++------ tests/test_timefuncs.py | 16 +++++++++++++ 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/pandas-stubs/core/indexes/datetimes.pyi b/pandas-stubs/core/indexes/datetimes.pyi index 84d71dea5..225c8f21e 100644 --- a/pandas-stubs/core/indexes/datetimes.pyi +++ b/pandas-stubs/core/indexes/datetimes.pyi @@ -1,10 +1,11 @@ from datetime import ( + date, timedelta, tzinfo, ) from typing import ( Hashable, - Literal, + Sequence, overload, ) @@ -27,6 +28,7 @@ from pandas._typing import ( AnyArrayLike, ArrayLike, DatetimeLike, + IntervalClosedType, ) from pandas.core.dtypes.dtypes import DatetimeTZDtype @@ -90,24 +92,38 @@ def date_range( start: str | DatetimeLike | None = ..., end: str | DatetimeLike | None = ..., periods: int | None = ..., - # TODO: Test timedelta and Timedelta, update pandas docs + # TODO: Add Timedelta to pandas docs freq: str | timedelta | Timedelta | BaseOffset = ..., tz: str | tzinfo = ..., normalize: bool = ..., name: Hashable | None = ..., - inclusive: Literal["left", "right"] | None = ..., + inclusive: IntervalClosedType = ..., ) -> DatetimeIndex: ... +@overload def bdate_range( start: str | DatetimeLike | None = ..., end: str | DatetimeLike | None = ..., periods: int | None = ..., - # TODO: Test timedelta and Timedelta, update pandas docs freq: str | timedelta | Timedelta | BaseOffset = ..., tz: str | tzinfo = ..., normalize: bool = ..., name: Hashable | None = ..., weekmask: str | None = ..., - # TODO: Check if dt.date is allowed - holidays: list[str | DatetimeLike] | None = ..., - inclusive: Literal["left", "right"] | None = ..., + holidays: None = ..., + inclusive: IntervalClosedType = ..., +) -> DatetimeIndex: ... +@overload +def bdate_range( + start: str | DatetimeLike | None = ..., + end: str | DatetimeLike | None = ..., + periods: int | None = ..., + *, + # TODO: Add Timedelta to pandas docs + freq: str | timedelta | Timedelta | BaseOffset, + tz: str | tzinfo = ..., + normalize: bool = ..., + name: Hashable | None = ..., + weekmask: str | None = ..., + holidays: Sequence[str | DatetimeLike | date], + inclusive: IntervalClosedType = ..., ) -> DatetimeIndex: ... diff --git a/tests/test_timefuncs.py b/tests/test_timefuncs.py index 7993defee..56c84fd24 100644 --- a/tests/test_timefuncs.py +++ b/tests/test_timefuncs.py @@ -635,3 +635,19 @@ def test_to_timedelta_index() -> None: check( assert_type(pd.to_timedelta(arg6, "ms"), pd.TimedeltaIndex), pd.TimedeltaIndex ) + + +def test_bdate_range_holidays(): + pd.bdate_range("2000-1-1", "2001-1-1", freq="C", holidays=["2000-12-15"]) + pd.bdate_range( + "2000-1-1", "2001-1-1", freq="C", holidays=[pd.Timestamp(2000, 12, 15)] + ) + pd.bdate_range( + "2000-1-1", "2001-1-1", freq="C", holidays=[np.datetime64("2000-12-15")] + ) + pd.bdate_range( + "2000-1-1", "2001-1-1", freq="C", holidays=[dt.datetime(2000, 12, 15)] + ) + pd.bdate_range( + "2000-1-1", "2001-1-1", freq="C", holidays=[dt.date(2000, 12, 15)], name=("a",) + ) From 860cad7d83b852a631d77b85fe4446f8d3d397ae Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Mon, 3 Oct 2022 19:07:26 +0100 Subject: [PATCH 10/14] TST/ENH: Add tests and improve period_range --- pandas-stubs/core/indexes/period.pyi | 4 ++- tests/test_timefuncs.py | 37 +++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/pandas-stubs/core/indexes/period.pyi b/pandas-stubs/core/indexes/period.pyi index 615fd5fee..665bd28b3 100644 --- a/pandas-stubs/core/indexes/period.pyi +++ b/pandas-stubs/core/indexes/period.pyi @@ -7,6 +7,8 @@ from pandas.core.indexes.datetimelike import ( ) from pandas.core.indexes.numeric import Int64Index +from pandas._libs.tslibs import BaseOffset + class PeriodIndex(DatetimeIndexOpsMixin, Int64Index): def __new__( cls, @@ -52,6 +54,6 @@ def period_range( start: str | pd.Period | None = ..., end: str | pd.Period | None = ..., periods: int | None = ..., - freq: str | pd.DateOffset | None = ..., + freq: str | BaseOffset | None = ..., name: Hashable | None = ..., ) -> PeriodIndex: ... diff --git a/tests/test_timefuncs.py b/tests/test_timefuncs.py index 56c84fd24..0cdb2d695 100644 --- a/tests/test_timefuncs.py +++ b/tests/test_timefuncs.py @@ -637,7 +637,7 @@ def test_to_timedelta_index() -> None: ) -def test_bdate_range_holidays(): +def test_bdate_range_holidays() -> None: pd.bdate_range("2000-1-1", "2001-1-1", freq="C", holidays=["2000-12-15"]) pd.bdate_range( "2000-1-1", "2001-1-1", freq="C", holidays=[pd.Timestamp(2000, 12, 15)] @@ -651,3 +651,38 @@ def test_bdate_range_holidays(): pd.bdate_range( "2000-1-1", "2001-1-1", freq="C", holidays=[dt.date(2000, 12, 15)], name=("a",) ) + + +def test_period_range() -> None: + check( + assert_type( + pd.period_range(pd.Period("2001Q1"), end=pd.Period("2010Q1")), + pd.PeriodIndex, + ), + pd.PeriodIndex, + ) + check( + assert_type(pd.period_range("2001Q1", end=pd.Period("2010Q1")), pd.PeriodIndex), + pd.PeriodIndex, + ) + check( + assert_type( + pd.period_range("2001-01-01", end="2010-01-01", freq="Q"), pd.PeriodIndex + ), + pd.PeriodIndex, + ) + check( + assert_type(pd.period_range("2001Q1", periods=100, freq="Q"), pd.PeriodIndex), + pd.PeriodIndex, + ) + check( + assert_type(pd.period_range("2001Q1", periods=100, freq=Day()), pd.PeriodIndex), + pd.PeriodIndex, + ) + check( + assert_type( + pd.period_range("2001Q1", periods=100, freq=Day(), name=("A",)), + pd.PeriodIndex, + ), + pd.PeriodIndex, + ) From c447e21ba1c43c75ba153ba2d2b4341847dc08a8 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 4 Oct 2022 01:01:34 +0100 Subject: [PATCH 11/14] TST: Add tests --- pandas-stubs/_typing.pyi | 22 ++++ pandas-stubs/core/tools/datetimes.pyi | 32 +----- tests/test_timefuncs.py | 158 ++++++++++++++++++++++++++ 3 files changed, 186 insertions(+), 26 deletions(-) diff --git a/pandas-stubs/_typing.pyi b/pandas-stubs/_typing.pyi index a14b9647d..0ce1918ab 100644 --- a/pandas-stubs/_typing.pyi +++ b/pandas-stubs/_typing.pyi @@ -19,6 +19,7 @@ from typing import ( import numpy as np from numpy import typing as npt from pandas.core.arrays import ExtensionArray +from pandas.core.frame import DataFrame from pandas.core.generic import NDFrame from pandas.core.groupby.grouper import Grouper from pandas.core.indexes.base import Index @@ -46,6 +47,27 @@ PandasScalar: TypeAlias = Union[ DatetimeLike: TypeAlias = Union[datetime.datetime, np.datetime64, Timestamp] +DatetimeDictArg: TypeAlias = Union[ + Sequence[int], Sequence[float], list[str], tuple[Scalar, ...], AnyArrayLike +] +DictConvertible: TypeAlias = Union[FulldatetimeDict, DataFrame] + +class YearMonthDayDict(TypedDict, total=True): + year: DatetimeDictArg + month: DatetimeDictArg + day: DatetimeDictArg + +class FulldatetimeDict(YearMonthDayDict, total=False): + hour: DatetimeDictArg + hours: DatetimeDictArg + minute: DatetimeDictArg + minutes: DatetimeDictArg + second: DatetimeDictArg + seconds: DatetimeDictArg + ms: DatetimeDictArg + us: DatetimeDictArg + ns: DatetimeDictArg + # dtypes NpDtype: TypeAlias = Union[ str, np.dtype[np.generic], type[Union[str, complex, bool, object]] diff --git a/pandas-stubs/core/tools/datetimes.pyi b/pandas-stubs/core/tools/datetimes.pyi index 906f5cceb..989018c4b 100644 --- a/pandas-stubs/core/tools/datetimes.pyi +++ b/pandas-stubs/core/tools/datetimes.pyi @@ -1,8 +1,10 @@ -from datetime import datetime +from datetime import ( + date, + datetime, +) from typing import ( Literal, Sequence, - TypedDict, Union, overload, ) @@ -14,7 +16,6 @@ from pandas import ( Timestamp, ) from pandas.core.arrays import ExtensionArray -from pandas.core.frame import DataFrame from pandas.core.indexes.datetimes import DatetimeIndex from pandas.core.series import ( Series, @@ -26,36 +27,17 @@ from pandas._libs.tslibs import NaTType from pandas._typing import ( AnyArrayLike, DateTimeErrorChoices, + DictConvertible, IgnoreRaise, npt, ) ArrayConvertible: TypeAlias = Union[list, tuple, AnyArrayLike] Scalar: TypeAlias = Union[float, str] -DatetimeScalar: TypeAlias = Union[Scalar, datetime, np.datetime64] +DatetimeScalar: TypeAlias = Union[Scalar, datetime, np.datetime64, date] DatetimeScalarOrArrayConvertible: TypeAlias = Union[DatetimeScalar, ArrayConvertible] -DatetimeDictArg: TypeAlias = Union[list[Scalar], tuple[Scalar, ...], AnyArrayLike] - -class YearMonthDayDict(TypedDict, total=True): - year: DatetimeDictArg - month: DatetimeDictArg - day: DatetimeDictArg - -class FulldatetimeDict(YearMonthDayDict, total=False): - hour: DatetimeDictArg - hours: DatetimeDictArg - minute: DatetimeDictArg - minutes: DatetimeDictArg - second: DatetimeDictArg - seconds: DatetimeDictArg - ms: DatetimeDictArg - us: DatetimeDictArg - ns: DatetimeDictArg - -DictConvertible: TypeAlias = Union[FulldatetimeDict, DataFrame] - @overload def to_datetime( arg: DatetimeScalar, @@ -101,14 +83,12 @@ def to_datetime( ) -> TimestampSeries: ... @overload def to_datetime( - # TODO: Test other types arg: Sequence[int | float | datetime] | list[str] | tuple[int | float | str | datetime, ...] | npt.NDArray[np.datetime64] | npt.NDArray[np.str_] | npt.NDArray[np.int_] - | npt.NDArray[np.float_] | Index | ExtensionArray, errors: DateTimeErrorChoices = ..., diff --git a/tests/test_timefuncs.py b/tests/test_timefuncs.py index 0cdb2d695..3f41ee648 100644 --- a/tests/test_timefuncs.py +++ b/tests/test_timefuncs.py @@ -4,6 +4,7 @@ import datetime as dt from typing import ( TYPE_CHECKING, + Any, Optional, Union, ) @@ -18,6 +19,10 @@ from pandas._libs import NaTType from pandas._libs.tslibs import BaseOffset +if TYPE_CHECKING: + from pandas._typing import FulldatetimeDict +else: + FulldatetimeDict = Any from tests import ( TYPE_CHECKING_INVALID_USAGE, check, @@ -686,3 +691,156 @@ def test_period_range() -> None: ), pd.PeriodIndex, ) + + +def test_to_datetime_scalar() -> None: + check(assert_type(pd.to_datetime("2000-01-01"), pd.Timestamp), pd.Timestamp) + check(assert_type(pd.to_datetime(1), pd.Timestamp), pd.Timestamp) + check(assert_type(pd.to_datetime(1.5), pd.Timestamp), pd.Timestamp) + check( + assert_type(pd.to_datetime(dt.datetime(2000, 1, 1)), pd.Timestamp), pd.Timestamp + ) + check(assert_type(pd.to_datetime(dt.date(2000, 1, 1)), pd.Timestamp), pd.Timestamp) + check( + assert_type(pd.to_datetime(np.datetime64("2000-01-01")), pd.Timestamp), + pd.Timestamp, + ) + + +def test_to_datetime_scalar_extended() -> None: + check(assert_type(pd.to_datetime("2000-01-01"), pd.Timestamp), pd.Timestamp) + check(assert_type(pd.to_datetime(1), pd.Timestamp), pd.Timestamp) + check(assert_type(pd.to_datetime(1.5), pd.Timestamp), pd.Timestamp) + check( + assert_type(pd.to_datetime(dt.datetime(2000, 1, 1)), pd.Timestamp), pd.Timestamp + ) + check(assert_type(pd.to_datetime(dt.date(2000, 1, 1)), pd.Timestamp), pd.Timestamp) + check( + assert_type(pd.to_datetime(np.datetime64("2000-01-01")), pd.Timestamp), + pd.Timestamp, + ) + + +def test_to_datetime_series() -> None: + s = pd.Series(["2000-01-01", "2000-01-02"]) + check(assert_type(pd.to_datetime(s), "TimestampSeries"), pd.Series) + d: FulldatetimeDict = { + "year": [2000, 2000, 2000], + "month": [1, 1, 1], + "day": [1, 2, 3], + } + df = pd.DataFrame(d) + d_ex: FulldatetimeDict = { + "year": [2000, 2000, 2000], + "month": [1, 1, 1], + "day": [1, 2, 3], + "hour": [1, 1, 1], + "hours": [1, 1, 1], + "minute": [1, 1, 1], + "minutes": [1, 1, 1], + "second": [1, 1, 1], + "seconds": [1, 1, 1], + "ms": [1, 1, 1], + "us": [1, 1, 1], + "ns": [1, 1, 1], + } + check(assert_type(pd.to_datetime(df), "TimestampSeries"), pd.Series) + check(assert_type(pd.to_datetime(d), "TimestampSeries"), pd.Series) + check(assert_type(pd.to_datetime(d_ex), "TimestampSeries"), pd.Series) + + +def test_to_datetime_array() -> None: + check(assert_type(pd.to_datetime([1, 2, 3]), pd.DatetimeIndex), pd.DatetimeIndex) + check( + assert_type(pd.to_datetime([1.5, 2.5, 3.5]), pd.DatetimeIndex), pd.DatetimeIndex + ) + check( + assert_type( + pd.to_datetime( + [ + dt.datetime(2000, 1, 1), + dt.datetime(2000, 1, 2), + dt.datetime(2000, 1, 3), + ] + ), + pd.DatetimeIndex, + ), + pd.DatetimeIndex, + ) + check( + assert_type( + pd.to_datetime(["2000-01-01", "2000-01-02", "2000-01-03"]), pd.DatetimeIndex + ), + pd.DatetimeIndex, + ) + check(assert_type(pd.to_datetime((1, 2, 3)), pd.DatetimeIndex), pd.DatetimeIndex) + check( + assert_type(pd.to_datetime((1.5, 2.5, 3.5)), pd.DatetimeIndex), pd.DatetimeIndex + ) + check( + assert_type( + pd.to_datetime( + ( + dt.datetime(2000, 1, 1), + dt.datetime(2000, 1, 2), + dt.datetime(2000, 1, 3), + ) + ), + pd.DatetimeIndex, + ), + pd.DatetimeIndex, + ) + check( + assert_type( + pd.to_datetime(("2000-01-01", "2000-01-02", "2000-01-03")), pd.DatetimeIndex + ), + pd.DatetimeIndex, + ) + check( + assert_type( + pd.to_datetime( + np.array( + [ + np.datetime64("2000-01-01"), + np.datetime64("2000-01-02"), + np.datetime64("2000-01-03"), + ] + ) + ), + pd.DatetimeIndex, + ), + pd.DatetimeIndex, + ) + check( + assert_type( + pd.to_datetime(np.array(["2000-01-01", "2000-01-02", "2000-01-03"])), + pd.DatetimeIndex, + ), + pd.DatetimeIndex, + ) + check( + assert_type(pd.to_datetime(np.array([1, 2, 3])), pd.DatetimeIndex), + pd.DatetimeIndex, + ) + pd.to_datetime( + pd.Index([2451544.5, 2451545.5, 2451546.5]), + unit="D", + origin="julian", + ) + check( + assert_type( + pd.to_datetime(pd.Index([1, 2, 3]), origin="unix"), pd.DatetimeIndex + ), + pd.DatetimeIndex, + ) + check( + assert_type(pd.to_datetime(pd.Index([1, 2, 3]), origin=4), pd.DatetimeIndex), + pd.DatetimeIndex, + ) + check( + assert_type( + pd.to_datetime(pd.Index([1, 2, 3]), origin=pd.Timestamp("1999-12-31")), + pd.DatetimeIndex, + ), + pd.DatetimeIndex, + ) From b167110af96cac0fc222b18236ce393c4b7de18d Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 4 Oct 2022 01:13:02 +0100 Subject: [PATCH 12/14] TST: Add check and assert type, add more tests --- tests/test_timefuncs.py | 135 +++++++++++++++++++++++++++++----------- 1 file changed, 97 insertions(+), 38 deletions(-) diff --git a/tests/test_timefuncs.py b/tests/test_timefuncs.py index 3f41ee648..ea596bbd2 100644 --- a/tests/test_timefuncs.py +++ b/tests/test_timefuncs.py @@ -542,44 +542,44 @@ def test_types_to_numpy() -> None: def test_to_timdelta_units() -> None: - pd.to_timedelta(1, "W") - pd.to_timedelta(1, "w") - pd.to_timedelta(1, "D") - pd.to_timedelta(1, "d") - pd.to_timedelta(1, "days") - pd.to_timedelta(1, "day") - pd.to_timedelta(1, "hours") - pd.to_timedelta(1, "hour") - pd.to_timedelta(1, "hr") - pd.to_timedelta(1, "h") - pd.to_timedelta(1, "m") - pd.to_timedelta(1, "minute") - pd.to_timedelta(1, "min") - pd.to_timedelta(1, "minutes") - pd.to_timedelta(1, "t") - pd.to_timedelta(1, "s") - pd.to_timedelta(1, "seconds") - pd.to_timedelta(1, "sec") - pd.to_timedelta(1, "second") - pd.to_timedelta(1, "ms") - pd.to_timedelta(1, "milliseconds") - pd.to_timedelta(1, "millisecond") - pd.to_timedelta(1, "milli") - pd.to_timedelta(1, "millis") - pd.to_timedelta(1, "l") - pd.to_timedelta(1, "us") - pd.to_timedelta(1, "microseconds") - pd.to_timedelta(1, "microsecond") - pd.to_timedelta(1, "µs") - pd.to_timedelta(1, "micro") - pd.to_timedelta(1, "micros") - pd.to_timedelta(1, "u") - pd.to_timedelta(1, "ns") - pd.to_timedelta(1, "nanoseconds") - pd.to_timedelta(1, "nano") - pd.to_timedelta(1, "nanos") - pd.to_timedelta(1, "nanosecond") - pd.to_timedelta(1, "n") + check(assert_type(pd.to_timedelta(1, "W"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "w"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "D"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "d"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "days"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "day"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "hours"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "hour"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "hr"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "h"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "m"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "minute"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "min"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "minutes"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "t"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "s"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "seconds"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "sec"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "second"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "ms"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "milliseconds"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "millisecond"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "milli"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "millis"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "l"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "us"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "microseconds"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "microsecond"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "µs"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "micro"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "micros"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "u"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "ns"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "nanoseconds"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "nano"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "nanos"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "nanosecond"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.to_timedelta(1, "n"), pd.Timedelta), pd.Timedelta) def test_to_timedelta_scalar() -> None: @@ -844,3 +844,62 @@ def test_to_datetime_array() -> None: ), pd.DatetimeIndex, ) + + +def test_timedelta_range() -> None: + check( + assert_type( + pd.timedelta_range( + pd.Timedelta(1, unit="D"), pd.Timedelta(10, unit="D"), periods=10 + ), + pd.TimedeltaIndex, + ), + pd.TimedeltaIndex, + ) + check( + assert_type( + pd.timedelta_range(dt.timedelta(1), dt.timedelta(10), periods=10), + pd.TimedeltaIndex, + ), + pd.TimedeltaIndex, + ) + check( + assert_type( + pd.timedelta_range( + np.timedelta64(86400000000000), + np.timedelta64(864000000000000), + periods=10, + ), + pd.TimedeltaIndex, + ), + pd.TimedeltaIndex, + ) + check( + assert_type( + pd.timedelta_range("1 day", "10 days", periods=10), pd.TimedeltaIndex + ), + pd.TimedeltaIndex, + ) + check( + assert_type( + pd.timedelta_range( + np.int64(86400000000000), np.int64(864000000000000), periods=10 + ), + pd.TimedeltaIndex, + ), + pd.TimedeltaIndex, + ) + check( + assert_type( + pd.timedelta_range(86400000000000, 864000000000000, periods=10), + pd.TimedeltaIndex, + ), + pd.TimedeltaIndex, + ) + check( + assert_type( + pd.timedelta_range(86400000000000.0, 864000000000000.0, periods=10), + pd.TimedeltaIndex, + ), + pd.TimedeltaIndex, + ) From fda97876576ce71c51ab8891fa99b7467161bf19 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 4 Oct 2022 01:15:28 +0100 Subject: [PATCH 13/14] CLN: Remove unnecessary TODO --- pandas-stubs/core/indexes/datetimes.pyi | 1 - pandas-stubs/core/tools/datetimes.pyi | 1 - 2 files changed, 2 deletions(-) diff --git a/pandas-stubs/core/indexes/datetimes.pyi b/pandas-stubs/core/indexes/datetimes.pyi index 225c8f21e..803c69c08 100644 --- a/pandas-stubs/core/indexes/datetimes.pyi +++ b/pandas-stubs/core/indexes/datetimes.pyi @@ -92,7 +92,6 @@ def date_range( start: str | DatetimeLike | None = ..., end: str | DatetimeLike | None = ..., periods: int | None = ..., - # TODO: Add Timedelta to pandas docs freq: str | timedelta | Timedelta | BaseOffset = ..., tz: str | tzinfo = ..., normalize: bool = ..., diff --git a/pandas-stubs/core/tools/datetimes.pyi b/pandas-stubs/core/tools/datetimes.pyi index 989018c4b..aa29bf2c5 100644 --- a/pandas-stubs/core/tools/datetimes.pyi +++ b/pandas-stubs/core/tools/datetimes.pyi @@ -68,7 +68,6 @@ def to_datetime( ) -> Timestamp | NaTType: ... @overload def to_datetime( - # TODO: Test dataframe return type arg: Series | DictConvertible, errors: DateTimeErrorChoices = ..., dayfirst: bool = ..., From 978694605c29fccbcd754ecc4b7960bb44a22ed6 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Tue, 4 Oct 2022 08:53:02 +0100 Subject: [PATCH 14/14] ENH: Improve timestamp convertible --- pandas-stubs/_typing.pyi | 2 +- pandas-stubs/core/indexes/datetimes.pyi | 1 - pandas-stubs/core/tools/datetimes.pyi | 10 +++++----- tests/test_timefuncs.py | 21 +++++++++++++++++++++ 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/pandas-stubs/_typing.pyi b/pandas-stubs/_typing.pyi index 0ce1918ab..4ef2c6c75 100644 --- a/pandas-stubs/_typing.pyi +++ b/pandas-stubs/_typing.pyi @@ -200,7 +200,7 @@ IndexingInt: TypeAlias = Union[ int, np.int_, np.integer, np.unsignedinteger, np.signedinteger, np.int8 ] TimestampConvertibleTypes: TypeAlias = Union[ - Timestamp, datetime.datetime, np.datetime64, np.int64, float, str + Timestamp, datetime.datetime, datetime.date, np.datetime64, np.int64, float, str ] TimedeltaConvertibleTypes: TypeAlias = Union[ Timedelta, datetime.timedelta, np.timedelta64, np.int64, float, str diff --git a/pandas-stubs/core/indexes/datetimes.pyi b/pandas-stubs/core/indexes/datetimes.pyi index 803c69c08..5b6cc4216 100644 --- a/pandas-stubs/core/indexes/datetimes.pyi +++ b/pandas-stubs/core/indexes/datetimes.pyi @@ -117,7 +117,6 @@ def bdate_range( end: str | DatetimeLike | None = ..., periods: int | None = ..., *, - # TODO: Add Timedelta to pandas docs freq: str | timedelta | Timedelta | BaseOffset, tz: str | tzinfo = ..., normalize: bool = ..., diff --git a/pandas-stubs/core/tools/datetimes.pyi b/pandas-stubs/core/tools/datetimes.pyi index aa29bf2c5..6ed6fe864 100644 --- a/pandas-stubs/core/tools/datetimes.pyi +++ b/pandas-stubs/core/tools/datetimes.pyi @@ -29,6 +29,7 @@ from pandas._typing import ( DateTimeErrorChoices, DictConvertible, IgnoreRaise, + TimestampConvertibleTypes, npt, ) @@ -49,7 +50,7 @@ def to_datetime( exact: bool = ..., unit: str | None = ..., infer_datetime_format: bool = ..., - origin: int | Literal["julian", "unix"] | pd.Timestamp = ..., + origin: Literal["julian", "unix"] | TimestampConvertibleTypes = ..., cache: bool = ..., ) -> Timestamp: ... @overload @@ -63,7 +64,7 @@ def to_datetime( exact: bool = ..., unit: str | None = ..., infer_datetime_format: bool = ..., - origin: Literal["julian", "unix"] | pd.Timestamp = ..., + origin: Literal["julian", "unix"] | TimestampConvertibleTypes = ..., cache: bool = ..., ) -> Timestamp | NaTType: ... @overload @@ -77,7 +78,7 @@ def to_datetime( exact: bool = ..., unit: str | None = ..., infer_datetime_format: bool = ..., - origin: int | Literal["julian", "unix"] | pd.Timestamp = ..., + origin: Literal["julian", "unix"] | TimestampConvertibleTypes = ..., cache: bool = ..., ) -> TimestampSeries: ... @overload @@ -98,7 +99,6 @@ def to_datetime( exact: bool = ..., unit: str | None = ..., infer_datetime_format: bool = ..., - # TODO: Origin needs int in pandas docs - origin: int | Literal["julian", "unix"] | pd.Timestamp = ..., + origin: Literal["julian", "unix"] | TimestampConvertibleTypes = ..., cache: bool = ..., ) -> DatetimeIndex: ... diff --git a/tests/test_timefuncs.py b/tests/test_timefuncs.py index ea596bbd2..c6d1fe3b7 100644 --- a/tests/test_timefuncs.py +++ b/tests/test_timefuncs.py @@ -844,6 +844,27 @@ def test_to_datetime_array() -> None: ), pd.DatetimeIndex, ) + check( + assert_type( + pd.to_datetime(pd.Index([1, 2, 3]), origin=np.datetime64("1999-12-31")), + pd.DatetimeIndex, + ), + pd.DatetimeIndex, + ) + check( + assert_type( + pd.to_datetime(pd.Index([1, 2, 3]), origin=dt.datetime(1999, 12, 31)), + pd.DatetimeIndex, + ), + pd.DatetimeIndex, + ) + check( + assert_type( + pd.to_datetime(pd.Index([1, 2, 3]), origin=dt.date(1999, 12, 31)), + pd.DatetimeIndex, + ), + pd.DatetimeIndex, + ) def test_timedelta_range() -> None: