Skip to content
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

Callable attribute is considered a method #9489

Closed
NiklasRosenstein opened this issue Sep 25, 2020 · 4 comments
Closed

Callable attribute is considered a method #9489

NiklasRosenstein opened this issue Sep 25, 2020 · 4 comments
Labels
bug mypy got something wrong

Comments

@NiklasRosenstein
Copy link

NiklasRosenstein commented Sep 25, 2020

Small example to illustrate the issue:

import typing as t
from dataclasses import dataclass, field

@dataclass
class Example:
  a: t.Callable[[], int] = field(default=lambda: 42)

  def call_a(self) -> None:
    self.a()   # Attribute function "a" with type "Callable[[], int]" does not accept self argument

Curiously, adding Example as the first argument to the type of a makes the call be recognized OK but the default not.

from typing import t
from dataclasses import dataclass, field

@dataclass
class Example:
  a: t.Callable[['Example'], int] = field(default=lambda: 42)  # Incompatible types in assignment (expression has type "Callable[[], int]", variable has type "Callable[[Example], int]")

  def call_a(self):
    self.a()

Your Environment

  • Mypy version used: mypy 0.782
  • Mypy command-line flags:
  • Mypy configuration options from mypy.ini (and other config files):
  • Python version used: 3.7
  • Operating system and version: Debian WSL
@NiklasRosenstein NiklasRosenstein added the bug mypy got something wrong label Sep 25, 2020
@gvanrossum
Copy link
Member

Hm, this is unfortunate. I think it's due to mypy not really understanding the difference between class and instance attributes.

I expect it'll be hard to fix. In the meantime, here's a weird workaround: if you make the type Optional and check for None before the call, it works:

class Example:
    a: Optional[Callable[[int], int]]
    def f(self) -> int:
        assert self.a is not None
        return self.a(42)

@NiklasRosenstein NiklasRosenstein changed the title Callable attribute is is considered a method Callable attribute is considered a method Sep 26, 2020
@NiklasRosenstein
Copy link
Author

NiklasRosenstein commented Sep 26, 2020

I just found another workaround using a Protocol:

if t.TYPE_CHECKING:
  class AProtocol(t.Protocol):
    def __call__(self) -> int:
      pass

@dataclass
class Example:
  a: 'AProtocol' = field(default=lambda: 42) 

I feel like there should be a way for mypy to distinguish these cases, unless there are conflicting use cases (which I am not aware of yet). But I haven't taken a look into the related mypy code.

Edit Ctrl+Enter too early again 😄 Completed the comment

@troiganto
Copy link

I'm hitting the same issue, but with a different error. In case anyone else is affect, here is the MWE:

from dataclasses import dataclass
from typing import Callable


@dataclass
class Example:
    func: Callable[[str], str]


def the_func(s: str) -> str:
    return s


example = Example(the_func)
string = example.func("passthrough")
print(string)

This runs without problems and should pass Mypy, but instead produces the following errors:

error: Invalid self argument "Example" to attribute function "func" with type "Callable[[str], str]"
error: Too many arguments

As in the original issue, one workaround is to declare the field as Optional and assert that it is not None before usage.

My understanding is that because func is declared on the class, Mypy thinks that it is a class attribute (and not an instance attribute). If this were true, example.func would indeed give a bound method. But because func exists on the instance, we get the_func back unmodified.

@hauntsaninja
Copy link
Collaborator

Fixed by #10548

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong
Projects
None yet
Development

No branches or pull requests

4 participants