PEP612 adds ParameterSpec to the typing module, allowing you to type-check functions that are wrapped by function decorators (and type-check the decorators themselves with the help of Concatenate).
In one of the discussions leading to acceptance of the PEP, scenarios where functions simply forwarded *args, **kwargs to other functions were cited, but from what I can tell, this is still not supported unless you are using a decorator because ParamSpec can only be used when a Callable type is already in-scope.
For example, I don't know how any of the following fits in (if at all):
def plot_special(df: pd.DataFrame, p1: int, p2: int, *plot_args, **plot_kwargs) -> None:
# do something with p1, p2
df.plot(*plot_args, **plot_kwargs)
or
class A:
def f(self, x: int, y: int) -> int:
return x + y
class B:
def __init__(self) -> None:
self.a = A()
f = A.a # Does not work, self is not of type A
# Since B.f is not wrapping A.f, does not seem to be a way
# to contextualize a ParameterSpec
def f(self, *args, **kwargs) -> int:
self.a.f(*args, **kwargs)
or
class A:
def __int__(self, p1: int, p2: int) -> None:
self.p1 = p1
self.p2 = p2
def f(x: int, y: int) -> int:
return x + y
class MixinForA:
def __init__(self, p3: str, *args, **kwargs) -> None:
self.p3 = p3
super().__init__(*args, **kwargs)
Unless *args and **kwargs are homogeneous, it seems we're still unable to take advantage of type-checking functions that a invoked from other functions where those functions wish to only pass along *args, **kwargs (instead of duplicating the function signatures).
