python / python/mypy

The implementation of the abstract class is judged by mypy to be unconstructable

Open
#18,830 0 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug topic-join-v-union
Dominant language
Python
Stars
20.6k
Forks
3.3k
PR merge metrics
PR metrics pending

Description

Bug Report

Consider the following code:

#!/usr/bin/env python3

from abc import ABC, abstractmethod
from typing import override


class Base(ABC):
    def __init__(self, val: int):
        self.__val = val

    def show(self) -> None:
        print(f'hello: {self.__val}')

    @abstractmethod
    def impl(self) -> None:
        pass


class Derive1(Base):
    def __init__(self):
        super().__init__(1)

    @override
    def impl(self) -> None:
        pass


class Derive2(Base):
    def __init__(self):
        super().__init__(2)

    @override
    def impl(self) -> None:
        pass


def demo(index: int) -> Base:
    classes = [Derive1, Derive2]
    return classes[index]()


if __name__ == '__main__':
    demo(0).show()

It implements Derive1 and Derive2 on the Base abstract class, which implement the impl interface. When checking it with mypy, everything looks fine:

> mypy demo.py
Success: no issues found in 1 source file

At this time, if you try to add Derive3, the code is as follows:

#!/usr/bin/env python3

from abc import ABC, abstractmethod
from typing import override


class Base(ABC):
    def __init__(self, val: int):
        self.__val = val

    def show(self) -> None:
        print(f'hello: {self.__val}')

    @abstractmethod
    def impl(self) -> None:
        pass


class Derive1(Base):
    def __init__(self):
        super().__init__(1)

    @override
    def impl(self) -> None:
        pass


class Derive2(Base):
    def __init__(self):
        super().__init__(2)

    @override
    def impl(self) -> None:
        pass


class Derive3(Base):  # add Derive3 just like the previous two
    def __init__(self):
        super().__init__(3)

    @override
    def impl(self) -> None:
        pass


def demo(index: int) -> Base:
    classes = [Derive1, Derive2, Derive3]  # add Derive3 item
    return classes[index]()


if __name__ == '__main__':
    demo(0).show()

At this time, mypy will issue the following complaint:

> mypy demo.py
demo.py:48: error: Cannot instantiate abstract class "Base" with abstract attribute "impl"  [abstract]
Found 1 error in 1 file (checked 1 source file)

The strange thing is why there is no error when there are two implementations, but there will be an error when there are three or more.

I tried pyright and pycharm, and they both gave no error messages for the above two codes, and I didn't find any reports or explanations of the problem on the search engine.

Environment

  • Mypy version used: 1.15.0
  • Mypy command-line flags: mypy demo.py
  • Python version used: 3.13.2

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the examples in demo.py with mypy 1.15.0 under Python 3.13.2, comparing the two-class and three-class lists. Trace why the inferred class collection produces an abstract Base instantiation error only in the latter case. Done means the behavior is explained and, if confirmed as a bug, a regression test prevents the spurious diagnostic without hiding genuine abstract-class errors.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.