diff --git a/pandas-stubs/_typing.pyi b/pandas-stubs/_typing.pyi index 9ad72236e..b0f125601 100644 --- a/pandas-stubs/_typing.pyi +++ b/pandas-stubs/_typing.pyi @@ -890,15 +890,14 @@ SliceType: TypeAlias = Hashable | None ## All types below this point are only used in pandas-stubs ###### -BuiltinNotStrDtypeArg: TypeAlias = ( +BuiltinNotStrObjDtypeArg: TypeAlias = ( BuiltinBooleanDtypeArg | BuiltinIntDtypeArg | BuiltinFloatDtypeArg | BuiltinComplexDtypeArg | BuiltinBytesDtypeArg - | BuiltinObjectDtypeArg ) -BuiltinDtypeArg: TypeAlias = BuiltinNotStrDtypeArg | BuiltinStrDtypeArg +BuiltinNotObjDtypeArg: TypeAlias = BuiltinNotStrObjDtypeArg | BuiltinStrDtypeArg NumpyNotTimeDtypeArg: TypeAlias = ( NumpyBooleanDtypeArg | NumpyIntDtypeArg 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 3670f032e..14e059e45 100644 --- a/pandas-stubs/core/construction.pyi +++ b/pandas-stubs/core/construction.pyi @@ -1,8 +1,8 @@ -from collections.abc import ( - MutableSequence, - Sequence, +from collections.abc import Sequence +from datetime import ( + datetime, + timedelta, ) -from datetime import datetime from typing import ( Any, Never, @@ -11,11 +11,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, @@ -23,17 +28,30 @@ 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 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, + BuiltinNotStrObjDtypeArg, + BuiltinObjectDtypeArg, + BuiltinStrDtypeArg, + CategoryDtypeArg, + IntervalT, Just, NumpyNotTimeDtypeArg, + NumpyTimedeltaDtypeArg, NumpyTimestampDtypeArg, PandasBaseStrDtypeArg, PandasBooleanDtypeArg, @@ -51,41 +69,90 @@ 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, + SparseDtype, +) _NAStrElement: TypeAlias = str | np.str_ | NAType | None _NaNStrElement: TypeAlias = Just[float] | _NAStrElement -_NaNStrData: TypeAlias = ( - tuple[_NaNStrElement, ...] - | MutableSequence[_NaNStrElement] - | np_ndarray - | BaseStringArray -) +_NaNStrData: TypeAlias = Sequence[_NaNStrElement] | np_ndarray | BaseStringArray _NaTDatetimeElement: TypeAlias = ( Just[float] | str | datetime | np.datetime64 | NaTType | None ) @overload -def array( # empty data, [float("nan")] +def array(data: str, dtype: Any = None, copy: bool = True) -> Never: ... +@overload +def array( # empty data, [float("nan")] # pyright: ignore[reportOverlappingOverload] data: Sequence[Just[float]], dtype: PandasFloatDtypeArg | None = None, copy: bool = True, ) -> FloatingArray: ... @overload def array( - data: tuple[Any, ...] | MutableSequence[Any], - dtype: BuiltinNotStrDtypeArg | NumpyNotTimeDtypeArg, + data: Sequence[Any], + dtype: BuiltinNotStrObjDtypeArg | NumpyNotTimeDtypeArg, copy: bool = True, ) -> NumpyExtensionArray: ... @overload def array( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] data: Sequence[NAType | None], - dtype: BuiltinNotStrDtypeArg | NumpyNotTimeDtypeArg | None = None, + dtype: BuiltinNotStrObjDtypeArg | NumpyNotTimeDtypeArg | None = None, copy: bool = True, ) -> NumpyExtensionArray: ... @overload +def array( + data: Sequence[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: Sequence[Any] | np_ndarray | ExtensionArray | Index | Series, + dtype: SparseDtype, + copy: bool = True, +) -> SparseArray: ... +@overload +def array(data: SparseArray, dtype: None = None, copy: bool = True) -> SparseArray: ... +@overload def array( # pyright: ignore[reportOverlappingOverload] data: ( Sequence[Timedelta] @@ -143,12 +210,7 @@ def array( # type: ignore[overload-overlap] ) -> FloatingArray: ... @overload def array( - data: ( - tuple[_NaTDatetimeElement, ...] - | MutableSequence[_NaTDatetimeElement] - | np_ndarray - | DatetimeArray - ), + data: Sequence[_NaTDatetimeElement] | np_ndarray | DatetimeArray, dtype: ( DatetimeTZDtype | PandasTimestampDtypeArg @@ -159,9 +221,8 @@ def array( ) -> 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] + data: ( + Sequence[datetime | np.datetime64 | NaTType | None] | np_ndarray_dt | DatetimeArray ), @@ -169,6 +230,30 @@ def array( # type: ignore[overload-overlap] copy: bool = True, ) -> DatetimeArray: ... @overload +def array( # type: ignore[overload-overlap] + data: ( + Sequence[datetime | 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: ... @@ -180,30 +265,25 @@ def array( def array( data: _NaNStrData, dtype: PandasStrDtypeArg, copy: bool = True ) -> StringArray: ... - -# TODO: pandas-dev/pandas#54466 add BuiltinStrDtypeArg after Pandas 3.0 @overload -def array( - data: _NaNStrData, dtype: PandasBaseStrDtypeArg, copy: bool = True +def array( # type: ignore[overload-overlap] + data: _NaNStrData, + dtype: BuiltinStrDtypeArg | PandasBaseStrDtypeArg, + copy: bool = True, ) -> BaseStringArray: ... @overload -def array( # pyright: ignore[reportOverlappingOverload] - data: ( - tuple[_NAStrElement, ...] - | MutableSequence[_NAStrElement] - | np_ndarray_str - | BaseStringArray - ), +def array( + data: Sequence[_NAStrElement] | np_ndarray_str | BaseStringArray, dtype: None = None, copy: bool = True, ) -> BaseStringArray: ... @overload def array( - data: tuple[Any, ...] | MutableSequence[Any], dtype: None = None, copy: bool = True + data: Sequence[Any], dtype: BuiltinObjectDtypeArg | None = None, copy: bool = True ) -> NumpyExtensionArray: ... @overload def array( data: np_ndarray | NumpyExtensionArray | RangeIndex, - dtype: BuiltinNotStrDtypeArg | NumpyNotTimeDtypeArg | None = None, + dtype: BuiltinNotStrObjDtypeArg | NumpyNotTimeDtypeArg | None = None, copy: bool = True, ) -> NumpyExtensionArray: ... diff --git a/tests/_typing.py b/tests/_typing.py index 2adac9dea..a1cfee36f 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. @@ -12,10 +13,10 @@ BuiltinBooleanDtypeArg, BuiltinBytesDtypeArg, BuiltinComplexDtypeArg, - BuiltinDtypeArg, BuiltinFloatDtypeArg, BuiltinIntDtypeArg, - BuiltinNotStrDtypeArg, + BuiltinNotObjDtypeArg, + BuiltinNotStrObjDtypeArg, BuiltinObjectDtypeArg, BuiltinStrDtypeArg, BytesDtypeArg, @@ -93,10 +94,10 @@ "BuiltinBooleanDtypeArg", "BuiltinBytesDtypeArg", "BuiltinComplexDtypeArg", - "BuiltinDtypeArg", + "BuiltinNotObjDtypeArg", "BuiltinFloatDtypeArg", "BuiltinIntDtypeArg", - "BuiltinNotStrDtypeArg", + "BuiltinNotStrObjDtypeArg", "BuiltinObjectDtypeArg", "BuiltinStrDtypeArg", "BytesDtypeArg", diff --git a/tests/arrays/test_arrow_extension_array.py b/tests/arrays/test_arrow.py similarity index 100% rename from tests/arrays/test_arrow_extension_array.py rename to tests/arrays/test_arrow.py diff --git a/tests/arrays/test_base_string_array.py b/tests/arrays/test_base_string_.py similarity index 83% rename from tests/arrays/test_base_string_array.py rename to tests/arrays/test_base_string_.py index ae3409530..d7e64c199 100644 --- a/tests/arrays/test_base_string_array.py +++ b/tests/arrays/test_base_string_.py @@ -12,14 +12,16 @@ import numpy as np import pandas as pd -from pandas.core.arrays.numpy_ import NumpyExtensionArray from pandas.core.arrays.string_ import BaseStringArray import pytest from pandas._libs.missing import NAType from tests import check -from tests._typing import PandasBaseStrDtypeArg +from tests._typing import ( + BuiltinStrDtypeArg, + PandasBaseStrDtypeArg, +) from tests.dtypes import ( PANDAS_BASE_STRING_ARGS, PYTHON_STRING_ARGS, @@ -72,8 +74,7 @@ def test_construction_array_like() -> None: ) def test_construction_dtype( data: tuple[str | np.str_, ...], - # TODO: pandas-dev/pandas#54466 add BuiltinStrDtypeArg after Pandas 3.0 - dtype: PandasBaseStrDtypeArg, + dtype: BuiltinStrDtypeArg | PandasBaseStrDtypeArg, target_dtype: type, ) -> None: is_builtin_str = dtype in PYTHON_STRING_ARGS @@ -92,12 +93,8 @@ def test_construction_dtype( check(pd.array([*data, *data, np.nan], dtype), BaseStringArray, dtype_na) if TYPE_CHECKING: - # TODO: pandas-dev/pandas#54466 should give BaseStringArray after 3.0 - # TODO: pandas-dev/pandas-stubs#1641 should give BaseStringArray after 3.0 with the stubs - # The following one still gives NumpyExtensionArray because issubclass(str, object), - # and pd.array([], object) gives NumpyExtensionArray - assert_type(pd.array([], str), NumpyExtensionArray) - pd.array([], "str") # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + assert_type(pd.array([], str), BaseStringArray) + assert_type(pd.array([], "str"), BaseStringArray) assert_type(pd.array([], pd.StringDtype()), BaseStringArray) assert_type(pd.array([], "string"), BaseStringArray) @@ -130,9 +127,16 @@ def test_construction_dtype( def test_dtype() -> None: - arr = pd.array(["a"], "string") - check(assert_type(arr.dtype, pd.StringDtype), pd.StringDtype) - assert assert_type(arr.dtype.storage, Literal["python", "pyarrow"]) in { + arr_string = pd.array(["a"], "string") + check(assert_type(arr_string.dtype, pd.StringDtype), pd.StringDtype) + assert assert_type(arr_string.dtype.storage, Literal["python", "pyarrow"]) in { "python", "pyarrow", } + + arr_str = pd.array([pd.NA], str) + check(assert_type(arr_str, BaseStringArray), BaseStringArray, float) + assert pd.isna(assert_type(arr_str.dtype.na_value, NAType | float)) + + arr_str = pd.array([pd.NA], pd.StringDtype(na_value=pd.NA)) + check(assert_type(arr_str, BaseStringArray), BaseStringArray, NAType) diff --git a/tests/arrays/test_categorical.py b/tests/arrays/test_categorical.py index 6d282f420..c23ec0b8a 100644 --- a/tests/arrays/test_categorical.py +++ b/tests/arrays/test_categorical.py @@ -19,6 +19,31 @@ ) +def test_construction_array_like() -> None: + check(assert_type(pd.array(pd.Categorical([1])), Categorical), Categorical) + check(assert_type(pd.array(pd.CategoricalIndex([1])), Categorical), Categorical) + + +def test_construction_dtype() -> None: + check(assert_type(pd.array([], pd.CategoricalDtype()), Categorical), Categorical) + check( + assert_type(pd.array(np.array([1]), pd.CategoricalDtype()), Categorical), + Categorical, + ) + check( + assert_type(pd.array(pd.array([1]), pd.CategoricalDtype()), Categorical), + Categorical, + ) + check( + assert_type(pd.array(pd.Index([1]), pd.CategoricalDtype()), Categorical), + Categorical, + ) + check( + assert_type(pd.array(pd.Series([1]), pd.CategoricalDtype()), Categorical), + Categorical, + ) + + def test_constructor() -> None: """Test init method for Categorical.""" cat = Categorical(["a", "b", "c", "a"]) diff --git a/tests/arrays/test_datetime_array.py b/tests/arrays/test_datetime_array.py index e57e5abe6..0b512a4f2 100644 --- a/tests/arrays/test_datetime_array.py +++ b/tests/arrays/test_datetime_array.py @@ -12,6 +12,7 @@ TYPE_CHECKING, Any, assert_type, + cast, ) from zoneinfo import ZoneInfo @@ -45,7 +46,15 @@ @pytest.mark.parametrize("typ", [list, tuple, UserList]) @pytest.mark.parametrize( - "data", powerset([datetime(2026, 1, 4), pd.Timestamp(2026, 1, 8)], 1) + "data", + powerset( + [ + datetime(2026, 1, 4), + pd.Timestamp(2026, 1, 8), + np.datetime64("2131-01-05 01:25"), + ], + 1, + ), ) @pytest.mark.parametrize("missing_values", powerset([None, pd.NaT])) def test_construction_sequence_pandas( @@ -53,8 +62,6 @@ def test_construction_sequence_pandas( missing_values: tuple[Any, ...], typ: Callable[[Sequence[Any]], Sequence[Any]], ) -> None: - # TODO: pandas-dev/pandas#57064 - # In Pandas 3.0, mixing np.datetime64, datetime and pd.Timestamp also gives DatetimeArray check(pd.array(typ([*data, *missing_values])), DatetimeArray) check(pd.array(typ([datetime(2077, 1, 1), *data, *missing_values])), DatetimeArray) check( @@ -67,6 +74,7 @@ def test_construction_sequence_pandas( pd.array([pd.Timestamp(2026, 1, 5, tzinfo=ZoneInfo("Africa/Ouagadougou"))]), DatetimeArray, ) + assert_type(pd.array([np.datetime64("2026-01-05 23:27:59")]), DatetimeArray) assert_type( pd.array([datetime(2100, 1, 5, 1), datetime(1, 1, 6, 2)]), DatetimeArray @@ -77,67 +85,39 @@ def test_construction_sequence_pandas( assert_type( pd.array([datetime(2052, 1, 5), pd.Timestamp(2, 1, 6)]), DatetimeArray ) + assert_type( + pd.array([np.datetime64("2131-01-05 01:25"), np.datetime64("1748-01-06")]), + DatetimeArray, + ) + assert_type( + pd.array([np.datetime64("2130-01-01 01:25"), datetime(1749, 1, 6)]), + DatetimeArray, + ) + assert_type( + pd.array([np.datetime64("2129-01-05 01:25"), pd.Timestamp("1760-01-06")]), + DatetimeArray, + ) assert_type(pd.array([datetime(2061, 1, 5, 1), None]), DatetimeArray) assert_type(pd.array([pd.Timestamp(1902, 1, 5, 3), None]), DatetimeArray) + assert_type(pd.array([np.datetime64("2111-01-05"), None]), DatetimeArray) - assert_type(pd.array([datetime(1921, 1, 5, 1), pd.NaT]), DatetimeArray) # type: ignore[assert-type] - assert_type(pd.array([pd.Timestamp(1872, 1, 5, 3), pd.NaT]), DatetimeArray) # type: ignore[assert-type] + assert_type(pd.array([datetime(1921, 1, 5, 1), pd.NaT]), DatetimeArray) + assert_type(pd.array([pd.Timestamp(1872, 1, 5, 3), pd.NaT]), DatetimeArray) + assert_type(pd.array([np.datetime64("2113-01-05"), pd.NaT]), DatetimeArray) assert_type(pd.array([datetime(1751, 1, 5, 1), None, pd.NaT]), DatetimeArray) assert_type( pd.array([pd.Timestamp(2102, 1, 5, 3), None, pd.NaT]), DatetimeArray ) - - assert_type(pd.array((datetime(2026, 1, 5),)), DatetimeArray) - assert_type(pd.array(UserList([pd.Timestamp(2026, 1, 5)])), DatetimeArray) - - -def test_construction_sequence_numpy() -> None: - # TODO: pandas-dev/pandas#57064 - # In Pandas 3.0, mixing np.datetime64, datetime and pd.Timestamp also gives DatetimeArray - check( - assert_type(pd.array([np.datetime64("2026-01-05 23:27:59")]), DatetimeArray), - DatetimeArray, - pd.Timestamp, - ) - check( - assert_type( - pd.array([np.datetime64("2131-01-05 01:25"), np.datetime64("1748-01-06")]), - DatetimeArray, - ), - DatetimeArray, - pd.Timestamp, - ) - - check( - assert_type(pd.array([np.datetime64("2111-01-05"), None]), DatetimeArray), - DatetimeArray, - pd.Timestamp, - ) - check( - assert_type(pd.array([np.datetime64("2113-01-05"), pd.NaT]), DatetimeArray), # type: ignore[assert-type] - DatetimeArray, - pd.Timestamp, - ) - check( assert_type( pd.array([np.datetime64("2114-01-05"), None, pd.NaT]), DatetimeArray - ), - DatetimeArray, - pd.Timestamp, - ) + ) - check( - assert_type(pd.array((np.datetime64("1959-01-05"),)), DatetimeArray), - DatetimeArray, - pd.Timestamp, - ) - check( - assert_type(pd.array(UserList([np.datetime64("1701-01-05")])), DatetimeArray), - DatetimeArray, - pd.Timestamp, - ) + assert_type(pd.array((datetime(2026, 1, 5),)), DatetimeArray) + assert_type(pd.array(UserList([pd.Timestamp(2026, 1, 5)])), DatetimeArray) + assert_type(pd.array((np.datetime64("1959-01-05"),)), DatetimeArray) + assert_type(pd.array(UserList([np.datetime64("1701-01-05")])), DatetimeArray) @pytest.mark.parametrize("data", powerset([datetime(1710, 10, 10), "2020-11-11 10:00"])) @@ -269,3 +249,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 6bb2132ac..f8f4e3104 100644 --- a/tests/arrays/test_interval.py +++ b/tests/arrays/test_interval.py @@ -20,6 +20,23 @@ ) +def test_construction_sequence() -> None: + itv = pd.Interval(0, 1) + check(assert_type(pd.array([itv]), IntervalArray), IntervalArray) + check(assert_type(pd.array([itv, None]), IntervalArray), IntervalArray) + + +def test_construction_array_like() -> None: + itv = pd.Interval(0, 1) + 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_construction_dtype() -> None: + check(assert_type(pd.array([], IntervalDtype()), 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_numpy_extension_array.py b/tests/arrays/test_numpy_.py similarity index 97% rename from tests/arrays/test_numpy_extension_array.py rename to tests/arrays/test_numpy_.py index 5effe50f3..f54ee0a13 100644 --- a/tests/arrays/test_numpy_extension_array.py +++ b/tests/arrays/test_numpy_.py @@ -20,13 +20,15 @@ exception_on_platform, ) from tests._typing import ( - BuiltinNotStrDtypeArg, + BuiltinNotStrObjDtypeArg, + BuiltinObjectDtypeArg, NumpyNotTimeDtypeArg, np_ndarray, ) from tests.dtypes import ( NUMPY_NOT_DATETIMELIKE_DTYPE_ARGS, - PYTHON_NOT_STR_DTYPE_ARGS, + PYTHON_NOT_STR_OBJ_DTYPE_ARGS, + PYTHON_OBJECT_ARGS, ) from tests.utils import powerset @@ -75,10 +77,15 @@ def test_construction_dtype_nan() -> None: @pytest.mark.parametrize( ("dtype", "target_dtype"), - (PYTHON_NOT_STR_DTYPE_ARGS | NUMPY_NOT_DATETIMELIKE_DTYPE_ARGS).items(), + ( + PYTHON_NOT_STR_OBJ_DTYPE_ARGS + | PYTHON_OBJECT_ARGS + | NUMPY_NOT_DATETIMELIKE_DTYPE_ARGS + ).items(), ) def test_construction_dtype( - dtype: BuiltinNotStrDtypeArg | NumpyNotTimeDtypeArg, target_dtype: type + dtype: BuiltinNotStrObjDtypeArg | BuiltinObjectDtypeArg | NumpyNotTimeDtypeArg, + target_dtype: type, ) -> None: exc = exception_on_platform(dtype) if exc: diff --git a/tests/arrays/test_period.py b/tests/arrays/test_period.py index c92817ab3..84f6a8314 100644 --- a/tests/arrays/test_period.py +++ b/tests/arrays/test_period.py @@ -24,6 +24,24 @@ ) +def test_construction_sequence() -> 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) + + +def test_construction_array_like() -> None: + prd = pd.Period("2023-01-01") + 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_construction_dtype() -> None: + check(assert_type(pd.array([], PeriodDtype("D")), 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 15e81f564..3f8882dc3 100644 --- a/tests/arrays/test_sparse.py +++ b/tests/arrays/test_sparse.py @@ -26,6 +26,30 @@ ) +def test_construction_array_like() -> None: + check(assert_type(pd.array(SparseArray([1])), SparseArray), SparseArray) + + +def test_construction_dtype() -> None: + check(assert_type(pd.array([], SparseDtype(int, 0)), SparseArray), SparseArray) + check( + assert_type(pd.array(np.array([1]), SparseDtype(int, 0)), SparseArray), + SparseArray, + ) + check( + assert_type(pd.array(pd.array([1]), SparseDtype(int, 0)), SparseArray), + SparseArray, + ) + check( + assert_type(pd.array(pd.Index([1]), SparseDtype(int, 0)), SparseArray), + SparseArray, + ) + check( + assert_type(pd.array(pd.Series([1]), SparseDtype(int, 0)), SparseArray), + SparseArray, + ) + + def test_constructor() -> None: """Test __new__ method for SparseArray.""" arr = SparseArray([1, 0, 0, 2, 3]) diff --git a/tests/arrays/test_arrow_string_array.py b/tests/arrays/test_string_arrow.py similarity index 91% rename from tests/arrays/test_arrow_string_array.py rename to tests/arrays/test_string_arrow.py index bcc8ddb46..25fd63ce6 100644 --- a/tests/arrays/test_arrow_string_array.py +++ b/tests/arrays/test_string_arrow.py @@ -2,7 +2,6 @@ TYPE_CHECKING, Literal, assert_type, - cast, ) import numpy as np @@ -105,9 +104,3 @@ def test_dtype() -> None: arr = pd.array(["a"], "string[pyarrow]") check(assert_type(arr.dtype, "pd.StringDtype[Literal['pyarrow']]"), pd.StringDtype) assert assert_type(arr.dtype.storage, Literal["pyarrow"]) == "pyarrow" - - # TODO: pandas-dev/pandas#54466 should give BaseStringArray after 3.0 - # TODO: pandas-dev/pandas-stubs#1641 should give BaseStringArray after 3.0 with the stubs - arr_arrow = cast("ArrowStringArray", pd.array([pd.NA], str)) - check(assert_type(arr_arrow, ArrowStringArray), ArrowStringArray, float) - assert pd.isna(assert_type(arr_arrow.dtype.na_value, NAType | float)) diff --git a/tests/arrays/test_timedeltas.py b/tests/arrays/test_timedeltas.py index 6e53f0c1e..91613775c 100644 --- a/tests/arrays/test_timedeltas.py +++ b/tests/arrays/test_timedeltas.py @@ -30,11 +30,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")] diff --git a/tests/dtypes.py b/tests/dtypes.py index 694383563..01dac135e 100644 --- a/tests/dtypes.py +++ b/tests/dtypes.py @@ -13,10 +13,10 @@ BuiltinBooleanDtypeArg, BuiltinBytesDtypeArg, BuiltinComplexDtypeArg, - BuiltinDtypeArg, BuiltinFloatDtypeArg, BuiltinIntDtypeArg, - BuiltinNotStrDtypeArg, + BuiltinNotObjDtypeArg, + BuiltinNotStrObjDtypeArg, BuiltinObjectDtypeArg, BuiltinStrDtypeArg, BytesDtypeArg, @@ -268,15 +268,14 @@ NUMPY_VOID_ARGS = dict.fromkeys((np.void, "void", "V"), np.void) ASTYPE_VOID_ARGS = NUMPY_VOID_ARGS -PYTHON_NOT_STR_DTYPE_ARGS = ( +PYTHON_NOT_STR_OBJ_DTYPE_ARGS = ( PYTHON_BOOL_ARGS | PYTHON_INT_ARGS | PYTHON_FLOAT_ARGS | PYTHON_COMPLEX_ARGS | PYTHON_BYTES_ARGS - | PYTHON_OBJECT_ARGS ) -PYTHON_DTYPE_ARGS = PYTHON_NOT_STR_DTYPE_ARGS | PYTHON_STRING_ARGS +PYTHON_NOT_OBJ_DTYPE_ARGS = PYTHON_NOT_STR_OBJ_DTYPE_ARGS | PYTHON_STRING_ARGS NUMPY_NOT_DATETIMELIKE_DTYPE_ARGS = ( NUMPY_BOOL_ARGS | NUMPY_INT_ARGS @@ -296,10 +295,10 @@ BuiltinBooleanDtypeArg: PYTHON_BOOL_ARGS, BuiltinBytesDtypeArg: PYTHON_BYTES_ARGS, BuiltinComplexDtypeArg: PYTHON_COMPLEX_ARGS, - BuiltinDtypeArg: PYTHON_DTYPE_ARGS, + BuiltinNotObjDtypeArg: PYTHON_NOT_OBJ_DTYPE_ARGS, BuiltinFloatDtypeArg: PYTHON_FLOAT_ARGS, BuiltinIntDtypeArg: PYTHON_INT_ARGS, - BuiltinNotStrDtypeArg: PYTHON_NOT_STR_DTYPE_ARGS, + BuiltinNotStrObjDtypeArg: PYTHON_NOT_STR_OBJ_DTYPE_ARGS, BuiltinObjectDtypeArg: PYTHON_OBJECT_ARGS, BuiltinStrDtypeArg: PYTHON_STRING_ARGS, BytesDtypeArg: ASTYPE_BYTES_ARGS,