Description
Bug Report
When assigning self
to a list element, where the list is of type list[Self]
, mypy will treat self
to be incompatible with Self
as long as Self
does not appear in the method signature.
To Reproduce
Playground: https://mypy-play.net/?mypy=latest&python=3.11&gist=124fa26ca946c7ae040c43d788a694cb
from typing import Self
class A:
def __init__(self) -> None:
self.siblings: list[Self] = []
def insert(self, index: int):
self.siblings[index] = self # this fails
def insert__no_return(self, index: int) -> None:
self.siblings[index] = self # this fails
def insert__return(self, index: int) -> list[Self]:
self.siblings[index] = self # this does not fail
return self.siblings
def insert__annotate_self(self: Self, index: int):
self.siblings[index] = self # this does not fail
def local_variable(self) -> None:
l: list[Self] = [self] # this fails
l[0] = self # this fails
def local_variable__return(self) -> list[Self]:
l: list[Self] = [self] # this does not fail
l[0] = self # this does not fail
return l
Expected Behavior
- No errors.
- Assigning
self
to a target of typeSelf
should obviously work (or am I missing something here?) - returning the list and specifying the function return type should not change the behavior
- specifying the type of
self
to beSelf
should not change the behavior
Actual Behavior
Mypy detects imcompatible assignments:
main.py:15: error: Incompatible types in assignment (expression has type "A", target has type "Self") [assignment]
main.py:18: error: Incompatible types in assignment (expression has type "A", target has type "Self") [assignment]
main.py:28: error: List item 0 has incompatible type "A"; expected "Self" [list-item]
main.py:29: error: Incompatible types in assignment (expression has type "A", target has type "Self") [assignment]
Found 4 errors in 1 file (checked 1 source file)
Maybe it's actually undefined behavior?
Digging deeper, it looks like PEP 673 lists examples of what are valid or invalid use cases of the Self
type. It explicitly states that
"Self used in the signature of a method is treated as if it were a TypeVar bound to the class"
This definition would not cover my example above, as it does only fail if Self
has been used in only the body, but not the signature. On the other hand, this case is listed neither as a positive or negative use case; it is not covered at all by PEP 673, but all examples show that the intention of PEP 673 was to avoid having to explicitly state a signature of self: Self
, as that would state the obvious.
Thus, considering PEP 673, it might be undefined behavior?
On the other hand, following PEP 484:
the first argument of class and instance methods [...] is assumed to have the type of the containing class for instance methods [...]
I guess that's the old definition and does not include how to apply Self
. It would explain mypy behavior - at least to some end. If this were the explanation, then mypy should actually fail or at least warn about incorrect usage of Self
in __init__
and local_variable
. With Self
being treated as a special case if and only if it appears in method signatures, it does not make sense to use it at those places; at least I cannot think of a use case. I do believe that it is not intended to be used on its own. Thus, an explicit warning, or even an error, would be very helpful in this case.
So is this a bug in mypy or is it something that actually simply strictly follows PEP definition? In the second case, I would still consider my example code to be desirable behavior and would be happy to get some hints on how to make this behavior become part of python typing definitions :)
Or if you would think that this would not be desirable, i'd be happy to learn about your rationale.
Your Environment
- Mypy version used: 1.0.0
- Mypy command-line flags: none
- Mypy configuration options from
mypy.ini
(and other config files): installed mypy in a fresh virtualenv, no manual configuration - Python version used: 3.11.2