python / python/mypy

Assigning wrapped class members to a member defined by a base class fails with incompatible types in assignment

Open
#14,408 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug topic-inference topic-type-context
Dominant language
Python
Stars
20.6k
Forks
3.3k
PR merge metrics
PR metrics pending

Description

Bug Report

Consider the following code, where wrap is some decorator that preserves the function signature:

class Base:
    def f(self, a: int) -> int:
        return a + 1

    def g(self, a: int) -> int:
        return a + 1

class Derived(Base):
    @wrap
    def f(self, a: int) -> int:
        return a + 2

    def _g(self, a: int) -> int:
        return a + 2 

    g = wrap(_g)

The assignment g = wrap(_g) fails with Argument 1 to "wrap" has incompatible type "Callable[[Dervied, int], int]"; expected "Callable[[Base, int], int]". I would have expected both ways of wrapping a function to be the same (ans as far as I can tell they do so at runtime) and therefore both should be allowed.

This is also not a general issue with assignments as the following code type checks:

class Base:
    def f(self, a: int) -> int:
        return a + 1

class Derived(Base):
    def _f(self, a: int) -> int:
        return a + 2

    f = _f

To Reproduce

https://mypy-play.net/?mypy=master&python=3.11&gist=2455e6265bf5ec9cc5ffac2d95accf98

Note that mypy-play seems to use c660354846688ff8158d0f0178eb298171b74f5b rather than the latest commit from master for some reason. The output on current master is slightly different (the type of C.abc is no longer consider def (self: __main__.A, a: builtins.int) -> builtins.int):

test_assign_function_subclass.py:32: error: Incompatible types in assignment (expression has type "Callable[[C, int], int]", base class "A" defined the type as "Callable[[A, int], int]")  [assignment]
test_assign_function_subclass.py:50: error: Cannot determine type of "abc"  [has-type]
test_assign_function_subclass.py:55: note: Revealed type is "def (self: test_assign_function_subclass.A, a: builtins.int) -> builtins.int"
test_assign_function_subclass.py:56: note: Revealed type is "def (self: test_assign_function_subclass.B, a: builtins.int) -> builtins.int"
test_assign_function_subclass.py:57: error: Cannot determine type of "abc"  [has-type]
test_assign_function_subclass.py:57: note: Revealed type is "Any"
test_assign_function_subclass.py:58: note: Revealed type is "def (self: test_assign_function_subclass.D, a: builtins.int) -> builtins.int"
test_assign_function_subclass.py:59: note: Revealed type is "def (self: test_assign_function_subclass.E, a: builtins.int) -> builtins.int"
Found 3 errors in 1 file (checked 1 source file)

Expected Behavior

No error, code type checks

Actual Behavior

main.py:32: error: Argument 1 to "wrap" has incompatible type "Callable[[C, int], int]"; expected "Callable[[A, int], int]"  [arg-type]

Your Environment

  • Mypy version used: 98cc165a657a316accb93f1ed57fdc128b086d9f
  • Mypy command-line flags: None
  • Mypy configuration options from mypy.ini (and other config files): None
  • Python version used: 3.10 & 3.11

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 linked mypy-play reproducer on the current mypy version and compare the decorator form with the direct assignment form. Investigate how mypy checks wrapped class members against inherited members; done means both equivalent examples type-check without the incompatible-argument or assignment errors.

Written by the indexing model from the issue text.

Assessment

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.