-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
"Statement is unreachable" false positive when calling callable
on union with object
#11764
Comments
oops didn't mean to click feature but i can't remove it |
Sorry, but this is true. >>> o = object()
>>> o()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'object' object is not callable But, Or am I missing something? |
sure def foo(value: object | str) -> None:
if callable(value):
print(1) # Statement is unreachable [unreachable]
foo(lambda: ...) # no error because a `Callable` is a subtype of `object`
callable(lambda: ...) # True |
Subtype of any type can be callable 🙂 Do you mean that |
no it shouldn't be treated specifically, instead function foo(value: unknown | string) { //unknown is the typescript equivalent of object
if (typeof value === 'function') {
value() //narrowed to Function
}
} if you look at the signature of def callable(__obj: object) -> TypeGuard[Callable[..., object]]: ... in fact, if we just copy that signature and make our own from typing import TypeGuard, Callable
def callable2(__obj: object) -> TypeGuard[Callable[..., object]]: ...
def foo(value: object | str) -> None:
if callable2(value):
reveal_type(value) # note: Revealed type is "def (*Any, **Any) -> builtins.object"
print(1)
def bar(value: object | str) -> None:
if callable(value):
reveal_type(value) # error: Statement is unreachable [unreachable] so it seems that the problem is that there's some sort of intrinsic behavior on |
Oh, now I can see a problem: from typing import TypeGuard, Callable
def callable2(__obj: object) -> TypeGuard[Callable[..., object]]: ...
def foo(value: object | str) -> None:
if callable2(value):
reveal_type(value) # note: Revealed type is "def (*Any, **Any) -> builtins.object"
print(1)
def bar(value: object | str) -> None:
if callable(value):
reveal_type(value) # error: Statement is unreachable [unreachable] This is inconsistent and probably should be solved. I will take a look, thanks a lot for your explanation! 👍 |
Right now in typeshed But, mypy does some in-depth analysis of Lines 4062 to 4142 in 56684e4
I am not sure how to solve this problem 🤔 On one hand, I understand that some subtypes of any types can be callble. And |
An This was particularly surprising to me because from __future__ import annotations
from typing import Optional
def func1(value: Optional[object]) -> None:
if callable(value):
_ = True # got: Statement is unreachable [unreachable]
# expected: no error
# ADDITIONAL MATERIAL - NOT NECESSARY TO REPRODUCE:
def func2(value: object) -> None:
if callable(value):
_ = True # no error (as expected)
obj1: object
reveal_type(callable(obj1)) # Revealed type is 'bool' (as expected)
obj2: Optional[object]
reveal_type(callable(obj2)) # Revealed type is 'bool' (as expected) |
Could we just simplify the union here? @finite-state-machine |
@KotlinIsland wrote:
Oh, I agree, there's no point in writing from __future__ import annotations
from typing import *
T = TypeVar('T')
class SomeClass:
def __init__(self, magic_test: T):
self.magic_test = magic_test
def is_magic(self, value: object) -> bool:
if callable(self.magic_test):
return self.magic_test(value) # "unreachable"
return value is self.magic_test An earlier revision of @finite-state-machine had the idea – probably not very good one, in retrospect – to allow "magic" tests such as the following: # where values can't be 'None' anyway:
inst = SomeClass(magic_test=None)
# a specific, undifferentiated 'object' might act as the sentinal (again, using the 'is' test):
definitely_magic = object()
inst = SomeClass(magic_test=definitely_magic)
# where it's helpful to have more than one distinct value considered 'magic':
@dataclass
class MagicClass:
detail_a: int
detail_b: str
inst = SomeClass(magic_test=lambda _value: isinstance(_value, MagicClass)) While I certainly agree that: value: Union[CallableThing, NotObviouslyCallableThing]
if callable(value):
...
else:
... ... should narrow the type for both the |
https://mypy-play.net/?mypy=master&python=3.10&flags=show-error-codes%2Callow-redefinition%2Cstrict%2Ccheck-untyped-defs%2Cdisallow-any-decorated%2Cdisallow-any-expr%2Cdisallow-any-explicit%2Cdisallow-any-generics%2Cdisallow-any-unimported%2Cdisallow-incomplete-defs%2Cdisallow-subclassing-any%2Cdisallow-untyped-calls%2Cdisallow-untyped-decorators%2Cdisallow-untyped-defs%2Cno-implicit-optional%2Cno-implicit-reexport%2Cstrict-equality%2Cwarn-incomplete-stub%2Cwarn-redundant-casts%2Cwarn-return-any%2Cwarn-unreachable%2Cwarn-unused-configs%2Cwarn-unused-ignores&gist=a72eb2ed08576c38916daccddd89fed7
The text was updated successfully, but these errors were encountered: