You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
full typing support for validate_call as well as easy access to raw calls #9883
I have searched Google & GitHub for similar requests and couldn't find anything
I have read and followed the docs and still think this feature is missing
Description
while working with openapi-codegen generated apis, i foudn that validate_call decorated apis are quite a pain when wanting to be trypesafe and/or invoking them
i want to propose using a fully typed callable protocol to typecheck them and including a way to correctly invoke the raw function even for bound methods
while working with openapi-codegen generated apis, i foudn that validate_call decorated apis are quite a pain when wanting to be trypesafe and/or invoking them
Could you give an example where it isn't typesafe?
validate_call is currently typed as (omitting the first overload):
So from a type checking perspective, it returns the same decorated callable untouched.
Regarding the .unchecked call, you can already do it this way:
frompydanticimportvalidate_call@validate_calldeftest(a: int) ->None:
passtest.raw_function(a="a") # OK at runtime
However, type checkers can't know about raw_function. As you suggested, this would require exposing ValidateCallWrapper (or any other new class) in some way, and make it generic over a ParamSpec and a TypeVar for the return type:
P=ParamSpec("P")
T=TypeVar("T")
classValidateCallWrapper(Generic[P, T]):
...
def__call__(self, *args: P.args, **kwargs: P.kwargs) ->T: ...
defraw_function(self, *args: P.args, **kwargs: P.kwargs) ->T: ...
defvalidate_call(func: Callable[P, T]) ->ValidateCallWrapper[P, T]: ...
@validate_calldeftest(a: int) ->None:
passtest(a=1) # type checkstest.raw_function(a=1) # type checks as well
However, you will hit issues when decorating methods, as type checkers aren't going to understand when the decorated method is bound or not.
The same issue can be found for functools.cache in typeshed, and there's currently no ideal solution for this, see:
additional the raw function is not typed and missing from the type signature
As I described, there's no way to currently type check raw_function. We'll have to wait for the semantics of ParamSpec to be updated so that it can support both methods and function (or unbound methods). Additional discussion can be found here, and doesn't seem trivial.
i worked it out in python/mypy#16200 (comment) already as i needed a similar helper with extra properties and technically speaking its incorrect to pretend a callable protocol object is/can be the same as a plain function (there are numerous callable objects that do not bind, and sometimes intentionally/rightfully so)
But I'm pretty certain you will face the same issues as functools.cache. In particular, I experimented with here python/typeshed#11767 (one of the issue is ParamSpec doesn't know about default values in a function signature).
So that we preserve type checking of arguments, at the expense of not having the .raw_function exposed.
functools.cache is doing it the other way around, exposing methods (such as cache_clear) on the wrapper but dropping the arguments type checking. It's an unfortunate tradeoff but considering the negligible usage of .raw_function I believe we are doing the right choice here.
Happy to reopen once we get the necessary typing constructs to support both use cases.
I'm afraid it will not be sufficient. If you think this is possible, please provide an example implementation that would type check the code snippet I gave here.
Activity
Viicos commentedon Jul 11, 2024
Could you give an example where it isn't typesafe?
validate_callis currently typed as (omitting the first overload):pydantic/pydantic/validate_call_decorator.py
Lines 24 to 25 in d654a07
So from a type checking perspective, it returns the same decorated callable untouched.
Regarding the
.uncheckedcall, you can already do it this way:However, type checkers can't know about
raw_function. As you suggested, this would require exposingValidateCallWrapper(or any other new class) in some way, and make it generic over aParamSpecand aTypeVarfor the return type:However, you will hit issues when decorating methods, as type checkers aren't going to understand when the decorated method is bound or not.
The same issue can be found for
functools.cachein typeshed, and there's currently no ideal solution for this, see:RonnyPfannschmidt commentedon Jul 11, 2024
@Viicos in my example i was using a decorated method, where the raw function does not automatically get bound
additional the raw function is not typed and missing from the type signature
Viicos commentedon Jul 11, 2024
As I described, there's no way to currently type check
raw_function. We'll have to wait for the semantics ofParamSpecto be updated so that it can support both methods and function (or unbound methods). Additional discussion can be found here, and doesn't seem trivial.RonnyPfannschmidt commentedon Jul 11, 2024
i worked it out in python/mypy#16200 (comment) already as i needed a similar helper with extra properties and technically speaking its incorrect to pretend a callable protocol object is/can be the same as a plain function (there are numerous callable objects that do not bind, and sometimes intentionally/rightfully so)
Viicos commentedon Jul 11, 2024
Well you can still experiment with it and see if it works, considering the following should type check:
But I'm pretty certain you will face the same issues as
functools.cache. In particular, I experimented with here python/typeshed#11767 (one of the issue isParamSpecdoesn't know about default values in a function signature).Viicos commentedon Aug 6, 2024
Closing for now as we can't fully express the functionality with the current typing constructs. We decided to type
validate_callas:pydantic/pydantic/validate_call_decorator.py
Line 25 in 5e241c6
So that we preserve type checking of arguments, at the expense of not having the
.raw_functionexposed.functools.cacheis doing it the other way around, exposing methods (such ascache_clear) on the wrapper but dropping the arguments type checking. It's an unfortunate tradeoff but considering the negligible usage of.raw_functionI believe we are doing the right choice here.Happy to reopen once we get the necessary typing constructs to support both use cases.
RonnyPfannschmidt commentedon Aug 6, 2024
as per python/mypy#16200 (comment) the necessary constructs exist
Viicos commentedon Aug 6, 2024
I'm afraid it will not be sufficient. If you think this is possible, please provide an example implementation that would type check the code snippet I gave here.