Are there any alternative to this overload case in python with typing?

Question:

currently I am implementing a lot of subclasses that should implement a function, this is a minimal example of the current project.

In this case, I have a function that needs to call, to the login of a user, but depending of the implementation injected previously the application will use UserUP or UserToken

Because in login_user I have all data available for the two options, I set the params like follow.

from typing import Protocol, runtime_checkable

@runtime_checkable
class User(Protocol):
    def login(self, **kwargs) -> None:
        raise NotImplementedError


class UserUP(User):
    def login(self, user: str, password:str, **kwargs) -> None:
        print(user)
        print(password)


class UserToken(User):
    def login(self, token:str, **kwargs) -> None:
        print(token)


def login_user(user: User) -> None:
    user.login(user="user", password="password", token="Token")

login_user(UserUP())
login_user(UserToken())

The problem is that when I run mypy I get errors like the following:

app.py:10: error: Signature of "login" incompatible with supertype "User"  [override]
app.py:10: note:      Superclass:
app.py:10: note:          def login(self, **kwargs: Any) -> None
app.py:10: note:      Subclass:
app.py:10: note:          def login(self, user: str, password: str, **kwargs: Any) -> None
app.py:16: error: Signature of "login" incompatible with supertype "User"  [override]
app.py:16: note:      Superclass:
app.py:16: note:          def login(self, **kwargs: Any) -> None
app.py:16: note:      Subclass:
app.py:16: note:          def login(self, token: str, **kwargs: Any) -> None

Of course, the signature is incompatible, but which alternatives do I have to implement things like this?

Asked By: Tlaloc-ES

||

Answers:

Use keyword_only marker in all signatures and describe all possible parameter in User.login

You need to expose which possible keywords can be used, and which type, in the main function.

from typing import Protocol, runtime_checkable


@runtime_checkable
class User(Protocol):
    def login(self, *, user: str, password: str, token: str, **kwargs) -> None:
        raise NotImplementedError


class UserUP(User):
    def login(self, *, user: str, password: str, **kwargs) -> None:
        print(user)
        print(password)


class UserToken(User):
    def login(self, *, token: str, **kwargs) -> None:
        print(token)


def login_user(user: User) -> None:
    user.login(user="user", password="password", token="Token")


login_user(UserUP())
login_user(UserToken())
Success: no issues found in 1 source file
Answered By: Dorian Turba
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.