cenobites / flask-jsonrpc

Basic JSON-RPC implementation for your Flask-powered sites

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Feature request: function (view) overloading?

Talkless opened this issue · comments

Not sure if this would be doable in Flask at all, but instead of having view with compex signatures using Unions / Optionals / Variants:

 #if first parameter is integer, second parameter is ignored
 time_from_or_days_ago: Union[str, int], time_to: Optional[str]

...we could have something like this, by introducing "aliases" (or some other term) to group overloads:

@foo.method("foo.bar_dates", alias="foo.bar")
def foo_bar_dates(time_from: str, time_to: str) -> str
    # ...
    
@foo.method("foo.bar_days", alias="foo.bar")
def foo_bar_days(days_ago: int) -> str
    # ...

image

It seems good to me, even the presentation of the overloadings, 👍

Not sure about "alias" keyword though, maybe it there will be "needed" for other feature in the future, but not sure what else to suggest.

overload_set="foo.bar" might be correctly specific, but maybe too cryptic?

group="foo.bar" could be another alternative, though not sure why it's better than alias.

I was thought in some think like that:

from __future__ import annotations

from collections.abc import Sequence
from typing import overload

from flask import Flask

from flask_jsonrpc import JSONRPC

app = Flask('application')
jsonrpc = JSONRPC(app, '/api', enable_web_browsable_api=True)

@overload
def double(input_: int) -> int:
    ...

@overload
def double(input_: Sequence[int]) -> list[int]:
    ...

@jsonrpc.method('App.double')
def double(input_: int | Sequence[int]) -> int | list[int]:
    if isinstance(input_, Sequence):
        return [i * 2 for i in input_]
    return input_ * 2

The idea of overloading was to avoid having if isinstance... logic inside function.

Maybe I do not follow this example. What will be in the bodies of these two @overload'ed functions if I see all code in @jsonrpc.method('App.double') then?

Maybe I do not follow this example. What will be in the bodies of these two @overload'ed functions if I see all code in @jsonrpc.method('App.double') then?

No, did you see it right, I didn't see that were two completely different functions, and I thought about the typing.overload support that can be used with typing.TypeGuard[1] together.

In that case, I have a bad feeling regarding it, Flask doesn't allow mapping two functions to one URL, the opposite is true. Besides that, to do that, we will need to analyze the input (payload) and choice the right function to trigger, and further more, changing the way of register of functions in Flask-JSONRPC, from Dict[str, Callable] to Dict[str, List[Callable]].

[1] - https://peps.python.org/pep-0647/

Flask doesn't allow mapping two functions to one URL

OK, could then some sort of jsonrpc.register_overload_set('foo.bar') (not an decorator) be used to register "generated" single method with single URL to make Flask happy?

Then, inside that "generated" method implementation, it would select best match from @jsonrpc.overloaded_method('foo.bar')'s for given argument set.

Not sure how would @jwt_required() would for these "not-really-a-flask-views"?