-
Notifications
You must be signed in to change notification settings - Fork 242
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
Partial Type Specifications For Callable #696
Comments
You should be able to solve this with callback protocols, which also support overloads for more complicated cases. |
@srittau I've edited the description to address this. The problem with overloads is that I must know all possible implementations of, for example, a route handler for a web server, or use Imagine that I wanted to write an RouteHandler = Callable[[Arg(Request), ...], Any]
def authenticated(r: RouteHandler) -> RouteHandler: ... |
@srittau It's entirely possible that the error is on my end, but here is a complicated example I was not able to get working with a callback protocol and had to fallback to from typing import Any, Callable
from typing_extensions import Protocol
class Config: pass
class System: pass
class ActionReturn: pass
StepType = Callable[[Config, System], ActionReturn]
class VerifyFunctionType(Protocol):
# not sure why this is necessary by mypy complains missing __name__ without
__name__: str = "VerifyFunctionType"
def __call__(self, config: Config, system: System, **kw: Any) -> None: ...
def collect_credential(**kw: str) -> Callable[[VerifyFunctionType], StepType]:
def decorator(func: VerifyFunctionType) -> StepType:
def wrapper(config: Config, system: System) -> ActionReturn:
secrets = dict(foo="bar")
func(config, system, **secrets)
return ActionReturn()
return wrapper
return decorator
@collect_credential(token="SOME_TOKEN")
def verify_token_credentials(config: Config, system: System, *, token: str) -> None:
pass Which reports an error like this: mypy ex_callback_deco.py
ex_callback_deco.py:27: error: Argument 1 has incompatible type "Callable[[Config, System, NamedArg(str, 'token')], None]"; expected "VerifyFunctionType"
Found 1 error in 1 file (checked 1 source file) |
I'm guessing this is because the |
@gvanrossum No that just changes the error message to include ex_callback_deco.py:27: error: Argument 1 has incompatible type "Callable[[Config, System, NamedArg(str, 'token'), KwArg(Any)], None]"; expected "VerifyFunctionType" |
Hm, then I'm guessing it would work if you also removed I wonder if PEP 612 (not yet accepted or implemented) might help. However this seems a different case from the original post. |
Quite possibly and apologies if so! I have been searching for a solution and latched on to
and the OP mentions of decorators as possibly relevant (but I was not 100% sure) |
It's been a while since I read through PEP-612 so I could be wrong, but I think that PEP might actually resolve this issue. Taking the examples provided above, and my recollection, it seems like the following would be allowable: p = ParamSpec("P")
RouteHandler = Callable[Concatenate[Request, P], Any]
def authenitcated(f: RouteHandler) -> RouteHandler: ... |
Now that PEP 612 is accepted, please re-review if you still need this issue open. |
Closing - PEP-612 provides an example of a |
The Feature Request
It would be awesome if it were possible to create a partial type spec for
Callable
. For example, I might want to be able to specify that the first argument of a function must be an integer, but that any other parameters are allowed. This could be accomplished with the following extension to PEP-484 which would allow...
to be included in the argument list toCallable
if it followed any extended callable types. As a result we could write a type specFirstArgIsInt
which would match all the following functions and any number of other arbitrary functions so long as their first argument is an integer:A Real World Use Case
Partial type specifications for
Callable
are useful if parameters are being passed on to a function from a decorator as in request handlers for many web frameworks like Django's view funtions or Sanic's routes:Imagine that you wanted to write an
authenticated
decorator which ensures a user who accesses any particular route is logged in. What would be the type ofRouteHandler
if notCallable[..., Response]
:It would be
Callable[[Arg(Request), ...], Any]
, or some other expression of the same idea.Current Work Arounds
Callable[..., Response]
, however this provides no precision for the function parameters.Callable[[Arg(Request), VarArg(), KwArg()], Response]
however this is problematic since, these route handlers don't actually need to be able to accept arbitrary arguments.Protocol
with overloads, however there are cases (e.g. decorators for route handlers as above) where it's not feasible to enumerate all possible route handler implementations.The text was updated successfully, but these errors were encountered: