diff --git a/README.md b/README.md
index a622fff7..9aafe052 100644
--- a/README.md
+++ b/README.md
@@ -364,7 +364,7 @@ This is why these `optype` interfaces don't accept generic type arguments.
do_int |
DoesInt |
__int__ |
- CanInt[+R: int = int] |
+ CanInt |
bool(_) |
@@ -378,72 +378,28 @@ This is why these `optype` interfaces don't accept generic type arguments.
do_bytes |
DoesBytes |
__bytes__ |
- CanBytes[+R: bytes = bytes] |
+ CanBytes |
str(_) |
do_str |
DoesStr |
__str__ |
- CanStr[+R: str = str] |
-
-
-
-> [!NOTE]
-> The `Can*` interfaces of the types that can used as `typing.Literal`
-> accept an optional type parameter `R`.
-> This can be used to indicate a literal return type,
-> for surgically precise typing, e.g. `None`, `True`, and `42` are
-> instances of `CanBool[Literal[False]]`, `CanInt[Literal[1]]`, and
-> `CanStr[Literal['42']]`, respectively.
-
-These formatting methods are allowed to return instances that are a subtype
-of the `str` builtin. The same holds for the `__format__` argument.
-So if you're a 10x developer that wants to hack Python's f-strings, but only
-if your type hints are spot-on; `optype` is you friend.
-
-
-
- | operator |
- operand |
-
-
- | expression |
- function |
- type |
- method |
- type |
+ CanStr |
repr(_) |
do_repr |
DoesRepr |
__repr__ |
- CanRepr[+R:str = str] |
+ CanRepr |
format(_, x) |
do_format |
DoesFormat |
__format__ |
- CanFormat[-T:str = str, +R:str = str] |
-
-
-
-Additionally, `optype` provides protocols for types with (custom) *hash* or
-*index* methods:
-
-
-
- | operator |
- operand |
-
-
- | expression |
- function |
- type |
- method |
- type |
+ CanFormat |
hash(_) |
@@ -460,7 +416,7 @@ Additionally, `optype` provides protocols for types with (custom) *hash* or
do_index |
DoesIndex |
__index__ |
- CanIndex[+R: int = int] |
+ CanIndex |
@@ -1434,7 +1390,7 @@ Additionally, there is `optype.CanAIterSelf[R]`, with both the
do_len |
DoesLen |
__len__ |
- CanLen[+R:int=int] |
+ CanLen |
|
@@ -1444,7 +1400,7 @@ Additionally, there is `optype.CanAIterSelf[R]`, with both the
| do_length_hint |
DoesLengthHint |
__length_hint__ |
- CanLengthHint[+R:int=int] |
+ CanLengthHint |
_[k] |
@@ -1491,7 +1447,7 @@ Additionally, there is `optype.CanAIterSelf[R]`, with both the
__reversed__ |
CanReversed[+R], or
- CanSequence[-I, +V, +N=int]
+ CanSequence[-I, +V]
|
@@ -1526,7 +1482,7 @@ specific and flexible `collections.abc.Sequence[V]`.
do_getattr |
DoesGetattr |
__getattr__ |
- CanGetattr[-K:str=str, +V=object] |
+ CanGetattr[+V=object] |
|
@@ -1536,7 +1492,7 @@ specific and flexible `collections.abc.Sequence[V]`.
| do_setattr |
DoesSetattr |
__setattr__ |
- CanSetattr[-K:str=str, -V=object] |
+ CanSetattr[-V=object] |
|
@@ -1546,14 +1502,14 @@ specific and flexible `collections.abc.Sequence[V]`.
| do_delattr |
DoesDelattr |
__delattr__ |
- CanDelattr[-K:str=str] |
+ CanDelattr |
dir(_) |
do_dir |
DoesDir |
__dir__ |
- CanDir[+R:CanIter[CanIterSelf[str]]] |
+ CanDir[+R: Iterable[str]] |
@@ -1683,7 +1639,7 @@ Interfaces for [descriptors](https://docs.python.org/3/howto/descriptor.html).
class T: d = _ |
__set_name__ |
- CanSetName[-T, -N: str = str] |
+ CanSetName[-T] |
@@ -1704,7 +1660,7 @@ Interfaces for emulating buffer types using the [buffer protocol][BP].
v = memoryview(_) |
__buffer__ |
- CanBuffer[-T: int = int] |
+ CanBuffer |
del v |
diff --git a/optype/_core/_can.py b/optype/_core/_can.py
index 911d4c76..4c7834c3 100644
--- a/optype/_core/_can.py
+++ b/optype/_core/_can.py
@@ -1,10 +1,7 @@
-# mypy: disable-error-code="override"
-# ruff: noqa: PYI034
-
import sys
import types
-from collections.abc import Generator
-from typing import Never, Protocol, Self, SupportsIndex, TypeAlias, overload
+from collections.abc import Generator, Iterable
+from typing import Any, Never, Protocol, Self, SupportsIndex, TypeAlias, overload
if sys.version_info >= (3, 13):
from typing import ParamSpec, TypeVar, override, runtime_checkable
@@ -203,8 +200,8 @@ def __dir__() -> list[str]:
_Tss = ParamSpec("_Tss", default=...)
_T = TypeVar("_T")
-_T_contra = TypeVar("_T_contra", contravariant=True)
_T_co = TypeVar("_T_co", covariant=True)
+_T_contra = TypeVar("_T_contra", contravariant=True)
_TT_co = TypeVar("_TT_co", covariant=True, default=_T_contra)
_K_contra = TypeVar("_K_contra", contravariant=True)
@@ -212,12 +209,7 @@ def __dir__() -> list[str]:
_V_co = TypeVar("_V_co", covariant=True)
_VV_co = TypeVar("_VV_co", default=_V_co, covariant=True)
-_BoolT_co = TypeVar("_BoolT_co", bound=bool, default=bool, covariant=True)
-_IntT_contra = TypeVar("_IntT_contra", bound=int, default=int, contravariant=True)
-_IntT_co = TypeVar("_IntT_co", bound=int, default=int, covariant=True)
-_BytesT_co = TypeVar("_BytesT_co", bound=bytes, default=bytes, covariant=True)
-_StrT_contra = TypeVar("_StrT_contra", bound=str, default=str, contravariant=True)
-_StrT_co = TypeVar("_StrT_co", bound=str, default=str, covariant=True)
+_BoolT_co = TypeVar("_BoolT_co", default=bool, covariant=True)
_ExcT = TypeVar("_ExcT", bound=BaseException)
_T_object_contra = TypeVar("_T_object_contra", contravariant=True, default=object)
@@ -230,6 +222,14 @@ def __dir__() -> list[str]:
_T_Never_contra = TypeVar("_T_Never_contra", default=Never, contravariant=True)
_T_Never_co = TypeVar("_T_Never_co", default=Never, covariant=True)
+_IterT_str_co = TypeVar(
+ "_IterT_str_co",
+ # we use `Any` instead of `object` to side-step LSP errors in `CanDir`
+ bound=Iterable[Any],
+ default=Iterable[str],
+ covariant=True,
+)
+
# we can't use `CanIndex` here, because of a recent regression in pyright 1.1.392
_IndexT_contra = TypeVar(
"_IndexT_contra",
@@ -257,8 +257,8 @@ def __bool__(self, /) -> _BoolT_co: ...
@runtime_checkable
-class CanInt(Protocol[_IntT_co]):
- def __int__(self, /) -> _IntT_co: ...
+class CanInt(Protocol):
+ def __int__(self, /) -> int: ...
@runtime_checkable
@@ -272,26 +272,14 @@ def __complex__(self, /) -> complex: ...
@runtime_checkable
-class CanBytes(Protocol[_BytesT_co]):
- """
- The `__bytes__: (CanBytes[Y]) -> Y` method is *co*variant on `+Y`.
- So if `__bytes__` returns an instance of a custom `bytes` subtype
- `Y <: bytes`, then `bytes()` will also return `Y` (i.e. no upcasting).
- """
-
- def __bytes__(self, /) -> _BytesT_co: ...
+class CanBytes(Protocol):
+ def __bytes__(self, /) -> bytes: ...
@runtime_checkable
-class CanStr(Protocol[_StrT_co]):
- """
- Each `object` has a *co*variant `__str__: (CanStr[Y=str]) -> Y` method on
- `+Y`. That means that if `__str__()` returns an instance of a custom `str`
- subtype `Y <: str`, then `str()` will also return `Y` (i.e. no upcasting).
- """
-
+class CanStr(Protocol):
@override
- def __str__(self, /) -> _StrT_co: ...
+ def __str__(self, /) -> str: ...
# Object representation
@@ -304,32 +292,20 @@ def __hash__(self, /) -> int: ...
@runtime_checkable
-class CanIndex(Protocol[_IntT_co]):
- def __index__(self, /) -> _IntT_co: ...
+class CanIndex(Protocol):
+ def __index__(self, /) -> int: ...
@runtime_checkable
-class CanRepr(Protocol[_StrT_co]):
- """
- Each `object` has a *co*variant `__repr__: (CanRepr[Y=str]) -> Y` method.
- That means that if `__repr__` returns an instance of a custom `str`
- subtype `Y <: str`, then `repr()` will also return `Y` (i.e. no upcasting).
- """
-
+class CanRepr(Protocol):
@override
- def __repr__(self, /) -> _StrT_co: ...
+ def __repr__(self, /) -> str: ...
@runtime_checkable
-class CanFormat(Protocol[_StrT_contra, _StrT_co]):
- """
- Each `object` has a `__format__: (CanFormat[X, Y], X) -> Y` method, with
- `-X` *contra*variant, and `+Y` *co*variant. Both `X` and `Y` can be `str`
- or `str` subtypes. Note that `format()` *does not* upcast `Y` to `str`.
- """
-
+class CanFormat(Protocol):
@override
- def __format__(self, fmt: _StrT_contra, /) -> _StrT_co: ... # pyright: ignore[reportIncompatibleMethodOverride] # pyrefly: ignore[bad-override]
+ def __format__(self, format_spec: str, /) -> str: ...
# Iteration
@@ -408,7 +384,7 @@ class CanEq(Protocol[_T_object_contra, _T_bool_co]): # noqa: PLW1641
"""
@override
- def __eq__(self, rhs: _T_object_contra, /) -> _T_bool_co: ... # pyright:ignore[reportIncompatibleMethodOverride] # pyrefly: ignore[bad-override]
+ def __eq__(self, rhs: _T_object_contra, /) -> _T_bool_co: ... # type: ignore[override] # pyright:ignore[reportIncompatibleMethodOverride] # pyrefly: ignore[bad-override]
@runtime_checkable
@@ -419,7 +395,7 @@ class CanNe(Protocol[_T_object_contra, _T_bool_co]):
"""
@override
- def __ne__(self, rhs: _T_object_contra, /) -> _T_bool_co: ... # pyright:ignore[reportIncompatibleMethodOverride] # pyrefly: ignore[bad-override]
+ def __ne__(self, rhs: _T_object_contra, /) -> _T_bool_co: ... # type: ignore[override] # pyright:ignore[reportIncompatibleMethodOverride] # pyrefly: ignore[bad-override]
@runtime_checkable
@@ -447,6 +423,8 @@ def __ge__(self, rhs: _T_object_contra, /) -> _T_bool_co: ...
@runtime_checkable
class CanCall(Protocol[_Tss, _T_object_co]):
+ """Equivalent to `typing.Callable` in theory, but not always in practice."""
+
def __call__(self, /, *args: _Tss.args, **kwargs: _Tss.kwargs) -> _T_object_co: ...
@@ -454,49 +432,36 @@ def __call__(self, /, *args: _Tss.args, **kwargs: _Tss.kwargs) -> _T_object_co:
@runtime_checkable
-class CanGetattr(Protocol[_StrT_contra, _T_object_co]):
- def __getattr__(self, name: _StrT_contra, /) -> _T_object_co: ... # type: ignore[misc]
+class CanGetattr(Protocol[_T_object_co]):
+ def __getattr__(self, name: str, /) -> _T_object_co: ...
@runtime_checkable
-class CanGetattribute(Protocol[_StrT_contra, _T_object_co]):
+class CanGetattribute(Protocol[_T_object_co]):
"""Note that `isinstance(x, CanGetattribute)` is always `True`."""
@override
- def __getattribute__(self, name: _StrT_contra, /) -> _T_object_co: ... # type: ignore[misc] # pyright: ignore[reportIncompatibleMethodOverride]
+ def __getattribute__(self, name: str, /) -> _T_object_co: ...
@runtime_checkable
-class CanSetattr(Protocol[_StrT_contra, _T_object_contra]):
+class CanSetattr(Protocol[_T_object_contra]):
"""Note that `isinstance(x, CanSetattr)` is always true."""
@override
- def __setattr__( # type: ignore[misc] # pyright: ignore[reportIncompatibleMethodOverride]
- self,
- name: _StrT_contra,
- value: _T_object_contra,
- /,
- ) -> _Ignored: ...
+ def __setattr__(self, name: str, value: _T_object_contra, /) -> _Ignored: ... # type: ignore[misc, override] # pyright: ignore[reportIncompatibleMethodOverride]
@runtime_checkable
-class CanDelattr(Protocol[_StrT_contra]):
+class CanDelattr(Protocol):
@override
- def __delattr__(self, name: _StrT_contra, /) -> _Ignored: ... # pyright: ignore[reportIncompatibleMethodOverride] # pyrefly: ignore[bad-override]
-
-
-_AnyStrIterT_co = TypeVar(
- "_AnyStrIterT_co",
- bound=CanIter[CanNext[object]],
- covariant=True,
- default=CanIter[CanIterSelf[str]],
-)
+ def __delattr__(self, name: str, /) -> _Ignored: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] # pyrefly: ignore[bad-override]
@runtime_checkable
-class CanDir(Protocol[_AnyStrIterT_co]):
+class CanDir(Protocol[_IterT_str_co]):
@override
- def __dir__(self, /) -> _AnyStrIterT_co: ... # pyright: ignore[reportIncompatibleMethodOverride]
+ def __dir__(self, /) -> _IterT_str_co: ...
# Descriptors
@@ -531,21 +496,21 @@ def __delete__(self, owner: _T_contra, /) -> _Ignored: ...
@runtime_checkable
-class CanSetName(Protocol[_T_contra, _StrT_contra]):
- def __set_name__(self, cls: type[_T_contra], name: _StrT_contra, /) -> _Ignored: ...
+class CanSetName(Protocol[_T_contra]):
+ def __set_name__(self, cls: type[_T_contra], name: str, /) -> _Ignored: ...
# Collection type operands.
@runtime_checkable
-class CanLen(Protocol[_IntT_co]):
- def __len__(self, /) -> _IntT_co: ...
+class CanLen(Protocol):
+ def __len__(self, /) -> int: ...
@runtime_checkable
-class CanLengthHint(Protocol[_IntT_co]):
- def __length_hint__(self, /) -> _IntT_co: ...
+class CanLengthHint(Protocol):
+ def __length_hint__(self, /) -> int: ...
@runtime_checkable
@@ -571,10 +536,10 @@ def __reversed__(self, /) -> _T_co: ...
@runtime_checkable
-class CanContains(Protocol[_T_object_contra, _BoolT_co]):
+class CanContains(Protocol[_T_object_contra]):
# usually the key is required to also be a hashable object, but this
# isn't strictly required
- def __contains__(self, key: _T_object_contra, /) -> _BoolT_co: ...
+ def __contains__(self, key: _T_object_contra, /) -> bool: ...
@runtime_checkable
@@ -593,8 +558,8 @@ class CanGetMissing(
@runtime_checkable
class CanSequence(
CanGetitem[_IndexT_contra, _V_co],
- CanLen[_IntT_co],
- Protocol[_IndexT_contra, _V_co, _IntT_co],
+ CanLen,
+ Protocol[_IndexT_contra, _V_co],
):
"""
A sequence is an object with a __len__ method and a
@@ -1130,6 +1095,8 @@ def __ror__(self, lhs: _T_contra, /) -> Self: ...
###
# Augmented arithmetic operands
+# ruff: noqa: PYI034
+
# __iadd__
@@ -1572,11 +1539,7 @@ def __exit__( # noqa: PYI036
@runtime_checkable
-class CanWith(
- CanEnter[_T_co],
- CanExit[_T_None_co],
- Protocol[_T_co, _T_None_co],
-): ...
+class CanWith(CanEnter[_T_co], CanExit[_T_None_co], Protocol[_T_co, _T_None_co]): ...
@runtime_checkable
@@ -1630,8 +1593,8 @@ class CanAsyncWithSelf(CanAEnterSelf, CanAExit[_T_None_co], Protocol[_T_None_co]
@runtime_checkable
-class CanBuffer(Protocol[_IntT_contra]):
- def __buffer__(self, buffer: _IntT_contra, /) -> memoryview: ...
+class CanBuffer(Protocol):
+ def __buffer__(self, buffer: int, /) -> memoryview: ...
@runtime_checkable
diff --git a/optype/_core/_do.py b/optype/_core/_do.py
index 3b874657..de4c6c24 100644
--- a/optype/_core/_do.py
+++ b/optype/_core/_do.py
@@ -2,7 +2,7 @@
import math
import operator as _o
-from typing import Final, Literal, TypeVar, cast, overload
+from typing import Final, TypeVar, cast, overload
import optype._core._can as _c
import optype._core._does as _d
@@ -101,48 +101,48 @@ def __dir__() -> list[str]:
# type conversion
-do_bool: Final = cast("_d.DoesBool", bool)
-do_int: Final = cast("_d.DoesInt", int)
-do_float: Final = cast("_d.DoesFloat", float)
-do_complex: Final = cast("_d.DoesComplex", complex)
-do_bytes: Final = cast("_d.DoesBytes", bytes)
-do_str: Final = cast("_d.DoesStr", str)
+do_bool: Final[_d.DoesBool] = cast("_d.DoesBool", bool)
+do_int: Final[_d.DoesInt] = cast("_d.DoesInt", int)
+do_float: Final[_d.DoesFloat] = cast("_d.DoesFloat", float)
+do_complex: Final[_d.DoesComplex] = cast("_d.DoesComplex", complex)
+do_bytes: Final[_d.DoesBytes] = cast("_d.DoesBytes", bytes)
+do_str: Final[_d.DoesStr] = cast("_d.DoesStr", str)
# formatting
-do_repr: Final = cast("_d.DoesRepr", repr)
-do_format: Final = cast("_d.DoesFormat", format)
+do_repr: Final[_d.DoesRepr] = repr
+do_format: Final[_d.DoesFormat] = format
# iteration
-do_next: Final = next
-do_iter: Final = cast("_d.DoesIter", iter)
+do_next: Final[_d.DoesNext] = next
+do_iter: Final[_d.DoesIter] = cast("_d.DoesIter", iter)
# async iteration
-do_anext: Final = cast("_d.DoesANext", anext)
-do_aiter: Final = cast("_d.DoesAIter", aiter)
+do_anext: Final[_d.DoesANext] = cast("_d.DoesANext", anext)
+do_aiter: Final[_d.DoesAIter] = cast("_d.DoesAIter", aiter)
# rich comparison
-do_lt: Final = cast("_d.DoesLt", _o.lt)
-do_le: Final = cast("_d.DoesLe", _o.le)
-do_eq: Final = cast("_d.DoesEq", _o.eq)
-do_ne: Final = cast("_d.DoesNe", _o.ne)
-do_gt: Final = cast("_d.DoesGt", _o.gt)
-do_ge: Final = cast("_d.DoesGe", _o.ge)
+do_lt: Final[_d.DoesLt] = cast("_d.DoesLt", _o.lt)
+do_le: Final[_d.DoesLe] = cast("_d.DoesLe", _o.le)
+do_eq: Final[_d.DoesEq] = cast("_d.DoesEq", _o.eq)
+do_ne: Final[_d.DoesNe] = cast("_d.DoesNe", _o.ne)
+do_gt: Final[_d.DoesGt] = cast("_d.DoesGt", _o.gt)
+do_ge: Final[_d.DoesGe] = cast("_d.DoesGe", _o.ge)
# attributes
-do_getattr: Final = cast("_d.DoesGetattr", getattr)
-do_setattr: Final = cast("_d.DoesSetattr", setattr)
-do_delattr: Final = delattr
-do_dir: Final = cast("_d.DoesDir", dir)
+do_getattr: Final[_d.DoesGetattr] = cast("_d.DoesGetattr", getattr)
+do_setattr: Final[_d.DoesSetattr] = cast("_d.DoesSetattr", setattr)
+do_delattr: Final[_d.DoesDelattr] = delattr
+do_dir: Final[_d.DoesDir] = cast("_d.DoesDir", dir)
# callables
-do_call: Final = _o.call
+do_call: Final[_d.DoesCall] = _o.call # pyrefly: ignore[bad-assignment]
# containers and sequences
-do_len: Final = cast("_d.DoesLen", len)
-do_length_hint: Final = cast("_d.DoesLengthHint", _o.length_hint)
+do_len: Final[_d.DoesLen] = len
+do_length_hint: Final[_d.DoesLengthHint] = cast("_d.DoesLengthHint", _o.length_hint)
# `operator.getitem` isn't used, because it has an (unreasonably loose, and
@@ -181,36 +181,33 @@ def do_missing(obj: _c.CanMissing[_KT, _DT], key: _KT, /) -> _DT:
return obj.__missing__(key)
-_BoolT = TypeVar("_BoolT", Literal[False], Literal[True], bool)
-
-
# `operator.contains` cannot be used, as it incorrectly requires `key`
# to be exactly of type `object`, so that it only accepts `object()`...
-def do_contains(obj: _c.CanContains[_KT, _BoolT], key: _KT, /) -> _BoolT:
+def do_contains(obj: _c.CanContains[_KT], key: _KT, /) -> bool:
"""Same as `key in obj`."""
- return cast("_BoolT", key in obj) # type: ignore[redundant-cast]
+ return key in obj
# `builtins.reversed` is annotated incorrectly within typeshed:
# https://github.com/python/typeshed/issues/11645
-do_reversed: Final = cast("_d.DoesReversed", reversed)
+do_reversed: Final[_d.DoesReversed] = cast("_d.DoesReversed", reversed)
# infix ops
-do_add: Final = cast("_d.DoesAdd", _o.add)
-do_sub: Final = cast("_d.DoesSub", _o.sub)
-do_mul: Final = cast("_d.DoesMul", _o.mul)
-do_matmul: Final = cast("_d.DoesMatmul", _o.matmul)
-do_truediv: Final = cast("_d.DoesTruediv", _o.truediv)
-do_floordiv: Final = cast("_d.DoesFloordiv", _o.floordiv)
-do_mod: Final = cast("_d.DoesMod", _o.mod)
-do_divmod: Final = divmod
-do_pow: Final = cast("_d.DoesPow", pow)
-do_lshift: Final = cast("_d.DoesLshift", _o.lshift)
-do_rshift: Final = cast("_d.DoesRshift", _o.rshift)
-do_and: Final = cast("_d.DoesAnd", _o.and_)
-do_xor: Final = cast("_d.DoesXor", _o.xor)
-do_or: Final = cast("_d.DoesOr", _o.or_)
+do_add: Final[_d.DoesAdd] = cast("_d.DoesAdd", _o.add)
+do_sub: Final[_d.DoesSub] = cast("_d.DoesSub", _o.sub)
+do_mul: Final[_d.DoesMul] = cast("_d.DoesMul", _o.mul)
+do_matmul: Final[_d.DoesMatmul] = cast("_d.DoesMatmul", _o.matmul)
+do_truediv: Final[_d.DoesTruediv] = cast("_d.DoesTruediv", _o.truediv)
+do_floordiv: Final[_d.DoesFloordiv] = cast("_d.DoesFloordiv", _o.floordiv)
+do_mod: Final[_d.DoesMod] = cast("_d.DoesMod", _o.mod)
+do_divmod: Final[_d.DoesDivmod] = divmod
+do_pow: Final[_d.DoesPow] = cast("_d.DoesPow", pow)
+do_lshift: Final[_d.DoesLshift] = cast("_d.DoesLshift", _o.lshift)
+do_rshift: Final[_d.DoesRshift] = cast("_d.DoesRshift", _o.rshift)
+do_and: Final[_d.DoesAnd] = cast("_d.DoesAnd", _o.and_)
+do_xor: Final[_d.DoesXor] = cast("_d.DoesXor", _o.xor)
+do_or: Final[_d.DoesOr] = cast("_d.DoesOr", _o.or_)
# reflected ops
@@ -293,33 +290,33 @@ def do_ror(a: _c.CanROr[_LeftT, _OutT], b: _LeftT, /) -> _OutT:
# augmented ops
-do_iadd: Final = cast("_d.DoesIAdd", _o.iadd)
-do_isub: Final = cast("_d.DoesISub", _o.isub)
-do_imul: Final = cast("_d.DoesIMul", _o.imul)
-do_imatmul: Final = cast("_d.DoesIMatmul", _o.imatmul)
-do_itruediv: Final = cast("_d.DoesITruediv", _o.itruediv)
-do_ifloordiv: Final = cast("_d.DoesIFloordiv", _o.ifloordiv)
-do_imod: Final = cast("_d.DoesIMod", _o.imod)
-do_ipow: Final = cast("_d.DoesIPow", _o.ipow)
-do_ilshift: Final = cast("_d.DoesILshift", _o.ilshift)
-do_irshift: Final = cast("_d.DoesIRshift", _o.irshift)
-do_iand: Final = cast("_d.DoesIAnd", _o.iand)
-do_ixor: Final = cast("_d.DoesIXor", _o.ixor)
-do_ior: Final = cast("_d.DoesIOr", _o.ior)
+do_iadd: Final[_d.DoesIAdd] = cast("_d.DoesIAdd", _o.iadd)
+do_isub: Final[_d.DoesISub] = cast("_d.DoesISub", _o.isub)
+do_imul: Final[_d.DoesIMul] = cast("_d.DoesIMul", _o.imul)
+do_imatmul: Final[_d.DoesIMatmul] = cast("_d.DoesIMatmul", _o.imatmul)
+do_itruediv: Final[_d.DoesITruediv] = cast("_d.DoesITruediv", _o.itruediv)
+do_ifloordiv: Final[_d.DoesIFloordiv] = cast("_d.DoesIFloordiv", _o.ifloordiv)
+do_imod: Final[_d.DoesIMod] = cast("_d.DoesIMod", _o.imod)
+do_ipow: Final[_d.DoesIPow] = cast("_d.DoesIPow", _o.ipow)
+do_ilshift: Final[_d.DoesILshift] = cast("_d.DoesILshift", _o.ilshift)
+do_irshift: Final[_d.DoesIRshift] = cast("_d.DoesIRshift", _o.irshift)
+do_iand: Final[_d.DoesIAnd] = cast("_d.DoesIAnd", _o.iand)
+do_ixor: Final[_d.DoesIXor] = cast("_d.DoesIXor", _o.ixor)
+do_ior: Final[_d.DoesIOr] = cast("_d.DoesIOr", _o.ior)
# unary ops
-do_neg: Final = _o.neg
-do_pos: Final = _o.pos
-do_abs: Final = abs
-do_invert: Final = _o.invert
+do_neg: Final[_d.DoesNeg] = _o.neg
+do_pos: Final[_d.DoesPos] = _o.pos
+do_abs: Final[_d.DoesAbs] = abs
+do_invert: Final[_d.DoesInvert] = _o.invert
# fingerprinting
-do_hash: Final = hash
-do_index: Final = cast("_d.DoesIndex", _o.index)
+do_hash: Final[_d.DoesHash] = hash
+do_index: Final[_d.DoesIndex] = _o.index
# rounding
# (the typeshed stubs for `round` are unnecessarily strict)
-do_round: Final = cast("_d.DoesRound", round)
-do_trunc: Final = math.trunc
-do_floor: Final = cast("_d.DoesFloor", math.floor)
-do_ceil: Final = cast("_d.DoesCeil", math.ceil)
+do_round: Final[_d.DoesRound] = cast("_d.DoesRound", round)
+do_trunc: Final[_d.DoesTrunc] = math.trunc
+do_floor: Final[_d.DoesFloor] = cast("_d.DoesFloor", math.floor)
+do_ceil: Final[_d.DoesCeil] = cast("_d.DoesCeil", math.ceil)
diff --git a/optype/_core/_does.py b/optype/_core/_does.py
index 8e79bd66..96f5a6a0 100644
--- a/optype/_core/_does.py
+++ b/optype/_core/_does.py
@@ -1,6 +1,6 @@
import sys
from collections.abc import AsyncIterator, Callable, Iterable, Iterator
-from typing import Literal, Protocol, TypeAlias, overload
+from typing import Protocol, overload
if sys.version_info >= (3, 13):
from typing import ParamSpec, TypeVar
@@ -101,17 +101,6 @@ def __dir__() -> list[str]:
###
-_JustFalse: TypeAlias = Literal[False]
-_JustTrue: TypeAlias = Literal[True]
-_Just0: TypeAlias = Literal[0]
-# cannot use `optype.typing.LiteralByte` here, as it starts at 0
-_PosInt: TypeAlias = Literal[
- 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
- 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
- 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
- 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
-] # fmt: skip
-
_Tss = ParamSpec("_Tss")
_KeyT = TypeVar("_KeyT")
@@ -128,10 +117,6 @@ def __dir__() -> list[str]:
_AIteratorT = TypeVar("_AIteratorT", bound=AsyncIterator[object] | _c.CanANext[object])
_IterT = TypeVar("_IterT", bound=Iterable[object])
_BoolT = TypeVar("_BoolT", bound=bool)
-_IntT = TypeVar("_IntT", bound=int)
-_StrT = TypeVar("_StrT", bound=str)
-_FormatT = TypeVar("_FormatT", bound=str)
-_BytesT = TypeVar("_BytesT", bound=bytes)
###
@@ -205,42 +190,35 @@ def __call__(self, obj: _c.CanFloat, /) -> float: ...
class DoesInt(Protocol):
- def __call__(self, obj: _c.CanInt[_IntT], /) -> _IntT: ...
+ def __call__(self, obj: _c.CanInt, /) -> int: ...
class DoesBool(Protocol):
@overload
def __call__(self, obj: _c.CanBool[_BoolT], /) -> _BoolT: ...
@overload
- def __call__(self, obj: _c.CanLen[_Just0], /) -> _JustFalse: ...
- @overload
- def __call__(self, obj: _c.CanLen[_PosInt], /) -> _JustTrue: ...
+ def __call__(self, obj: _c.CanLen, /) -> bool: ...
@overload
def __call__(self, obj: object, /) -> bool: ...
class DoesStr(Protocol):
- def __call__(self, obj: _c.CanStr[_StrT], /) -> _StrT: ...
+ def __call__(self, obj: _c.CanStr, /) -> str: ...
class DoesBytes(Protocol):
- def __call__(self, obj: _c.CanBytes[_BytesT], /) -> _BytesT: ...
+ def __call__(self, obj: _c.CanBytes, /) -> bytes: ...
# formatting
class DoesRepr(Protocol):
- def __call__(self, obj: _c.CanRepr[_StrT], /) -> _StrT: ...
+ def __call__(self, obj: _c.CanRepr, /) -> str: ...
class DoesFormat(Protocol):
- def __call__(
- self,
- obj: _c.CanFormat[_FormatT, _StrT],
- format_spec: _FormatT = ...,
- /,
- ) -> _StrT: ...
+ def __call__(self, obj: _c.CanFormat, format_spec: str = ..., /) -> str: ...
# rich comparison
@@ -293,27 +271,22 @@ def __call__(self, lhs: _LeftT, rhs: _c.CanLe[_LeftT, _OutT], /) -> _OutT: ...
class DoesGetattr(Protocol):
@overload
- def __call__(self, obj: _c.CanGetattr[_StrT, _AttrT], name: _StrT, /) -> _AttrT: ...
+ def __call__(self, obj: _c.CanGetattr[_AttrT], name: str, /) -> _AttrT: ...
@overload
- def __call__(
- self,
- obj: _c.CanGetattribute[_StrT, _AttrT],
- name: _StrT,
- /,
- ) -> _AttrT: ...
+ def __call__(self, obj: _c.CanGetattribute[_AttrT], name: str, /) -> _AttrT: ...
@overload
def __call__(
self,
- obj: _c.CanGetattr[_StrT, _AttrT],
- name: _StrT,
+ obj: _c.CanGetattr[_AttrT],
+ name: str,
default: _DefaultT,
/,
) -> _AttrT | _DefaultT: ...
@overload
def __call__(
self,
- obj: _c.CanGetattribute[_StrT, _AttrT],
- name: _StrT,
+ obj: _c.CanGetattribute[_AttrT],
+ name: str,
default: _DefaultT,
/,
) -> _AttrT | _DefaultT: ...
@@ -322,15 +295,15 @@ def __call__(
class DoesSetattr(Protocol):
def __call__(
self,
- obj: _c.CanSetattr[_StrT, _AttrT],
- name: _StrT,
+ obj: _c.CanSetattr[_AttrT],
+ name: str,
value: _AttrT,
/,
) -> None: ...
class DoesDelattr(Protocol):
- def __call__(self, obj: _c.CanDelattr[_StrT], name: _StrT, /) -> None: ...
+ def __call__(self, obj: _c.CanDelattr, name: str, /) -> None: ...
class DoesDir(Protocol):
@@ -357,11 +330,11 @@ def __call__(
class DoesLen(Protocol):
- def __call__(self, obj: _c.CanLen[_IntT], /) -> _IntT: ...
+ def __call__(self, obj: _c.CanLen, /) -> int: ...
class DoesLengthHint(Protocol):
- def __call__(self, obj: _c.CanLengthHint[_IntT], /) -> _IntT: ...
+ def __call__(self, obj: _c.CanLengthHint, /) -> int: ...
class DoesGetitem(Protocol):
@@ -397,7 +370,7 @@ def __call__(
class DoesContains(Protocol):
- def __call__(self, obj: _c.CanContains[_KeyT, _BoolT], key: _KeyT, /) -> _BoolT: ...
+ def __call__(self, obj: _c.CanContains[_KeyT], key: _KeyT, /) -> bool: ...
class DoesReversed(Protocol):
@@ -789,7 +762,7 @@ def __call__(self, obj: _c.CanInvert[_OutT], /) -> _OutT: ...
class DoesIndex(Protocol):
- def __call__(self, obj: _c.CanIndex[_IntT], /) -> _IntT: ...
+ def __call__(self, obj: _c.CanIndex, /) -> int: ...
class DoesHash(Protocol):
diff --git a/optype/typing.py b/optype/typing.py
index 69b818ee..866ec93e 100644
--- a/optype/typing.py
+++ b/optype/typing.py
@@ -50,7 +50,6 @@ def __dir__() -> tuple[str, ...]:
###
_T = TypeVar("_T")
-_IntT = TypeVar("_IntT", bound=int, default=int)
_ValueT = TypeVar("_ValueT", default=object)
@@ -101,7 +100,7 @@ class JustComplex(_just.JustComplex, Protocol, just=complex): ... # type: ignor
# Anything that can *always* be converted to an `int` / `float` / `complex`
-AnyInt: TypeAlias = _IntT | _c.CanInt[_IntT] | _c.CanIndex[_IntT]
+AnyInt: TypeAlias = int | _c.CanInt | _c.CanIndex
AnyFloat: TypeAlias = _c.CanFloat | _c.CanIndex
AnyComplex: TypeAlias = _c.CanComplex | _c.CanFloat | _c.CanIndex
diff --git a/pyproject.toml b/pyproject.toml
index e3d96c2a..8626ffd5 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -8,7 +8,7 @@ module-root = ""
[project]
name = "optype"
description = "Building Blocks for Precise & Flexible Type Hints"
-version = "0.14.1.dev0"
+version = "0.15.0.dev0"
authors = [{ name = "Joren Hammudoglu", email = "jhammudoglu@gmail.com" }]
license = "BSD-3-Clause"
license-files = ["LICENSE"]
diff --git a/tests/core/test_do.py b/tests/core/test_do.py
index 9b624ea8..78534a8a 100644
--- a/tests/core/test_do.py
+++ b/tests/core/test_do.py
@@ -16,7 +16,7 @@ def test_static() -> None:
_do_setitem: _does.DoesSetitem = _do.do_setitem
_do_delitem: _does.DoesDelitem = _do.do_delitem
_do_missing: _does.DoesMissing = _do.do_missing
- _do_contains: _does.DoesContains = _do.do_contains # type: ignore[assignment]
+ _do_contains: _does.DoesContains = _do.do_contains
_do_radd: _does.DoesRAdd = _do.do_radd
_do_rsub: _does.DoesRSub = _do.do_rsub
diff --git a/tests/test_typing.py b/tests/test_typing.py
index 65fc2c9e..139ac682 100644
--- a/tests/test_typing.py
+++ b/tests/test_typing.py
@@ -1,6 +1,6 @@
import enum
import sys
-from typing import Generic, Literal, final
+from typing import Generic, final
if sys.version_info >= (3, 13):
from typing import TypeVar
@@ -73,9 +73,9 @@ def __getitem__(self, index: int, /) -> _V_co:
def test_any_int() -> None:
p_bool: opt.AnyInt = True
- p_int: opt.AnyInt[Literal[2]] = 2
- p_index: opt.AnyInt[Literal[3]] = SimpleIndex(3)
- p_int_like: opt.AnyInt[Literal[4]] = SimpleInt(4)
+ p_int: opt.AnyInt = 2
+ p_index: opt.AnyInt = SimpleIndex(3)
+ p_int_like: opt.AnyInt = SimpleInt(4)
n_complex: opt.AnyInt = 5j # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
n_str: opt.AnyInt = "6" # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
diff --git a/uv.lock b/uv.lock
index 9970c691..6b10e81b 100644
--- a/uv.lock
+++ b/uv.lock
@@ -313,7 +313,7 @@ wheels = [
[[package]]
name = "optype"
-version = "0.14.1.dev0"
+version = "0.15.0.dev0"
source = { editable = "." }
dependencies = [
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },