Skip to content

Incompatible types detected in assignment of self to target of type Self, when using Self only in method body #14708

Closed as not planned
@noresistence

Description

@noresistence

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 type Self 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 be Self 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmypy got something wrongtopic-self-typesTypes for self

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions