10000 ENH: make dtype generic over scalar type by person142 · Pull Request #16759 · numpy/numpy · GitHub
[go: up one dir, main page]

Skip to content

ENH: make dtype generic over scalar type #16759

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
318 changes: 313 additions & 5 deletions numpy/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ from numpy.typing import (
_FloatLike,
_ComplexLike,
_NumberLike,
_SupportsDtype,
_VoidDtypeLike,
)
from numpy.typing._callable import (
_BoolOp,
Expand Down Expand Up @@ -527,16 +529,322 @@ where: Any
who: Any

_NdArraySubClass = TypeVar("_NdArraySubClass", bound=ndarray)
_DTypeScalar = TypeVar("_DTypeScalar", bound=generic)
_ByteOrder = Literal["S", "<", ">", "=", "|", "L", "B", "N", "I"]

class dtype:
class dtype(Generic[_DTypeScalar]):
names: Optional[Tuple[str, ...]]
def __init__(
self,
dtype: DtypeLike,
# Overload for subclass of generic
@overload
def __new__(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In reality this is done by the _DTypeMeta metaclass.

cls,
dtype: Type[_DTypeScalar],
align: bool = ...,
copy: bool = ...,
) -> None: ...
) -> dtype[_DTypeScalar]: ...
# Overloads for string aliases, Python types, and some assorted
# other special cases. Order is sometimes important because of the
# subtype relationships
#
# bool < int < float < complex
#
# so we have to make sure the overloads for the narrowest type is
# first.
@overload
def __new__(
cls,
dtype: Union[
Type[bool],
Literal[
"?",
"=?",
"<?",
">?",
"bool",
"bool_",
],
],
align: bool = ...,
copy: bool = ...,
) -> dtype[bool_]: ...
@overload
def __new__(
cls,
dtype: Literal[
"uint8",
"u1",
"=u1",
"<u1",
">u1",
],
align: bool = ...,
copy: bool = ...,
) -> dtype[uint8]: ...
@overload
def __new__(
cls,
dtype: Literal[
"uint16",
"u2",
"=u2",
"<u2",
">u2",
],
align: bool = ...,
copy: bool = ...,
) -> dtype[uint16]: ...
@overload
def __new__(
cls,
dtype: Literal[
"uint32",
"u4",
"=u4",
"<u4",
">u4",
],
align: bool = ...,
copy: bool = ...,
) -> dtype[uint32]: ...
@overload
def __new__(
cls,
dtype: Literal[
"uint64",
"u8",
"=u8",
"<u8",
">u8",
],
align: bool = ...,
copy: bool = ...,
) -> dtype[uint64]: ...
@overload
def __new__(
cls,
dtype: Literal[
"int8",
"i1",
"=i1",
"<i1",
">i1",
],
align: bool = ...,
copy: bool = ...,
) -> dtype[int8]: ...
@overload
def __new__(
cls,
dtype: Literal[
"int16",
"i2",
"=i2",
"<i2",
">i2",
],
align: bool = ...,
copy: bool = ...,
) -> dtype[int16]: ...
@overload
def __new__(
cls,
dtype: Literal[
"int32",
"i4",
"=i4",
"<i4",
">i4",
],
align: bool = ...,
copy: bool = ...,
) -> dtype[int32]: ...
@overload
def __new__(
cls,
dtype: Literal[
"int64",
"i8",
"=i8",
"<i8",
">i8",
],
align: bool = ...,
copy: bool = ...,
) -> dtype[int64]: ...
# "int"/int resolve to int_, which is system dependent and as of
# now untyped. Long-term we'll do something fancier here.
@overload
def __new__(
cls,
dtype: Union[Type[int], Literal["int"]],
align: bool = ...,
copy: bool = ...,
) -> dtype: ...
@overload
def __new__(
cls,
dtype: Literal[
"float16",
"f4",
"=f4",
"<f4",
">f4",
"e",
"=e",
"<e",
">e",
"half",
],
align: bool = ...,
copy: bool = ...,
) -> dtype[float16]: ...
@overload
def __new__(
cls,
dtype: Literal[
"float32",
"f4",
"=f4",
"<f4",
">f4",
"f",
"=f",
"<f",
">f",
"single",
],
align: bool = ...,
copy: bool = ...,
) -> dtype[float32]: ...
@overload
def __new__(
cls,
dtype: Union[
None,
Type[float],
Literal[
"float64",
"f8",
"=f8",
"<f8",
">f8",
"d",
"<d",
">d",
"float",
"double",
"float_",
],
],
align: bool = ...,
copy: bool = ...,
) -> dtype[float64]: ...
@overload
def __new__(
cls,
dtype: Literal[
"complex64",
"c8",
"=c8",
"<c8",
">c8",
"F",
"=F",
"<F",
">F",
],
align: bool = ...,
copy: bool = ...,
) -> dtype[complex64]: ...
@overload
def __new__(
cls,
dtype: Union[
Type[complex],
Literal[
"complex128",
"c16",
"=c16",
"<c16",
">c16",
"D",
"=D",
"<D",
">D",
],
],
align: bool = ...,
copy: bool = ...,
) -> dtype[complex128]: ...
@overload
def __new__(
cls,
dtype: Union[
Type[bytes],
Literal[
"S",
"=S",
"<S",
">S",
"bytes",
"bytes_",
"bytes0",
],
],
align: bool = ...,
copy: bool = ...,
) -> dtype[bytes_]: ...
@overload
def __new__(
cls,
dtype: Union[
Type[str],
Literal[
"U",
"=U",
# <U and >U intentionally not included; they are not
# the same dtype and which one dtype("U") translates
# to is platform-dependent.
"str",
"str_",
"str0",
],
],
align: bool = ...,
copy: bool = ...,
) -> dtype[str_]: ...
# dtype of a dtype is the same dtype
@overload
def __new__(
cls,
dtype: dtype[_DTypeScalar],
align: bool = ...,
copy: bool = ...,
) -> dtype[_DTypeScalar]: ...
# TODO: handle _SupportsDtype better
@overload
def __new__(
cls,
dtype: _SupportsDtype,
align: bool = ...,
copy: bool = ...,
) -> dtype[Any]: ...
# Handle strings that can't be expressed as literals; i.e. s1, s2, ...
@overload
def __new__(
cls,
dtype: str,
align: bool = ...,
copy: bool = ...,
) -> dtype[Any]: ...
# Catchall overload
@overload
def __new__(
cls,
dtype: _VoidDtypeLike,
align: bool = ...,
copy: bool = ...,
) -> dtype[void]: ...
def __eq__(self, other: DtypeLike) -> bool: ...
def __ne__(self, other: DtypeLike) -> bool: ...
def __gt__(self, other: DtypeLike) -> bool: ...
Expand Down
2 changes: 1 addition & 1 deletion numpy/typing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@
)
from ._array_like import _SupportsArray, ArrayLike
from ._shape import _Shape, _ShapeLike
from ._dtype_like import DtypeLike
from ._dtype_like import _SupportsDtype, _VoidDtypeLike, DtypeLike

from numpy._pytesttester import PytestTester
test = PytestTester(__name__)
Expand Down
30 changes: 18 additions & 12 deletions numpy/typing/_dtype_like.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,9 @@ class _SupportsDtype(Protocol):
_DtypeDict = Any
_SupportsDtype = Any

# Anything that can be coerced into numpy.dtype.
# Reference: https://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html
DtypeLike = Union[
dtype,
# default data type (float64)
None,
# array-scalar types and generic types
type, # TODO: enumerate these when we add type hints for numpy scalars
# anything with a dtype attribute
_SupportsDtype,
# character codes, type strings or comma-separated fields, e.g., 'float64'
str,

# Would create a dtype[np.void]
_VoidDtypeLike = Union[
# (flexible_dtype, itemsize)
Tuple[_DtypeLikeNested, int],
# (fixed_dtype, shape)
Expand All @@ -67,6 +58,21 @@ class _SupportsDtype(Protocol):
Tuple[_DtypeLikeNested, _DtypeLikeNested],
]

# Anything that can be coerced into numpy.dtype.
# Reference: https://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html
DtypeLike = Union[
dtype,
# default data type (float64)
None,
# array-scalar types and generic types
type, # TODO: enumerate these when we add type hints for numpy scalars
# anything with a dtype attribute
_SupportsDtype,
# character codes, type strings or comma-separated fields, e.g., 'float64'
str,
_VoidDtypeLike,
]

# NOTE: while it is possible to provide the dtype as a dict of
# dtype-like objects (e.g. `{'field1': ..., 'field2': ..., ...}`),
# this syntax is officially discourged and
Expand Down
Loading
0