Skip to content
Merged
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
39 changes: 26 additions & 13 deletions quaddtype/numpy_quaddtype/_quaddtype_main.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,14 @@ import numpy as np
from typing_extensions import Never, Self, override

_Backend: TypeAlias = Literal["sleef", "longdouble"]
_IntoQuad: TypeAlias = QuadPrecision | float | str
_CastsQuad: TypeAlias = _IntoQuad | np.floating[Any] | np.integer[Any] | np.bool_
_IntoQuad: TypeAlias = (
QuadPrecision
| float
| str
| np.floating[Any]
| np.integer[Any]
| np.bool_
) # fmt: skip

@final
class QuadPrecDType(np.dtype[QuadPrecision]): # type: ignore[misc, type-var] # pyright: ignore[reportGeneralTypeIssues, reportInvalidTypeArguments]
Expand Down Expand Up @@ -64,8 +70,15 @@ class QuadPrecDType(np.dtype[QuadPrecision]): # type: ignore[misc, type-var] #
@override
def __getitem__(self, key: Never, /) -> Self: ... # type: ignore[override]

# NOTE: Until `QuadPrecision` will become a subclass of `np.generic`, this class cannot
Copy link
Member

Choose a reason for hiding this comment

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

In [5]: issubclass(npq.QuadPrecDType().type, np.generic)
Out[5]: True

In [6]: npq.QuadPrecDType().type
Out[6]: numpy_quaddtype.QuadPrecision

In [7]: issubclass(npq.QuadPrecision, np.generic)
Out[7]: True

I think it is as Quadprecision already subclassing the np.floating

Copy link
Member Author

Choose a reason for hiding this comment

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

Nice! I'll open a separate PR for that then.

Copy link
Member Author

@jorenham jorenham Oct 24, 2025

Choose a reason for hiding this comment

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

What does numpy_quaddtype.QuadPrecision.mro() return? (sorry I wasn't able to get it to build locally) Because there's a chance that there's some __subclasscheck__ trickery going on.

Copy link
Member

Choose a reason for hiding this comment

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

In [11]: npq.QuadPrecision.mro()
Out[11]: 
[numpy_quaddtype.QuadPrecision,
 numpy.floating,
 numpy.inexact,
 numpy.number,
 numpy.generic,
 object]

Building it requires the numpy build from source right now :)

# be considered "type-safe".
@final
class QuadPrecision: # NOTE: It doesn't inherit from `np.generic` which is type-unsafe
class QuadPrecision:
# NOTE: At runtime this constructor also accepts array-likes, for which it returns
# `np.ndarray` instances with `dtype=QuadPrecDType()`.
# But because of mypy limitations, it is currently impossible to annotate
# constructors that do no return instances of their class (or a subclass thereof).
# See https://github.com/python/mypy/issues/18343#issuecomment-2571784915
def __new__(cls, /, value: _IntoQuad, backend: _Backend = "sleef") -> Self: ...

# Rich comparison operators
Expand All @@ -80,16 +93,16 @@ class QuadPrecision: # NOTE: It doesn't inherit from `np.generic` which is type
def __ge__(self, other: _IntoQuad, /) -> bool: ...

# Binary operators
def __add__(self, other: _CastsQuad, /) -> Self: ...
def __radd__(self, other: _CastsQuad, /) -> Self: ...
def __sub__(self, other: _CastsQuad, /) -> Self: ...
def __rsub__(self, other: _CastsQuad, /) -> Self: ...
def __mul__(self, other: _CastsQuad, /) -> Self: ...
def __rmul__(self, other: _CastsQuad, /) -> Self: ...
def __pow__(self, other: _CastsQuad, mod: None = None, /) -> Self: ...
def __rpow__(self, other: _CastsQuad, mod: None = None, /) -> Self: ...
def __truediv__(self, other: _CastsQuad, /) -> Self: ...
def __rtruediv__(self, other: _CastsQuad, /) -> Self: ...
def __add__(self, other: _IntoQuad, /) -> Self: ...
def __radd__(self, other: _IntoQuad, /) -> Self: ...
def __sub__(self, other: _IntoQuad, /) -> Self: ...
def __rsub__(self, other: _IntoQuad, /) -> Self: ...
def __mul__(self, other: _IntoQuad, /) -> Self: ...
def __rmul__(self, other: _IntoQuad, /) -> Self: ...
def __pow__(self, other: _IntoQuad, mod: None = None, /) -> Self: ...
def __rpow__(self, other: _IntoQuad, mod: None = None, /) -> Self: ...
def __truediv__(self, other: _IntoQuad, /) -> Self: ...
def __rtruediv__(self, other: _IntoQuad, /) -> Self: ...

# Unary operators
def __neg__(self, /) -> Self: ...
Expand Down