diff --git a/src/_numtype/op.pyi b/src/_numtype/op.pyi index 24d35fbe..4ddf77cd 100644 --- a/src/_numtype/op.pyi +++ b/src/_numtype/op.pyi @@ -40,7 +40,7 @@ __all__ = [ # noqa: RUF022 ### -_T_contra = TypeVar("_T_contra", contravariant=True, default=object) +_T_contra = TypeVar("_T_contra", contravariant=True, default=Any) _T_co = TypeVar("_T_co", covariant=True, default=Any) ### diff --git a/src/numpy-stubs/@test/static/accept/ctypeslib.pyi b/src/numpy-stubs/@test/static/accept/ctypeslib.pyi index 923f5f50..14b31d1e 100644 --- a/src/numpy-stubs/@test/static/accept/ctypeslib.pyi +++ b/src/numpy-stubs/@test/static/accept/ctypeslib.pyi @@ -78,6 +78,3 @@ assert_type(np.ctypeslib.as_ctypes(AR_f8), ct.Array[ct.c_double]) assert_type(np.ctypeslib.as_array(AR_u1), npt.NDArray[np.ubyte]) assert_type(np.ctypeslib.as_array(1), npt.NDArray[Any]) assert_type(np.ctypeslib.as_array(pointer), npt.NDArray[Any]) - -assert_type(np.ctypeslib.as_ctypes_type(int), type[ct.c_ssize_t]) -assert_type(np.ctypeslib.as_ctypes_type("N"), type[ct.c_size_t]) diff --git a/src/numpy-stubs/__init__.pyi b/src/numpy-stubs/__init__.pyi index 34fc7460..0529f9f2 100644 --- a/src/numpy-stubs/__init__.pyi +++ b/src/numpy-stubs/__init__.pyi @@ -1017,6 +1017,14 @@ _HasDTypeWithItem: TypeAlias = _HasDType[_HasTypeWithItem[_T]] _HasDTypeWithReal: TypeAlias = _HasDType[_HasTypeWithReal[_T]] _HasDTypeWithImag: TypeAlias = _HasDType[_HasTypeWithImag[_T]] +_CT = TypeVar("_CT", bound=ct._SimpleCData[Any]) +_CT_co = TypeVar("_CT_co", bound=ct._SimpleCData[Any], covariant=True) + +@type_check_only +class _HasCType(Protocol[_CT_co]): + @property + def __ctype__(self, /) -> _CT_co: ... + @type_check_only class _HasDateAttributes(Protocol): # The `datetime64` constructors requires an object with the three attributes below, @@ -1028,22 +1036,6 @@ class _HasDateAttributes(Protocol): @property def year(self) -> int: ... -@type_check_only -class _CanLT(Protocol): - def __lt__(self, x: Any, /) -> Any: ... - -@type_check_only -class _CanLE(Protocol): - def __le__(self, x: Any, /) -> Any: ... - -@type_check_only -class _CanGT(Protocol): - def __gt__(self, x: Any, /) -> Any: ... - -@type_check_only -class _CanGE(Protocol): - def __ge__(self, x: Any, /) -> Any: ... - ### # Mixins (for internal use only) @@ -1077,33 +1069,33 @@ class _CmpOpMixin(Generic[_ScalarLikeT_contra, _ArrayLikeT_contra]): @overload def __lt__(self, x: _ScalarLikeT_contra, /) -> bool_: ... @overload - def __lt__(self, x: _ArrayLikeT_contra | _NestedSequence[_CanGT], /) -> NDArray[bool_]: ... + def __lt__(self, x: _ArrayLikeT_contra | _NestedSequence[_nt.op.CanGt], /) -> NDArray[bool_]: ... @overload - def __lt__(self, x: _CanGT, /) -> bool_: ... + def __lt__(self, x: _nt.op.CanGt, /) -> bool_: ... # @overload def __le__(self, x: _ScalarLikeT_contra, /) -> bool_: ... @overload - def __le__(self, x: _ArrayLikeT_contra | _NestedSequence[_CanGE], /) -> NDArray[bool_]: ... + def __le__(self, x: _ArrayLikeT_contra | _NestedSequence[_nt.op.CanGe], /) -> NDArray[bool_]: ... @overload - def __le__(self, x: _CanGE, /) -> bool_: ... + def __le__(self, x: _nt.op.CanGe, /) -> bool_: ... # @overload def __gt__(self, x: _ScalarLikeT_contra, /) -> bool_: ... @overload - def __gt__(self, x: _ArrayLikeT_contra | _NestedSequence[_CanLT], /) -> NDArray[bool_]: ... + def __gt__(self, x: _ArrayLikeT_contra | _NestedSequence[_nt.op.CanLt], /) -> NDArray[bool_]: ... @overload - def __gt__(self, x: _CanLT, /) -> bool_: ... + def __gt__(self, x: _nt.op.CanLt, /) -> bool_: ... # @overload def __ge__(self, x: _ScalarLikeT_contra, /) -> bool_: ... @overload - def __ge__(self, x: _ArrayLikeT_contra | _NestedSequence[_CanLE], /) -> NDArray[bool_]: ... + def __ge__(self, x: _ArrayLikeT_contra | _NestedSequence[_nt.op.CanLe], /) -> NDArray[bool_]: ... @overload - def __ge__(self, x: _CanLE, /) -> bool_: ... + def __ge__(self, x: _nt.op.CanLe, /) -> bool_: ... @type_check_only class _IntMixin(Generic[_IntSizeT_co]): @@ -1908,6 +1900,11 @@ class _ArrayOrScalarCommon: class ndarray(_ArrayOrScalarCommon, Generic[_ShapeT_co, _DTypeT_co]): __hash__: ClassVar[None] # type: ignore[assignment] # pyright: ignore[reportIncompatibleMethodOverride] + # + @property + @type_check_only + def __ctype__(self: _HasDType[_HasType[_HasCType[_CT]]], /) -> ct.Array[_CT]: ... + # @property def base(self) -> NDArray[Any] | None: ... @@ -3927,6 +3924,11 @@ class generic(_ArrayOrScalarCommon, Generic[_ItemT_co]): # NOTE: Naming it `bool_` results in less unreadable type-checker output class bool_(generic[_BoolItemT_co], Generic[_BoolItemT_co]): + @property + @type_check_only + def __ctype__(self) -> ct.c_bool: ... + + # @type_check_only def __nep50__(self, below: _nt.co_number | timedelta64, above: Never, /) -> bool_: ... @type_check_only @@ -4386,7 +4388,6 @@ class number(_CmpOpMixin[_nt.CoComplex_0d, _nt.CoComplex_1nd], generic[_NumberIt @abc.abstractmethod @type_check_only def __nep50_complex__(self, /) -> complexfloating: ... - # @type_check_only def __nep50_rule6__(self, other: _JustNumber, /) -> number: ... @@ -4682,6 +4683,11 @@ class signedinteger(integer): def __nep50_rule5__(self, other: _JustInteger | _JustUnsignedInteger, /) -> signedinteger | float64: ... class int8(_IntMixin[L[1]], signedinteger): + @property + @type_check_only + def __ctype__(self) -> ct.c_int8: ... + + # @override @type_check_only def __nep50__( @@ -4703,6 +4709,11 @@ class int8(_IntMixin[L[1]], signedinteger): byte = int8 class int16(_IntMixin[L[2]], signedinteger): + @property + @type_check_only + def __ctype__(self) -> ct.c_int16: ... + + # @override @type_check_only def __nep50__( @@ -4724,6 +4735,11 @@ class int16(_IntMixin[L[2]], signedinteger): short = int16 class int32(_IntMixin[L[4]], signedinteger): + @property + @type_check_only + def __ctype__(self) -> ct.c_int32: ... + + # @override @type_check_only def __nep50__( @@ -4748,6 +4764,11 @@ class int32(_IntMixin[L[4]], signedinteger): intc = int32 class int64(_IntMixin[L[8]], signedinteger): + @property + @type_check_only + def __ctype__(self) -> ct.c_int64: ... + + # @override @type_check_only def __nep50__( @@ -4799,6 +4820,11 @@ class unsignedinteger(integer): def __nep50_rule3__(self, other: _JustUnsignedInteger, /) -> unsignedinteger: ... class uint8(_IntMixin[L[1]], unsignedinteger): + @property + @type_check_only + def __ctype__(self) -> ct.c_uint8: ... + + # @override @type_check_only def __nep50__( @@ -4824,6 +4850,11 @@ class uint8(_IntMixin[L[1]], unsignedinteger): ubyte = uint8 class uint16(_IntMixin[L[2]], unsignedinteger): + @property + @type_check_only + def __ctype__(self) -> ct.c_uint16: ... + + # @override @type_check_only def __nep50__( @@ -4851,6 +4882,11 @@ class uint16(_IntMixin[L[2]], unsignedinteger): ushort = uint16 class uint32(_IntMixin[L[4]], unsignedinteger): + @property + @type_check_only + def __ctype__(self) -> ct.c_uint32: ... + + # @override @type_check_only def __nep50__( @@ -4878,6 +4914,11 @@ class uint32(_IntMixin[L[4]], unsignedinteger): uintc = uint32 class uint64(_IntMixin[L[8]], unsignedinteger): + @property + @type_check_only + def __ctype__(self) -> ct.c_uint64: ... + + # @override @type_check_only def __nep50__( @@ -5021,6 +5062,11 @@ class float16(_FloatMixin[L[2]], floating): half = float16 class float32(_FloatMixin[L[4]], floating): + @property + @type_check_only + def __ctype__(self) -> ct.c_float: ... + + # @override @type_check_only def __nep50__(self, below: _float32_min | complexfloating, above: float16 | _nt.co_integer16, /) -> float32: ... @@ -5040,6 +5086,11 @@ class float32(_FloatMixin[L[4]], floating): single = float32 class float64(_FloatMixin[L[8]], floating, float): # type: ignore[misc] + @property + @type_check_only + def __ctype__(self) -> ct.c_double: ... + + # @override @type_check_only def __nep50__(self, below: _inexact64_min, above: _float32_max | _nt.co_integer, /) -> float64: ... @@ -5076,6 +5127,11 @@ class float64(_FloatMixin[L[8]], floating, float): # type: ignore[misc] double = float64 class longdouble(_FloatMixin[L[12, 16]], floating): + @property + @type_check_only + def __ctype__(self) -> ct.c_longdouble: ... + + # @override @type_check_only def __nep50__( diff --git a/src/numpy-stubs/ctypeslib.pyi b/src/numpy-stubs/ctypeslib.pyi index c8b43ec1..3f077a91 100644 --- a/src/numpy-stubs/ctypeslib.pyi +++ b/src/numpy-stubs/ctypeslib.pyi @@ -2,31 +2,15 @@ import _ctypes as _ct import ctypes as ct from _typeshed import StrOrBytesPath from collections.abc import Iterable, Sequence -from typing import Any, ClassVar, Generic, Literal as L, TypeAlias, overload +from typing import Any, ClassVar, Generic, Literal as L, Protocol, TypeAlias, overload, type_check_only from typing_extensions import TypeVar import _numtype as _nt import numpy as np from numpy._core._internal import _ctypes from numpy._core.multiarray import flagsobj -from numpy._typing import _ArrayLike, _BoolCodes, _DTypeLike, _Shape, _ShapeLike, _VoidDTypeLike -from numpy._typing._char_codes import ( - _Float32Codes, - _Float64Codes, - _Int8Codes, - _Int16Codes, - _Int32Codes, - _Int64Codes, - _IntPCodes, - _LongCodes, - _LongDoubleCodes, - _UInt8Codes, - _UInt16Codes, - _UInt32Codes, - _UInt64Codes, - _UIntPCodes, - _ULongCodes, -) +from numpy._typing import _ArrayLike, _DTypeLike, _Shape, _ShapeLike, _VoidDTypeLike +from numpy._typing._char_codes import _LongCodes, _ULongCodes __all__ = ["as_array", "as_ctypes", "as_ctypes_type", "c_intp", "load_library", "ndpointer"] @@ -51,6 +35,16 @@ _FlagsKind: TypeAlias = L[ ### +_CT = TypeVar("_CT", bound=ct._CData) +_CT_co = TypeVar("_CT_co", bound=ct._CData, covariant=True) + +@type_check_only +class _HasCType(Protocol[_CT_co]): + @property + def __ctype__(self, /) -> _CT_co: ... + +### + c_intp = ct.c_ssize_t class _ndptr(ct.c_void_p, Generic[_DTypeT0_co, _ShapeT0_co]): @@ -122,97 +116,38 @@ def as_array(obj: _ArrayLike[_ScalarT], shape: _ShapeLike | None = ...) -> _nt.A @overload def as_array(obj: object, shape: _ShapeLike | None = ...) -> _nt.Array[Any]: ... -# NOTE: The overlapping overloads ignores are a temporary workaround for the non-unique -# intp/long/longlong issues, and otherwise mypy false positives. -# NOTE: `as_ctypes` doesn't support `void` values at the moment -@overload # bool -def as_ctypes(obj: np.bool) -> ct.c_bool: ... -@overload -def as_ctypes(obj: _nt.Array[np.bool]) -> ct.Array[ct.c_bool]: ... -@overload # int8 / byte -def as_ctypes(obj: np.int8) -> ct.c_int8: ... -@overload -def as_ctypes(obj: _nt.Array[np.int8]) -> ct.Array[ct.c_int8]: ... -@overload # int16 / short -def as_ctypes(obj: np.int16) -> ct.c_int16: ... -@overload -def as_ctypes(obj: _nt.Array[np.int16]) -> ct.Array[ct.c_int16]: ... -@overload # int32 / int[c] -def as_ctypes(obj: np.int32) -> ct.c_int32: ... -@overload -def as_ctypes(obj: _nt.Array[np.int32]) -> ct.Array[ct.c_int32]: ... -@overload # int64 / longlong (which might be an alias for for `long`) -def as_ctypes(obj: np.int64) -> ct.c_int64: ... -@overload -def as_ctypes(obj: _nt.Array[np.int64]) -> ct.Array[ct.c_int64]: ... -@overload # uint8 / ubyte -def as_ctypes(obj: np.uint8) -> ct.c_uint8: ... -@overload -def as_ctypes(obj: _nt.Array[np.uint8]) -> ct.Array[ct.c_uint8]: ... -@overload # uint16 / ushort -def as_ctypes(obj: np.uint16) -> ct.c_uint16: ... -@overload -def as_ctypes(obj: _nt.Array[np.uint16]) -> ct.Array[ct.c_uint16]: ... -@overload # uint32 / uint -def as_ctypes(obj: np.uint32) -> ct.c_uint32: ... -@overload -def as_ctypes(obj: _nt.Array[np.uint32]) -> ct.Array[ct.c_uint32]: ... -@overload # uint64 / ulonglong -def as_ctypes(obj: np.uint64) -> ct.c_uint64: ... -@overload -def as_ctypes(obj: _nt.Array[np.uint64]) -> ct.Array[ct.c_uint64]: ... -@overload # float32 / single / float -def as_ctypes(obj: np.float32) -> ct.c_float: ... -@overload -def as_ctypes(obj: _nt.Array[np.float32]) -> ct.Array[ct.c_float]: ... -@overload # float64 / double -def as_ctypes(obj: np.float64) -> ct.c_double: ... -@overload -def as_ctypes(obj: _nt.Array[np.float64]) -> ct.Array[ct.c_double]: ... -@overload # float96 / float128 / longdouble -def as_ctypes(obj: np.longdouble) -> ct.c_longdouble: ... -@overload -def as_ctypes(obj: _nt.Array[np.longdouble]) -> ct.Array[ct.c_longdouble]: ... +# +def as_ctypes(obj: _HasCType[_CT]) -> _CT: ... -# TODO(jorenham): https://github.com/numpy/numtype/issues/522 +# @overload -def as_ctypes_type(dtype: _DTypeLike[np.bool] | type[bool | ct.c_bool] | _BoolCodes) -> type[ct.c_bool]: ... +def as_ctypes_type(dtype: _nt.ToDTypeBool) -> type[ct.c_bool]: ... @overload -def as_ctypes_type(dtype: _DTypeLike[np.int8] | type[ct.c_int8 | ct.c_byte] | _Int8Codes) -> type[ct.c_int8]: ... +def as_ctypes_type(dtype: _nt.ToDTypeInt8) -> type[ct.c_int8]: ... @overload -def as_ctypes_type(dtype: _DTypeLike[np.int16] | type[ct.c_int16 | ct.c_short] | _Int16Codes) -> type[ct.c_int16]: ... +def as_ctypes_type(dtype: _nt.ToDTypeUInt8) -> type[ct.c_uint8]: ... @overload -def as_ctypes_type(dtype: _DTypeLike[np.int32] | type[ct.c_int32 | ct.c_int] | _Int32Codes) -> type[ct.c_int32]: ... +def as_ctypes_type(dtype: _nt.ToDTypeInt16) -> type[ct.c_int16]: ... @overload -def as_ctypes_type(dtype: type[ct.c_long] | _LongCodes) -> type[ct.c_long]: ... +def as_ctypes_type(dtype: _nt.ToDTypeUInt16) -> type[ct.c_uint16]: ... @overload -def as_ctypes_type(dtype: type[_nt.JustInt | ct.c_ssize_t] | _IntPCodes) -> type[ct.c_ssize_t]: ... +def as_ctypes_type(dtype: _nt.ToDTypeInt32) -> type[ct.c_int32]: ... @overload -def as_ctypes_type(dtype: _DTypeLike[np.int64] | type[ct.c_int64] | _Int64Codes) -> type[ct.c_int64]: ... +def as_ctypes_type(dtype: _nt.ToDTypeUInt32) -> type[ct.c_uint32]: ... @overload -def as_ctypes_type(dtype: _DTypeLike[np.uint8] | type[ct.c_uint8 | ct.c_ubyte] | _UInt8Codes) -> type[ct.c_uint8]: ... +def as_ctypes_type(dtype: _nt.ToDTypeInt64) -> type[ct.c_int64]: ... @overload -def as_ctypes_type( - dtype: _DTypeLike[np.uint16] | type[ct.c_uint16 | ct.c_ushort] | _UInt16Codes, -) -> type[ct.c_uint16]: ... +def as_ctypes_type(dtype: _nt.ToDTypeUInt64) -> type[ct.c_uint64]: ... @overload -def as_ctypes_type( - dtype: _DTypeLike[np.uint32] | type[ct.c_uint32 | ct.c_uint] | _UInt32Codes, -) -> type[ct.c_uint32]: ... +def as_ctypes_type(dtype: type[ct.c_long] | _LongCodes) -> type[ct.c_long]: ... @overload def as_ctypes_type(dtype: type[ct.c_ulong] | _ULongCodes) -> type[ct.c_ulong]: ... @overload -def as_ctypes_type(dtype: type[ct.c_void_p | ct.c_size_t] | _UIntPCodes) -> type[ct.c_size_t]: ... -@overload -def as_ctypes_type(dtype: _DTypeLike[np.uint64] | type[ct.c_uint64] | _UInt64Codes) -> type[ct.c_uint64]: ... -@overload -def as_ctypes_type(dtype: _DTypeLike[np.float32] | type[ct.c_float] | _Float32Codes) -> type[ct.c_float]: ... +def as_ctypes_type(dtype: _nt.ToDTypeFloat32) -> type[ct.c_float]: ... @overload -def as_ctypes_type(dtype: _DTypeLike[np.float64] | type[ct.c_double] | _Float64Codes) -> type[ct.c_double]: ... +def as_ctypes_type(dtype: _nt.ToDTypeFloat64) -> type[ct.c_double]: ... @overload -def as_ctypes_type( - dtype: _DTypeLike[np.longdouble] | type[ct.c_longdouble] | _LongDoubleCodes, -) -> type[ct.c_longdouble]: ... +def as_ctypes_type(dtype: _nt.ToDTypeLongDouble) -> type[ct.c_longdouble]: ... @overload def as_ctypes_type(dtype: _VoidDTypeLike) -> _ct._UnionType | _ct._PyCStructType: ... @overload