Skip to content

Error about incompatible subclass of @final class #19033

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

Closed
mharding-hpe opened this issue May 5, 2025 · 1 comment · Fixed by #19035
Closed

Error about incompatible subclass of @final class #19033

mharding-hpe opened this issue May 5, 2025 · 1 comment · Fixed by #19035
Labels
bug mypy got something wrong topic-final PEP 591

Comments

@mharding-hpe
Copy link

mharding-hpe commented May 5, 2025

Bug Report

mypy reports an error because of a concern about potentially incompatible subclasses, even though the class in question is marked @final.

To Reproduce

https://mypy-play.net/?mypy=latest&python=3.13&gist=c475ec59941e76a62c4d458819ebc828

from __future__ import annotations
from typing import Self, final

class A:
    pass

@final
class B(A):
    @final
    def __init__(self) -> None:
        pass

    @classmethod
    def __new__(cls: type[B]) -> B:
        """ cls is type[B] and return is B, because class is final """
        new_instance: B = super().__new__(cls)
        new_instance.__init__()
        return new_instance

@final
class B2(A):
    @final
    def __init__(self) -> None:
        pass

    @classmethod
    def __new__(cls) -> Self:
        new_instance: Self = super().__new__(cls)
        new_instance.__init__()
        return new_instance

Expected Behavior

No errors reported.

Note that I think marking __init__ as @final is redundant, but I included it just to show that it doesn't make a difference. I would expect no errors if the class is marked @final OR if __init__ is marked @final. Or both, of course.

I also think the first case, where I explicitly annotate the B types, should not be necessary. Because the class is @final, I would expect the second case using Self to be fine. Again, I included that just to show that the error is reported either way.

Actual Behavior

main.py:17: error: Accessing "__init__" on an instance is unsound, since instance.__init__ could be from an incompatible subclass  [misc]
main.py:29: error: Accessing "__init__" on an instance is unsound, since instance.__init__ could be from an incompatible subclass  [misc]

Your Environment

  • Mypy version used: 1.15.0
  • Mypy command-line flags: None
  • Mypy configuration options from mypy.ini (and other config files): None
  • Python version used: 3.13
@mharding-hpe mharding-hpe added the bug mypy got something wrong label May 5, 2025
@mharding-hpe
Copy link
Author

Note that the error can be worked around just by calling __init__ through the class. i.e.

class B2(A):
    def __init__(self) -> None:
        pass

    @classmethod
    def __new__(cls) -> Self:
        new_instance: Self = super().__new__(cls)
        cls.__init__(new_instance)
        return new_instance

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-final PEP 591
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants