-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Define return type based on boolean flag #8634
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
You should use overloads that specify a different return type based on the value of the argument (either Something like this (untested): from typing import overload, Literal
@overload
def test_func(ret_str: Literal[True] = ...) -> str: ...
@overload
def test_func(ret_str: Literal[False]) -> int: ...
def test_func(ret_str: bool = True) -> Union[int, str]:
return "Hello " if ret_str else 0 |
@JelleZijlstra Thanks for the help, that solved that particular issue! |
Actually, @JelleZijlstra followup issue, I might have spoken too soon. Is there any reason the second overload treats the ret_str as a positional argument? Let's look at a slightly more complicated example. # scratch.py
from typing import overload, Union
from typing_extensions import Literal
@overload
def test_func(arg1: int, kwarg1: int = 0, ret_str: Literal[True] = ...) -> str: ...
@overload
def test_func(arg1: int, kwarg1: int = 0, ret_str: Literal[False] = False) -> int: ...
def test_func(arg1: int, kwarg1: int = 0, ret_str: bool = True) -> Union[int, str]:
return "Hello " if ret_str else 0
if __name__ == "__main__":
print(test_func(0, 0, True)+"World!")
print(test_func(0, 0, False)+10) This outputs the error:
|
You should have a default for only one of the overloads, so they don't overlap. |
@JelleZijlstra Sure that makes sense but maybe I don't completely follow. When I place the kwarg in front of the other kwarg, things certainly work. from typing import overload, Union
from typing_extensions import Literal
@overload
def test_func(arg1: int, ret_str: Literal[True] = ..., kwarg1 = True) -> str: ...
@overload
def test_func(arg1: int, ret_str: Literal[False], kwarg1 = True) -> int: ...
def test_func(arg1: int, ret_str: bool = True, kwarg1: bool = True) -> Union[int, str]:
return "Hello " if ret_str else 0
if __name__ == "__main__":
print(test_func(0, True)+"World!")
print(test_func(0, False)+10) How would I go about making it work without having to change the position of the final kwarg? |
I tried marking ret_str as a keyword-only argument as noted in #5486 but I'm getting the following error: from typing import overload, Union
from typing_extensions import Literal
@overload
def test_func(arg1: int, kwarg1: int = 0, ret_str: Literal[True] = ...) -> str: ...
@overload
def test_func(arg1: int, kwarg1: int = 0, *, ret_str: Literal[False]) -> int: ...
def test_func(arg1: int, kwarg1: int = 0, ret_str: bool = True) -> Union[int, str]:
return "Hello " if ret_str else 0
if __name__ == "__main__":
print(test_func(0, 0, True)+"World!")
print(test_func(0, 0, False)+10) Error: scratch.py:15: error: No overload variant of "test_func" matches argument types "int", "int", "bool"
scratch.py:15: note: Possible overload variant:
scratch.py:15: note: def test_func(arg1: int, kwarg1: int = ..., ret_str: Literal[True] = ...) -> str
scratch.py:15: note: <1 more non-matching overload not shown>
Found 1 error in 1 file (checked 1 source file) |
Okay, after more debugging this works, which makes sense. I guess there isn't any way to make this work without converting ret_str to a keyword-only argument. from typing import overload, Union
from typing_extensions import Literal
@overload
def test_func(arg1: int, kwarg1: int = 0, *, ret_str: Literal[True] = ...) -> str: ...
@overload
def test_func(arg1: int, kwarg1: int = 0, *, ret_str: Literal[False]) -> int: ...
def test_func(arg1: int, kwarg1: int = 0, *, ret_str: bool = True) -> Union[int, str]:
return "Hello " if ret_str else 0
if __name__ == "__main__":
print(test_func(0, 0, True)+"World!")
print(test_func(0, 0, False)+10) |
The following works: from typing import overload, Union
from typing_extensions import Literal
@overload
def test_func(arg1: int, kwarg1: int = 0, ret_str: Literal[True] = ...) -> str: ...
@overload
def test_func(arg1: int, kwarg1: int, ret_str: Literal[False]) -> int: ...
@overload
def test_func(arg1: int, kwarg1: int = 0, *, ret_str: Literal[False]) -> int: ...
def test_func(arg1: int, kwarg1: int = 0, ret_str: bool = True) -> Union[int, str]:
return "Hello " if ret_str else 0
if __name__ == "__main__":
print(test_func(0) + "World!")
print(test_func(0, 0) + "World!")
print(test_func(0, 0, True) + "World!")
print(test_func(0, 0, False) + 10)
print(test_func(0, ret_str=False) + 1)
print(test_func(0, 0, ret_str=False) + 1)
print(test_func(0, ret_str=True) + "World!")
print(test_func(0, 0, ret_str=True) + "World!") When you pass |
@knbk that's helpful, and makes sense: thank you! |
Situation
$ mypy test.py
Error
Expectation
I, the programmer, know that I can expect a string from the functions as a result of the boolean flag. How would I go about clueing the static type checker into that as well. I know that I can use instanceof in the code that calls the function but that doesn't make much sense when one is guaranteed the return type due to the boolean flag.
The text was updated successfully, but these errors were encountered: