-
-
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
type[Any]
not considered Hashable
#11470
Comments
This is why it happens: from typing import Hashable, Any
t1: type[Any] = type
reveal_type(type.__hash__) # N: Revealed type is "def (self: builtins.object) -> builtins.int"
reveal_type(t1.__hash__) # N: Revealed type is "def () -> builtins.int" And I will try to fix |
No, I was wrong. The same works with just a slight modification: from typing import Hashable, Any
t1: type = type
reveal_type(type.__hash__) # N: Revealed type is "def (self: builtins.object) -> builtins.int"
reveal_type(t1.__hash__) # N: Revealed type is "def () -> builtins.int"
h1: Hashable = t1 # no error |
Moreover, this also works: from typing import Hashable, Any
t1: type[type] = type
h1: Hashable = t1 |
Related #11469 |
I was about to report the same problem for the |
I think a |
There are also some problems with using instance: Type[object]
assert isinstance(instance, Hashable) # mypy thinks this is unsatisfiable
... # mypy thinks this is unreachable More details may be found in the duplicate bug #12993. |
Just chiming in that this is still an open issue as of Mypy 1.7.0 (Python 3.12.0). from typing import Any, Hashable
def foo(t: type) -> None:
x: Hashable = t # OK
def bar(t: type[Any]) -> None:
x: Hashable = t # error |
To give a reproducer of TypeVar usage (which could be included in tests): from functools import lru_cache
from typing import TypeVar
T = TypeVar("T")
@lru_cache
def foo(t):
...
def check(t: type[T]):
foo(t) # error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "type[T]"; expected "Hashable" [arg-type]
check(dict[str, object]) It seems that it only considers |
In fact, not all types are hashable: mypy-play.net from __future__ import annotations
from typing import *
# this might seem to be reasonable:
def test_func(klass: Type[object]) -> None:
klasses: Set[Type[Any]] = set()
# ...but this isn't completely sound:
klasses.add(klass)
# (mypy 1.8.0 isn't issuing an error here, which might be the right
# call because _almost_ all types are hashable)
class SomeMeta(type):
'''this metaclass defines '__eq__()' but not '__hash__()', making
instances of it unhashable
'''
def __eq__(self, other: object) -> bool:
return NotImplemented
class SomeClass(metaclass=SomeMeta):
'''this class uses 'SomeMeta', meaning the class itself is unhashable
'''
# This will raise an exception at runtime:
hash(SomeClass) # line 31
# Traceback (most recent call last):
# ...
# TypeError: unhashable type: 'SomeMeta'
# As will the 2nd line of this paragraph (if line 31 is commented out):
some_set: Set[Type[Any]] = set()
some_set.add(SomeClass)
# Traceback (most recent call last):
# ...
# TypeError: unhashable type: 'SomeMeta' This issues no mypy errors (ca. v1.8.0), despite being unsound. That's probably the right thing to do, but it should be a carefully weighed choice (and maybe a check which could be enabled with an |
(That said, there are errors issued by the example in #12993. IMHO this inconsistency is undesirable.) |
Indeed, as per my comment, mypy seems to consider Curiously, in my example, if I change from the TypeVar to using a custom class directly ( |
I think we can all agree that the hashability of |
One possible approach to determining if a value is likely In a way, it's a pity |
I'm not sure if this is true. Below are some tests with mypy 1.12. from dataclasses import dataclass
from typing import Hashable, Any, NamedTuple
t1: type[Any] = type
h1: Hashable = t1 # error: Incompatible types in assignment
t2: type[str] = str
h2: Hashable = t2 # success!
@dataclass(frozen=True, unsafe_hash=True)
class Foo:
x: int
t3: type[Foo] = Foo
h3: Hashable = t3 # error: Incompatible types in assignment
class Bar(NamedTuple):
x: int
t4: type[Bar] = Bar
h4: Hashable = t4 # error: Incompatible types in assignment
t5: type[int] = int
h5: Hashable = t5 # error: Incompatible types in assignment
t6: type[type] = type
h6: Hashable = t6 # success!
t7: type = int
h7: Hashable = t7 # success! |
Which seems strange because
type[type]
is consideredHashable
, demonstrating that atype
can beHashable
.The text was updated successfully, but these errors were encountered: