-
- Notifications
You must be signed in to change notification settings - Fork 339
Description
I was trying out the async resource provider to verify that it is actually closing the resource.
However, I noticed that it is not closing the resource.
After deep investigations I found out that the @Inject decorator on the API
makes python think that the function is not an async generator.
FastAPI decides whether the dependency is a generator on this line https://github.com/tiangolo/fastapi/blob/master/fastapi/dependencies/utils.py#L522
Which then tries to inspect the code using the builtin inspect function
def is_gen_callable(call: Callable[..., Any]) -> bool: if inspect.isgeneratorfunction(call): return True call = getattr(call, "__call__", None) return inspect.isgeneratorfunction(call) def is_async_gen_callable(call: Callable[..., Any]) -> bool: if inspect.isasyncgenfunction(call): return True call = getattr(call, "__call__", None) return inspect.isasyncgenfunction(call)Which is returning false for async generators decorated with @Inject
I have attached the test code.
I'll try investigating the @Inject decorator
To see whether it could be fixed
import contextlib import os from functools import partial from dependency_injector import containers, providers, resources from dependency_injector.wiring import Provide, inject, Closing from fastapi import FastAPI, Depends from pydantic import BaseSettings, Field from sqlalchemy.ext.asyncio import AsyncEngine, create_async_engine, AsyncSession from sqlalchemy.orm import sessionmaker os.environ["sql_alchemy_str"] = "sqlite+aiosqlite:///database.db" class DatabaseSettings(BaseSettings): sql_alchemy_str: str = Field(env="sql_alchemy_str") async def make(engine=None): print(f"Make {engine}") session = sessionmaker( engine, expire_on_commit=False, class_=AsyncSession ) yield session() with open("kill.txt", "w") as f: f.write("killed") print("kill") class DatabaseContainer(containers.DeclarativeContainer): config = providers.Configuration[DatabaseSettings]("DatabaseConfig") alchemy_engine: AsyncEngine = providers.Singleton(create_async_engine, config.sql_alchemy_str, echo=True) async_session = providers.Resource(make, alchemy_engine) app = FastAPI() @app.get("/Hello") @inject async def say_hi(session: AsyncSession = Depends(Closing[Provide[DatabaseContainer.async_session]], use_cache=False)): print(f"Got {session}") container = DatabaseContainer() container.config.from_pydantic(DatabaseSettings()) container.wire(modules=[__name__]) @app.on_event("startup") async def startup_event(): print(container.alchemy_engine())Gamazic, Voldemat, katunilya, Medhi83, analogstar and 2 moreskair72
Metadata
Metadata
Assignees
Labels
No labels