Class method calling abstract method after constructing an instance

Open
#1,314 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
20/100
Issue type
Feature
Clarity
Needs clarification
Activity status
Stale
Tech stack
python
Domain
devtools

Research direction

Start by reviewing the class-method checking discussion in PR #1313 and the Type.deserialize example linked from PR #1292. Trace how mypy handles class methods that construct instances and invoke abstract methods. Done would be a decided, documented approach for checking this pattern and expressing any required constraint in stubs.

Written by the indexing model from the issue text.

Description

feature priority-1-normal

When turning on type checking the 'cls' argument of class methods (https://github.com/python/mypy/pull/1313) I came across an interesting special case: a class method that constructs an instance of the class and then calls an abstract method on the instance. E.g.

class C(metaclass=ABCMeta):
    @classmethod
    def foo(cls) -> None: cls().bar()
    @abstractmethod
    def bar(self): raise NotImplementedError

Clearly in this case calling

C.foo()  # not cool

will be a runtime error since the cls() call is not allowed.

But just as clearly the intention of the author is that there's a concrete subclass that implements bar(), and then the call works fine:

class D(C):
    def bar(self): pass
D.foo()  # this is fine

I discussed this briefly with @ddfisher and we don't think you can just disallow calling all class methods on abstract classes (a nice example is Type.deserialize() here: https://github.com/python/mypy/pull/1292/files#diff-abd352ca9f518956b2d76e1cfc9ad35bR121

Maybe we can internally recognize class methods that construct instances? This would have to be a transitive closure of class methods. But then how would you say in a stub file that a given class method can only be called on a concrete subclass? That's where we left it for now. I don't think this has high priority.

Dominant language
Python
Stars
20.6k
Forks
3.3k
Avg merge
1d 18h
Merged PRs (30d)
54

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.

More from python/mypy

All issues in python/mypy

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.