-
Notifications
You must be signed in to change notification settings - Fork 26
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
Proof of concept: annotation-based argument extractor/replacer #274
Conversation
This explores the posibility of automatically generating the argument extractor and replacer based on inline type annotations (for simple cases). So, for example `scipy.fft.fft` might look like: ```python @_dispatch def fft(x: ua.typing.Dispatchable[ArrayLike, np.ndarray], n=None, axis=-1, norm=None, overwrite_x=False, workers=None, *, plan=None): pass ``` The signature is inspected ahead-of-time so as to minimize call overhead but a Python implementation is still too slow. ~400 ns for even a simple `f(x)` signature. However, if it were lowered to C++ then the concept may still be viable. This also relies on `typing.Annotated` to specify `dispatch_type` and `coercible` but `typing.Annotated` itself requires Python 3.9. To support older Pythons versions we'd have to move the annotations out-of-line. Perhaps something like: ```python _generate_arg_extractor_replacer(func, [ DispatchableArg(name='a', dispatch_type='int', coercible=True), DispatchableArg(name='b', dispatch_type='float', coercible=False), ]) ```
I'd be very supportive of this! It'd cover almost all use-cases besides |
Should Also, something that might be important to remember is __all__ = ["Dispatchable"]
if not TYPE_CHECKING:
class Dispatchable: ... # Insert class details
else:
from typing import Annotated as Dispatchable
def test_func(a: Dispatchable[str | list[str], str], b: int) -> None: ...
# Revealed type is "def (a: Union[builtins.str, builtins.list[builtins.str]], b: builtins.int)"
reveal_type(test_func) |
Hrm you're right. It seems In that case I'm thinking |
6bc44fe
to
19b72ed
Compare
In general, I like the idea of using a decorator because it simplifies the workflow for API authors. Minor nit: If we are going with @_dispatch(x=ua.DispatchableArg(type=np.ndarray, coercible=True))
def fft(x, n=None, axis=-1, norm=None, overwrite_x=False, workers=None, *, plan=None):
pass |
@thomasjpfan I'm not sure that will work because the general decorator also needs to specify |
Brainstorming: A dispatcher for a given domain: dispatch = Dispatcher(domain="scipy.fft")
@dispatch.register(
x=DispatchableArg(...)
)
def fft(x):
...
Edit: I see other issues with using |
This explores the posibility of automatically generating the argument extractor and replacer based on inline type annotations (for simple cases). So, for example
scipy.fft.fft
might look like:The signature is inspected ahead-of-time so as to minimize call overhead but a Python implementation is still too slow. ~400 ns for
even a simple
f(x)
signature. However, if it were lowered to C++ then the concept may still be viable.This also relies on
typing.Annotated
to specifydispatch_type
andcoercible
buttyping.Annotated
itself requires Python 3.9. It may be possible to emulate on earlier python versions, otherwise I think the dispatch metadata would need to go elsewhere. Perhaps something like:cc @thomasjpfan