Wrapped methods are not properly resolved until after the class definition
Nadie ha tomado este issue todavía.
- Lenguaje dominante
- Python
- Estrellas
- 20.6k
- Forks
- 3.3k
- Métricas de merge de PR
- Métricas de PR pendientes
Descripción
Context & setup
Consider the following simple protocol:
class Proto(Protocol):
@property
def f(self) -> int:
...
One can implement this protocol wrongly as follows:
T = TypeVar("T")
P = ParamSpec("P")
def wrapper(f: Callable[P, T]) -> Callable[P, str]:
def wrapped(*args: P.args, **kwargs: P.kwargs) -> str:
return 0
return wrapped
class Impl:
@wrapper # converts return type from `bool` to `str`, while the protocol expects `int`
def f(self) -> bool:
return False
# error: Incompatible return value type (got "Impl", expected "Proto") [return-value]
# note: Following member(s) of "Impl" have conflicts:
# note: Expected:
# note: def f(self) -> int
# note: Got:
# note: def f(self) -> str
def b() -> Proto:
return Impl()
The bug (false negative)
When this same function b is placed before class Impl, mypy does not report an error. Adding reveal_type(Impl.f) before and after the class definition hints at what is going on:
main.py:21: error: Expression has type "Any" [misc]
main.py:21: error: Cannot determine type of "f" [has-type]
main.py:21: note: Revealed type is "Any"
main.py:21: error: Name "Impl" is used before definition [used-before-def]
main.py:28: note: Revealed type is "def (self: __main__.Impl) -> builtins.str"
If f is not decorated but explicitly returns str, one gets
main.py:21: note: Revealed type is "def (self: __main__.Impl) -> builtins.str"
main.py:21: error: Name "Impl" is used before definition [used-before-def]
main.py:27: note: Revealed type is "def (self: __main__.Impl) -> builtins.str"
as expected. This indicates that the wrapped decorator is only properly resolved for code after the class definition.
False positive variant
If f is decorated with @property, this can also produce false positives. This is how I encountered the issue in the first place. Playground.
Additional info
Python: 3.11
Mypy: 371219347a6d17e16924bbabf3e693c6874e7138
Flags: --strict --disallow-any-*
Guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Línea de trabajo
Reproduce el falso negativo y el falso positivo en main.py usando los ejemplos de mypy-play enlazados, comparando la ubicación de la función, @wrapper y @property. Rastrea cómo se resuelven el decorador y el tipo del método envuelto antes y después de class Impl; se considera terminado cuando ambas variantes informan de forma coherente los diagnósticos esperados de compatibilidad con el protocolo.
Escrito por el modelo de indexación a partir del texto del issue.
Evaluación
- Stack tecnológico
- python
- Área
- tooling
- 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