Consider adding `implemented_abstractmethod`

Currently, type checkers distinguish between “implemented” abstract methods and unimplemented ones using logic particular to each one. See Calling abstract methods for background.

To make this difference explicit, would it be possible to:

  • add implemented_abstractmethod for this very rare case, and
  • deprecate the use of abstractmethod for that case.

Thus, we might have:

class X:
  @abstractmethod
  def f(self) -> int:
    raise NotImplementedError  # Should always raise this?

  @implemented_abstractmethod
  def g(self) -> int:
    return 2  # Free to do whatever it wants.

class Y(X):
  def f(self) -> int:
    super().f()  # Type checkers can know that this is an error

  def g(self) -> int:
    super().g()  # Just fine.

There is a note for abstractmethod:

Note: Unlike Java abstract methods, these abstract methods may have an implementation. This implementation can be called via the super() mechanism from the class that overrides it. This could be useful as an end-point for a super-call in a framework that uses cooperative multiple-inheritance.

This could be removed and made into the docs for implemented_abstractmethod.

This change would also resolve confusion that linters have, e.g., Useless super delegation in method when overriding abstract methods. · Issue #1594 · pylint-dev/pylint · GitHub