Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
noresistence opened this issue Feb 15, 2023 · 2 comments
Labels
bug mypy got something wrong topic-self-types Types for self

Comments

@noresistence
Copy link

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
@noresistence noresistence added the bug mypy got something wrong label Feb 15, 2023
@noresistence noresistence changed the title 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 Feb 15, 2023
@davfsa
Copy link
Contributor

davfsa commented Feb 15, 2023

As you mentioned, this behaviour seems to be intended:

def bad(self) -> None:
# This is unfortunate, but required by PEP 484
self.x = self # E: Incompatible types in assignment (expression has type "C", variable has type "Self")

and the inconsistencies you are seeing is due to self being treated as typing.Self if there is any usage of typing.Self in the signature (implementation detail)


That being said, a fix for this would be to change

leading_type = fill_typevars(info)
to

leading_type = info.self_type if info.self_type is not None else fill_typevars(info)

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 AlexWaygood added the topic-self-types Types for self label Feb 15, 2023
@AlexWaygood
Copy link
Member

Duplicate of #14075

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-self-types Types for self
Projects
None yet
Development

No branches or pull requests

3 participants