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

How to deal with *args/**kwargs in decorator? #9032

Closed
waxlamp opened this issue Jun 22, 2020 · 1 comment
Closed

How to deal with *args/**kwargs in decorator? #9032

waxlamp opened this issue Jun 22, 2020 · 1 comment

Comments

@waxlamp
Copy link

waxlamp commented Jun 22, 2020

(mypy is a blessing, it has made my programming life far more enjoyable; thank you!)

I am trying to write a generic decorator for a class of functions that take an initial, named argument, followed by arbitrary other arguments. Here's a dummy implementation, showing an "identity" decorator:

F = Callable[[Arg(str, "workspace"), VarArg(), KwArg()], Any]

def deco(f: F) -> F:
    def wrapper(workspace: str, *args: Any, **kwargs: Any) -> Any:
        return f(workspace, *args, **kwargs)

    return wrapper

When I try to use this decorator as follows:

@deco 
def do_something(workspace: str) -> Any:
   pass

I get the following error from mypy:

error: Argument 1 to "do_something" has incompatible type "Callable[[str], Any]"; expected "Callable[[str, VarArg(Any), KwArg(Any)], Any]"

Shouldn't do_something be compatible with the VarArg-laden Callable type? If not, what can I do to make this pass typechecking?

I also tried using a Protocol for this:

class WorkspaceFn(Protocol):
    def __call__(self, workspace: str, *args: Any, **kwargs: Any) -> Any: ...

Replacing the F = ... line from above with F = WorkspaceFn yields this similar error message:

error: Argument 1 to "do_something" has incompatible type "Callable[[str], Any]"; expected "WorkspaceFn"
@ilevkivskyi
Copy link
Member

Technically mypy is correct, because (str) -> Any is not a subtype of (str, *Any, **Any) -> Any. But it is pretty typical to use *args, **kwargs as a synonym for "don't care". So essentially this is no different than #5876

For now you can use:

F = TypeVar('F', bound=Callable[..., Any])
def deco(f: F) -> F:
    ...

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

No branches or pull requests

2 participants