-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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
Making a decorator which preserves function signature #1927
Comments
Also the type of |
I use a I do agree there are two separate bugs here:
|
This looks like it's an instance of python/typing#239 (comment) |
Yeah, although in this case you can do it already (since there's no change |
I think that There's something a bit unsettling here because if mypy did accept |
I follow your reasoning that we probably shouldn't fix the need for a cast or type-ignore on the return, but even if we were able to type this example using variadic type variables, the wrapper implementation would probably still use |
That's right unless you also had the ability to do something like this: def print_on_call(func: Callable[[*Args, **Kwargs], Res]) -> Callable[[*Args, *Kwargs], Res]:
def wrapped(*args: *Args, **kwargs: **Kwargs) -> Res:
print("Running", func.__name__)
return func(*args, **kwargs)
return wrapped Note the new syntax in the signature of |
(To maybe clarify, |
New kinds of type variables are in fashion. I wish the unary This example highlights something interesting about the whole domain. "All the same arguments", in python, is spelled with two separate special ways of argument passing, that happen to work in tandem to provide very specifically correct transferral of all positional arguments including variadic ones ( My unmodified proposal over there has a way of saying "all kinds of arguments, no matter what", but then the typechecking of the body of the function ends up with some erasure of types (and argument names) that I thought was unavoidable, and ends up equivalent to replacing the internal argument lists with I've been trying to concoct some kind of way of resolving this problem so that I think we can typecheck the body cleanly, but I am not there yet. The closest I've come is wishing for some new even-more-magical python argument-passing syntax: Ts = TypeVar('Ts', variadic=True)
Arg = ArgVar('Arg')
def print_on_call(func: Callable[[Expand[Arg[Ts]]], Res]) -> Callable[[Expand[Arg[Ts]]], Res]:
def wrapped(***super_args: Ts) -> Res:
print("Running", func.__name__)
return func(***super_args)
return wrapped Or something. Wishful thinking. I also may be misunderstanding something about @rwbarton's proposal. |
Does that not work with PEP 448? |
@kirbyfan64 I don't think the ones to the right of the colons in the type annotation of the function work out. |
Right, as far as I know they actually aren't legal.
I don't think you are and I haven't really been thinking about this very carefully. The issue you mention with |
Yes, I think so
…
|
Hm, the OP's example still gives
if you remove the |
Hm, I think this would be fixed by variadic type variables. Your #3113 fixes other things, like decorator factories. So I think this is not fixed and we need to keep it open until we have variadic type variables. (For which we don't seem to have a PR yet, though there's a typing issue: python/typing#193). Sorry for the confusion. |
Raising priority based on internal needs. |
Lowering priority because function plugins can often be used to work around this issue. |
Without the cast mypy creates the following error. Incompatible return value type (got "Callable[..., Any]", expected "CallableT This is a known issue. python/mypy#1927
Without the cast mypy raises the following error: Incompatible return value type (got "Callable[..., Any]", expected "CallableT") This is a known issue: python/mypy#1927
Without the cast mypy raises the following error: Incompatible return value type (got "Callable[..., Any]", expected "CallableT") This is a known issue: python/mypy#1927
ok, works with this advice python/mypy#1927 + overloads
This is what we use for the sake of preserving decorated function signature: Checking this code with MyPy:
...gives:
|
PEP 612 (ParamSpec) should fix this. |
This seems to work great in the latest MyPy. |
python/mypy#1927 Signed-off-by: Yury Pliner <[email protected]>
Would you please link to an example and/or documentation on this? Is it possible without |
from functools import update_wrapper
from typing import Generic, TypeVar
from typing_extensions import ParamSpec
R_co = TypeVar('R_co', covariant=True)
P = ParamSpec('P')
class FunctionDecorator(Generic[P, R_co]):
def __init__(self,
func: Callable[P, R_co]):
super().__init__()
update_wrapper(self, func)
self.func = func
def __call__(self, /, *args: P.args, **kwargs: P.kwargs) -> R_co:
return self.func(*args, **kwargs) |
Currently this is how I annotate decorators which don't modify the function signature:
I have to use the
# type: ignore
otherwise I get this error:I'm wondering if there is a better way to do this which doesn't need the
type: ignore
. What do you all suggest?Maybe mypy can figure out from
(*args, **kwargs)
that the parameter types are the same. Maybe it can also see that the return value offunc
is the return value ofwrapped
so the return type is the same, and hence the function signatures are the same.The text was updated successfully, but these errors were encountered: