Open sobolevn opened 3 years ago
I have a little explanation while I was walking through the code!
The class responsible for is ValidatedFunction! In its __init__
it process all parameters and types.
When we call validate(...)
under the hood we're calling init_model_instance ant it calls two functions:
validate(...)
The model is created in create_model method, at the end we have a normal BaseModel but instead of class specifications we have function specifications! The validations occur in the validate_model function.
@thepabloaguilar can we adopt this / similar approach to speed up our @curry
?
Well, pydantic
approach seems more complicated, I don't know if it'll be faster than our actual implementation.
I have something in mind for a long time, maybe we can use partial
to build curry
. Did you try it??
When we have a partial from a partial, both are merged:
>>> from functools import partial
>>> def f(a, b, c):
... ...
...
>>> p1 = partial(f, 1)
>>> str(p1)
'functools.partial(<function f at 0x105bae160>, 1)'
>>> p2 = partial(p1, 2)
>>> str(p2)
'functools.partial(<function f at 0x105bae160>, 1, 2)'
# We have access to `args`, `kwargs` and `func`
>>> (p2.args, p2.keywords, p.func)
((1, 2), {}, <function a at 0x105b95ca0>)
I don't know if it's possible to build something using that approach, it's just thinking!
We need some logical flag to decide when to actually call a function: https://github.com/dry-python/returns/blob/master/returns/curry.py#L138-L139
Hummmm. I want to make some tests around partial
and pydantic
approach!
Using partial
we can use the inspect
module to determine if we need to call:
>>> import inspect
# Consider `p1` and `p2` from my last example
>>> inspect.signature(p2)
<Signature (c)>
>>> inspect.signature(p1)
<Signature (b, c)>
>>> inspect.getfullargspec(p1)
FullArgSpec(args=['b', 'c'], varargs=None, varkw=None, defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={})
>>> inspect.getfullargspec(p2)
FullArgSpec(args=['c'], varargs=None, varkw=None, defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={})
Pydantic:
This for loop is responsible to get all of the function fields. To follow this approach we'll need to transform curry
in a callable class instead of a function!
We need to chec how
pydantic
validates function arguments without calling the function itself: https://pydantic-docs.helpmanual.io/usage/validation_decorator/#validate-without-calling-the-functionWe need this because our
@curry
implementation relies on this logic. And right now it is very slow.