Repository navigation
Incompatible types detected in assignment of self to target of type Self, when using Self only in method body #14708
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 lExpected Behavior
- No errors.
- Assigning
selfto a target of typeSelfshould 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
selfto beSelfshould 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
Activity
[-]Incompatible types detected in assignment of `self` to target of type `Self`, when using `Self` only in function body[/-][+]Incompatible types detected in assignment of `self` to target of type `Self`, when using `Self` only in method body[/+]davfsa commentedon Feb 15, 2023
As you mentioned, this behaviour seems to be intended:
mypy/test-data/unit/check-selftype.test
Lines 1695 to 1697 in 0bbeab8
and the inconsistencies you are seeing is due to
selfbeing treated astyping.Selfif there is any usage oftyping.Selfin the signature (implementation detail)That being said, a fix for this would be to change
mypy/mypy/semanal.py
Line 979 in 0bbeab8
took me way too long to debug and try to fix this issue just to realize that it is actually intentional 😔
I will leave this information here for a maintainer of the project to read and give guidance on how to continue. If deemed a bug and PEP 0673 is the one to follow, I would be happy to open a PR :)
AlexWaygood commentedon Feb 15, 2023
Duplicate of #14075
Selftype even if it doesn't appear in method annotation #14075Typeshed cherry-pick: Make type of `unitest.mock.Any` a subclass of `…