You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fromtypingimportHashable, Anyt1: type[Any] =typeh1: Hashable=t1# error: Incompatible types in assignment (expression has type "Type[Any]", variable has type "Hashable")
Which seems strange because type[type] is considered Hashable, demonstrating that a typecan be Hashable.
No, I was wrong. The same works with just a slight modification:
fromtypingimportHashable, Anyt1: type=typereveal_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
I was about to report the same problem for the @cache decorator case, and just want to chime in that Type[_T] for TypeVar _T is also a problem. I see discussion of Type[Any] and type[type] but it's not clear to me if that covers the type var case as well.
I think a type[T] where the upper bound of T produces a Hashabletype[T] (default upper bound is object, and type[object] is hashable) should be considered Hashable.
To give a reproducer of TypeVar usage (which could be included in tests):
fromfunctoolsimportlru_cachefromtypingimportTypeVarT=TypeVar("T")
@lru_cachedeffoo(t):
...
defcheck(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 type[T] to be hashable if T is hashable. Thus, the error disappears if doing TypeVar("T", bound=Hashable). However, that is not correct as you then can't pass dict[str, object] in the last line.
from __future__ importannotationsfromtypingimport*# this might seem to be reasonable:deftest_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)classSomeMeta(type):
'''this metaclass defines '__eq__()' but not '__hash__()', making instances of it unhashable '''def__eq__(self, other: object) ->bool:
returnNotImplementedclassSomeClass(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 --enable-flag).
(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 type[X] hashable only if X is hashable, which seems completely unrelated.
Curiously, in my example, if I change from the TypeVar to using a custom class directly (def check(t: type[Bar])), then I still get the same error, yet I don't get the error if I just call foo(Bar), which should be the same thing...
One possible approach to determining if a value is likely Hashable: in the entire system being type-checked, is there any known example of the specified type that is notHashable? For most projects, that would mean Type[Any/object] would be Hashable. OTOH this involves spooky action at a distance: defining a metaclass in one place could cause errors to appear on the other side of the code base.
In a way, it's a pityHashable isn't Generic-like: being able to writeHashable[Type[Any]], Hashable[Mapping[K, V]], Hashable[SomeProtocol], etc., would be quite useful. This is a special case of #213, and would like be solved by the as-yet-unnumbered PEP being drafted for that issue, which will presumably introduce a syntax like Type[Any] & Hashable.
i'm not entirely sure what the correct "resolution" is here / what the proper way to type this is, but fwiw, I hit this error with the following on 1.14.1:
fromfunctoolsimportlru_cachefromtypingimportTypeVar, TypeT=TypeVar("T", bound=object)
@lru_cache(maxsize=None)def_get_specifiable_attributes(cls: Type[T]): ...
defrun(dest_type: Type[T]):
_get_specifiable_attributes(dest_type)
# main.py:10: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "type[T]"; expected "Hashable" [arg-type]classFooBar:
...
run(FooBar)
Activity
sobolevn commentedon Nov 5, 2021
This is why it happens:
And
def () -> builtins.intis not compatible withHashable🤔I will try to fix
t1.__hash__inference.sobolevn commentedon Nov 5, 2021
No, I was wrong. The same works with just a slight modification:
sobolevn commentedon Nov 5, 2021
Moreover, this also works:
KotlinIsland commentedon Nov 6, 2021
Related #11469
gwk commentedon Mar 21, 2022
I was about to report the same problem for the
@cachedecorator case, and just want to chime in thatType[_T]for TypeVar _T is also a problem. I see discussion ofType[Any]andtype[type]but it's not clear to me if that covers the type var case as well.KotlinIsland commentedon Mar 21, 2022
I think a
type[T]where the upper bound ofTproduces aHashabletype[T](default upper bound isobject, andtype[object]is hashable) should be consideredHashable.finite-state-machine commentedon Jun 17, 2022
There are also some problems with using
assertstatements to work around this, as in the following:More details may be found in the duplicate bug #12993.
sg495 commentedon Nov 13, 2023
Just chiming in that this is still an open issue as of Mypy 1.7.0 (Python 3.12.0).
Dreamsorcerer commentedon Feb 12, 2024
To give a reproducer of TypeVar usage (which could be included in tests):
It seems that it only considers
type[T]to be hashable ifTis hashable. Thus, the error disappears if doingTypeVar("T", bound=Hashable). However, that is not correct as you then can't passdict[str, object]in the last line.finite-state-machine commentedon Feb 13, 2024
In fact, not all types are hashable: mypy-play.net
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
--enable-flag).finite-state-machine commentedon Feb 13, 2024
(That said, there are errors issued by the example in #12993. IMHO this inconsistency is undesirable.)
Dreamsorcerer commentedon Feb 13, 2024
Indeed, as per my comment, mypy seems to consider
type[X]hashable only ifXis hashable, which seems completely unrelated.Curiously, in my example, if I change from the TypeVar to using a custom class directly (
def check(t: type[Bar])), then I still get the same error, yet I don't get the error if I just callfoo(Bar), which should be the same thing...finite-state-machine commentedon Feb 13, 2024
I think we can all agree that the hashability of
type[X]has nothing to do with the hashability ofXinstances.finite-state-machine commentedon Feb 13, 2024
One possible approach to determining if a value is likely
Hashable: in the entire system being type-checked, is there any known example of the specified type that is notHashable? For most projects, that would meanType[Any/object]would beHashable. OTOH this involves spooky action at a distance: defining a metaclass in one place could cause errors to appear on the other side of the code base.In a way, it's a pity
Hashableisn'tGeneric-like: being able to writeHashable[Type[Any]],Hashable[Mapping[K, V]],Hashable[SomeProtocol], etc., would be quite useful. This is a special case of #213, and would like be solved by the as-yet-unnumbered PEP being drafted for that issue, which will presumably introduce a syntax likeType[Any] & Hashable.chadrik commentedon Oct 17, 2024
I'm not sure if this is true. Below are some tests with mypy 1.12.
type[int]is not consideredHashable.thearchitector commentedon Jan 25, 2025
i'm not entirely sure what the correct "resolution" is here / what the proper way to type this is, but fwiw, I hit this error with the following on 1.14.1:
though for some reason this works fine: