falconry / falcon

The no-magic web data plane API and microservices framework for Python developers, with a focus on reliability, correctness, and performance at scale.
https://falcon.readthedocs.io/en/stable/
Apache License 2.0
9.5k stars 935 forks source link

Type Hints: Add type hints to tutorials, snippets and examples #1820

Open CaselIT opened 3 years ago

CaselIT commented 3 years ago

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

open-collective-bot[bot] commented 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!

vytas7 commented 3 years ago

See also https://github.com/falconry/falcon/issues/1350, which strives after full typing support for the whole codebase.

bibekjoshi54 commented 3 years ago

@vytas7 I can start working on this

vytas7 commented 3 years ago

@bibekjoshi54 Awesome sauce! Go ahead.

CaselIT commented 3 years ago

That would be great!

davetapley commented 7 months ago

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 🤞🏻

CaselIT commented 7 months ago

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"""
    ...
davetapley commented 7 months ago

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:

  1. They already have type annotations in their resource class, and:
  2. Those type annotations are incorrect.

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 😑

VOndrej42 commented 2 months ago

I'll try to help with it :)