I'm trying to use typehints and Mypy (also PyCharm) to enforce variance for containers, see, butchered, code below:
from typing import TypeVar, Generic
class T: ...
class M(T): ...
class B(M): ...
InMT = TypeVar('InMT', bound=M)
ContraMT = TypeVar('ContraMT', bound=M, contravariant=True)
CoMT = TypeVar('CoMT', bound=M, covariant=True)
class In(Generic[InMT]):
x: InMT
class Contra(Generic[ContraMT]):
x: ContraMT
class Co(Generic[CoMT]):
x: CoMT
t = T()
m = M()
b = B()
m_in: In[M] = In()
m_contra: Contra[M] = Contra()
m_co: Co[M] = Co()
m_in.x = t # mypy: Incompatible types in assignment (expression has type "T", variable has type "M").
m_in.x = m
m_in.x = b
m_contra.x = t # mypy: Incompatible types in assignment (expression has type "T", variable has type "M").
m_contra.x = m
m_contra.x = b
m_co.x = t # mypy: Incompatible types in assignment (expression has type "T", variable has type "M").
m_co.x = m
m_co.x = b
Mypy finds some problems, see comments in above code, and PyCharm finds none! However I think Mypy misses a number of problems, incorrectly reports a problem, and gives misleading error messages:
-
Error message for
m_in.x = t
is wrong since the variable is of typeInMT
notM
. -
m_in.x = b
should be an error because aB
is not anInMT
(only anM
is). -
m_contra.x = t
should not be an error because aT
is aContraMT
. -
m_contra.x = b
should be an error because aB
is not anContraMT
(only anM
or aT
are). -
As point 1 above, variable is of type
CoMT
notM
.
What am I doing wrong; or am I misunderstanding what Mypy is meant to do?