python / python/mypy

bool(obj) does not infer from obj.__bool__()

Abierto
#15,523 3 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

bug topic-type-narrowing
Lenguaje dominante
Python
Estrellas
20.6k
Forks
3.3k
Métricas de merge de PR
Métricas de PR pendientes

Descripción

Bug Report

(Although there are other issues that allude to this problem, I haven't been able to locate an issue which specifically addresses truthiness where __bool__() is defined and @final. The search term "truthy bool" may be helpful for finding related issues.)

Implicit truthiness does not (always?) take an object's __bool__() into account, even when that method is @final.

To Reproduce

This example is posted to mypy-play.net.

from typing import *

@final
class SomeClass:
    def __bool__(self) -> Literal[True]:
        return True

instance: SomeClass

reveal_type(instance.__bool__())    # 'Literal[True]' - correct
reveal_type(bool(instance))         # 'bool' - incorrect (should be 'Literal[True]')

if instance:
    reveal_type(instance)           # 'SomeClass' - correct
else:
    assert_never(instance)          # ...'SomeClass' - incorrect (should be silent)

(Whether the class or method is decorated @final makes no difference.)

Expected Behavior

if instance: ... and bool(instnace) should take into account that SomeClass has a @final __bool__() with return type Literal[True], and consistently treat instances of SomeClass as definitely truthy.

In general, implicit truthiness for an object should take into account the truthiness of the return type of any @final __bool__() the object's class defines.

Comments inline in the above code highlight differences from expected behaviour.

Actual Behavior

main.py:10: note: Revealed type is "Literal[True]"
main.py:11: note: Revealed type is "builtins.bool"
main.py:14: note: Revealed type is "__main__.SomeClass"
main.py:16: error: Argument 1 to "assert_never" has incompatible type "SomeClass"; expected "NoReturn"  [arg-type]
Found 1 error in 1 file (checked 1 source file)

Your Environment

  • Mypy version used: 1.4.0, master (2023-06-26)
  • Mypy command-line flags: (none)
  • Mypy configuration options from mypy.ini (and other config files): (none)
  • Python version used: 3.11

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Línea de trabajo

Comienza con el reproductor main.py del issue y compara el tratamiento de instance.bool(), bool(instance) y el estrechamiento por truthiness en las sentencias if. Rastrea los puntos de entrada relevantes de la inferencia de tipos y del estrechamiento, y después añade cobertura para un bool() final que devuelva Literal[True]. Se considera terminado cuando bool(instance) revela Literal[True] y la rama else inalcanzable ya no produce un error de assert_never.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
python
Área
devtools
Tipo de issue
Error
Dificultad
4/5
Tiempo estimado
3-5 días
Estado de actividad
Estancado
Claridad
Bastante claro
Aptitud para principiantes
35/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.