Open jorenham opened 3 weeks ago
I think this ultimately boils down to the definition of SupportsDunderLT
etc:
These expect the dunders to return a real bool
. I'm not sure how np.bool
is implemented, so this may be hard to fix.
Unfortunately bool
isn't subclassable, so np.bool
is its own separate thing. It's backed by 0 and 1 8-bit int values.
This should be solvable by returning SupportsBool
where
class SupportsBool(Protocol):
def __bool__(self) -> bool: ...
That protocol is equivalent to object
in practice, so we'd be better off simply using object
as the return type in the SupportDunder*
protocols.
@JelleZijlstra At runtime yes, but currently the type hints for object
do not include __bool__
. Hence, it makes a difference at type checking time: Code sample in pyright playground
from typing import Protocol
class SupportsBool(Protocol):
def __bool__(self) -> bool: ...
x: SupportsBool = object() # raises reportAssignmentType
I'm not sure why __bool__
is not declared on object
, but there is probably some reason for it.
EDIT: It's because object
does not have __bool__
at runtime.
OK object
seems the right thing as the following works at runtime:
class Foo:
def __lt__(self, other): return self
def __gt__(self, other): return self
def __le__(self, other): return self
def __ge__(self, other): return self
x = Foo()
y = Foo()
assert min(x, y) is y # ✅
x.__bool__ # ❌ AttributeError
There is also a very similar definition in _operator.pyi
, with this chance these maybe can be combined
PR https://github.com/python/typeshed/pull/12573 replaces these bool
return hints with object
. mypy-primer looks good.
However, it makes me wonder whether the bool
return hint should be replaced by object
in other cases as well, such as SupportsGetItem.__contains__
and similar protocols.
Since NumPy 2.1 all subtypes of
numpy.number
implement__lt__
that returns anumpy.bool
(which isn't abuiltins.bool
), matching the runtime behavior (https://github.com/numpy/numpy/pull/26942).But as was noticed in https://github.com/numpy/numpy/issues/27251, the consequence of this is that
builtins.min
with e.g.numpy.int32
input is now rejected (tested with the latest mypy and pyright).So at runtime we have
But mypy 1.11.1 rejects
min(np.int32(8), np.int32(9))
as:Similarly, Pyright 1.1.376 reports
and