Some Guy
Some Guy

Reputation: 725

Type hinting for a function wrapping another function, accepting the same arguments

def function(a: int, b: str) -> None:
    pass 

def wrapper(extra: int, *args, **kwargs) -> None:
    do_something_with_extra(extra)
    function(*args, **kwargs)

Is there an easy way for wrapper to inherit function()'s type hints without retyping all of them? Normally I'd write

def wrapper(extra: int, a: int, b: str) -> None:

But it becomes very verbose with a lot of arguments, and I have to update wrapper() every time I update function()'s arguments, and using *args, **kwargs means there won't be proper autocomplete in vscode and other editors.

Upvotes: 11

Views: 2779

Answers (1)

The best that you can do is to use a decorator for this purpose, and you can use Concatenate and ParamSpec. I use python 3.8 and I had to install typing_extensions for them. In the code below, if you type function in VSCode, it will show the int argument but without the "extra" name in front of it.

from typing import Callable, TypeVar
from typing_extensions import Concatenate, ParamSpec


P = ParamSpec('P')
R = TypeVar('R')

def wrapper(func: Callable[P, R]) -> Callable[Concatenate[int, P], R]:
    def inner(extra, *args, **kwargs):
        print(extra)
        func(*args, **kwargs)
    
    return inner

@wrapper
def function(a: int, b: str) -> None:
    print(a, b)
    pass 

# typing function will show 'function: (int, a: int, b: str) -> None'

Upvotes: 6

Related Questions