From fd4eee3f6bf7d113d22ff8c2a85dd359d13016bd Mon Sep 17 00:00:00 2001 From: jorenham Date: Wed, 24 Dec 2025 15:49:00 +0100 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=91=BD=EF=B8=8F=20`=5F=5Fnumpy=5Fdtyp?= =?UTF-8?q?e=5F=5F`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/numpy-stubs/_typing/_dtype_like.pyi | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/numpy-stubs/_typing/_dtype_like.pyi b/src/numpy-stubs/_typing/_dtype_like.pyi index db4ee6ca..afce7049 100644 --- a/src/numpy-stubs/_typing/_dtype_like.pyi +++ b/src/numpy-stubs/_typing/_dtype_like.pyi @@ -1,6 +1,6 @@ from _typeshed import Incomplete from collections.abc import Sequence -from typing import Any, Protocol, Required, TypeAlias, TypedDict, runtime_checkable +from typing import Any, Protocol, Required, TypeAlias, TypedDict, type_check_only from typing_extensions import TypeVar import numpy as np @@ -21,11 +21,13 @@ from ._char_codes import ( ) _ScalarT = TypeVar("_ScalarT", bound=np.generic) +_DTypeT = TypeVar("_DTypeT", bound=np.dtype) _DTypeT_co = TypeVar("_DTypeT_co", covariant=True, bound=np.dtype) # TODO(jorenham): Actually annotate this _DTypeLikeNested: TypeAlias = Incomplete +@type_check_only class _DTypeDict(TypedDict, total=False): names: Required[Sequence[str]] formats: Required[Sequence[_DTypeLikeNested]] @@ -36,11 +38,17 @@ class _DTypeDict(TypedDict, total=False): # but `titles` can in principle accept any object titles: Sequence[Any] -# A protocol for anything with the dtype attribute -@runtime_checkable -class _SupportsDType(Protocol[_DTypeT_co]): +@type_check_only +class _HasDTypeLegacy(Protocol[_DTypeT_co]): @property - def dtype(self) -> _DTypeT_co: ... + def dtype(self, /) -> _DTypeT_co: ... + +@type_check_only +class _HasDType(Protocol[_DTypeT_co]): + @property + def __numpy_dtype__(self, /) -> _DTypeT_co: ... + +_SupportsDType: TypeAlias = _HasDType[_DTypeT] | _HasDTypeLegacy[_DTypeT] # A subset of `npt.DTypeLike` that can be parametrized w.r.t. `np.generic` _DTypeLike: TypeAlias = type[_ScalarT] | np.dtype[_ScalarT] | _SupportsDType[np.dtype[_ScalarT]] From 1d9e4b0d81d26f7f619a16a559157022d284f865 Mon Sep 17 00:00:00 2001 From: jorenham Date: Wed, 24 Dec 2025 16:02:16 +0100 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=8F=B7=EF=B8=8F=20also=20support=20`?= =?UTF-8?q?=5F=5Fnumpy=5Fdtype=5F=5F`=20in=20`=5Fnumtype`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/_numtype/_dtype.pyi | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/_numtype/_dtype.pyi b/src/_numtype/_dtype.pyi index 43dd52c3..e0e873b9 100644 --- a/src/_numtype/_dtype.pyi +++ b/src/_numtype/_dtype.pyi @@ -72,18 +72,33 @@ __all__ = [ _T = TypeVar("_T") _ScalarT = TypeVar("_ScalarT", bound=np.generic) _ScalarT_co = TypeVar("_ScalarT_co", bound=np.generic, covariant=True, default=Any) +_DTypeT = TypeVar("_DTypeT", bound=np.dtype) _DTypeT_co = TypeVar("_DTypeT_co", bound=np.dtype, covariant=True, default=np.dtype) @type_check_only -class _HasDType(Protocol[_DTypeT_co]): +class _HasDTypeOld(Protocol[_DTypeT_co]): @property def dtype(self) -> _DTypeT_co: ... @type_check_only -class _HasDTypeOf(Protocol[_ScalarT_co]): +class _HasDTypeNew(Protocol[_DTypeT_co]): + @property + def __numpy_dtype__(self) -> _DTypeT_co: ... + +_HasDType = TypeAliasType("_HasDType", _HasDTypeNew[_DTypeT] | _HasDTypeOld[_DTypeT], type_params=(_DTypeT,)) + +@type_check_only +class _HasDTypeOldOf(Protocol[_ScalarT_co]): @property def dtype(self) -> np.dtype[_ScalarT_co]: ... +@type_check_only +class _HasDTypeNewOf(Protocol[_ScalarT_co]): + @property + def __numpy_dtype__(self) -> np.dtype[_ScalarT_co]: ... + +_HasDTypeOf = TypeAliasType("_HasDTypeOf", _HasDTypeNewOf[_ScalarT] | _HasDTypeOldOf[_ScalarT], type_params=(_ScalarT,)) + _ToDType = TypeAliasType( "_ToDType", type[_ScalarT] | np.dtype[_ScalarT] | _HasDTypeOf[_ScalarT], type_params=(_ScalarT,) )