Skip to content
30 changes: 15 additions & 15 deletions src/_numtype/@test/test_nep50.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ i1_from_c16: CanCast0D[np.int8] = c16 # type: ignore[assignment] # pyright: ig
i1_from_cld: CanCast0D[np.int8] = cld # type: ignore[assignment] # pyright: ignore[reportAssignmentType]

i1_to_b1: CanCast0D[Any, np.int8] = b1 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
i1_to_i1: CanCast0D[Any, np.int8] = i1
i1_to_i1: CanCast0D[Any, np.int8] = i1 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
i1_to_u1: CanCast0D[Any, np.int8] = u1 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
i1_to_i2: CanCast0D[Any, np.int8] = i2
i1_to_u2: CanCast0D[Any, np.int8] = u2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
Expand Down Expand Up @@ -110,7 +110,7 @@ u1_from_cld: CanCast0D[np.uint8] = cld # type: ignore[assignment] # pyright: i

u1_to_b1: CanCast0D[Any, np.uint8] = b1 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
u1_to_i1: CanCast0D[Any, np.uint8] = i1 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
u1_to_u1: CanCast0D[Any, np.uint8] = u1
u1_to_u1: CanCast0D[Any, np.uint8] = u1 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
u1_to_i2: CanCast0D[Any, np.uint8] = i2
u1_to_u2: CanCast0D[Any, np.uint8] = u2
u1_to_i4: CanCast0D[Any, np.uint8] = i4
Expand Down Expand Up @@ -145,7 +145,7 @@ i2_from_cld: CanCast0D[np.int16] = cld # type: ignore[assignment] # pyright: i
i2_to_b1: CanCast0D[Any, np.int16] = b1 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
i2_to_i1: CanCast0D[Any, np.int16] = i1 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
i2_to_u1: CanCast0D[Any, np.int16] = u1 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
i2_to_i2: CanCast0D[Any, np.int16] = i2
i2_to_i2: CanCast0D[Any, np.int16] = i2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
i2_to_u2: CanCast0D[Any, np.int16] = u2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
i2_to_i4: CanCast0D[Any, np.int16] = i4
i2_to_u4: CanCast0D[Any, np.int16] = u4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
Expand Down Expand Up @@ -180,7 +180,7 @@ u2_to_b1: CanCast0D[Any, np.uint16] = b1 # type: ignore[assignment] # pyright:
u2_to_i1: CanCast0D[Any, np.uint16] = i1 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
u2_to_u1: CanCast0D[Any, np.uint16] = u1 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
u2_to_i2: CanCast0D[Any, np.uint16] = i2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
u2_to_u2: CanCast0D[Any, np.uint16] = u2
u2_to_u2: CanCast0D[Any, np.uint16] = u2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
u2_to_i4: CanCast0D[Any, np.uint16] = i4
u2_to_u4: CanCast0D[Any, np.uint16] = u4
u2_to_i8: CanCast0D[Any, np.uint16] = i8
Expand Down Expand Up @@ -215,7 +215,7 @@ i4_to_i1: CanCast0D[Any, np.int32] = i1 # type: ignore[assignment] # pyright:
i4_to_u1: CanCast0D[Any, np.int32] = u1 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
i4_to_i2: CanCast0D[Any, np.int32] = i2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
i4_to_u2: CanCast0D[Any, np.int32] = u2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
i4_to_i4: CanCast0D[Any, np.int32] = i4
i4_to_i4: CanCast0D[Any, np.int32] = i4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
i4_to_u4: CanCast0D[Any, np.int32] = u4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
i4_to_i8: CanCast0D[Any, np.int32] = i8
i4_to_u8: CanCast0D[Any, np.int32] = u8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
Expand Down Expand Up @@ -250,7 +250,7 @@ u4_to_u1: CanCast0D[Any, np.uint32] = u1 # type: ignore[assignment] # pyright:
u4_to_i2: CanCast0D[Any, np.uint32] = i2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
u4_to_u2: CanCast0D[Any, np.uint32] = u2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
u4_to_i4: CanCast0D[Any, np.uint32] = i4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
u4_to_u4: CanCast0D[Any, np.uint32] = u4
u4_to_u4: CanCast0D[Any, np.uint32] = u4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
u4_to_i8: CanCast0D[Any, np.uint32] = i8
u4_to_u8: CanCast0D[Any, np.uint32] = u8
u4_to_f2: CanCast0D[Any, np.uint32] = f2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
Expand Down Expand Up @@ -285,7 +285,7 @@ i8_to_i2: CanCast0D[Any, np.int64] = i2 # type: ignore[assignment] # pyright:
i8_to_u2: CanCast0D[Any, np.int64] = u2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
i8_to_i4: CanCast0D[Any, np.int64] = i4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
i8_to_u4: CanCast0D[Any, np.int64] = u4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
i8_to_i8: CanCast0D[Any, np.int64] = i8
i8_to_i8: CanCast0D[Any, np.int64] = i8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
i8_to_u8: CanCast0D[Any, np.int64] = u8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
i8_to_f2: CanCast0D[Any, np.int64] = f2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
i8_to_f4: CanCast0D[Any, np.int64] = f4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
Expand Down Expand Up @@ -320,7 +320,7 @@ u8_to_u2: CanCast0D[Any, np.uint64] = u2 # type: ignore[assignment] # pyright:
u8_to_i4: CanCast0D[Any, np.uint64] = i4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
u8_to_u4: CanCast0D[Any, np.uint64] = u4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
u8_to_i8: CanCast0D[Any, np.uint64] = i8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
u8_to_u8: CanCast0D[Any, np.uint64] = u8
u8_to_u8: CanCast0D[Any, np.uint64] = u8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
u8_to_f2: CanCast0D[Any, np.uint64] = f2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
u8_to_f4: CanCast0D[Any, np.uint64] = f4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
u8_to_f8: CanCast0D[Any, np.uint64] = f8
Expand Down Expand Up @@ -355,7 +355,7 @@ f2_to_i4: CanCast0D[Any, np.float16] = i4 # type: ignore[assignment] # pyright
f2_to_u4: CanCast0D[Any, np.float16] = u4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
f2_to_i8: CanCast0D[Any, np.float16] = i8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
f2_to_u8: CanCast0D[Any, np.float16] = u8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
f2_to_f2: CanCast0D[Any, np.float16] = f2
f2_to_f2: CanCast0D[Any, np.float16] = f2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
f2_to_f4: CanCast0D[Any, np.float16] = f4
f2_to_f8: CanCast0D[Any, np.float16] = f8
f2_to_ld: CanCast0D[Any, np.float16] = ld
Expand Down Expand Up @@ -390,7 +390,7 @@ f4_to_u4: CanCast0D[Any, np.float32] = u4 # type: ignore[assignment] # pyright
f4_to_i8: CanCast0D[Any, np.float32] = i8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
f4_to_u8: CanCast0D[Any, np.float32] = u8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
f4_to_f2: CanCast0D[Any, np.float32] = f2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
f4_to_f4: CanCast0D[Any, np.float32] = f4
f4_to_f4: CanCast0D[Any, np.float32] = f4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
f4_to_f8: CanCast0D[Any, np.float32] = f8
f4_to_ld: CanCast0D[Any, np.float32] = ld
f4_to_c8: CanCast0D[Any, np.float32] = c8
Expand Down Expand Up @@ -425,7 +425,7 @@ f8_to_i8: CanCast0D[Any, np.float64] = i8 # type: ignore[assignment] # pyright
f8_to_u8: CanCast0D[Any, np.float64] = u8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
f8_to_f2: CanCast0D[Any, np.float64] = f2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
f8_to_f4: CanCast0D[Any, np.float64] = f4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
f8_to_f8: CanCast0D[Any, np.float64] = f8
f8_to_f8: CanCast0D[Any, np.float64] = f8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
f8_to_ld: CanCast0D[Any, np.float64] = ld
f8_to_c8: CanCast0D[Any, np.float64] = c8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
f8_to_c16: CanCast0D[Any, np.float64] = c16
Expand Down Expand Up @@ -460,7 +460,7 @@ ld_to_u8: CanCast0D[Any, np.longdouble] = u8 # type: ignore[assignment] # pyri
ld_to_f2: CanCast0D[Any, np.longdouble] = f2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
ld_to_f4: CanCast0D[Any, np.longdouble] = f4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
ld_to_f8: CanCast0D[Any, np.longdouble] = f8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
ld_to_ld: CanCast0D[Any, np.longdouble] = ld
ld_to_ld: CanCast0D[Any, np.longdouble] = ld # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
ld_to_c8: CanCast0D[Any, np.longdouble] = c8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
ld_to_c16: CanCast0D[Any, np.longdouble] = c16 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
ld_to_cld: CanCast0D[Any, np.longdouble] = cld
Expand Down Expand Up @@ -495,7 +495,7 @@ c8_to_f2: CanCast0D[Any, np.complex64] = f2 # type: ignore[assignment] # pyrig
c8_to_f4: CanCast0D[Any, np.complex64] = f4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
c8_to_f8: CanCast0D[Any, np.complex64] = f8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
c8_to_ld: CanCast0D[Any, np.complex64] = ld # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
c8_to_c8: CanCast0D[Any, np.complex64] = c8
c8_to_c8: CanCast0D[Any, np.complex64] = c8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
c8_to_c16: CanCast0D[Any, np.complex64] = c16
c8_to_cld: CanCast0D[Any, np.complex64] = cld

Expand Down Expand Up @@ -530,7 +530,7 @@ c16_to_f4: CanCast0D[Any, np.complex128] = f4 # type: ignore[assignment] # pyr
c16_to_f8: CanCast0D[Any, np.complex128] = f8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
c16_to_ld: CanCast0D[Any, np.complex128] = ld # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
c16_to_c8: CanCast0D[Any, np.complex128] = c8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
c16_to_c16: CanCast0D[Any, np.complex128] = c16
c16_to_c16: CanCast0D[Any, np.complex128] = c16 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
c16_to_cld: CanCast0D[Any, np.complex128] = cld

cld_from_b1: CanCast0D[np.clongdouble] = b1
Expand Down Expand Up @@ -565,4 +565,4 @@ cld_to_f8: CanCast0D[Any, np.clongdouble] = f8 # type: ignore[assignment] # py
cld_to_ld: CanCast0D[Any, np.clongdouble] = ld # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
cld_to_c8: CanCast0D[Any, np.clongdouble] = c8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
cld_to_c16: CanCast0D[Any, np.clongdouble] = c16 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
cld_to_cld: CanCast0D[Any, np.clongdouble] = cld
cld_to_cld: CanCast0D[Any, np.clongdouble] = cld # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
64 changes: 55 additions & 9 deletions src/_numtype/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import decimal
import fractions
from collections.abc import Sequence
from typing import Any, TypeAlias, type_check_only
from typing_extensions import Protocol, TypeAliasType, TypeVar, Unpack
from typing_extensions import Never, Protocol, TypeAliasType, TypeVar, Unpack

import numpy as np
from numpy._typing import _NestedSequence
Expand Down Expand Up @@ -48,9 +48,11 @@ from ._just import (
JustStr as JustStr,
)
from ._nep50 import (
CanCast as CanCast,
CanCast0D as CanCast0D,
CanCastND as CanCastND,
CanNEP50 as CanNEP50,
MatchND as MatchND,
PromoteWith as PromoteWith,
)
from ._scalar import (
inexact32 as inexact32,
Expand Down Expand Up @@ -97,17 +99,16 @@ from ._scalar_co import (
# Type parameters

_T = TypeVar("_T")
_ShapeT = TypeVar("_ShapeT", bound=tuple[int, ...], default=tuple[int, ...])
_ShapeT_co = TypeVar("_ShapeT_co", bound=tuple[int, ...], covariant=True)
_ScalarT = TypeVar("_ScalarT", bound=np.generic)
_ScalarT_co = TypeVar("_ScalarT_co", bound=np.generic, covariant=True)
_ScalarT0 = TypeVar("_ScalarT0", bound=np.generic, default=Any)
_NaT = TypeVar("_NaT", default=Never)
_NaT0 = TypeVar("_NaT0", default=Any)
_NaT_co = TypeVar("_NaT_co", covariant=True)
_ToT = TypeVar("_ToT")

###
# Type constraints (bijective type mappings)

_ShapeT = TypeVar("_ShapeT", bound=tuple[int, ...], default=tuple[int, ...])

###
# Protocols

Expand Down Expand Up @@ -141,6 +142,10 @@ class CanLenArray(Protocol[_ScalarT_co, _ShapeT_co]):
def __len__(self, /) -> int: ...
def __array__(self, /) -> np.ndarray[_ShapeT_co, np.dtype[_ScalarT_co]]: ...

@type_check_only
class _CanStringArray(Protocol[_ShapeT_co, _NaT_co]):
def __array__(self, /) -> np.ndarray[_ShapeT_co, np.dtypes.StringDType[_NaT_co]]: ...

###
# Shape aliases

Expand All @@ -158,6 +163,7 @@ Sequence2D: TypeAlias = Sequence[Sequence[_T]]
Sequence3D: TypeAlias = Sequence[Sequence[Sequence[_T]]]

# nested sequences with at least k dims, e.g. `2nd` denotes a dimensionality in the interval [2, n]
SequenceND: TypeAlias = _T | _NestedSequence[_T]
Sequence1ND: TypeAlias = _NestedSequence[_T]
Sequence2ND: TypeAlias = Sequence[_NestedSequence[_T]]
Sequence3ND: TypeAlias = Sequence[Sequence[_NestedSequence[_T]]]
Expand All @@ -180,6 +186,37 @@ MArray3D = TypeAliasType("MArray3D", np.ma.MaskedArray[tuple[int, int, int], np.

Matrix = TypeAliasType("Matrix", np.matrix[tuple[int, int], np.dtype[_ScalarT0]], type_params=(_ScalarT0,))

StringArray = TypeAliasType(
"StringArray",
np.ndarray[_ShapeT, np.dtypes.StringDType[_NaT]],
type_params=(_ShapeT, _NaT),
)
StringArray0D = TypeAliasType(
"StringArray0D",
np.ndarray[tuple[()], np.dtypes.StringDType[_NaT]],
type_params=(_NaT,),
)
StringArray1D = TypeAliasType(
"StringArray1D",
np.ndarray[tuple[int], np.dtypes.StringDType[_NaT]],
type_params=(_NaT,),
)
StringArray2D = TypeAliasType(
"StringArray2D",
np.ndarray[tuple[int, int], np.dtypes.StringDType[_NaT]],
type_params=(_NaT,),
)
StringArray3D = TypeAliasType(
"StringArray3D",
np.ndarray[tuple[int, int, int], np.dtypes.StringDType[_NaT]],
type_params=(_NaT,),
)
StringArrayND = TypeAliasType(
"StringArrayND",
np.ndarray[tuple[int, ...], np.dtypes.StringDType[_NaT]],
type_params=(_NaT,),
)

###
# helper aliases

Expand All @@ -192,8 +229,8 @@ _PyObject: TypeAlias = decimal.Decimal | fractions.Fraction
_PyScalar: TypeAlias = complex | _PyCharacter | _PyObject

_ToArray2_0d: TypeAlias = CanArray0D[_ScalarT] | _ToT
_ToArray_nd: TypeAlias = CanArrayND[_ScalarT] | Sequence1ND[CanArrayND[_ScalarT]]
_ToArray2_nd: TypeAlias = CanArrayND[_ScalarT] | _ToT | Sequence1ND[_ToT | CanArrayND[_ScalarT]]
_ToArray_nd: TypeAlias = SequenceND[CanArrayND[_ScalarT]]
_ToArray2_nd: TypeAlias = SequenceND[CanArrayND[_ScalarT] | _ToT]

# don't require matching shape-types by default
_ToArray_1d: TypeAlias = CanLenArrayND[_ScalarT] | Sequence[CanArray0D[_ScalarT]]
Expand Down Expand Up @@ -636,6 +673,15 @@ ToObject_1nd = TypeAliasType("ToObject_1nd", _ToArray2_1nd[np.object_, _PyObject
ToObject_2nd = TypeAliasType("ToObject_2nd", _ToArray2_2nd[np.object_, _PyObject])
ToObject_3nd = TypeAliasType("ToObject_3nd", _ToArray2_3nd[np.object_, _PyObject])

# StringDType
ToString_nd = TypeAliasType("ToString_nd", _CanStringArray[AtLeast0D, _NaT0], type_params=(_NaT0,))
ToString_1ds = TypeAliasType("ToString_1ds", _CanStringArray[tuple[int], _NaT0], type_params=(_NaT0,))
ToString_2ds = TypeAliasType("ToString_2ds", _CanStringArray[tuple[int, int], _NaT0], type_params=(_NaT0,))
ToString_3ds = TypeAliasType("ToString_3ds", _CanStringArray[tuple[int, int, int], _NaT0], type_params=(_NaT0,))
ToString_1nd = TypeAliasType("ToString_1nd", _CanStringArray[AtLeast1D, _NaT0], type_params=(_NaT0,))
ToString_2nd = TypeAliasType("ToString_2nd", _CanStringArray[AtLeast2D, _NaT0], type_params=(_NaT0,))
ToString_3nd = TypeAliasType("ToString_3nd", _CanStringArray[AtLeast3D, _NaT0], type_params=(_NaT0,))

# any scalar
ToGeneric_nd = TypeAliasType("ToGeneric_nd", _ToArray2_nd[np.generic, _PyScalar])
ToGeneric_0d = TypeAliasType("ToGeneric_0d", _ToArray2_0d[np.generic, _PyScalar])
Expand Down
55 changes: 44 additions & 11 deletions src/_numtype/_nep50.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,70 @@
# https://numpy.org/neps/nep-0050-scalar-promotion.html

from typing import Any, Protocol, type_check_only
from typing_extensions import TypeVar
from typing_extensions import TypeAliasType, TypeVar

import numpy as np

__all__ = ["CanCast", "CanCast0D", "CanCastND"]
__all__ = ["CanCast0D", "CanCastND", "CanNEP50", "MatchND", "PromoteWith"]

_T_co = TypeVar("_T_co", covariant=True)
_BelowT_contra = TypeVar("_BelowT_contra", bound=np.generic, contravariant=True)
_AboveT_contra = TypeVar("_AboveT_contra", bound=np.generic, contravariant=True, default=Any)
_OtherT_contra = TypeVar("_OtherT_contra", contravariant=True)
_MatchT_co = TypeVar("_MatchT_co", bound=np.generic, covariant=True, default=Any)
_ShapeT_co = TypeVar("_ShapeT_co", bound=tuple[int, ...], covariant=True)
_ToScalarT_contra = TypeVar("_ToScalarT_contra", bound=np.generic, contravariant=True)
_FromScalarT_contra = TypeVar("_FromScalarT_contra", bound=np.generic, contravariant=True, default=Any)
_SelfScalarT_co = TypeVar("_SelfScalarT_co", bound=np.generic, covariant=True, default=Any)

@type_check_only
class CanNEP50(Protocol[_BelowT_contra, _AboveT_contra, _MatchT_co]):
def __nep50__(self, below: _BelowT_contra, above: _AboveT_contra, /) -> _MatchT_co: ...

@type_check_only
class _CanNEP50Int(Protocol[_OtherT_contra, _T_co]):
def __nep50_int__(self, other: _OtherT_contra, /) -> _T_co: ...

@type_check_only
class _CanNEP50Float(Protocol[_OtherT_contra, _T_co]):
def __nep50_float__(self, other: _OtherT_contra, /) -> _T_co: ...

@type_check_only
class _CanNEP50Complex(Protocol[_OtherT_contra, _T_co]):
def __nep50_complex__(self, other: _OtherT_contra, /) -> _T_co: ...

_WithT = TypeVar("_WithT")
_OutT = TypeVar("_OutT", bound=np.generic)

PromoteWith = TypeAliasType(
"PromoteWith",
_CanNEP50Int[_WithT, _OutT] | _CanNEP50Float[_WithT, _OutT] | _CanNEP50Complex[_WithT, _OutT],
type_params=(_WithT, _OutT),
)

###

@type_check_only
class _HasType(Protocol[_T_co]):
@property
def type(self, /) -> type[_T_co]: ...

@type_check_only
class CanCast(Protocol[_ToScalarT_contra, _FromScalarT_contra, _SelfScalarT_co]):
def __nep50__(self, to: _ToScalarT_contra, from_: _FromScalarT_contra, /) -> _SelfScalarT_co: ...
class MatchND(Protocol[_ShapeT_co, _T_co]):
@property
def shape(self, /) -> _ShapeT_co: ...
@property
def dtype(self, /) -> _HasType[_T_co]: ...

# TODO(jorenham): Rename these

@type_check_only
class CanCast0D(Protocol[_ToScalarT_contra, _FromScalarT_contra, _SelfScalarT_co]):
class CanCast0D(Protocol[_BelowT_contra, _AboveT_contra, _MatchT_co]):
@property
def shape(self, /) -> tuple[()]: ...
@property
def dtype(self, /) -> _HasType[CanCast[_ToScalarT_contra, _FromScalarT_contra, _SelfScalarT_co]]: ...
def dtype(self, /) -> _HasType[CanNEP50[_BelowT_contra, _AboveT_contra, _MatchT_co]]: ...

@type_check_only
class CanCastND(Protocol[_ShapeT_co, _ToScalarT_contra, _FromScalarT_contra, _SelfScalarT_co]):
class CanCastND(Protocol[_ShapeT_co, _BelowT_contra, _AboveT_contra, _MatchT_co]):
@property
def shape(self, /) -> _ShapeT_co: ...
@property
def dtype(self, /) -> _HasType[CanCast[_ToScalarT_contra, _FromScalarT_contra, _SelfScalarT_co]]: ...
def dtype(self, /) -> _HasType[CanNEP50[_BelowT_contra, _AboveT_contra, _MatchT_co]]: ...
Loading