Skip to content

Conversation

@srittau
Copy link
Collaborator

@srittau srittau commented Jul 7, 2025

As @JelleZijlstra pointed out, this is basically equivalent to returning object (since all objects implement __bool__). So I'm reverting this.

@srittau srittau merged commit 096cf56 into python:main Jul 7, 2025
63 checks passed
@srittau srittau deleted the rv-12939 branch July 7, 2025 14:25
@github-actions
Copy link
Contributor

github-actions bot commented Jul 7, 2025

Diff from mypy_primer, showing the effect of this PR on open source code:

colour (https://github.com/colour-science/colour)
+ colour/plotting/colorimetry.py:565: error: Value of type variable "SupportsRichComparisonT" of "min" cannot be "floating[_16Bit] | floating[_32Bit] | float64"  [type-var]
+ colour/plotting/colorimetry.py:566: error: Value of type variable "SupportsRichComparisonT" of "max" cannot be "floating[_16Bit] | floating[_32Bit] | float64"  [type-var]

jax (https://github.com/google/jax)
- jax/_src/pallas/mosaic/pipeline.py:1546: error: Unused "type: ignore" comment  [unused-ignore]

ibis (https://github.com/ibis-project/ibis)
+ ibis/expr/types/relations.py:2986: error: Value of type variable "SupportsRichComparisonT" of "sorted" cannot be "NumericValue | float"  [type-var]

arviz (https://github.com/arviz-devs/arviz)
+ arviz/stats/ecdf_utils.py:72: error: Value of type variable "SupportsRichComparisonT" of "min" cannot be "Any | float64"  [type-var]

@jorenham
Copy link
Contributor

jorenham commented Jul 7, 2025

As @JelleZijlstra pointed out, this is basically equivalent to returning object (since all objects implement __bool__).

It isn't though:

from typing import Protocol, final

@final
class NotTruthy:
    __bool__ = None

class SupportsBool(Protocol):
    def __bool__(self, /) -> bool: ...

x: SupportsBool = NotTruthy()  # rejected

basedpyright playground

@srittau
Copy link
Collaborator Author

srittau commented Jul 7, 2025

@jorenham I don't think that's currently an officially supported pattern – opposed to __hash__ = None. Neither is mentioned in the typing spec, though, but typeshed does not contain a single instance of __bool__ = None, yet. That said, I'd definitely be in favor of that pattern, but this should be a wider discussion on discuss.python.org, and then be added to the spec (together with __hash__). (I seem to remember that I mentioned something like this in previous discuss threads, but I'm not sure.) Then we could revisit this PR.

@AlexWaygood
Copy link
Member

The official data model states:

Setting a special method to None indicates that the corresponding operation is not available. For example, if a class sets __iter__() to None, the class is not iterable, so calling iter() on its instances will raise a TypeError (without falling back to __getitem__()).

See also https://mail.python.org/archives/list/[email protected]/thread/YGAK34DRWJFSIV2VZ4NC2J24XO37GCMM/

@jorenham
Copy link
Contributor

jorenham commented Jul 7, 2025

@jorenham I don't think that's currently an officially supported pattern – opposed to __hash__ = None. Neither is mentioned in the typing spec, though, but typeshed does not contain a single instance of __bool__ = None, yet. That said, I'd definitely be in favor of that pattern, but this should be a wider discussion on discuss.python.org, and then be added to the spec (together with __hash__). (I seem to remember that I mentioned something like this in previous discuss threads, but I'm not sure.) Then we could revisit this PR.

Ok fair enough. But then what about the fact that object.__bool__ doesn't exist?

class object:
__doc__: str | None
__dict__: dict[str, Any]
__module__: str
__annotations__: dict[str, Any]
@property
def __class__(self) -> type[Self]: ...
@__class__.setter
def __class__(self, type: type[Self], /) -> None: ...
def __init__(self) -> None: ...
def __new__(cls) -> Self: ...
# N.B. `object.__setattr__` and `object.__delattr__` are heavily special-cased by type checkers.
# Overriding them in subclasses has different semantics, even if the override has an identical signature.
def __setattr__(self, name: str, value: Any, /) -> None: ...
def __delattr__(self, name: str, /) -> None: ...
def __eq__(self, value: object, /) -> bool: ...
def __ne__(self, value: object, /) -> bool: ...
def __str__(self) -> str: ... # noqa: Y029
def __repr__(self) -> str: ... # noqa: Y029
def __hash__(self) -> int: ...
def __format__(self, format_spec: str, /) -> str: ...
def __getattribute__(self, name: str, /) -> Any: ...
def __sizeof__(self) -> int: ...
# return type of pickle methods is rather hard to express in the current type system
# see #6661 and https://docs.python.org/3/library/pickle.html#object.__reduce__
def __reduce__(self) -> str | tuple[Any, ...]: ...
def __reduce_ex__(self, protocol: SupportsIndex, /) -> str | tuple[Any, ...]: ...
if sys.version_info >= (3, 11):
def __getstate__(self) -> object: ...
def __dir__(self) -> Iterable[str]: ...
def __init_subclass__(cls) -> None: ...
@classmethod
def __subclasshook__(cls, subclass: type, /) -> bool: ...

>>> object.__bool__
Traceback (most recent call last):
  File "<python-input-1>", line 1, in <module>
    object.__bool__
AttributeError: type object 'object' has no attribute '__bool__'. Did you mean: '__doc__'?

@srittau
Copy link
Collaborator Author

srittau commented Jul 7, 2025

Ok, makes sense to me. So let's re-apply the original PR and start using bool = None in typeshed where applicable?

@jorenham
Copy link
Contributor

jorenham commented Jul 7, 2025

and start using bool = None in typeshed where applicable?

That should only be needed if a base class implements __bool__:

from typing import Protocol

class SupportsBool(Protocol):
    def __bool__(self, /) -> bool: ...

x: SupportsBool = object()  # rejected

basedpyright playground

@randolf-scholz
Copy link
Contributor

randolf-scholz commented Jul 14, 2025

@srittau I already reopened the PR with an additional unit test that checks that plain object is not accepted at type checking time (despite working at runtime); see #14375.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants