sanic-org / sanic-ext

Extended Sanic functionality

Home Page:https://sanic.dev/en/plugins/sanic-ext/getting-started.html

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[Bug] Dependency injection not working with inheritance

guacs opened this issue · comments

commented

Describe the bug
The dependency injection does not work when the type of the argument is set as the protocol and not the actual implementation of the said protocol.

To Reproduce

from typing import Protocol
from sanic import Sanic, text
from sanic import Request


class ExampleServiceProtocol(Protocol):
    def some_method(self) -> int:
        ...


class ExampleServiceImplementation(ExampleServiceProtocol):
    def some_method(self) -> int:
        return 1


def protocol_route(request: Request, example_service: ExampleServiceProtocol):
    return text("ok")


def implemented_route(request: Request, example_service: ExampleServiceImplementation):
    return text("ok")


def create_app() -> Sanic:
    app = Sanic("sample-app")

    app.add_route(protocol_route, "/protocol")
    app.add_route(implemented_route, "/implemented")

    example_service = ExampleServiceImplementation()
    app.ext.dependency(example_service)

    return app

In the above example, requests to /implemented works without any issues, but requests to /protocol results in the following error:

⚠️ 500 — Internal Server Error
==============================
protocol_route() missing 1 required positional argument: 'example_service'

TypeError: protocol_route() missing 1 required positional argument: 'example_service' while handling path /protocol

Expected behavior
The argument should be passed if there is an instance in the registered dependencies that is a subclass of the type specified in the route handler signature.

Environment (please complete the following information):

  • OS: Ubuntu 20.04.6 LTS (via WSL2 version 1.1.3.0)
  • Sanic version: Sanic 23.3.0; Routing 22.8.0
  • Sanic Ext version: 23.3.0

Additional context
Of all the issues, this is the closest issue I found which might be related to it.

Not a bug. Injection requires the type to be registered.

To be more specific, when you use the higher level dependency method, the type of the object is inspected. When that type is found as an annotation, it is injected. Something like this should work:

app.ext.add_dependency(
    ExampleServiceProtocol,
    lambda: example_service)

Sorry for the brevity. On my phone from PTO. Hope this helps.

commented

Oh the solution you gave works perfectly! My bad for marking it as a bug. I just misunderstood how the API worked.

No worries. good luck 😎