From 87acbc4e2d74a93e49dcb080072868f895b3f271 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Sun, 2 Nov 2025 15:30:36 +0100 Subject: [PATCH 01/21] add NumpyExtensionArray --- pandas-stubs/_libs/arrays.pyi | 1 + pandas-stubs/core/arrays/_mixins.pyi | 5 +++++ pandas-stubs/core/arrays/numpy_.pyi | 6 ++++++ pandas-stubs/core/strings/object_array.pyi | 1 + 4 files changed, 13 insertions(+) create mode 100644 pandas-stubs/_libs/arrays.pyi create mode 100644 pandas-stubs/core/arrays/_mixins.pyi create mode 100644 pandas-stubs/core/strings/object_array.pyi diff --git a/pandas-stubs/_libs/arrays.pyi b/pandas-stubs/_libs/arrays.pyi new file mode 100644 index 000000000..740dc7469 --- /dev/null +++ b/pandas-stubs/_libs/arrays.pyi @@ -0,0 +1 @@ +class NDArrayBacked: ... diff --git a/pandas-stubs/core/arrays/_mixins.pyi b/pandas-stubs/core/arrays/_mixins.pyi new file mode 100644 index 000000000..c34cbd231 --- /dev/null +++ b/pandas-stubs/core/arrays/_mixins.pyi @@ -0,0 +1,5 @@ +from pandas.core.arrays.base import ExtensionArray + +from pandas._libs.arrays import NDArrayBacked + +class NDArrayBackedExtensionArray(NDArrayBacked, ExtensionArray): ... diff --git a/pandas-stubs/core/arrays/numpy_.pyi b/pandas-stubs/core/arrays/numpy_.pyi index 760d82e84..96a7a72a3 100644 --- a/pandas-stubs/core/arrays/numpy_.pyi +++ b/pandas-stubs/core/arrays/numpy_.pyi @@ -1,9 +1,12 @@ import numpy as np from numpy.lib.mixins import NDArrayOperatorsMixin +from pandas.core.arraylike import OpsMixin +from pandas.core.arrays._mixins import NDArrayBackedExtensionArray from pandas.core.arrays.base import ( ExtensionArray, ExtensionOpsMixin, ) +from pandas.core.strings.object_array import ObjectStringArrayMixin from pandas.core.dtypes.dtypes import ExtensionDtype @@ -14,3 +17,6 @@ class PandasDtype(ExtensionDtype): def itemsize(self) -> int: ... class PandasArray(ExtensionArray, ExtensionOpsMixin, NDArrayOperatorsMixin): ... +class NumpyExtensionArray( + OpsMixin, NDArrayBackedExtensionArray, ObjectStringArrayMixin +): ... diff --git a/pandas-stubs/core/strings/object_array.pyi b/pandas-stubs/core/strings/object_array.pyi new file mode 100644 index 000000000..3fd853b0f --- /dev/null +++ b/pandas-stubs/core/strings/object_array.pyi @@ -0,0 +1 @@ +class ObjectStringArrayMixin: ... From 11918f0c940efe85411402b084182bd2e76fe355 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Tue, 4 Nov 2025 11:54:58 +0100 Subject: [PATCH 02/21] add all arrays --- pandas-stubs/_libs/arrays.pyi | 39 +++++++++++++- pandas-stubs/core/arrays/__init__.pyi | 54 ++++++++++++++----- .../core/arrays/_arrow_string_mixins.pyi | 1 + pandas-stubs/core/arrays/_mixins.pyi | 12 ++++- pandas-stubs/core/arrays/arrow/__init__.pyi | 7 +++ pandas-stubs/core/arrays/arrow/accessors.pyi | 5 ++ pandas-stubs/core/arrays/arrow/array.pyi | 7 +++ pandas-stubs/core/arrays/base.pyi | 4 +- pandas-stubs/core/arrays/period.pyi | 13 +++++ pandas-stubs/core/arrays/string_.pyi | 7 ++- pandas-stubs/core/arrays/string_arrow.pyi | 7 +++ 11 files changed, 138 insertions(+), 18 deletions(-) create mode 100644 pandas-stubs/core/arrays/_arrow_string_mixins.pyi create mode 100644 pandas-stubs/core/arrays/arrow/accessors.pyi create mode 100644 pandas-stubs/core/arrays/arrow/array.pyi create mode 100644 pandas-stubs/core/arrays/string_arrow.pyi diff --git a/pandas-stubs/_libs/arrays.pyi b/pandas-stubs/_libs/arrays.pyi index 740dc7469..59a8da922 100644 --- a/pandas-stubs/_libs/arrays.pyi +++ b/pandas-stubs/_libs/arrays.pyi @@ -1 +1,38 @@ -class NDArrayBacked: ... +from collections.abc import Sequence +from typing import Any + +import numpy as np +from typing_extensions import Self + +from pandas._typing import ( + AnyArrayLikeInt, + AxisInt, + DtypeObj, + Shape, +) + +class NDArrayBacked: + _dtype: DtypeObj + _ndarray: np.ndarray + def __setstate__(self, state: Any) -> None: ... + def __len__(self) -> int: ... + @property + def shape(self) -> Shape: ... + @property + def ndim(self) -> int: ... + @property + def size(self) -> int: ... + @property + def nbytes(self) -> int: ... + def copy(self, order=...) -> Self: ... + def delete(self, loc, axis=...) -> Self: ... + def swapaxes(self, axis1, axis2) -> Self: ... + def repeat( + self, + repeats: int | Sequence[int] | AnyArrayLikeInt, + axis: AxisInt | None = None, + ) -> Self: ... + def reshape(self, *args: Any, **kwargs: Any) -> Self: ... + def ravel(self, order=...) -> Self: ... + @property + def T(self) -> Self: ... diff --git a/pandas-stubs/core/arrays/__init__.pyi b/pandas-stubs/core/arrays/__init__.pyi index b9fb5f749..f183e9236 100644 --- a/pandas-stubs/core/arrays/__init__.pyi +++ b/pandas-stubs/core/arrays/__init__.pyi @@ -1,15 +1,43 @@ +from pandas.core.arrays.arrow import ArrowExtensionArray from pandas.core.arrays.base import ( - ExtensionArray as ExtensionArray, - ExtensionOpsMixin as ExtensionOpsMixin, - ExtensionScalarOpsMixin as ExtensionScalarOpsMixin, + ExtensionArray, + ExtensionOpsMixin, + ExtensionScalarOpsMixin, ) -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 PandasArray as PandasArray -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.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, + period_array, +) +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", + "ExtensionOpsMixin", + "ExtensionScalarOpsMixin", + "FloatingArray", + "IntegerArray", + "IntervalArray", + "NumpyExtensionArray", + "PeriodArray", + "SparseArray", + "StringArray", + "TimedeltaArray", + "period_array", +] diff --git a/pandas-stubs/core/arrays/_arrow_string_mixins.pyi b/pandas-stubs/core/arrays/_arrow_string_mixins.pyi new file mode 100644 index 000000000..8c2984e50 --- /dev/null +++ b/pandas-stubs/core/arrays/_arrow_string_mixins.pyi @@ -0,0 +1 @@ +class ArrowStringArrayMixin: ... diff --git a/pandas-stubs/core/arrays/_mixins.pyi b/pandas-stubs/core/arrays/_mixins.pyi index c34cbd231..4141b6538 100644 --- a/pandas-stubs/core/arrays/_mixins.pyi +++ b/pandas-stubs/core/arrays/_mixins.pyi @@ -1,5 +1,15 @@ from pandas.core.arrays.base import ExtensionArray +from pandas.core.series import Series +from typing_extensions import Self from pandas._libs.arrays import NDArrayBacked +from pandas._typing import ( + AxisInt, + Scalar, +) -class NDArrayBackedExtensionArray(NDArrayBacked, ExtensionArray): ... +class NDArrayBackedExtensionArray(NDArrayBacked, ExtensionArray): + def argmin(self, axis: AxisInt = 0, skipna: bool = True) -> int: ... + def argmax(self, axis: AxisInt = 0, skipna: bool = True) -> int: ... + def insert(self, loc: int, item: Scalar) -> Self: ... + def value_counts(self, dropna: bool = True) -> Series[int]: ... diff --git a/pandas-stubs/core/arrays/arrow/__init__.pyi b/pandas-stubs/core/arrays/arrow/__init__.pyi index e69de29bb..50274a2de 100644 --- a/pandas-stubs/core/arrays/arrow/__init__.pyi +++ b/pandas-stubs/core/arrays/arrow/__init__.pyi @@ -0,0 +1,7 @@ +from pandas.core.arrays.arrow.accessors import ( + ListAccessor, + StructAccessor, +) +from pandas.core.arrays.arrow.array import ArrowExtensionArray + +__all__ = ["ArrowExtensionArray", "ListAccessor", "StructAccessor"] diff --git a/pandas-stubs/core/arrays/arrow/accessors.pyi b/pandas-stubs/core/arrays/arrow/accessors.pyi new file mode 100644 index 000000000..409d642c7 --- /dev/null +++ b/pandas-stubs/core/arrays/arrow/accessors.pyi @@ -0,0 +1,5 @@ +from abc import ABCMeta + +class ArrowAccessor(metaclass=ABCMeta): ... +class ListAccessor(ArrowAccessor): ... +class StructAccessor(ArrowAccessor): ... diff --git a/pandas-stubs/core/arrays/arrow/array.pyi b/pandas-stubs/core/arrays/arrow/array.pyi new file mode 100644 index 000000000..026fe1955 --- /dev/null +++ b/pandas-stubs/core/arrays/arrow/array.pyi @@ -0,0 +1,7 @@ +from pandas.core.arraylike import OpsMixin +from pandas.core.arrays._arrow_string_mixins import ArrowStringArrayMixin +from pandas.core.arrays.base import ExtensionArraySupportsAnyAll + +class ArrowExtensionArray( + OpsMixin, ExtensionArraySupportsAnyAll, ArrowStringArrayMixin +): ... diff --git a/pandas-stubs/core/arrays/base.pyi b/pandas-stubs/core/arrays/base.pyi index 7ce4f26c6..3ca00baac 100644 --- a/pandas-stubs/core/arrays/base.pyi +++ b/pandas-stubs/core/arrays/base.pyi @@ -87,7 +87,7 @@ class ExtensionArray: ) -> np.intp: ... def factorize(self, use_na_sentinel: bool = True) -> tuple[np_1darray, Self]: ... def repeat( - self, repeats: int | AnyArrayLikeInt | Sequence[int], axis: None = None + self, repeats: int | Sequence[int] | AnyArrayLikeInt, axis: None = None ) -> Self: ... def take( self, @@ -114,6 +114,8 @@ class ExtensionArray: **kwargs: Any, ) -> Self: ... +class ExtensionArraySupportsAnyAll(ExtensionArray): ... + class ExtensionOpsMixin: @classmethod def _add_arithmetic_ops(cls) -> None: ... diff --git a/pandas-stubs/core/arrays/period.pyi b/pandas-stubs/core/arrays/period.pyi index 5eaf014dc..783702ce3 100644 --- a/pandas-stubs/core/arrays/period.pyi +++ b/pandas-stubs/core/arrays/period.pyi @@ -1,3 +1,5 @@ +from collections.abc import Sequence + from pandas import PeriodDtype from pandas.core.arrays.datetimelike import ( DatelikeOps, @@ -5,8 +7,13 @@ from pandas.core.arrays.datetimelike import ( ) from pandas._libs.tslibs import Timestamp +from pandas._libs.tslibs.offsets import ( + BaseOffset, + Tick, +) from pandas._libs.tslibs.period import Period from pandas._typing import ( + AnyArrayLike, NpDtype, PeriodFrequency, np_1darray, @@ -47,3 +54,9 @@ class PeriodArray(DatetimeLikeArrayMixin, DatelikeOps): self, freq: PeriodFrequency | None = None, how: str = ... ) -> Timestamp: ... def asfreq(self, freq: str | None = ..., how: str = "E") -> Period: ... + +def period_array( + data: Sequence[Period | str | None] | AnyArrayLike, + freq: str | Tick | BaseOffset | None = None, + copy: bool = False, +) -> PeriodArray: ... diff --git a/pandas-stubs/core/arrays/string_.pyi b/pandas-stubs/core/arrays/string_.pyi index 845870de7..556c92436 100644 --- a/pandas-stubs/core/arrays/string_.pyi +++ b/pandas-stubs/core/arrays/string_.pyi @@ -1,6 +1,7 @@ from typing import Literal -from pandas.core.arrays import PandasArray +from pandas.core.arrays.base import ExtensionArray +from pandas.core.arrays.numpy_ import NumpyExtensionArray from pandas._libs.missing import NAType @@ -11,7 +12,9 @@ class StringDtype(ExtensionDtype): @property def na_value(self) -> NAType: ... -class StringArray(PandasArray): +class BaseStringArray(ExtensionArray): ... + +class StringArray(BaseStringArray, NumpyExtensionArray): def __init__(self, values, copy: bool = ...) -> None: ... def __arrow_array__(self, type=...): ... def __setitem__(self, key, value) -> None: ... diff --git a/pandas-stubs/core/arrays/string_arrow.pyi b/pandas-stubs/core/arrays/string_arrow.pyi new file mode 100644 index 000000000..20be1de04 --- /dev/null +++ b/pandas-stubs/core/arrays/string_arrow.pyi @@ -0,0 +1,7 @@ +from pandas.core.arrays.arrow.array import ArrowExtensionArray +from pandas.core.arrays.string_ import BaseStringArray +from pandas.core.strings.object_array import ObjectStringArrayMixin + +class ArrowStringArray( + ObjectStringArrayMixin, ArrowExtensionArray, BaseStringArray +): ... From 75d591852c74d4a533b2b3919a66abdb7e402496 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Tue, 4 Nov 2025 12:45:15 +0100 Subject: [PATCH 03/21] removed disappeared classes --- pandas-stubs/core/arrays/numpy_.pyi | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/pandas-stubs/core/arrays/numpy_.pyi b/pandas-stubs/core/arrays/numpy_.pyi index 96a7a72a3..afe191746 100644 --- a/pandas-stubs/core/arrays/numpy_.pyi +++ b/pandas-stubs/core/arrays/numpy_.pyi @@ -1,22 +1,7 @@ -import numpy as np -from numpy.lib.mixins import NDArrayOperatorsMixin from pandas.core.arraylike import OpsMixin from pandas.core.arrays._mixins import NDArrayBackedExtensionArray -from pandas.core.arrays.base import ( - ExtensionArray, - ExtensionOpsMixin, -) from pandas.core.strings.object_array import ObjectStringArrayMixin -from pandas.core.dtypes.dtypes import ExtensionDtype - -class PandasDtype(ExtensionDtype): - @property - def numpy_dtype(self) -> np.dtype: ... - @property - def itemsize(self) -> int: ... - -class PandasArray(ExtensionArray, ExtensionOpsMixin, NDArrayOperatorsMixin): ... class NumpyExtensionArray( OpsMixin, NDArrayBackedExtensionArray, ObjectStringArrayMixin ): ... From b197d33336c35c73084d4b56707f1d0e0b3ac028 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Tue, 4 Nov 2025 12:54:20 +0100 Subject: [PATCH 04/21] fixup --- pandas-stubs/arrays/__init__.pyi | 39 ++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/pandas-stubs/arrays/__init__.pyi b/pandas-stubs/arrays/__init__.pyi index 8dd78cc95..f7199f86e 100644 --- a/pandas-stubs/arrays/__init__.pyi +++ b/pandas-stubs/arrays/__init__.pyi @@ -1,12 +1,31 @@ from pandas.core.arrays import ( - BooleanArray as BooleanArray, - Categorical as Categorical, - DatetimeArray as DatetimeArray, - IntegerArray as IntegerArray, - IntervalArray as IntervalArray, - PandasArray as PandasArray, - PeriodArray as PeriodArray, - SparseArray as SparseArray, - StringArray as StringArray, - TimedeltaArray as TimedeltaArray, + ArrowExtensionArray, + ArrowStringArray, + BooleanArray, + Categorical, + DatetimeArray, + FloatingArray, + IntegerArray, + IntervalArray, + NumpyExtensionArray, + PeriodArray, + SparseArray, + StringArray, + TimedeltaArray, ) + +__all__ = [ + "ArrowExtensionArray", + "ArrowStringArray", + "BooleanArray", + "Categorical", + "DatetimeArray", + "FloatingArray", + "IntegerArray", + "IntervalArray", + "NumpyExtensionArray", + "PeriodArray", + "SparseArray", + "StringArray", + "TimedeltaArray", +] From c577c1303ec47f7e3f1e8c395727f17777dd9dd6 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Mon, 10 Nov 2025 13:25:07 +0100 Subject: [PATCH 05/21] remove internal APIs and add tests --- pandas-stubs/core/arrays/boolean.pyi | 21 ++++-- pandas-stubs/core/arrays/datetimes.pyi | 80 ++++++---------------- pandas-stubs/core/arrays/timedeltas.pyi | 76 +++++++-------------- pandas-stubs/core/construction.pyi | 89 ++++++++++++++++++++++--- tests/arrays/test_arrays.py | 12 ---- tests/arrays/test_boolean_arrays.py | 13 ++++ tests/arrays/test_integer_arrays.py | 13 ++++ 7 files changed, 164 insertions(+), 140 deletions(-) delete mode 100644 tests/arrays/test_arrays.py create mode 100644 tests/arrays/test_boolean_arrays.py create mode 100644 tests/arrays/test_integer_arrays.py diff --git a/pandas-stubs/core/arrays/boolean.pyi b/pandas-stubs/core/arrays/boolean.pyi index 478ef8f9a..c3ff2e8e9 100644 --- a/pandas-stubs/core/arrays/boolean.pyi +++ b/pandas-stubs/core/arrays/boolean.pyi @@ -1,9 +1,10 @@ from collections.abc import Sequence -from typing import Any import numpy as np from pandas.core.arrays.integer import IntegerArray from pandas.core.arrays.masked import BaseMaskedArray as BaseMaskedArray +from pandas.core.indexes.base import Index +from pandas.core.series import Series from typing_extensions import Self from pandas._libs.missing import NAType @@ -22,13 +23,21 @@ class BooleanDtype(ExtensionDtype): class BooleanArray(BaseMaskedArray): def __init__( - self, values: np_ndarray_bool, mask: np_ndarray_bool, copy: bool = ... + self, + values: ( + Sequence[bool | np.bool] + | np_ndarray_bool + | Index[bool] + | Series[bool] + | Self + ), + mask: np_ndarray_bool, + copy: bool = False, ) -> None: ... @property - def dtype(self): ... - def __setitem__(self, key, value) -> None: ... - def any(self, *, skipna: bool = ..., **kwargs: Any): ... - def all(self, *, skipna: bool = ..., **kwargs: Any): ... + def dtype( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + self, + ) -> np.dtypes.BoolDType: ... def __and__( self, other: ( diff --git a/pandas-stubs/core/arrays/datetimes.pyi b/pandas-stubs/core/arrays/datetimes.pyi index 82d884fe6..3932eb452 100644 --- a/pandas-stubs/core/arrays/datetimes.pyi +++ b/pandas-stubs/core/arrays/datetimes.pyi @@ -1,4 +1,5 @@ -from datetime import tzinfo as _tzinfo +from collections.abc import Sequence +from datetime import datetime import numpy as np from pandas.core.arrays.datetimelike import ( @@ -6,68 +7,27 @@ from pandas.core.arrays.datetimelike import ( DatetimeLikeArrayMixin, TimelikeOps, ) +from pandas.core.indexes.datetimes import DatetimeIndex +from pandas.core.series import Series +from typing_extensions import Self -from pandas._typing import ( - TimeAmbiguous, - TimeNonexistent, - TimeZones, -) - -from pandas.core.dtypes.dtypes import DatetimeTZDtype as DatetimeTZDtype +from pandas._libs.tslibs.timestamps import Timestamp class DatetimeArray(DatetimeLikeArrayMixin, TimelikeOps, DatelikeOps): __array_priority__: int = ... - def __init__(self, values, dtype=..., freq=..., copy: bool = ...) -> None: ... - # ignore in dtype() is from the pandas source - @property - def dtype(self) -> np.dtype | DatetimeTZDtype: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] - @property - def tz(self): ... - @tz.setter - def tz(self, value) -> None: ... - @property - def tzinfo(self) -> _tzinfo | None: ... - @property - def is_normalized(self): ... - def __iter__(self): ... - def tz_convert(self, tz: TimeZones): ... - def tz_localize( + def __init__( self, - tz: TimeZones, - ambiguous: TimeAmbiguous = "raise", - nonexistent: TimeNonexistent = "raise", - ): ... - def to_pydatetime(self): ... - def normalize(self): ... - def to_period(self, freq=...): ... - def to_perioddelta(self, freq): ... - def month_name(self, locale=...): ... - def day_name(self, locale=...): ... - @property - def time(self): ... + values: ( + Sequence[datetime | np.datetime64] + | np.typing.NDArray[np.datetime64] + | DatetimeIndex + | Series[Timestamp] + | Self + ), + dtype: np.dtype | None = None, + copy: bool = False, + ) -> None: ... @property - def timetz(self): ... - @property - def date(self): ... - year = ... - month = ... - day = ... - hour = ... - minute = ... - second = ... - microsecond = ... - nanosecond = ... - dayofweek = ... - weekday = ... - dayofyear = ... - quarter = ... - days_in_month = ... - daysinmonth = ... - is_month_start = ... - is_month_end = ... - is_quarter_start = ... - is_quarter_end = ... - is_year_start = ... - is_year_end = ... - is_leap_year = ... - def to_julian_date(self): ... + def dtype( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + self, + ) -> np.dtypes.DateTime64DType: ... diff --git a/pandas-stubs/core/arrays/timedeltas.pyi b/pandas-stubs/core/arrays/timedeltas.pyi index fd0d71c99..1994bcaca 100644 --- a/pandas-stubs/core/arrays/timedeltas.pyi +++ b/pandas-stubs/core/arrays/timedeltas.pyi @@ -1,64 +1,38 @@ from collections.abc import Sequence from datetime import timedelta +import numpy as np from pandas.core.arrays.datetimelike import ( DatetimeLikeArrayMixin, TimelikeOps, ) +from pandas.core.indexes.timedeltas import TimedeltaIndex +from pandas.core.series import Series +from typing_extensions import Self + +from pandas._libs.tslibs.timedeltas import Timedelta +from pandas._typing import np_1darray + +from pandas.core.dtypes.base import ExtensionDtype class TimedeltaArray(DatetimeLikeArrayMixin, TimelikeOps): __array_priority__: int = ... @property - def dtype(self): ... - def __init__(self, values, dtype=..., freq=..., copy: bool = ...) -> None: ... - def sum( - self, - *, - axis=..., - dtype=..., - out=..., - keepdims: bool = ..., - initial=..., - skipna: bool = ..., - min_count: int = ..., - ): ... - def std( - self, - *, - axis=..., - dtype=..., - out=..., - ddof: int = ..., - keepdims: bool = ..., - skipna: bool = ..., - ): ... - def median( + def dtype( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] self, + ) -> np.dtypes.TimeDelta64DType: ... + def __init__(self, values, dtype=..., freq=..., copy: bool = ...) -> None: ... + @classmethod + def _from_sequence( + cls, + data: ( + Sequence[timedelta | np.timedelta64] + | np_1darray[np.timedelta64] + | TimedeltaIndex + | Series[Timedelta] + | Self + ), *, - axis=..., - out=..., - overwrite_input: bool = ..., - keepdims: bool = ..., - skipna: bool = ..., - ): ... - def __mul__(self, other): ... - __rmul__ = ... - def __truediv__(self, other): ... - def __rtruediv__(self, other): ... - def __floordiv__(self, other): ... - def __rfloordiv__(self, other): ... - def __mod__(self, other): ... - def __rmod__(self, other): ... - def __divmod__(self, other): ... - def __rdivmod__(self, other): ... - def __neg__(self): ... - def __pos__(self): ... - def __abs__(self): ... - def total_seconds(self) -> int: ... - def to_pytimedelta(self) -> Sequence[timedelta]: ... - days: int = ... - seconds: int = ... - microseconds: int = ... - nanoseconds: int = ... - @property - def components(self) -> int: ... + dtype: np.dtype | ExtensionDtype | None = None, + copy: bool = True, + ) -> TimedeltaArray: ... diff --git a/pandas-stubs/core/construction.pyi b/pandas-stubs/core/construction.pyi index 3638fac78..d07d5bd7c 100644 --- a/pandas-stubs/core/construction.pyi +++ b/pandas-stubs/core/construction.pyi @@ -1,21 +1,35 @@ from collections.abc import Sequence -from typing import overload +from typing import ( + Any, + overload, +) import numpy as np from pandas.core.arrays.base import ExtensionArray from pandas.core.arrays.boolean import BooleanArray +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.numpy_ import NumpyExtensionArray +from pandas.core.arrays.timedeltas import TimedeltaArray +from pandas.core.indexes.base import Index +from pandas.core.indexes.datetimes import DatetimeIndex +from pandas.core.indexes.range import RangeIndex +from pandas.core.indexes.timedeltas import TimedeltaIndex +from pandas.core.series import Series from pandas._libs.missing import NAType +from pandas._libs.tslibs.nattype import NaTType +from pandas._libs.tslibs.timedeltas import Timedelta +from pandas._libs.tslibs.timestamps import Timestamp from pandas._typing import ( PandasBooleanDtypeArg, - PandasFloatDtypeArg, - PandasIntDtypeArg, - PandasUIntDtypeArg, + np_ndarray, np_ndarray_anyint, np_ndarray_bool, + np_ndarray_dt, np_ndarray_float, + np_ndarray_td, ) from pandas.core.dtypes.dtypes import ExtensionDtype @@ -27,22 +41,75 @@ def array( # type: ignore[overload-overlap] # pyright: ignore[reportOverlapping copy: bool = True, ) -> BooleanArray: ... @overload +def array( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + data: Sequence[NAType | None], + dtype: str | np.dtype | ExtensionDtype | None = None, + copy: bool = True, +) -> NumpyExtensionArray: ... +@overload def array( # type: ignore[overload-overlap] - data: Sequence[int | np.integer | NAType | None] | np_ndarray_anyint | IntegerArray, - dtype: PandasIntDtypeArg | PandasUIntDtypeArg | None = None, + data: ( + Sequence[bool | np.bool | NAType | None] + | np_ndarray_bool + | BooleanArray + | Index[bool] + | Series[int] + ), + dtype: str | np.dtype | ExtensionDtype | None = None, + copy: bool = True, +) -> BooleanArray: ... +@overload +def array( # type: ignore[overload-overlap] + data: ( + Sequence[int | np.integer | NAType | None] + | np_ndarray_anyint + | IntegerArray + | Index[int] + | RangeIndex + | Series[int] + ), + dtype: str | np.dtype | ExtensionDtype | None = None, copy: bool = True, ) -> IntegerArray: ... @overload -def array( +def array( # type: ignore[overload-overlap] data: ( - Sequence[float | np.floating | NAType | None] | np_ndarray_float | FloatingArray + Sequence[float | np.floating | NAType | None] + | np_ndarray_float + | FloatingArray + | Index[float] + | Series[float] ), - dtype: PandasFloatDtypeArg | None = None, + dtype: str | np.dtype | ExtensionDtype | None = None, copy: bool = True, ) -> FloatingArray: ... @overload +def array( # type: ignore[overload-overlap] + data: ( + Sequence[Timestamp | np.datetime64 | NaTType | None] + | np_ndarray_dt + | DatetimeArray + | DatetimeIndex + | Series[Timestamp] + ), + dtype: str | np.dtype | ExtensionDtype | 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: str | np.dtype | ExtensionDtype | None = None, + copy: bool = True, +) -> TimedeltaArray: ... +@overload def array( - data: Sequence[object], + data: Sequence[Any] | np_ndarray | ExtensionArray | Index | Series, dtype: str | np.dtype | ExtensionDtype | None = None, copy: bool = True, -) -> ExtensionArray: ... +) -> NumpyExtensionArray: ... diff --git a/tests/arrays/test_arrays.py b/tests/arrays/test_arrays.py deleted file mode 100644 index fd4cca834..000000000 --- a/tests/arrays/test_arrays.py +++ /dev/null @@ -1,12 +0,0 @@ -from pandas.core.arrays.integer import IntegerArray -from pandas.core.construction import array -from typing_extensions import assert_type - -from pandas._libs.missing import NA - -from tests import check - - -def test_construction() -> None: - check(assert_type(array([1]), IntegerArray), IntegerArray) - check(assert_type(array([1, NA]), IntegerArray), IntegerArray) diff --git a/tests/arrays/test_boolean_arrays.py b/tests/arrays/test_boolean_arrays.py new file mode 100644 index 000000000..33a1835d1 --- /dev/null +++ b/tests/arrays/test_boolean_arrays.py @@ -0,0 +1,13 @@ +import numpy as np +import pandas as pd +from pandas.core.arrays.boolean import BooleanArray +from typing_extensions import assert_type + +from tests import check + + +def test_construction() -> None: + check(assert_type(pd.array([True]), BooleanArray), BooleanArray) + check(assert_type(pd.array([True, np.bool(True)]), BooleanArray), BooleanArray) + check(assert_type(pd.array([True, None]), BooleanArray), BooleanArray) + check(assert_type(pd.array([True, pd.NA]), BooleanArray), BooleanArray) diff --git a/tests/arrays/test_integer_arrays.py b/tests/arrays/test_integer_arrays.py new file mode 100644 index 000000000..3ccee7446 --- /dev/null +++ b/tests/arrays/test_integer_arrays.py @@ -0,0 +1,13 @@ +import numpy as np +import pandas as pd +from pandas.core.arrays.integer import IntegerArray +from typing_extensions import assert_type + +from tests import check + + +def test_construction() -> None: + check(assert_type(pd.array([1]), IntegerArray), IntegerArray) + check(assert_type(pd.array([1, np.int64(1)]), IntegerArray), IntegerArray) + check(assert_type(pd.array([1, None]), IntegerArray), IntegerArray) + check(assert_type(pd.array([1, pd.NA, None]), IntegerArray), IntegerArray) From 17923e304fcca794481ef24998041b3d440cdcfd Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Mon, 10 Nov 2025 15:40:43 +0100 Subject: [PATCH 06/21] tests --- pandas-stubs/core/construction.pyi | 48 ++++++++++++++--------------- tests/arrays/test_boolean_arrays.py | 4 +++ tests/arrays/test_integer_arrays.py | 9 ++++++ 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/pandas-stubs/core/construction.pyi b/pandas-stubs/core/construction.pyi index d07d5bd7c..034d21f2e 100644 --- a/pandas-stubs/core/construction.pyi +++ b/pandas-stubs/core/construction.pyi @@ -1,6 +1,7 @@ from collections.abc import Sequence from typing import ( Any, + Never, overload, ) @@ -23,7 +24,11 @@ from pandas._libs.tslibs.nattype import NaTType from pandas._libs.tslibs.timedeltas import Timedelta from pandas._libs.tslibs.timestamps import Timestamp from pandas._typing import ( - PandasBooleanDtypeArg, + BooleanDtypeArg, + FloatDtypeArg, + IntDtypeArg, + TimedeltaDtypeArg, + TimestampDtypeArg, np_ndarray, np_ndarray_anyint, np_ndarray_bool, @@ -36,12 +41,12 @@ from pandas.core.dtypes.dtypes import ExtensionDtype @overload def array( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] - data: Sequence[bool | np.bool | NAType | None] | np_ndarray_bool | BooleanArray, - dtype: PandasBooleanDtypeArg | None = None, + data: Sequence[Never] | Index[Never] | Series[Never], + dtype: str | np.dtype | ExtensionDtype | None = None, copy: bool = True, -) -> BooleanArray: ... +) -> ExtensionArray: ... @overload -def array( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] +def array( # type: ignore[overload-overlap] data: Sequence[NAType | None], dtype: str | np.dtype | ExtensionDtype | None = None, copy: bool = True, @@ -55,32 +60,21 @@ def array( # type: ignore[overload-overlap] | Index[bool] | Series[int] ), - dtype: str | np.dtype | ExtensionDtype | None = None, + dtype: BooleanDtypeArg | None = None, copy: bool = True, ) -> BooleanArray: ... @overload def array( # type: ignore[overload-overlap] - data: ( - Sequence[int | np.integer | NAType | None] - | np_ndarray_anyint - | IntegerArray - | Index[int] - | RangeIndex - | Series[int] - ), - dtype: str | np.dtype | ExtensionDtype | None = None, + data: Sequence[int | np.integer | NAType | None] | np_ndarray_anyint | IntegerArray, + dtype: IntDtypeArg | None = None, copy: bool = True, ) -> IntegerArray: ... @overload def array( # type: ignore[overload-overlap] data: ( - Sequence[float | np.floating | NAType | None] - | np_ndarray_float - | FloatingArray - | Index[float] - | Series[float] + Sequence[float | np.floating | NAType | None] | np_ndarray_float | FloatingArray ), - dtype: str | np.dtype | ExtensionDtype | None = None, + dtype: FloatDtypeArg | None = None, copy: bool = True, ) -> FloatingArray: ... @overload @@ -92,7 +86,7 @@ def array( # type: ignore[overload-overlap] | DatetimeIndex | Series[Timestamp] ), - dtype: str | np.dtype | ExtensionDtype | None = None, + dtype: TimestampDtypeArg | None = None, copy: bool = True, ) -> DatetimeArray: ... @overload @@ -104,12 +98,18 @@ def array( # type: ignore[overload-overlap] | TimedeltaIndex | Series[Timedelta] ), - dtype: str | np.dtype | ExtensionDtype | None = None, + dtype: TimedeltaDtypeArg | None = None, copy: bool = True, ) -> TimedeltaArray: ... @overload def array( - data: Sequence[Any] | np_ndarray | ExtensionArray | Index | Series, + data: Sequence[object] | np.typing.NDArray[np.object_] | RangeIndex, dtype: str | np.dtype | ExtensionDtype | None = None, copy: bool = True, ) -> NumpyExtensionArray: ... +@overload +def array( + data: Sequence[Any] | np_ndarray | ExtensionArray | Index[Any] | Series[Any], + dtype: str | np.dtype | ExtensionDtype | None = None, + copy: bool = True, +) -> ExtensionArray: ... diff --git a/tests/arrays/test_boolean_arrays.py b/tests/arrays/test_boolean_arrays.py index 33a1835d1..5d7344c25 100644 --- a/tests/arrays/test_boolean_arrays.py +++ b/tests/arrays/test_boolean_arrays.py @@ -11,3 +11,7 @@ def test_construction() -> None: check(assert_type(pd.array([True, np.bool(True)]), BooleanArray), BooleanArray) check(assert_type(pd.array([True, None]), BooleanArray), BooleanArray) check(assert_type(pd.array([True, pd.NA]), BooleanArray), BooleanArray) + + check(assert_type(pd.array(np.array([1], np.bool_)), BooleanArray), BooleanArray) + + check(assert_type(pd.array(pd.array([True])), BooleanArray), BooleanArray) diff --git a/tests/arrays/test_integer_arrays.py b/tests/arrays/test_integer_arrays.py index 3ccee7446..a8a3d574f 100644 --- a/tests/arrays/test_integer_arrays.py +++ b/tests/arrays/test_integer_arrays.py @@ -11,3 +11,12 @@ def test_construction() -> None: check(assert_type(pd.array([1, np.int64(1)]), IntegerArray), IntegerArray) check(assert_type(pd.array([1, None]), IntegerArray), IntegerArray) check(assert_type(pd.array([1, pd.NA, None]), IntegerArray), IntegerArray) + + check( + assert_type( # type: ignore[assert-type] # I do not understand + pd.array(np.array([1], np.int64)), IntegerArray + ), + IntegerArray, + ) + + check(assert_type(pd.array(pd.array([1])), IntegerArray), IntegerArray) From 98c51719f0fe117b9bdfacc887c7498ceba18ff9 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Mon, 10 Nov 2025 16:03:59 +0100 Subject: [PATCH 07/21] more overloads --- pandas-stubs/core/arrays/integer.pyi | 9 +++- pandas-stubs/core/construction.pyi | 64 +++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 3 deletions(-) diff --git a/pandas-stubs/core/arrays/integer.pyi b/pandas-stubs/core/arrays/integer.pyi index a32233414..3ed2b5d2f 100644 --- a/pandas-stubs/core/arrays/integer.pyi +++ b/pandas-stubs/core/arrays/integer.pyi @@ -1,3 +1,4 @@ +import numpy as np from pandas.core.arrays.masked import BaseMaskedArray from pandas._libs.missing import NAType @@ -16,8 +17,12 @@ class _IntegerDtype(ExtensionDtype): class IntegerArray(BaseMaskedArray): @property def dtype(self) -> _IntegerDtype: ... - def __init__(self, values, mask, copy: bool = ...) -> None: ... - def __setitem__(self, key, value) -> None: ... + def __init__( + self, + values: np.typing.NDArray[np.integer], + mask: np.typing.NDArray[np.bool], + copy: bool = False, + ) -> None: ... class Int8Dtype(_IntegerDtype): ... class Int16Dtype(_IntegerDtype): ... diff --git a/pandas-stubs/core/construction.pyi b/pandas-stubs/core/construction.pyi index 034d21f2e..06c4c8e0f 100644 --- a/pandas-stubs/core/construction.pyi +++ b/pandas-stubs/core/construction.pyi @@ -6,27 +6,43 @@ from typing import ( ) import numpy as np +from pandas.core.arrays.arrow.array 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.numpy_ import NumpyExtensionArray +from pandas.core.arrays.period import PeriodArray +from pandas.core.arrays.sparse.array import SparseArray +from pandas.core.arrays.string_ import StringArray 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.sparse import SparseIndex 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 ( BooleanDtypeArg, + CategoryDtypeArg, FloatDtypeArg, IntDtypeArg, + IntervalT, + SequenceNotStr, + StrDtypeArg, TimedeltaDtypeArg, TimestampDtypeArg, np_ndarray, @@ -34,10 +50,15 @@ from pandas._typing import ( np_ndarray_bool, np_ndarray_dt, np_ndarray_float, + np_ndarray_str, np_ndarray_td, ) -from pandas.core.dtypes.dtypes import ExtensionDtype +from pandas.core.dtypes.dtypes import ( + ExtensionDtype, + IntervalDtype, + PeriodDtype, +) @overload def array( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @@ -102,12 +123,53 @@ def array( # type: ignore[overload-overlap] copy: bool = True, ) -> TimedeltaArray: ... @overload +def array( + data: SequenceNotStr[str | np.str_ | NAType | None] | np_ndarray_str | StringArray, + dtype: StrDtypeArg | None = None, + copy: bool = True, +) -> StringArray: ... +@overload +def array( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + data: Sequence[Period | NAType | None] | PeriodArray | PeriodIndex | Series[Period], + dtype: PeriodDtype | None = None, + copy: bool = True, +) -> PeriodIndex: ... +@overload +def array( # type: ignore[overload-overlap] + data: ( + Sequence[IntervalT | NAType | None] + | IntervalIndex + | Series[Interval] + | IntervalArray + ), + dtype: IntervalDtype | None = None, + copy: bool = True, +) -> IntervalArray: ... +@overload +def array( + data: Categorical | CategoricalIndex, + dtype: CategoryDtypeArg | None = None, + copy: bool = True, +) -> Categorical: ... +@overload def array( data: Sequence[object] | np.typing.NDArray[np.object_] | RangeIndex, dtype: str | np.dtype | ExtensionDtype | None = None, copy: bool = True, ) -> NumpyExtensionArray: ... @overload +def array( # type: ignore[overload-overlap] + data: SparseArray | SparseIndex, + dtype: str | np.dtype | ExtensionDtype | None = None, + copy: bool = True, +) -> SparseIndex: ... +@overload +def array( + data: ArrowExtensionArray, + dtype: str | np.dtype | ExtensionDtype | None = None, + copy: bool = True, +) -> ArrowExtensionArray: ... +@overload def array( data: Sequence[Any] | np_ndarray | ExtensionArray | Index[Any] | Series[Any], dtype: str | np.dtype | ExtensionDtype | None = None, From 4dcb998f3747ead3b5248ee92c95b1312c46a9f2 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Mon, 10 Nov 2025 17:06:00 +0100 Subject: [PATCH 08/21] more tests --- pandas-stubs/core/construction.pyi | 11 ++++-- ...oolean_arrays.py => test_boolean_array.py} | 2 +- tests/arrays/test_datetime_array.py | 34 +++++++++++++++++++ ...nteger_arrays.py => test_integer_array.py} | 2 +- 4 files changed, 44 insertions(+), 5 deletions(-) rename tests/arrays/{test_boolean_arrays.py => test_boolean_array.py} (95%) create mode 100644 tests/arrays/test_datetime_array.py rename tests/arrays/{test_integer_arrays.py => test_integer_array.py} (95%) diff --git a/pandas-stubs/core/construction.pyi b/pandas-stubs/core/construction.pyi index 06c4c8e0f..55b5e35e0 100644 --- a/pandas-stubs/core/construction.pyi +++ b/pandas-stubs/core/construction.pyi @@ -1,7 +1,10 @@ from collections.abc import Sequence +from datetime import ( + datetime, + timedelta, +) from typing import ( Any, - Never, overload, ) @@ -27,6 +30,7 @@ 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 @@ -101,7 +105,8 @@ def array( # type: ignore[overload-overlap] @overload def array( # type: ignore[overload-overlap] data: ( - Sequence[Timestamp | np.datetime64 | NaTType | None] + Sequence[datetime | NaTType | None] + | Sequence[np.datetime64 | NaTType | None] | np_ndarray_dt | DatetimeArray | DatetimeIndex @@ -113,7 +118,7 @@ def array( # type: ignore[overload-overlap] @overload def array( # type: ignore[overload-overlap] data: ( - Sequence[Timedelta | np.timedelta64 | NaTType | None] + Sequence[timedelta | np.timedelta64 | NaTType | None] | np_ndarray_td | TimedeltaArray | TimedeltaIndex diff --git a/tests/arrays/test_boolean_arrays.py b/tests/arrays/test_boolean_array.py similarity index 95% rename from tests/arrays/test_boolean_arrays.py rename to tests/arrays/test_boolean_array.py index 5d7344c25..7b3c4c174 100644 --- a/tests/arrays/test_boolean_arrays.py +++ b/tests/arrays/test_boolean_array.py @@ -6,7 +6,7 @@ from tests import check -def test_construction() -> None: +def test_constructor() -> None: check(assert_type(pd.array([True]), BooleanArray), BooleanArray) check(assert_type(pd.array([True, np.bool(True)]), BooleanArray), BooleanArray) check(assert_type(pd.array([True, None]), BooleanArray), BooleanArray) diff --git a/tests/arrays/test_datetime_array.py b/tests/arrays/test_datetime_array.py new file mode 100644 index 000000000..3aeea9530 --- /dev/null +++ b/tests/arrays/test_datetime_array.py @@ -0,0 +1,34 @@ +from datetime import datetime + +import numpy as np +import pandas as pd +from pandas.core.arrays.datetimes import DatetimeArray +from typing_extensions import assert_type + +from tests import check + + +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) + check(assert_type(pd.array([np_dt, pd.NaT]), DatetimeArray), DatetimeArray) + + check( + assert_type( # type: ignore[assert-type] # I do not understand + pd.array(np.array([dt], np.datetime64)), 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_integer_arrays.py b/tests/arrays/test_integer_array.py similarity index 95% rename from tests/arrays/test_integer_arrays.py rename to tests/arrays/test_integer_array.py index a8a3d574f..66733083a 100644 --- a/tests/arrays/test_integer_arrays.py +++ b/tests/arrays/test_integer_array.py @@ -6,7 +6,7 @@ from tests import check -def test_construction() -> None: +def test_constructor() -> None: check(assert_type(pd.array([1]), IntegerArray), IntegerArray) check(assert_type(pd.array([1, np.int64(1)]), IntegerArray), IntegerArray) check(assert_type(pd.array([1, None]), IntegerArray), IntegerArray) From d7056b3fd9a37421805474a48333283a64b7a4ed Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Mon, 10 Nov 2025 18:13:00 +0100 Subject: [PATCH 09/21] mypy --- tests/arrays/test_datetime_array.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/arrays/test_datetime_array.py b/tests/arrays/test_datetime_array.py index 3aeea9530..10e36a7f7 100644 --- a/tests/arrays/test_datetime_array.py +++ b/tests/arrays/test_datetime_array.py @@ -1,10 +1,13 @@ from datetime import datetime +from typing import cast import numpy as np import pandas as pd from pandas.core.arrays.datetimes import DatetimeArray from typing_extensions import assert_type +from pandas._libs.tslibs.nattype import NaTType + from tests import check @@ -18,7 +21,8 @@ def test_constructor() -> None: np_dt = np.datetime64(dt) check(assert_type(pd.array([np_dt]), DatetimeArray), DatetimeArray) check(assert_type(pd.array([np_dt, None]), DatetimeArray), DatetimeArray) - check(assert_type(pd.array([np_dt, pd.NaT]), DatetimeArray), DatetimeArray) + dt_nat = cast(list[np.datetime64 | NaTType], [np_dt, pd.NaT]) + check(assert_type(pd.array(dt_nat), DatetimeArray), DatetimeArray) check( assert_type( # type: ignore[assert-type] # I do not understand From c2e9ab19ae887a602b4536a8cde441bdb9c951b0 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Tue, 11 Nov 2025 13:23:05 +0100 Subject: [PATCH 10/21] test_timedelta_array --- pandas-stubs/core/algorithms.pyi | 7 +++--- pandas-stubs/core/construction.pyi | 2 +- tests/arrays/test_timedelta_array.py | 33 ++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 tests/arrays/test_timedelta_array.py diff --git a/pandas-stubs/core/algorithms.pyi b/pandas-stubs/core/algorithms.pyi index b2dc73cb4..533e82512 100644 --- a/pandas-stubs/core/algorithms.pyi +++ b/pandas-stubs/core/algorithms.pyi @@ -38,10 +38,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 @@ -49,7 +49,8 @@ def unique(values: RangeIndex) -> np_1darray_int64: ... @overload def unique(values: MultiIndex) -> 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/construction.pyi b/pandas-stubs/core/construction.pyi index 55b5e35e0..72569f62c 100644 --- a/pandas-stubs/core/construction.pyi +++ b/pandas-stubs/core/construction.pyi @@ -104,7 +104,7 @@ def array( # type: ignore[overload-overlap] ) -> FloatingArray: ... @overload def array( # type: ignore[overload-overlap] - data: ( + 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 diff --git a/tests/arrays/test_timedelta_array.py b/tests/arrays/test_timedelta_array.py new file mode 100644 index 000000000..5c1c545d7 --- /dev/null +++ b/tests/arrays/test_timedelta_array.py @@ -0,0 +1,33 @@ +from datetime import timedelta + +import numpy as np +import pandas as pd +from pandas.core.arrays.timedeltas import TimedeltaArray +from typing_extensions import assert_type + +from tests import check + + +def test_constructor() -> None: + 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) + + check( + assert_type( # type: ignore[assert-type] # I do not understand + pd.array(np.array([td], np.timedelta64)), TimedeltaArray + ), + TimedeltaArray, + ) + + check(assert_type(pd.array(pd.array([td])), TimedeltaArray), TimedeltaArray) + + check(assert_type(pd.array(pd.Index([td])), TimedeltaArray), TimedeltaArray) + + check(assert_type(pd.array(pd.Series([td])), TimedeltaArray), TimedeltaArray) From e50a109d2c93576d000f5b03e80bd6a161380433 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Tue, 11 Nov 2025 22:28:30 +0100 Subject: [PATCH 11/21] two more test files --- pandas-stubs/core/arrays/__init__.pyi | 6 +---- pandas-stubs/core/arrays/period.pyi | 13 --------- pandas-stubs/core/construction.pyi | 12 +++++---- tests/arrays/test_period_array.py | 38 +++++++++++++++++++++++++++ tests/arrays/test_string_array.py | 18 +++++++++++++ 5 files changed, 64 insertions(+), 23 deletions(-) create mode 100644 tests/arrays/test_period_array.py create mode 100644 tests/arrays/test_string_array.py diff --git a/pandas-stubs/core/arrays/__init__.pyi b/pandas-stubs/core/arrays/__init__.pyi index f183e9236..be097e9ca 100644 --- a/pandas-stubs/core/arrays/__init__.pyi +++ b/pandas-stubs/core/arrays/__init__.pyi @@ -12,10 +12,7 @@ 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, - period_array, -) +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 @@ -39,5 +36,4 @@ __all__ = [ "SparseArray", "StringArray", "TimedeltaArray", - "period_array", ] diff --git a/pandas-stubs/core/arrays/period.pyi b/pandas-stubs/core/arrays/period.pyi index 783702ce3..5eaf014dc 100644 --- a/pandas-stubs/core/arrays/period.pyi +++ b/pandas-stubs/core/arrays/period.pyi @@ -1,5 +1,3 @@ -from collections.abc import Sequence - from pandas import PeriodDtype from pandas.core.arrays.datetimelike import ( DatelikeOps, @@ -7,13 +5,8 @@ from pandas.core.arrays.datetimelike import ( ) from pandas._libs.tslibs import Timestamp -from pandas._libs.tslibs.offsets import ( - BaseOffset, - Tick, -) from pandas._libs.tslibs.period import Period from pandas._typing import ( - AnyArrayLike, NpDtype, PeriodFrequency, np_1darray, @@ -54,9 +47,3 @@ class PeriodArray(DatetimeLikeArrayMixin, DatelikeOps): self, freq: PeriodFrequency | None = None, how: str = ... ) -> Timestamp: ... def asfreq(self, freq: str | None = ..., how: str = "E") -> Period: ... - -def period_array( - data: Sequence[Period | str | None] | AnyArrayLike, - freq: str | Tick | BaseOffset | None = None, - copy: bool = False, -) -> PeriodArray: ... diff --git a/pandas-stubs/core/construction.pyi b/pandas-stubs/core/construction.pyi index 72569f62c..0e49c4145 100644 --- a/pandas-stubs/core/construction.pyi +++ b/pandas-stubs/core/construction.pyi @@ -134,11 +134,13 @@ def array( copy: bool = True, ) -> StringArray: ... @overload -def array( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] - data: Sequence[Period | NAType | None] | PeriodArray | PeriodIndex | Series[Period], +def array( # type: ignore[overload-overlap] + data: ( + Sequence[Period | NaTType | None] | PeriodArray | PeriodIndex | Series[Period] + ), dtype: PeriodDtype | None = None, copy: bool = True, -) -> PeriodIndex: ... +) -> PeriodArray: ... @overload def array( # type: ignore[overload-overlap] data: ( @@ -163,11 +165,11 @@ def array( copy: bool = True, ) -> NumpyExtensionArray: ... @overload -def array( # type: ignore[overload-overlap] +def array( data: SparseArray | SparseIndex, dtype: str | np.dtype | ExtensionDtype | None = None, copy: bool = True, -) -> SparseIndex: ... +) -> SparseArray: ... @overload def array( data: ArrowExtensionArray, diff --git a/tests/arrays/test_period_array.py b/tests/arrays/test_period_array.py new file mode 100644 index 000000000..8b0f876c6 --- /dev/null +++ b/tests/arrays/test_period_array.py @@ -0,0 +1,38 @@ +import pandas as pd +from pandas.core.arrays.period import PeriodArray +from typing_extensions import assert_type + +from tests import check + + +def test_constructor() -> None: + prd = pd.Period("2023-01-01") + check( + assert_type( # type: ignore[assert-type] # I do not understand + pd.array([prd]), PeriodArray + ), + PeriodArray, + ) + check( + assert_type( # type: ignore[assert-type] # I do not understand + pd.array([prd, None]), PeriodArray + ), + PeriodArray, + ) + check( + assert_type( # type: ignore[assert-type] # I do not understand + pd.array([prd, pd.NaT, None]), PeriodArray + ), + PeriodArray, + ) + + check( + assert_type( # type: ignore[assert-type] # I do not understand + 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) diff --git a/tests/arrays/test_string_array.py b/tests/arrays/test_string_array.py new file mode 100644 index 000000000..2b76882d1 --- /dev/null +++ b/tests/arrays/test_string_array.py @@ -0,0 +1,18 @@ +import numpy as np +import pandas as pd +from pandas.core.arrays.string_ import StringArray +from typing_extensions import assert_type + +from tests import check + + +def test_constructor() -> None: + check(assert_type(pd.array(["🐼"]), StringArray), StringArray) + check( + assert_type(pd.array(["🐼", np.str_("🐼")]), StringArray), + StringArray, + ) + check(assert_type(pd.array(["🐼", None]), StringArray), StringArray) + check(assert_type(pd.array(["🐼", pd.NA, None]), StringArray), StringArray) + + check(assert_type(pd.array(pd.array(["🐼"])), StringArray), StringArray) From be5fc306fbe057b9ab724f4cb61ba2330d6dc461 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Tue, 11 Nov 2025 22:42:42 +0100 Subject: [PATCH 12/21] interval array --- pandas-stubs/core/construction.pyi | 11 ++++------ tests/arrays/test_interval_array.py | 32 +++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 7 deletions(-) create mode 100644 tests/arrays/test_interval_array.py diff --git a/pandas-stubs/core/construction.pyi b/pandas-stubs/core/construction.pyi index 0e49c4145..1bc701e64 100644 --- a/pandas-stubs/core/construction.pyi +++ b/pandas-stubs/core/construction.pyi @@ -49,6 +49,7 @@ from pandas._typing import ( StrDtypeArg, TimedeltaDtypeArg, TimestampDtypeArg, + UIntDtypeArg, np_ndarray, np_ndarray_anyint, np_ndarray_bool, @@ -91,7 +92,7 @@ def array( # type: ignore[overload-overlap] @overload def array( # type: ignore[overload-overlap] data: Sequence[int | np.integer | NAType | None] | np_ndarray_anyint | IntegerArray, - dtype: IntDtypeArg | None = None, + dtype: IntDtypeArg | UIntDtypeArg | None = None, copy: bool = True, ) -> IntegerArray: ... @overload @@ -143,12 +144,8 @@ def array( # type: ignore[overload-overlap] ) -> PeriodArray: ... @overload def array( # type: ignore[overload-overlap] - data: ( - Sequence[IntervalT | NAType | None] - | IntervalIndex - | Series[Interval] - | IntervalArray - ), + # float("nan") also works, but I don't know how to put it in + data: Sequence[IntervalT | None] | IntervalArray | IntervalIndex | Series[Interval], dtype: IntervalDtype | None = None, copy: bool = True, ) -> IntervalArray: ... diff --git a/tests/arrays/test_interval_array.py b/tests/arrays/test_interval_array.py new file mode 100644 index 000000000..6e01a26ae --- /dev/null +++ b/tests/arrays/test_interval_array.py @@ -0,0 +1,32 @@ +import pandas as pd +from pandas.core.arrays.interval import IntervalArray +from typing_extensions import assert_type + +from tests import check + + +def test_constructor() -> None: + itv = pd.Interval(0, 1) + check( + assert_type( # type: ignore[assert-type] # I do not understand + pd.array([itv]), IntervalArray + ), + IntervalArray, + ) + check( + assert_type( # type: ignore[assert-type] # I do not understand + pd.array([itv, None]), IntervalArray + ), + IntervalArray, + ) + + check( + assert_type( # type: ignore[assert-type] # I do not understand + 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) From d0c00177437cbacf00392104aafb4f7225120eca Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Wed, 12 Nov 2025 13:45:28 +0100 Subject: [PATCH 13/21] Categorical --- pandas-stubs/core/construction.pyi | 18 ++++++------ tests/arrays/test_categorical.py | 44 ++++++++++++++++++++++++++++ tests/arrays/test_datetime_array.py | 2 +- tests/arrays/test_integer_array.py | 2 +- tests/arrays/test_interval_array.py | 6 ++-- tests/arrays/test_period_array.py | 8 ++--- tests/arrays/test_string_array.py | 8 ++++- tests/arrays/test_timedelta_array.py | 2 +- 8 files changed, 70 insertions(+), 20 deletions(-) create mode 100644 tests/arrays/test_categorical.py diff --git a/pandas-stubs/core/construction.pyi b/pandas-stubs/core/construction.pyi index 1bc701e64..844e85512 100644 --- a/pandas-stubs/core/construction.pyi +++ b/pandas-stubs/core/construction.pyi @@ -30,7 +30,6 @@ 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 @@ -66,13 +65,13 @@ from pandas.core.dtypes.dtypes import ( ) @overload -def array( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] - data: Sequence[Never] | Index[Never] | Series[Never], - dtype: str | np.dtype | ExtensionDtype | None = None, +def array( # type: ignore[overload-overlap] + data: SequenceNotStr[Any] | np_ndarray | ExtensionArray | Index | Series, + dtype: CategoryDtypeArg, copy: bool = True, -) -> ExtensionArray: ... +) -> Categorical: ... @overload -def array( # type: ignore[overload-overlap] +def array( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] data: Sequence[NAType | None], dtype: str | np.dtype | ExtensionDtype | None = None, copy: bool = True, @@ -143,7 +142,7 @@ def array( # type: ignore[overload-overlap] copy: bool = True, ) -> PeriodArray: ... @overload -def array( # type: ignore[overload-overlap] +def array( # float("nan") also works, but I don't know how to put it in data: Sequence[IntervalT | None] | IntervalArray | IntervalIndex | Series[Interval], dtype: IntervalDtype | None = None, @@ -151,13 +150,14 @@ def array( # type: ignore[overload-overlap] ) -> IntervalArray: ... @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( - data: Sequence[object] | np.typing.NDArray[np.object_] | RangeIndex, + data: SequenceNotStr[object] | np.typing.NDArray[np.object_] | RangeIndex, dtype: str | np.dtype | ExtensionDtype | None = None, copy: bool = True, ) -> NumpyExtensionArray: ... @@ -175,7 +175,7 @@ def array( ) -> ArrowExtensionArray: ... @overload def array( - data: Sequence[Any] | np_ndarray | ExtensionArray | Index[Any] | Series[Any], + data: SequenceNotStr[Any] | np_ndarray | ExtensionArray | Index | Series, dtype: str | np.dtype | ExtensionDtype | None = None, copy: bool = True, ) -> ExtensionArray: ... diff --git a/tests/arrays/test_categorical.py b/tests/arrays/test_categorical.py new file mode 100644 index 000000000..558ead021 --- /dev/null +++ b/tests/arrays/test_categorical.py @@ -0,0 +1,44 @@ +import numpy as np +import pandas as pd +from pandas.core.arrays.categorical import Categorical +from typing_extensions import assert_type + +from tests import check + + +def test_constructor() -> None: + check(assert_type(pd.array(["🐼"], dtype="category"), Categorical), Categorical) + check( + assert_type( # type: ignore[assert-type] # I do not understand + pd.array(np.array(["🐼"]), dtype="category"), Categorical + ), + Categorical, + ) + check( + assert_type(pd.array(pd.array(["🐼"]), dtype="category"), Categorical), + Categorical, + ) + check( + assert_type(pd.array(pd.Index(["🐼"]), dtype="category"), Categorical), + Categorical, + ) + check( + assert_type(pd.array(pd.Series(["🐼"]), dtype="category"), Categorical), + Categorical, + ) + + check( + assert_type(pd.array(pd.array(["🐼"], dtype="category")), Categorical), + Categorical, + ) + check( + assert_type( # type: ignore[assert-type] # I do not understand + pd.array(pd.Index(["🐼"], dtype="category")), Categorical + ), + Categorical, + ) + # TODO: Categorical Series pandas-dev/pandas-stubs#1415 + # check( + # assert_type(pd.array(pd.Series(["🐼"], dtype="category")), Categorical), + # Categorical, + # ) diff --git a/tests/arrays/test_datetime_array.py b/tests/arrays/test_datetime_array.py index 10e36a7f7..8f339fcda 100644 --- a/tests/arrays/test_datetime_array.py +++ b/tests/arrays/test_datetime_array.py @@ -25,7 +25,7 @@ def test_constructor() -> None: check(assert_type(pd.array(dt_nat), DatetimeArray), DatetimeArray) check( - assert_type( # type: ignore[assert-type] # I do not understand + assert_type( # type: ignore[assert-type] # I do not understand pd.array(np.array([dt], np.datetime64)), DatetimeArray ), DatetimeArray, diff --git a/tests/arrays/test_integer_array.py b/tests/arrays/test_integer_array.py index 66733083a..a5973eac6 100644 --- a/tests/arrays/test_integer_array.py +++ b/tests/arrays/test_integer_array.py @@ -13,7 +13,7 @@ def test_constructor() -> None: check(assert_type(pd.array([1, pd.NA, None]), IntegerArray), IntegerArray) check( - assert_type( # type: ignore[assert-type] # I do not understand + assert_type( # type: ignore[assert-type] # I do not understand pd.array(np.array([1], np.int64)), IntegerArray ), IntegerArray, diff --git a/tests/arrays/test_interval_array.py b/tests/arrays/test_interval_array.py index 6e01a26ae..83985f3ae 100644 --- a/tests/arrays/test_interval_array.py +++ b/tests/arrays/test_interval_array.py @@ -8,20 +8,20 @@ def test_constructor() -> None: itv = pd.Interval(0, 1) check( - assert_type( # type: ignore[assert-type] # I do not understand + assert_type( # type: ignore[assert-type] # I do not understand pd.array([itv]), IntervalArray ), IntervalArray, ) check( - assert_type( # type: ignore[assert-type] # I do not understand + assert_type( # type: ignore[assert-type] # I do not understand pd.array([itv, None]), IntervalArray ), IntervalArray, ) check( - assert_type( # type: ignore[assert-type] # I do not understand + assert_type( # type: ignore[assert-type] # I do not understand pd.array(pd.array([itv])), IntervalArray ), IntervalArray, diff --git a/tests/arrays/test_period_array.py b/tests/arrays/test_period_array.py index 8b0f876c6..ec379c1c0 100644 --- a/tests/arrays/test_period_array.py +++ b/tests/arrays/test_period_array.py @@ -8,26 +8,26 @@ def test_constructor() -> None: prd = pd.Period("2023-01-01") check( - assert_type( # type: ignore[assert-type] # I do not understand + assert_type( # type: ignore[assert-type] # I do not understand pd.array([prd]), PeriodArray ), PeriodArray, ) check( - assert_type( # type: ignore[assert-type] # I do not understand + assert_type( # type: ignore[assert-type] # I do not understand pd.array([prd, None]), PeriodArray ), PeriodArray, ) check( - assert_type( # type: ignore[assert-type] # I do not understand + assert_type( # type: ignore[assert-type] # I do not understand pd.array([prd, pd.NaT, None]), PeriodArray ), PeriodArray, ) check( - assert_type( # type: ignore[assert-type] # I do not understand + assert_type( # type: ignore[assert-type] # I do not understand pd.array(pd.array([prd])), PeriodArray ), PeriodArray, diff --git a/tests/arrays/test_string_array.py b/tests/arrays/test_string_array.py index 2b76882d1..68654b971 100644 --- a/tests/arrays/test_string_array.py +++ b/tests/arrays/test_string_array.py @@ -3,7 +3,10 @@ from pandas.core.arrays.string_ import StringArray from typing_extensions import assert_type -from tests import check +from tests import ( + TYPE_CHECKING_INVALID_USAGE, + check, +) def test_constructor() -> None: @@ -16,3 +19,6 @@ def test_constructor() -> None: check(assert_type(pd.array(["🐼", pd.NA, None]), StringArray), StringArray) check(assert_type(pd.array(pd.array(["🐼"])), StringArray), StringArray) + + if TYPE_CHECKING_INVALID_USAGE: + pd.array("🐼🎫") # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] diff --git a/tests/arrays/test_timedelta_array.py b/tests/arrays/test_timedelta_array.py index 5c1c545d7..70d645eae 100644 --- a/tests/arrays/test_timedelta_array.py +++ b/tests/arrays/test_timedelta_array.py @@ -20,7 +20,7 @@ def test_constructor() -> None: check(assert_type(pd.array([td, pd.NaT, None]), TimedeltaArray), TimedeltaArray) check( - assert_type( # type: ignore[assert-type] # I do not understand + assert_type( # type: ignore[assert-type] # I do not understand pd.array(np.array([td], np.timedelta64)), TimedeltaArray ), TimedeltaArray, From e3659c89eb49b7997c740604a0bcfc63e2f2627d Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Wed, 12 Nov 2025 15:01:01 +0100 Subject: [PATCH 14/21] numpy_extension_array --- pandas-stubs/core/construction.pyi | 7 ++++- tests/arrays/test_numpy_extension_array.py | 33 ++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 tests/arrays/test_numpy_extension_array.py diff --git a/pandas-stubs/core/construction.pyi b/pandas-stubs/core/construction.pyi index 844e85512..5d75b631f 100644 --- a/pandas-stubs/core/construction.pyi +++ b/pandas-stubs/core/construction.pyi @@ -157,7 +157,12 @@ def array( ) -> Categorical: ... @overload def array( - data: SequenceNotStr[object] | np.typing.NDArray[np.object_] | RangeIndex, + data: ( + SequenceNotStr[object] + | np.typing.NDArray[np.object_] + | NumpyExtensionArray + | RangeIndex + ), dtype: str | np.dtype | ExtensionDtype | None = None, copy: bool = True, ) -> NumpyExtensionArray: ... diff --git a/tests/arrays/test_numpy_extension_array.py b/tests/arrays/test_numpy_extension_array.py new file mode 100644 index 000000000..0024fa2cd --- /dev/null +++ b/tests/arrays/test_numpy_extension_array.py @@ -0,0 +1,33 @@ +import numpy as np +import pandas as pd +from pandas.core.arrays.numpy_ import NumpyExtensionArray +from typing_extensions import assert_type + +from tests import check + + +def test_constructor() -> None: + check( + assert_type(pd.array([pd.NA, None]), NumpyExtensionArray), NumpyExtensionArray + ) + + check( + assert_type( # type: ignore[assert-type] # I do not understand + pd.array([1, "🐼"]), NumpyExtensionArray + ), + NumpyExtensionArray, + ) + check( + assert_type( # type: ignore[assert-type] # I do not understand, mypy must have problem with two Generic Variables somehow + pd.array(np.array([1, "🐼"], np.object_)), NumpyExtensionArray + ), + NumpyExtensionArray, + ) + check( + assert_type(pd.array(pd.array([pd.NA, None])), NumpyExtensionArray), + NumpyExtensionArray, + ) + check( + assert_type(pd.array(pd.RangeIndex(0, 1)), NumpyExtensionArray), + NumpyExtensionArray, + ) From de1ebf5c9ca974075c9f4d757d96db5df215080c Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Thu, 13 Nov 2025 11:36:47 +0100 Subject: [PATCH 15/21] refactor after separating dtype args --- pandas-stubs/core/construction.pyi | 124 ++++++++++++--------- tests/arrays/test_categorical.py | 8 +- tests/arrays/test_interval_array.py | 21 +--- tests/arrays/test_numpy_extension_array.py | 16 +-- tests/arrays/test_period_array.py | 28 +---- 5 files changed, 86 insertions(+), 111 deletions(-) diff --git a/pandas-stubs/core/construction.pyi b/pandas-stubs/core/construction.pyi index 5d75b631f..41b95f939 100644 --- a/pandas-stubs/core/construction.pyi +++ b/pandas-stubs/core/construction.pyi @@ -21,6 +21,7 @@ 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 StringArray +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 @@ -39,16 +40,22 @@ 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 ( - BooleanDtypeArg, + BuiltinBooleanDtypeArg, + BuiltinFloatDtypeArg, + BuiltinIntDtypeArg, + BuiltinStrDtypeArg, CategoryDtypeArg, - FloatDtypeArg, - IntDtypeArg, IntervalT, + NumpyDtypeArg, + PandasBooleanDtypeArg, + PandasFloatDtypeArg, + PandasIntDtypeArg, + PandasStrDtypeArg, + PandasTimestampDtypeArg, + PandasUIntDtypeArg, + PyArrowNotStrDtypeArg, + PyArrowStrDtypeArg, SequenceNotStr, - StrDtypeArg, - TimedeltaDtypeArg, - TimestampDtypeArg, - UIntDtypeArg, np_ndarray, np_ndarray_anyint, np_ndarray_bool, @@ -64,18 +71,46 @@ from pandas.core.dtypes.dtypes import ( PeriodDtype, ) +# @overload +# def array( +# data: SequenceNotStr[NAType | None], +# dtype: None = None, +# copy: bool = True +# ) -> NumpyExtensionArray: ... @overload -def array( # type: ignore[overload-overlap] +def array( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] data: SequenceNotStr[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] # pyright: ignore[reportOverlappingOverload] - data: Sequence[NAType | None], + data: ( + Sequence[Period | NaTType | None] | PeriodArray | PeriodIndex | Series[Period] + ), + dtype: PeriodDtype | None = None, + copy: bool = True, +) -> PeriodArray: ... +@overload +def array( # type: ignore[overload-overlap] + # float("nan") also works, but I don't know how to put it in + data: Sequence[IntervalT | None] | IntervalArray | IntervalIndex | Series[Interval], + dtype: IntervalDtype | None = None, + copy: bool = True, +) -> IntervalArray: ... +@overload +def array( + data: SparseArray | SparseIndex, dtype: str | np.dtype | ExtensionDtype | None = None, copy: bool = True, -) -> NumpyExtensionArray: ... +) -> SparseArray: ... @overload def array( # type: ignore[overload-overlap] data: ( @@ -85,13 +120,13 @@ def array( # type: ignore[overload-overlap] | Index[bool] | Series[int] ), - dtype: BooleanDtypeArg | None = None, + dtype: BuiltinBooleanDtypeArg | PandasBooleanDtypeArg | None = None, copy: bool = True, ) -> BooleanArray: ... @overload def array( # type: ignore[overload-overlap] data: Sequence[int | np.integer | NAType | None] | np_ndarray_anyint | IntegerArray, - dtype: IntDtypeArg | UIntDtypeArg | None = None, + dtype: BuiltinIntDtypeArg | PandasIntDtypeArg | PandasUIntDtypeArg | None = None, copy: bool = True, ) -> IntegerArray: ... @overload @@ -99,7 +134,7 @@ def array( # type: ignore[overload-overlap] data: ( Sequence[float | np.floating | NAType | None] | np_ndarray_float | FloatingArray ), - dtype: FloatDtypeArg | None = None, + dtype: BuiltinFloatDtypeArg | PandasFloatDtypeArg | None = None, copy: bool = True, ) -> FloatingArray: ... @overload @@ -112,11 +147,11 @@ def array( # type: ignore[overload-overlap] | DatetimeIndex | Series[Timestamp] ), - dtype: TimestampDtypeArg | None = None, + dtype: PandasTimestampDtypeArg | None = None, copy: bool = True, ) -> DatetimeArray: ... @overload -def array( # type: ignore[overload-overlap] +def array( data: ( Sequence[timedelta | np.timedelta64 | NaTType | None] | np_ndarray_td @@ -124,63 +159,42 @@ def array( # type: ignore[overload-overlap] | TimedeltaIndex | Series[Timedelta] ), - dtype: TimedeltaDtypeArg | None = None, + dtype: None = None, copy: bool = True, ) -> TimedeltaArray: ... @overload -def array( +def array( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] data: SequenceNotStr[str | np.str_ | NAType | None] | np_ndarray_str | StringArray, - dtype: StrDtypeArg | None = None, + dtype: BuiltinStrDtypeArg | PandasStrDtypeArg | None = None, copy: bool = True, ) -> StringArray: ... @overload def array( # type: ignore[overload-overlap] data: ( - Sequence[Period | NaTType | None] | PeriodArray | PeriodIndex | Series[Period] + SequenceNotStr[str | np.str_ | NAType | None] + | np_ndarray_str + | StringArray + | ArrowStringArray ), - dtype: PeriodDtype | None = None, - copy: bool = True, -) -> PeriodArray: ... -@overload -def array( - # float("nan") also works, but I don't know how to put it in - data: Sequence[IntervalT | None] | IntervalArray | IntervalIndex | Series[Interval], - dtype: IntervalDtype | None = None, + dtype: PyArrowStrDtypeArg | None = None, copy: bool = True, -) -> IntervalArray: ... -@overload -def array( - # TODO: Categorical Series pandas-dev/pandas-stubs#1415 - data: Categorical | CategoricalIndex, - dtype: CategoryDtypeArg | None = None, - copy: bool = True, -) -> Categorical: ... +) -> ArrowStringArray: ... @overload def array( - data: ( - SequenceNotStr[object] - | np.typing.NDArray[np.object_] - | NumpyExtensionArray - | RangeIndex - ), - dtype: str | np.dtype | ExtensionDtype | None = None, + data: SequenceNotStr[object] | np_ndarray | NumpyExtensionArray | RangeIndex, + dtype: NumpyDtypeArg | None = None, copy: bool = True, ) -> NumpyExtensionArray: ... @overload -def array( - data: SparseArray | SparseIndex, - dtype: str | np.dtype | ExtensionDtype | None = None, - copy: bool = True, -) -> SparseArray: ... -@overload def array( data: ArrowExtensionArray, - dtype: str | np.dtype | ExtensionDtype | None = None, + dtype: PyArrowNotStrDtypeArg | None = None, copy: bool = True, ) -> ArrowExtensionArray: ... -@overload -def array( - data: SequenceNotStr[Any] | np_ndarray | ExtensionArray | Index | Series, - dtype: str | np.dtype | ExtensionDtype | None = None, - copy: bool = True, -) -> ExtensionArray: ... + +# @overload +# def array( +# data: SequenceNotStr[Any] | np_ndarray | ExtensionArray | Index | Series, +# dtype: str | np.dtype | ExtensionDtype | None = None, +# copy: bool = True, +# ) -> ExtensionArray: ... diff --git a/tests/arrays/test_categorical.py b/tests/arrays/test_categorical.py index 558ead021..cdfcc15c2 100644 --- a/tests/arrays/test_categorical.py +++ b/tests/arrays/test_categorical.py @@ -9,9 +9,7 @@ def test_constructor() -> None: check(assert_type(pd.array(["🐼"], dtype="category"), Categorical), Categorical) check( - assert_type( # type: ignore[assert-type] # I do not understand - pd.array(np.array(["🐼"]), dtype="category"), Categorical - ), + assert_type(pd.array(np.array(["🐼"]), dtype="category"), Categorical), Categorical, ) check( @@ -32,9 +30,7 @@ def test_constructor() -> None: Categorical, ) check( - assert_type( # type: ignore[assert-type] # I do not understand - pd.array(pd.Index(["🐼"], dtype="category")), Categorical - ), + assert_type(pd.array(pd.Index(["🐼"], dtype="category")), Categorical), Categorical, ) # TODO: Categorical Series pandas-dev/pandas-stubs#1415 diff --git a/tests/arrays/test_interval_array.py b/tests/arrays/test_interval_array.py index 83985f3ae..b8ac9e868 100644 --- a/tests/arrays/test_interval_array.py +++ b/tests/arrays/test_interval_array.py @@ -7,25 +7,10 @@ def test_constructor() -> None: itv = pd.Interval(0, 1) - check( - assert_type( # type: ignore[assert-type] # I do not understand - pd.array([itv]), IntervalArray - ), - IntervalArray, - ) - check( - assert_type( # type: ignore[assert-type] # I do not understand - pd.array([itv, None]), IntervalArray - ), - IntervalArray, - ) + check(assert_type(pd.array([itv]), IntervalArray), IntervalArray) + check(assert_type(pd.array([itv, None]), IntervalArray), IntervalArray) - check( - assert_type( # type: ignore[assert-type] # I do not understand - pd.array(pd.array([itv])), IntervalArray - ), - IntervalArray, - ) + check(assert_type(pd.array(pd.array([itv])), IntervalArray), IntervalArray) check(assert_type(pd.array(pd.Index([itv])), IntervalArray), IntervalArray) diff --git a/tests/arrays/test_numpy_extension_array.py b/tests/arrays/test_numpy_extension_array.py index 0024fa2cd..5c26d76b6 100644 --- a/tests/arrays/test_numpy_extension_array.py +++ b/tests/arrays/test_numpy_extension_array.py @@ -7,9 +7,9 @@ def test_constructor() -> None: - check( - assert_type(pd.array([pd.NA, None]), NumpyExtensionArray), NumpyExtensionArray - ) + # check( + # assert_type(pd.array([pd.NA, None]), NumpyExtensionArray), NumpyExtensionArray + # ) check( assert_type( # type: ignore[assert-type] # I do not understand @@ -18,15 +18,15 @@ def test_constructor() -> None: NumpyExtensionArray, ) check( - assert_type( # type: ignore[assert-type] # I do not understand, mypy must have problem with two Generic Variables somehow + assert_type( # type: ignore[assert-type] # I do not understand pd.array(np.array([1, "🐼"], np.object_)), NumpyExtensionArray ), NumpyExtensionArray, ) - check( - assert_type(pd.array(pd.array([pd.NA, None])), NumpyExtensionArray), - NumpyExtensionArray, - ) + # check( + # assert_type(pd.array(pd.array([pd.NA, None])), NumpyExtensionArray), + # NumpyExtensionArray, + # ) check( assert_type(pd.array(pd.RangeIndex(0, 1)), NumpyExtensionArray), NumpyExtensionArray, diff --git a/tests/arrays/test_period_array.py b/tests/arrays/test_period_array.py index ec379c1c0..a125036b6 100644 --- a/tests/arrays/test_period_array.py +++ b/tests/arrays/test_period_array.py @@ -7,31 +7,11 @@ def test_constructor() -> None: prd = pd.Period("2023-01-01") - check( - assert_type( # type: ignore[assert-type] # I do not understand - pd.array([prd]), PeriodArray - ), - PeriodArray, - ) - check( - assert_type( # type: ignore[assert-type] # I do not understand - pd.array([prd, None]), PeriodArray - ), - PeriodArray, - ) - check( - assert_type( # type: ignore[assert-type] # I do not understand - pd.array([prd, pd.NaT, None]), PeriodArray - ), - PeriodArray, - ) + 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( # type: ignore[assert-type] # I do not understand - pd.array(pd.array([prd])), PeriodArray - ), - PeriodArray, - ) + check(assert_type(pd.array(pd.array([prd])), PeriodArray), PeriodArray) check(assert_type(pd.array(pd.Index([prd])), PeriodArray), PeriodArray) From 99df68ce2a32e76fd88578e53507e76e07d3e542 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Thu, 13 Nov 2025 18:24:07 +0100 Subject: [PATCH 16/21] test dtype --- pandas-stubs/core/construction.pyi | 3 +-- tests/__init__.py | 12 ++++++++++++ tests/_typing.py | 2 ++ tests/arrays/test_boolean_array.py | 14 +++++++++++++- 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/pandas-stubs/core/construction.pyi b/pandas-stubs/core/construction.pyi index 41b95f939..42087ae70 100644 --- a/pandas-stubs/core/construction.pyi +++ b/pandas-stubs/core/construction.pyi @@ -40,7 +40,6 @@ 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 ( - BuiltinBooleanDtypeArg, BuiltinFloatDtypeArg, BuiltinIntDtypeArg, BuiltinStrDtypeArg, @@ -120,7 +119,7 @@ def array( # type: ignore[overload-overlap] | Index[bool] | Series[int] ), - dtype: BuiltinBooleanDtypeArg | PandasBooleanDtypeArg | None = None, + dtype: PandasBooleanDtypeArg | None = None, copy: bool = True, ) -> BooleanArray: ... @overload diff --git a/tests/__init__.py b/tests/__init__.py index f11a46a34..288365f02 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,5 +1,6 @@ from __future__ import annotations +from collections.abc import Generator from contextlib import ( AbstractContextManager, nullcontext, @@ -242,3 +243,14 @@ def exception_on_platform(dtype: type | str | ExtensionDtype) -> type[Exception] if (WINDOWS or MAC) and dtype in {"f16", "float128"}: return TypeError return None + + +def get_dtype(dtype: object) -> Generator[type | str, None, None]: + """Extract types and string literals from a Union or Literal type.""" + if isinstance(dtype, str): + yield dtype + elif isinstance(dtype, type): + yield dtype() + else: + for arg in get_args(dtype): + yield from get_dtype(arg) diff --git a/tests/_typing.py b/tests/_typing.py index 39441f7e8..45d058241 100644 --- a/tests/_typing.py +++ b/tests/_typing.py @@ -18,6 +18,7 @@ PandasAstypeFloatDtypeArg, PandasAstypeTimedeltaDtypeArg, PandasAstypeTimestampDtypeArg, + PandasBooleanDtypeArg, PandasFloatDtypeArg, StrDtypeArg, TimedeltaDtypeArg, @@ -53,6 +54,7 @@ "np_1darray", "np_2darray", "np_ndarray", + "PandasBooleanDtypeArg", "np_1darray_bool", "BooleanDtypeArg", "BytesDtypeArg", diff --git a/tests/arrays/test_boolean_array.py b/tests/arrays/test_boolean_array.py index 7b3c4c174..1da41e7da 100644 --- a/tests/arrays/test_boolean_array.py +++ b/tests/arrays/test_boolean_array.py @@ -1,9 +1,14 @@ import numpy as np import pandas as pd from pandas.core.arrays.boolean import BooleanArray +import pytest from typing_extensions import assert_type -from tests import check +from tests import ( + check, + get_dtype, +) +from tests._typing import PandasBooleanDtypeArg def test_constructor() -> None: @@ -15,3 +20,10 @@ def test_constructor() -> None: check(assert_type(pd.array(np.array([1], np.bool_)), BooleanArray), BooleanArray) check(assert_type(pd.array(pd.array([True])), BooleanArray), BooleanArray) + + pd.array([True], dtype=pd.BooleanDtype()) + + +@pytest.mark.parametrize("dtype", get_dtype(PandasBooleanDtypeArg)) +def test_constructors_dtype(dtype: PandasBooleanDtypeArg): + check(assert_type(pd.array([True], dtype=dtype), BooleanArray), BooleanArray) From 0f5cdc55e70fa854067b3a5d6f2132076d2922a9 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Fri, 14 Nov 2025 16:43:12 +0100 Subject: [PATCH 17/21] fix 4ea83c77002a9f747aa49ef407dbf694fa323b9a --- pandas-stubs/_typing.pyi | 5 ++++- tests/__init__.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/pandas-stubs/_typing.pyi b/pandas-stubs/_typing.pyi index 2040c8b69..56c387781 100644 --- a/pandas-stubs/_typing.pyi +++ b/pandas-stubs/_typing.pyi @@ -505,7 +505,10 @@ PyArrowTimestampDtypeArg: TypeAlias = Literal[ "timestamp[ns][pyarrow]", ] TimestampDtypeArg: TypeAlias = ( - PandasTimestampDtypeArg | NumpyTimestampDtypeArg | PyArrowTimestampDtypeArg + PandasTimestampDtypeArg + | PandasAstypeTimestampDtypeArg + | NumpyTimestampDtypeArg + | PyArrowTimestampDtypeArg ) # Builtin str type and its string alias BuiltinStrDtypeArg: TypeAlias = type[str] | Literal["str"] diff --git a/tests/__init__.py b/tests/__init__.py index 288365f02..30a0b3392 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -250,7 +250,7 @@ def get_dtype(dtype: object) -> Generator[type | str, None, None]: if isinstance(dtype, str): yield dtype elif isinstance(dtype, type): - yield dtype() + yield dtype() if "pandas" in str(dtype) else dtype else: for arg in get_args(dtype): yield from get_dtype(arg) From bef16f09edf936198fd9a1a0a96bc5d44d3395b6 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Fri, 14 Nov 2025 17:14:13 +0100 Subject: [PATCH 18/21] dtype numpy extension array --- pandas-stubs/core/construction.pyi | 20 ++++++------ tests/_typing.py | 4 +++ tests/arrays/test_datetime_array.py | 8 ++--- tests/arrays/test_integer_array.py | 8 ++--- tests/arrays/test_numpy_extension_array.py | 36 +++++++++++++++++----- tests/arrays/test_timedelta_array.py | 8 ++--- 6 files changed, 48 insertions(+), 36 deletions(-) diff --git a/pandas-stubs/core/construction.pyi b/pandas-stubs/core/construction.pyi index 42087ae70..97c31c8a7 100644 --- a/pandas-stubs/core/construction.pyi +++ b/pandas-stubs/core/construction.pyi @@ -40,12 +40,12 @@ 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 ( - BuiltinFloatDtypeArg, - BuiltinIntDtypeArg, - BuiltinStrDtypeArg, + BuiltinDtypeArg, CategoryDtypeArg, IntervalT, - NumpyDtypeArg, + NumpyNotTimeDtypeArg, + NumpyTimedeltaDtypeArg, + NumpyTimestampDtypeArg, PandasBooleanDtypeArg, PandasFloatDtypeArg, PandasIntDtypeArg, @@ -125,7 +125,7 @@ def array( # type: ignore[overload-overlap] @overload def array( # type: ignore[overload-overlap] data: Sequence[int | np.integer | NAType | None] | np_ndarray_anyint | IntegerArray, - dtype: BuiltinIntDtypeArg | PandasIntDtypeArg | PandasUIntDtypeArg | None = None, + dtype: PandasIntDtypeArg | PandasUIntDtypeArg | None = None, copy: bool = True, ) -> IntegerArray: ... @overload @@ -133,7 +133,7 @@ def array( # type: ignore[overload-overlap] data: ( Sequence[float | np.floating | NAType | None] | np_ndarray_float | FloatingArray ), - dtype: BuiltinFloatDtypeArg | PandasFloatDtypeArg | None = None, + dtype: PandasFloatDtypeArg | None = None, copy: bool = True, ) -> FloatingArray: ... @overload @@ -146,7 +146,7 @@ def array( # type: ignore[overload-overlap] | DatetimeIndex | Series[Timestamp] ), - dtype: PandasTimestampDtypeArg | None = None, + dtype: PandasTimestampDtypeArg | NumpyTimestampDtypeArg | None = None, copy: bool = True, ) -> DatetimeArray: ... @overload @@ -158,13 +158,13 @@ def array( | TimedeltaIndex | Series[Timedelta] ), - dtype: None = None, + dtype: NumpyTimedeltaDtypeArg | None = None, copy: bool = True, ) -> TimedeltaArray: ... @overload def array( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] data: SequenceNotStr[str | np.str_ | NAType | None] | np_ndarray_str | StringArray, - dtype: BuiltinStrDtypeArg | PandasStrDtypeArg | None = None, + dtype: PandasStrDtypeArg | None = None, copy: bool = True, ) -> StringArray: ... @overload @@ -181,7 +181,7 @@ def array( # type: ignore[overload-overlap] @overload def array( data: SequenceNotStr[object] | np_ndarray | NumpyExtensionArray | RangeIndex, - dtype: NumpyDtypeArg | None = None, + dtype: BuiltinDtypeArg | NumpyNotTimeDtypeArg | None = None, copy: bool = True, ) -> NumpyExtensionArray: ... @overload diff --git a/tests/_typing.py b/tests/_typing.py index 45d058241..34bd0511a 100644 --- a/tests/_typing.py +++ b/tests/_typing.py @@ -8,11 +8,13 @@ from pandas._typing import ( BooleanDtypeArg, + BuiltinDtypeArg, BytesDtypeArg, CategoryDtypeArg, ComplexDtypeArg, FloatDtypeArg, IntDtypeArg, + NumpyNotTimeDtypeArg, ObjectDtypeArg, PandasAstypeComplexDtypeArg, PandasAstypeFloatDtypeArg, @@ -62,6 +64,8 @@ "ComplexDtypeArg", "IntDtypeArg", "np_ndarray_str", + "BuiltinDtypeArg", + "NumpyNotTimeDtypeArg", "ObjectDtypeArg", "PandasAstypeComplexDtypeArg", "PandasAstypeTimedeltaDtypeArg", diff --git a/tests/arrays/test_datetime_array.py b/tests/arrays/test_datetime_array.py index 8f339fcda..70d59b868 100644 --- a/tests/arrays/test_datetime_array.py +++ b/tests/arrays/test_datetime_array.py @@ -24,12 +24,8 @@ def test_constructor() -> None: dt_nat = cast(list[np.datetime64 | NaTType], [np_dt, pd.NaT]) check(assert_type(pd.array(dt_nat), DatetimeArray), DatetimeArray) - check( - assert_type( # type: ignore[assert-type] # I do not understand - pd.array(np.array([dt], np.datetime64)), 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) diff --git a/tests/arrays/test_integer_array.py b/tests/arrays/test_integer_array.py index a5973eac6..05430a756 100644 --- a/tests/arrays/test_integer_array.py +++ b/tests/arrays/test_integer_array.py @@ -12,11 +12,7 @@ def test_constructor() -> None: check(assert_type(pd.array([1, None]), IntegerArray), IntegerArray) check(assert_type(pd.array([1, pd.NA, None]), IntegerArray), IntegerArray) - check( - assert_type( # type: ignore[assert-type] # I do not understand - pd.array(np.array([1], np.int64)), IntegerArray - ), - IntegerArray, - ) + np_arr = np.array([1], np.int64) + check(assert_type(pd.array(np_arr), IntegerArray), IntegerArray) check(assert_type(pd.array(pd.array([1])), IntegerArray), IntegerArray) diff --git a/tests/arrays/test_numpy_extension_array.py b/tests/arrays/test_numpy_extension_array.py index 5c26d76b6..457c57a23 100644 --- a/tests/arrays/test_numpy_extension_array.py +++ b/tests/arrays/test_numpy_extension_array.py @@ -1,9 +1,17 @@ import numpy as np import pandas as pd from pandas.core.arrays.numpy_ import NumpyExtensionArray +import pytest from typing_extensions import assert_type -from tests import check +from tests import ( + check, + get_dtype, +) +from tests._typing import ( + BuiltinDtypeArg, + NumpyNotTimeDtypeArg, +) def test_constructor() -> None: @@ -11,18 +19,16 @@ def test_constructor() -> None: # assert_type(pd.array([pd.NA, None]), NumpyExtensionArray), NumpyExtensionArray # ) + pd_arr = pd.array([1, "🐼"]) check( assert_type( # type: ignore[assert-type] # I do not understand - pd.array([1, "🐼"]), NumpyExtensionArray - ), - NumpyExtensionArray, - ) - check( - assert_type( # type: ignore[assert-type] # I do not understand - pd.array(np.array([1, "🐼"], np.object_)), NumpyExtensionArray + pd_arr, NumpyExtensionArray ), NumpyExtensionArray, ) + + np_arr = np.array([1, "🐼"], np.object_) + check(assert_type(pd.array(np_arr), NumpyExtensionArray), NumpyExtensionArray) # check( # assert_type(pd.array(pd.array([pd.NA, None])), NumpyExtensionArray), # NumpyExtensionArray, @@ -31,3 +37,17 @@ def test_constructor() -> None: assert_type(pd.array(pd.RangeIndex(0, 1)), NumpyExtensionArray), NumpyExtensionArray, ) + + +@pytest.mark.parametrize("dtype", get_dtype(BuiltinDtypeArg | NumpyNotTimeDtypeArg)) +def test_constructors_dtype(dtype: BuiltinDtypeArg | NumpyNotTimeDtypeArg): + if dtype == "V" or "void" in str(dtype): + check( + assert_type(pd.array([b"1"], dtype=dtype), NumpyExtensionArray), + NumpyExtensionArray, + ) + else: + check( + assert_type(pd.array([1], dtype=dtype), NumpyExtensionArray), + NumpyExtensionArray, + ) diff --git a/tests/arrays/test_timedelta_array.py b/tests/arrays/test_timedelta_array.py index 70d645eae..48d710f01 100644 --- a/tests/arrays/test_timedelta_array.py +++ b/tests/arrays/test_timedelta_array.py @@ -19,12 +19,8 @@ def test_constructor() -> None: check(assert_type(pd.array([td, None]), TimedeltaArray), TimedeltaArray) check(assert_type(pd.array([td, pd.NaT, None]), TimedeltaArray), TimedeltaArray) - check( - assert_type( # type: ignore[assert-type] # I do not understand - pd.array(np.array([td], np.timedelta64)), TimedeltaArray - ), - TimedeltaArray, - ) + np_arr = np.array([td], np.timedelta64) + check(assert_type(pd.array(np_arr), TimedeltaArray), TimedeltaArray) check(assert_type(pd.array(pd.array([td])), TimedeltaArray), TimedeltaArray) From 7ba77074bf4339bfe27eb9fe238e5ec3acf19042 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Fri, 14 Nov 2025 17:52:19 +0100 Subject: [PATCH 19/21] fix: py310 --- tests/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/__init__.py b/tests/__init__.py index 30a0b3392..65f1bf39c 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -249,7 +249,8 @@ def get_dtype(dtype: object) -> Generator[type | str, None, None]: """Extract types and string literals from a Union or Literal type.""" if isinstance(dtype, str): yield dtype - elif isinstance(dtype, type): + elif isinstance(dtype, type) and not str(dtype).startswith("type["): + # isinstance(type[bool], type) in py310, but not in newer versions yield dtype() if "pandas" in str(dtype) else dtype else: for arg in get_args(dtype): From 06e3222bad5eff1f2736364ea145e238dea1dd95 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Fri, 14 Nov 2025 21:44:13 +0100 Subject: [PATCH 20/21] floating --- pandas-stubs/_typing.pyi | 5 +---- tests/arrays/test_boolean_array.py | 2 +- tests/arrays/test_numpy_extension_array.py | 16 +++++++++++----- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/pandas-stubs/_typing.pyi b/pandas-stubs/_typing.pyi index 56c387781..2040c8b69 100644 --- a/pandas-stubs/_typing.pyi +++ b/pandas-stubs/_typing.pyi @@ -505,10 +505,7 @@ PyArrowTimestampDtypeArg: TypeAlias = Literal[ "timestamp[ns][pyarrow]", ] TimestampDtypeArg: TypeAlias = ( - PandasTimestampDtypeArg - | PandasAstypeTimestampDtypeArg - | NumpyTimestampDtypeArg - | PyArrowTimestampDtypeArg + PandasTimestampDtypeArg | NumpyTimestampDtypeArg | PyArrowTimestampDtypeArg ) # Builtin str type and its string alias BuiltinStrDtypeArg: TypeAlias = type[str] | Literal["str"] diff --git a/tests/arrays/test_boolean_array.py b/tests/arrays/test_boolean_array.py index 1da41e7da..7287de24c 100644 --- a/tests/arrays/test_boolean_array.py +++ b/tests/arrays/test_boolean_array.py @@ -25,5 +25,5 @@ def test_constructor() -> None: @pytest.mark.parametrize("dtype", get_dtype(PandasBooleanDtypeArg)) -def test_constructors_dtype(dtype: PandasBooleanDtypeArg): +def test_constructor_dtype(dtype: PandasBooleanDtypeArg): check(assert_type(pd.array([True], dtype=dtype), BooleanArray), BooleanArray) diff --git a/tests/arrays/test_numpy_extension_array.py b/tests/arrays/test_numpy_extension_array.py index 457c57a23..621492c67 100644 --- a/tests/arrays/test_numpy_extension_array.py +++ b/tests/arrays/test_numpy_extension_array.py @@ -6,6 +6,7 @@ from tests import ( check, + exception_on_platform, get_dtype, ) from tests._typing import ( @@ -40,14 +41,19 @@ def test_constructor() -> None: @pytest.mark.parametrize("dtype", get_dtype(BuiltinDtypeArg | NumpyNotTimeDtypeArg)) -def test_constructors_dtype(dtype: BuiltinDtypeArg | NumpyNotTimeDtypeArg): +def test_constructor_dtype(dtype: BuiltinDtypeArg | NumpyNotTimeDtypeArg): if dtype == "V" or "void" in str(dtype): check( assert_type(pd.array([b"1"], dtype=dtype), NumpyExtensionArray), NumpyExtensionArray, ) else: - check( - assert_type(pd.array([1], dtype=dtype), NumpyExtensionArray), - NumpyExtensionArray, - ) + exc = exception_on_platform(dtype) + if exc: + with pytest.raises(exc): + pd.array([1], dtype=dtype) + else: + check( + assert_type(pd.array([1], dtype=dtype), NumpyExtensionArray), + NumpyExtensionArray, + ) From 86b2110c92a7a86fd072303c167c05d425c158c2 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Thu, 4 Dec 2025 14:26:24 +0100 Subject: [PATCH 21/21] pyright --- pandas-stubs/core/construction.pyi | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/pandas-stubs/core/construction.pyi b/pandas-stubs/core/construction.pyi index 97c31c8a7..df7195b58 100644 --- a/pandas-stubs/core/construction.pyi +++ b/pandas-stubs/core/construction.pyi @@ -77,7 +77,7 @@ from pandas.core.dtypes.dtypes import ( # copy: bool = True # ) -> NumpyExtensionArray: ... @overload -def array( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] +def array( # type: ignore[overload-overlap] data: SequenceNotStr[Any] | np_ndarray | ExtensionArray | Index | Series, dtype: CategoryDtypeArg, copy: bool = True, @@ -111,14 +111,8 @@ def array( copy: bool = True, ) -> SparseArray: ... @overload -def array( # type: ignore[overload-overlap] - data: ( - Sequence[bool | np.bool | NAType | None] - | np_ndarray_bool - | BooleanArray - | Index[bool] - | Series[int] - ), +def array( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + data: Sequence[bool | np.bool | NAType | None] | np_ndarray_bool | BooleanArray, dtype: PandasBooleanDtypeArg | None = None, copy: bool = True, ) -> BooleanArray: ...