Finistere / antidote

Dependency injection for Python
MIT License
90 stars 9 forks source link

Any example of how to use this with Starlette would be great #34

Closed taybin closed 2 years ago

taybin commented 2 years ago

Should starlette endpoints be able to have dependencies injected after the request argument? I've been having trouble getting it to work.

Finistere commented 2 years ago

I took a look with Starlette (https://www.starlette.io/), there's indeed an issue. Unfortunately, Python inspection functions are tricky. While Antidote does return a callable, it's not a "function" in the strict inspect.isfunction sense which only works with functions declared with def. So currently the only way to make it work is to avoid exposing injected functions directly to Starlette.

from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route

from antidote import inject, service

@service
class Dummy:
    pass

async def homepage(request):
    return await homepage_impl(request)

@inject
async def homepage_impl(request, dummy: Dummy = inject.me()):
    return JSONResponse({'hello': 'world', 'dummy': id(dummy)})

app = Starlette(debug=True, routes=[
    Route('/', homepage),
])

However, wrapt does seem to work and Antidote is using very similar code, so Antidote's wrapper is probably lacking something. Taking a look to solve this. :) Thanks for reporting the issue!

taybin commented 2 years ago

Thank you for investigating this with such sparse details from me!

Finistere commented 2 years ago

Everything seems to be working with the 1.1.1:

from starlette.applications import Starlette
from starlette.endpoints import HTTPEndpoint
from starlette.responses import JSONResponse
from starlette.routing import Route

from antidote import inject, service

@service
class Dummy:
    pass

@inject
async def test(request, dummy: Dummy = inject.me()):
    return JSONResponse({'hello': 'world', 'dummy': id(dummy)})

class Test(HTTPEndpoint):
    @inject
    async def get(self, request, dummy: Dummy = inject.me()):
        return JSONResponse({'hello': 'world', 'dummy': id(dummy)})

app = Starlette(debug=True, routes=[
    Route('/test', Test),
    Route('/test-class', test),
])

Closing the issue, feel free to re-open it if you have any other examples that don't work!