I have discovered today this bug in our code base (simplified example):
from abc import ABC, abstractmethod
class Interface(ABC):
@abstractmethod
def method(self, variable: str) -> str:
pass
class Implementation(Interface):
def method(self, variable_changed: str) -> str:
return "A"
Implementation().method("d") # works
Implementation().method(variable="d") # error
Implementation().method(variable_changed="d") # works
Here we have a class implementing an interface. That's all good, but the implementation change the name of the first argument of the method. If I run mypy, I would expect to get an error, because implementation is not following the contract defined by the Interface. To my surprise, this is not the case at all.
I'm not sure if this is intended or not, but I would like to detect those kinds of mismatchs as soon as possible. Any idea how to fix mypy or how to enable this kind of detection in case it's not an error?
CodePudding user response:
Mypy treats parameters as positional if they aren’t explicitly specified as named. Your Interface
therefore only requires that method
accepts one argument, not that it have a particular name.
To specify it as a named parameter (forcing implementations to match the name) you’d do:
def method(self, *, variable: str) -> str:
to say that variable
is a named parameter (and must always be called as such).
For discussion on changing this behavior in mypy see the related GitHub issue: https://github.com/python/mypy/issues/6709