Closed
Description
Bug Report
The order of declarations shouldn't matter to mypy, but in the example that follow, they do.
To Reproduce
(Exactly as written below: mypy-play.net)
(With slightly better comments, but different line numbers: mypy-play.net)
from __future__ import annotations
import functools
from typing import (
Any,
Callable,
cast,
Counter,
Optional,
TypeVar,
)
Tc = TypeVar('Tc', bound=Callable[..., Any])
def func_wraps(wraps: Tc) -> Callable[[Callable[..., Any]], Tc]:
'''declare that one function wraps another
Args:
wraps: the function being wrapped
Returns:
a function 'decorator()', where...
Args:
the function which wraps 'wraps'
Returns:
the input argument, unchanged
The type annotations of the return value of the 'decorator()' will
be those of 'wraps'.
'''
def inner(wrapper: Callable[..., Any], /) -> Tc:
'''decorator
Args:
wrapper: the function which wraps 'wraps'
Returns:
the same function, unchanged
'''
wrapper_ = cast(Tc, wrapper)
return functools.wraps(wraps)(wrapper_)
return inner
reveal_type(ParentClass)
reveal_type(ChildClass)
reveal_type(ParentClass.__init__)
reveal_type(ChildClass.__init__)
def function1() -> ChildClass:
return ChildClass()
class ParentClass:
def __init__(self, *, param: Optional[int] = None) -> None:
_ = param
class ChildClass(ParentClass):
some_counter: Counter[int]
@func_wraps(ParentClass.__init__)
def __init__(self, *args: Any, **kwargs: Any):
super().__init__(*args, **kwargs)
self.some_counter = Counter()
def function2() -> ChildClass:
return ChildClass()
reveal_type(ParentClass)
reveal_type(ChildClass)
reveal_type(ParentClass.__init__)
reveal_type(ChildClass.__init__)
Expected Behavior
The reveal_type
lines and function1
declaration, found before the class definitions, should result in the same output as those found after the class definitions.
mypy's output should be (lines which differ are marked with a "*
"):
bug.py:47: note: Revealed type is "def (*, param: Union[builtins.int, None] =) -> bug.ParentClass"
* bug.py:48: note: Revealed type is "def (*, param: Union[builtins.int, None] =) -> bug.ChildClass"
bug.py:49: note: Revealed type is "def (self: bug.ParentClass, *, param: Union[builtins.int, None] =)"
* bug.py:50: note: Revealed type is "def (self: bug.ParentClass, *, param: Union[builtins.int, None] =)"
[edit: removed line that shouldn't have been here]
bug.py:74: note: Revealed type is "def (*, param: Union[builtins.int, None] =) -> bug.ParentClass"
bug.py:75: note: Revealed type is "def (*, param: Union[builtins.int, None] =) -> bug.ChildClass"
bug.py:76: note: Revealed type is "def (self: bug.ParentClass, *, param: Union[builtins.int, None] =)"
bug.py:77: note: Revealed type is "def (self: bug.ParentClass, *, param: Union[builtins.int, None] =)"
* Success: no issues found in 1 source file
Actual Behavior
The first group ofreveal_type
lines and the function1
declaration misbehave, while everything after the class definitions behaves as expected.
The actual output is:
bug.py:47: note: Revealed type is "def (*, param: Union[builtins.int, None] =) -> bug.ParentClass"
* bug.py:48: note: Revealed type is "Any"
bug.py:49: note: Revealed type is "def (self: bug.ParentClass, *, param: Union[builtins.int, None] =)"
* bug.py:50: note: Revealed type is "Any"
* bug.py:54: error: Returning Any from function declared to return "ChildClass" [no-any-return]
bug.py:74: note: Revealed type is "def (*, param: Union[builtins.int, None] =) -> bug.ParentClass"
bug.py:75: note: Revealed type is "def (*, param: Union[builtins.int, None] =) -> bug.ChildClass"
bug.py:76: note: Revealed type is "def (self: bug.ParentClass, *, param: Union[builtins.int, None] =)"
bug.py:77: note: Revealed type is "def (self: bug.ParentClass, *, param: Union[builtins.int, None] =)"
* Found 1 error in 1 file (checked 1 source file)
Your Environment
- Mypy version used: 0.991, master (2023-01-23)
- Mypy command-line flags:
--follow-imports=silent --show-error-codes --strict --warn-unreachable
- Mypy configuration options from
mypy.ini
(and other config files): N/A - Python version used: 3.8, 3.11