diff --git a/pandas-stubs/core/algorithms.pyi b/pandas-stubs/core/algorithms.pyi index c7c538a5f..2631bc22d 100644 --- a/pandas-stubs/core/algorithms.pyi +++ b/pandas-stubs/core/algorithms.pyi @@ -39,10 +39,10 @@ def unique(values: IntervalIndex[IntervalT]) -> IntervalIndex[IntervalT]: ... @overload def unique(values: PeriodIndex) -> PeriodIndex: ... @overload -# switch to DatetimeIndex after Pandas 3.0 +# TODO: switch to DatetimeIndex after Pandas 3.0 pandas-dev/pandas#57064 def unique(values: DatetimeIndex) -> np_1darray_dt | DatetimeIndex: ... @overload -# switch to TimedeltaIndex after Pandas 3.0 +# TODO: switch to TimedeltaIndex after Pandas 3.0 pandas-dev/pandas#57064 def unique(values: TimedeltaIndex) -> np_1darray_td: ... @overload # switch to Index[int] after Pandas 3.0 @@ -59,7 +59,8 @@ else: ) -> np_ndarray: ... @overload -def unique(values: Index) -> np_1darray | Index: ... # switch to Index after Pandas 3.0 +# TODO: switch to Index after Pandas 3.0 pandas-dev/pandas#57064 +def unique(values: Index) -> np_1darray | Index: ... @overload def unique(values: Categorical) -> Categorical: ... diff --git a/pandas-stubs/core/arrays/__init__.pyi b/pandas-stubs/core/arrays/__init__.pyi index bc46b02bd..eb233a8b6 100644 --- a/pandas-stubs/core/arrays/__init__.pyi +++ b/pandas-stubs/core/arrays/__init__.pyi @@ -1,11 +1,33 @@ -from pandas.core.arrays.base import ExtensionArray as ExtensionArray -from pandas.core.arrays.boolean import BooleanArray as BooleanArray -from pandas.core.arrays.categorical import Categorical as Categorical -from pandas.core.arrays.datetimes import DatetimeArray as DatetimeArray -from pandas.core.arrays.integer import IntegerArray as IntegerArray -from pandas.core.arrays.interval import IntervalArray as IntervalArray -from pandas.core.arrays.numpy_ import NumpyExtensionArray as NumpyExtensionArray -from pandas.core.arrays.period import PeriodArray as PeriodArray -from pandas.core.arrays.sparse import SparseArray as SparseArray -from pandas.core.arrays.string_ import StringArray as StringArray -from pandas.core.arrays.timedeltas import TimedeltaArray as TimedeltaArray +from pandas.core.arrays.arrow import ArrowExtensionArray +from pandas.core.arrays.base import ExtensionArray +from pandas.core.arrays.boolean import BooleanArray +from pandas.core.arrays.categorical import Categorical +from pandas.core.arrays.datetimes import DatetimeArray +from pandas.core.arrays.floating import FloatingArray +from pandas.core.arrays.integer import IntegerArray +from pandas.core.arrays.interval import IntervalArray +from pandas.core.arrays.masked import BaseMaskedArray +from pandas.core.arrays.numpy_ import NumpyExtensionArray +from pandas.core.arrays.period import PeriodArray +from pandas.core.arrays.sparse import SparseArray +from pandas.core.arrays.string_ import StringArray +from pandas.core.arrays.string_arrow import ArrowStringArray +from pandas.core.arrays.timedeltas import TimedeltaArray + +__all__ = [ + "ArrowExtensionArray", + "ArrowStringArray", + "BaseMaskedArray", + "BooleanArray", + "Categorical", + "DatetimeArray", + "ExtensionArray", + "FloatingArray", + "IntegerArray", + "IntervalArray", + "NumpyExtensionArray", + "PeriodArray", + "SparseArray", + "StringArray", + "TimedeltaArray", +] diff --git a/pandas-stubs/core/construction.pyi b/pandas-stubs/core/construction.pyi index 32dc0f37c..f7ac2812a 100644 --- a/pandas-stubs/core/construction.pyi +++ b/pandas-stubs/core/construction.pyi @@ -2,7 +2,10 @@ from collections.abc import ( MutableSequence, Sequence, ) -from datetime import datetime +from datetime import ( + datetime, + timedelta, +) from typing import ( Any, TypeAlias, @@ -10,11 +13,16 @@ from typing import ( ) import numpy as np +from pandas.core.arrays.base import ExtensionArray from pandas.core.arrays.boolean import BooleanArray +from pandas.core.arrays.categorical import Categorical from pandas.core.arrays.datetimes import DatetimeArray from pandas.core.arrays.floating import FloatingArray from pandas.core.arrays.integer import IntegerArray +from pandas.core.arrays.interval import IntervalArray from pandas.core.arrays.numpy_ import NumpyExtensionArray +from pandas.core.arrays.period import PeriodArray +from pandas.core.arrays.sparse.array import SparseArray from pandas.core.arrays.string_ import ( BaseStringArray, StringArray, @@ -22,18 +30,29 @@ from pandas.core.arrays.string_ import ( ) from pandas.core.arrays.string_arrow import ArrowStringArray from pandas.core.arrays.timedeltas import TimedeltaArray +from pandas.core.indexes.base import Index +from pandas.core.indexes.category import CategoricalIndex +from pandas.core.indexes.datetimes import DatetimeIndex +from pandas.core.indexes.interval import IntervalIndex +from pandas.core.indexes.period import PeriodIndex from pandas.core.indexes.range import RangeIndex from pandas.core.indexes.timedeltas import TimedeltaIndex from pandas.core.series import Series from typing_extensions import Never +from pandas._libs.interval import Interval from pandas._libs.missing import NAType from pandas._libs.tslibs.nattype import NaTType +from pandas._libs.tslibs.period import Period from pandas._libs.tslibs.timedeltas import Timedelta +from pandas._libs.tslibs.timestamps import Timestamp from pandas._typing import ( BuiltinNotStrDtypeArg, + CategoryDtypeArg, + IntervalT, Just, NumpyNotTimeDtypeArg, + NumpyTimedeltaDtypeArg, NumpyTimestampDtypeArg, PandasBaseStrDtypeArg, PandasBooleanDtypeArg, @@ -51,9 +70,14 @@ from pandas._typing import ( np_ndarray_dt, np_ndarray_float, np_ndarray_str, + np_ndarray_td, ) -from pandas.core.dtypes.dtypes import DatetimeTZDtype +from pandas.core.dtypes.dtypes import ( + DatetimeTZDtype, + IntervalDtype, + PeriodDtype, +) _NAStrElement: TypeAlias = str | np.str_ | NAType | None _NaNStrElement: TypeAlias = Just[float] | _NAStrElement @@ -86,6 +110,50 @@ def array( # type: ignore[overload-overlap] # pyright: ignore[reportOverlapping copy: bool = True, ) -> NumpyExtensionArray: ... @overload +def array( + data: MutableSequence[Any] | np_ndarray | ExtensionArray | Index | Series, + dtype: CategoryDtypeArg, + copy: bool = True, +) -> Categorical: ... +@overload +def array( + # TODO: Categorical Series pandas-dev/pandas-stubs#1415 + data: Categorical | CategoricalIndex, + dtype: CategoryDtypeArg | None = None, + copy: bool = True, +) -> Categorical: ... +@overload +def array( # type: ignore[overload-overlap] + data: ( + Sequence[Period | NaTType | None] | PeriodArray | PeriodIndex | Series[Period] + ), + dtype: PeriodDtype | None = None, + copy: bool = True, +) -> PeriodArray: ... +@overload +def array( + data: ( + Sequence[IntervalT | None | float] + | IntervalArray + | IntervalIndex + | Series[Interval] + ), + dtype: IntervalDtype, + copy: bool = True, +) -> IntervalArray: ... +@overload +def array( # type: ignore[overload-overlap] + data: Sequence[IntervalT | None] | IntervalArray | IntervalIndex | Series[Interval], + dtype: None = None, + copy: bool = True, +) -> IntervalArray: ... +@overload +def array( + data: SparseArray, + dtype: None = None, + copy: bool = True, +) -> SparseArray: ... +@overload def array( # pyright: ignore[reportOverlappingOverload] data: ( Sequence[Timedelta] @@ -169,6 +237,31 @@ def array( # type: ignore[overload-overlap] copy: bool = True, ) -> DatetimeArray: ... @overload +def array( # type: ignore[overload-overlap] + data: ( # TODO: merge the two Sequence's after 3.0 pandas-dev/pandas#57064 + Sequence[datetime | NaTType | None] + | Sequence[np.datetime64 | NaTType | None] + | np_ndarray_dt + | DatetimeArray + | DatetimeIndex + | Series[Timestamp] + ), + dtype: PandasTimestampDtypeArg | NumpyTimestampDtypeArg | None = None, + copy: bool = True, +) -> DatetimeArray: ... +@overload +def array( # type: ignore[overload-overlap] + data: ( + Sequence[timedelta | np.timedelta64 | NaTType | None] + | np_ndarray_td + | TimedeltaArray + | TimedeltaIndex + | Series[Timedelta] + ), + dtype: NumpyTimedeltaDtypeArg | None = None, + copy: bool = True, +) -> TimedeltaArray: ... +@overload def array( # type: ignore[overload-overlap] data: _NaNStrData, dtype: StringDtype[Never], copy: bool = True ) -> BaseStringArray: ... diff --git a/tests/_typing.py b/tests/_typing.py index 2adac9dea..843f780a5 100644 --- a/tests/_typing.py +++ b/tests/_typing.py @@ -1,3 +1,4 @@ +# ruff: noqa: PLC0414 # This file serves as a stub file for static type checkers # (pyright does not like it if I call the file tests/_typing.pyi). # It can only import from pandas._typing. diff --git a/tests/arrays/test_datetime_array.py b/tests/arrays/test_datetime_array.py index 83d9d4469..aa05f91ef 100644 --- a/tests/arrays/test_datetime_array.py +++ b/tests/arrays/test_datetime_array.py @@ -11,6 +11,7 @@ from typing import ( TYPE_CHECKING, Any, + cast, ) from zoneinfo import ZoneInfo @@ -276,3 +277,26 @@ def test_properties() -> None: np_1darray, np.float64, ) + + +def test_constructor() -> None: + dt = datetime(2025, 11, 10) + check(assert_type(pd.array([dt]), DatetimeArray), DatetimeArray) + check(assert_type(pd.array([dt, pd.Timestamp(dt)]), DatetimeArray), DatetimeArray) + check(assert_type(pd.array([dt, None]), DatetimeArray), DatetimeArray) + check(assert_type(pd.array([dt, pd.NaT, None]), DatetimeArray), DatetimeArray) + + np_dt = np.datetime64(dt) + check(assert_type(pd.array([np_dt]), DatetimeArray), DatetimeArray) + check(assert_type(pd.array([np_dt, None]), DatetimeArray), DatetimeArray) + dt_nat = cast(list[np.datetime64 | NaTType], [np_dt, pd.NaT]) + check(assert_type(pd.array(dt_nat), DatetimeArray), DatetimeArray) + + np_arr = np.array([dt], np.datetime64) + check(assert_type(pd.array(np_arr), DatetimeArray), DatetimeArray) + + check(assert_type(pd.array(pd.array([dt])), DatetimeArray), DatetimeArray) + + check(assert_type(pd.array(pd.Index([dt])), DatetimeArray), DatetimeArray) + + check(assert_type(pd.array(pd.Series([dt])), DatetimeArray), DatetimeArray) diff --git a/tests/arrays/test_interval.py b/tests/arrays/test_interval.py index cc2786979..851b2f64c 100644 --- a/tests/arrays/test_interval.py +++ b/tests/arrays/test_interval.py @@ -19,6 +19,18 @@ ) +def test_construction() -> None: + itv = pd.Interval(0, 1) + check(assert_type(pd.array([itv]), IntervalArray), IntervalArray) + check(assert_type(pd.array([itv, None]), IntervalArray), IntervalArray) + + check(assert_type(pd.array(pd.array([itv])), IntervalArray), IntervalArray) + + check(assert_type(pd.array(pd.Index([itv])), IntervalArray), IntervalArray) + + check(assert_type(pd.array(pd.Series([itv])), IntervalArray), IntervalArray) + + def test_constructor() -> None: """Test constructor method for IntervalArray.""" intervals = [Interval(0, 1), Interval(1, 2), Interval(2, 3)] diff --git a/tests/arrays/test_period.py b/tests/arrays/test_period.py index 37207e50a..50017e03a 100644 --- a/tests/arrays/test_period.py +++ b/tests/arrays/test_period.py @@ -24,6 +24,19 @@ ) +def test_construction() -> None: + prd = pd.Period("2023-01-01") + check(assert_type(pd.array([prd]), PeriodArray), PeriodArray) + check(assert_type(pd.array([prd, None]), PeriodArray), PeriodArray) + check(assert_type(pd.array([prd, pd.NaT, None]), PeriodArray), PeriodArray) + + check(assert_type(pd.array(pd.array([prd])), PeriodArray), PeriodArray) + + check(assert_type(pd.array(pd.Index([prd])), PeriodArray), PeriodArray) + + check(assert_type(pd.array(pd.Series([prd])), PeriodArray), PeriodArray) + + def test_constructor() -> None: """Test init method for PeriodArray.""" # From numpy array of integers (ordinals) with dtype diff --git a/tests/arrays/test_sparse.py b/tests/arrays/test_sparse.py index 5720296fc..afb209bb1 100644 --- a/tests/arrays/test_sparse.py +++ b/tests/arrays/test_sparse.py @@ -29,6 +29,10 @@ ) +def test_construction() -> None: + check(assert_type(pd.array(SparseArray([1])), SparseArray), SparseArray) + + def test_constructor() -> None: """Test __new__ method for SparseArray.""" arr = SparseArray([1, 0, 0, 2, 3]) diff --git a/tests/arrays/test_timedeltas.py b/tests/arrays/test_timedeltas.py index b20f329e6..162c8f5ba 100644 --- a/tests/arrays/test_timedeltas.py +++ b/tests/arrays/test_timedeltas.py @@ -26,11 +26,25 @@ def test_construction() -> None: """Test pd.array method for TimedeltaArray.""" + + td = timedelta(2025, 11, 10) + np_dt = np.timedelta64(td) + check(assert_type(pd.array([td]), TimedeltaArray), TimedeltaArray) + check( + assert_type(pd.array([td, pd.Timedelta(td), np_dt]), TimedeltaArray), + TimedeltaArray, + ) + check(assert_type(pd.array([td, None]), TimedeltaArray), TimedeltaArray) + check(assert_type(pd.array([td, pd.NaT, None]), TimedeltaArray), TimedeltaArray) + # From TimedeltaIndex idx = pd.TimedeltaIndex(["1 days", "2 days", "3 days"]) arr = pd.array(idx) check(assert_type(arr, TimedeltaArray), TimedeltaArray) + # From Series + check(assert_type(pd.array(pd.Series(idx)), TimedeltaArray), TimedeltaArray) + # From numpy array of timedelta64 values = np.array( [np.timedelta64(1, "D"), np.timedelta64(2, "D"), np.timedelta64(3, "D")]