Open CaselIT opened 3 years ago
Hi :wave:,
Thanks for using Falcon. The large amount of time and effort needed to maintain the project and develop new features is not sustainable without the generous financial support of community members like you.
Please consider helping us secure the future of the Falcon framework with a one-time or recurring donation.
Thank you for your support!
See also https://github.com/falconry/falcon/issues/1350, which strives after full typing support for the whole codebase.
@vytas7 I can start working on this
@bibekjoshi54 Awesome sauce! Go ahead.
That would be great!
Just to throw it out there: I think a Protocol would be a great fit for resource
in :
https://github.com/falconry/falcon/blob/4910dd73ecd1b9c8cf6cae045b26ad432fa56128/falcon/routing/compiled.py#L150
Something like:
from typing import Protocol
from falcon.request import Request
from falcon.response import Response
class Resource(Protocol):
def on_get(self, request: Request, resp: Response)) -> None:
...
def on_post(self, request: Request, resp: Response)) -> None:
...
# and so on ...
Then the signature would become:
def add_route(self, uri_template: str, resource: Resource, suffix: str | None = None, compile: bool = False)
The only caveat is that implementor would have to provide all the methods
(although could easily just ...
those with no implementation)
... at least until optional protocol members are supported, something I've also raised here 🤞🏻
That's an option, but I'm not sure it would provide much in terms of help for a user, since once the add_route
call happens the class is already defined.
Maybe it could be used a "TypingResource" that may be used by user as superclass, where each method is defined in a type_checking block (to avoid it being picked up by the router). This could be useful since ide can autocomplete the signature of methods when overloading one.
Something like
class TypeCheckResource:
"""Superclass of a Resource for typing purposes"""
if TYPE_CHECKING:
def on_get(self, req: Request, resp: Response, **path_args: Any) -> None:
"""Handles the GET method"""
...
once the
add_route
call happens the class is already defined.
True, but in the current implementation if that class had say:
class MyResource:
def on_get(self, req: str, bad: int)
app.add_route(uri_template, MyResource())
Then it would still type check okay (and the IDE wouldn't complain), because there is currently no typing for resource
in:
https://github.com/falconry/falcon/blob/4910dd73ecd1b9c8cf6cae045b26ad432fa56128/falcon/routing/compiled.py#L150
A super class (or even better an ABC) would work,
but it would require* everyone to explicitly to register
(or subclass) TypeCheckResource
.
* assuming the goal would be to change the signature of add_route
to ⬇️ , so that is type checked correctly.
def add_route(self, uri_template: str, resource: TypeCheckResource,...
The nice thing about protocols is that we could add the resource: Resource
type to add_route
and no one would have* to change their code, except in the case that:
Put another way: it would allow graceful adoption of typing, without forcing everyone to do it.
* incidentally protocols do also allow for explicitly declaring an implementation if someone wanted to verify the types of a resource class before they tried to use it in add_route
.
... but that's all academic until/unless https://github.com/python/typing/issues/601 happens 😑
I'll try to help with it :)
To improve code readability and be friendlier to PEP 484, we should start adding type annotations to our code, probably starting from snippets, tutorials and examples.
Originally discussed here https://github.com/falconry/falcon/pull/1737#issuecomment-744064360