@ -1,10 +1,18 @@
import inspect
import sys
from functools import wraps
from functools import wraps
from typing import AsyncGenerator , Generator
from typing import AsyncGenerator , Generator
import pytest
import pytest
from fastapi import Depends , FastAPI
from fastapi import Depends , FastAPI
from fastapi . concurrency import iterate_in_threadpool , run_in_threadpool
from fastapi . testclient import TestClient
from fastapi . testclient import TestClient
if sys . version_info > = ( 3 , 13 ) : # pragma: no cover
from inspect import iscoroutinefunction
else : # pragma: no cover
from asyncio import iscoroutinefunction
def noop_wrap ( func ) :
def noop_wrap ( func ) :
@wraps ( func )
@wraps ( func )
@ -14,8 +22,163 @@ def noop_wrap(func):
return wrapper
return wrapper
def noop_wrap_async ( func ) :
if inspect . isgeneratorfunction ( func ) :
@wraps ( func )
async def gen_wrapper ( * args , * * kwargs ) :
async for item in iterate_in_threadpool ( func ( * args , * * kwargs ) ) :
yield item
return gen_wrapper
elif inspect . isasyncgenfunction ( func ) :
@wraps ( func )
async def async_gen_wrapper ( * args , * * kwargs ) :
async for item in func ( * args , * * kwargs ) :
yield item
return async_gen_wrapper
@wraps ( func )
async def wrapper ( * args , * * kwargs ) :
if inspect . isroutine ( func ) and iscoroutinefunction ( func ) :
return await func ( * args , * * kwargs )
if inspect . isclass ( func ) :
return await run_in_threadpool ( func , * args , * * kwargs )
dunder_call = getattr ( func , " __call__ " , None ) # noqa: B004
if iscoroutinefunction ( dunder_call ) :
return await dunder_call ( * args , * * kwargs )
return await run_in_threadpool ( func , * args , * * kwargs )
return wrapper
class ClassInstanceDep :
def __call__ ( self ) :
return True
class_instance_dep = ClassInstanceDep ( )
wrapped_class_instance_dep = noop_wrap ( class_instance_dep )
wrapped_class_instance_dep_async_wrapper = noop_wrap_async ( class_instance_dep )
class ClassInstanceGenDep :
def __call__ ( self ) :
yield True
class_instance_gen_dep = ClassInstanceGenDep ( )
wrapped_class_instance_gen_dep = noop_wrap ( class_instance_gen_dep )
class ClassInstanceWrappedDep :
@noop_wrap
def __call__ ( self ) :
return True
class_instance_wrapped_dep = ClassInstanceWrappedDep ( )
class ClassInstanceWrappedAsyncDep :
@noop_wrap_async
def __call__ ( self ) :
return True
class_instance_wrapped_async_dep = ClassInstanceWrappedAsyncDep ( )
class ClassInstanceWrappedGenDep :
@noop_wrap
def __call__ ( self ) :
yield True
class_instance_wrapped_gen_dep = ClassInstanceWrappedGenDep ( )
class ClassInstanceWrappedAsyncGenDep :
@noop_wrap_async
def __call__ ( self ) :
yield True
class_instance_wrapped_async_gen_dep = ClassInstanceWrappedAsyncGenDep ( )
class ClassDep :
def __init__ ( self ) :
self . value = True
wrapped_class_dep = noop_wrap ( ClassDep )
wrapped_class_dep_async_wrapper = noop_wrap_async ( ClassDep )
class ClassInstanceAsyncDep :
async def __call__ ( self ) :
return True
class_instance_async_dep = ClassInstanceAsyncDep ( )
wrapped_class_instance_async_dep = noop_wrap ( class_instance_async_dep )
wrapped_class_instance_async_dep_async_wrapper = noop_wrap_async (
class_instance_async_dep
)
class ClassInstanceAsyncGenDep :
async def __call__ ( self ) :
yield True
class_instance_async_gen_dep = ClassInstanceAsyncGenDep ( )
wrapped_class_instance_async_gen_dep = noop_wrap ( class_instance_async_gen_dep )
class ClassInstanceAsyncWrappedDep :
@noop_wrap
async def __call__ ( self ) :
return True
class_instance_async_wrapped_dep = ClassInstanceAsyncWrappedDep ( )
class ClassInstanceAsyncWrappedAsyncDep :
@noop_wrap_async
async def __call__ ( self ) :
return True
class_instance_async_wrapped_async_dep = ClassInstanceAsyncWrappedAsyncDep ( )
class ClassInstanceAsyncWrappedGenDep :
@noop_wrap
async def __call__ ( self ) :
yield True
class_instance_async_wrapped_gen_dep = ClassInstanceAsyncWrappedGenDep ( )
class ClassInstanceAsyncWrappedGenAsyncDep :
@noop_wrap_async
async def __call__ ( self ) :
yield True
class_instance_async_wrapped_gen_async_dep = ClassInstanceAsyncWrappedGenAsyncDep ( )
app = FastAPI ( )
app = FastAPI ( )
# Sync wrapper
@noop_wrap
@noop_wrap
def wrapped_dependency ( ) - > bool :
def wrapped_dependency ( ) - > bool :
@ -59,16 +222,225 @@ async def get_async_wrapped_gen_dependency(
return value
return value
@app . get ( " /wrapped-class-instance-dependency/ " )
async def get_wrapped_class_instance_dependency (
value : bool = Depends ( wrapped_class_instance_dep ) ,
) :
return value
@app . get ( " /wrapped-class-instance-async-dependency/ " )
async def get_wrapped_class_instance_async_dependency (
value : bool = Depends ( wrapped_class_instance_async_dep ) ,
) :
return value
@app . get ( " /wrapped-class-instance-gen-dependency/ " )
async def get_wrapped_class_instance_gen_dependency (
value : bool = Depends ( wrapped_class_instance_gen_dep ) ,
) :
return value
@app . get ( " /wrapped-class-instance-async-gen-dependency/ " )
async def get_wrapped_class_instance_async_gen_dependency (
value : bool = Depends ( wrapped_class_instance_async_gen_dep ) ,
) :
return value
@app . get ( " /class-instance-wrapped-dependency/ " )
async def get_class_instance_wrapped_dependency (
value : bool = Depends ( class_instance_wrapped_dep ) ,
) :
return value
@app . get ( " /class-instance-wrapped-async-dependency/ " )
async def get_class_instance_wrapped_async_dependency (
value : bool = Depends ( class_instance_wrapped_async_dep ) ,
) :
return value
@app . get ( " /class-instance-async-wrapped-dependency/ " )
async def get_class_instance_async_wrapped_dependency (
value : bool = Depends ( class_instance_async_wrapped_dep ) ,
) :
return value
@app . get ( " /class-instance-async-wrapped-async-dependency/ " )
async def get_class_instance_async_wrapped_async_dependency (
value : bool = Depends ( class_instance_async_wrapped_async_dep ) ,
) :
return value
@app . get ( " /class-instance-wrapped-gen-dependency/ " )
async def get_class_instance_wrapped_gen_dependency (
value : bool = Depends ( class_instance_wrapped_gen_dep ) ,
) :
return value
@app . get ( " /class-instance-wrapped-async-gen-dependency/ " )
async def get_class_instance_wrapped_async_gen_dependency (
value : bool = Depends ( class_instance_wrapped_async_gen_dep ) ,
) :
return value
@app . get ( " /class-instance-async-wrapped-gen-dependency/ " )
async def get_class_instance_async_wrapped_gen_dependency (
value : bool = Depends ( class_instance_async_wrapped_gen_dep ) ,
) :
return value
@app . get ( " /class-instance-async-wrapped-gen-async-dependency/ " )
async def get_class_instance_async_wrapped_gen_async_dependency (
value : bool = Depends ( class_instance_async_wrapped_gen_async_dep ) ,
) :
return value
@app . get ( " /wrapped-class-dependency/ " )
async def get_wrapped_class_dependency ( value : ClassDep = Depends ( wrapped_class_dep ) ) :
return value . value
@app . get ( " /wrapped-endpoint/ " )
@noop_wrap
def get_wrapped_endpoint ( ) :
return True
@app . get ( " /async-wrapped-endpoint/ " )
@noop_wrap
async def get_async_wrapped_endpoint ( ) :
return True
# Async wrapper
@noop_wrap_async
def wrapped_dependency_async_wrapper ( ) - > bool :
return True
@noop_wrap_async
def wrapped_gen_dependency_async_wrapper ( ) - > Generator [ bool , None , None ] :
yield True
@noop_wrap_async
async def async_wrapped_dependency_async_wrapper ( ) - > bool :
return True
@noop_wrap_async
async def async_wrapped_gen_dependency_async_wrapper ( ) - > AsyncGenerator [ bool , None ] :
yield True
@app . get ( " /wrapped-dependency-async-wrapper/ " )
async def get_wrapped_dependency_async_wrapper (
value : bool = Depends ( wrapped_dependency_async_wrapper ) ,
) :
return value
@app . get ( " /wrapped-gen-dependency-async-wrapper/ " )
async def get_wrapped_gen_dependency_async_wrapper (
value : bool = Depends ( wrapped_gen_dependency_async_wrapper ) ,
) :
return value
@app . get ( " /async-wrapped-dependency-async-wrapper/ " )
async def get_async_wrapped_dependency_async_wrapper (
value : bool = Depends ( async_wrapped_dependency_async_wrapper ) ,
) :
return value
@app . get ( " /async-wrapped-gen-dependency-async-wrapper/ " )
async def get_async_wrapped_gen_dependency_async_wrapper (
value : bool = Depends ( async_wrapped_gen_dependency_async_wrapper ) ,
) :
return value
@app . get ( " /wrapped-class-instance-dependency-async-wrapper/ " )
async def get_wrapped_class_instance_dependency_async_wrapper (
value : bool = Depends ( wrapped_class_instance_dep_async_wrapper ) ,
) :
return value
@app . get ( " /wrapped-class-instance-async-dependency-async-wrapper/ " )
async def get_wrapped_class_instance_async_dependency_async_wrapper (
value : bool = Depends ( wrapped_class_instance_async_dep_async_wrapper ) ,
) :
return value
@app . get ( " /wrapped-class-dependency-async-wrapper/ " )
async def get_wrapped_class_dependency_async_wrapper (
value : ClassDep = Depends ( wrapped_class_dep_async_wrapper ) ,
) :
return value . value
@app . get ( " /wrapped-endpoint-async-wrapper/ " )
@noop_wrap_async
def get_wrapped_endpoint_async_wrapper ( ) :
return True
@app . get ( " /async-wrapped-endpoint-async-wrapper/ " )
@noop_wrap_async
async def get_async_wrapped_endpoint_async_wrapper ( ) :
return True
client = TestClient ( app )
client = TestClient ( app )
@pytest . mark . parametrize (
@pytest . mark . parametrize (
" route " ,
" route " ,
[
[
" /wrapped-dependency " ,
" /wrapped-dependency/ " ,
" /wrapped-gen-dependency " ,
" /wrapped-gen-dependency/ " ,
" /async-wrapped-dependency " ,
" /async-wrapped-dependency/ " ,
" /async-wrapped-gen-dependency " ,
" /async-wrapped-gen-dependency/ " ,
" /wrapped-class-instance-dependency/ " ,
" /wrapped-class-instance-async-dependency/ " ,
" /wrapped-class-instance-gen-dependency/ " ,
" /wrapped-class-instance-async-gen-dependency/ " ,
" /class-instance-wrapped-dependency/ " ,
" /class-instance-wrapped-async-dependency/ " ,
" /class-instance-async-wrapped-dependency/ " ,
" /class-instance-async-wrapped-async-dependency/ " ,
" /class-instance-wrapped-gen-dependency/ " ,
" /class-instance-wrapped-async-gen-dependency/ " ,
" /class-instance-async-wrapped-gen-dependency/ " ,
" /class-instance-async-wrapped-gen-async-dependency/ " ,
" /wrapped-class-dependency/ " ,
" /wrapped-endpoint/ " ,
" /async-wrapped-endpoint/ " ,
" /wrapped-dependency-async-wrapper/ " ,
" /wrapped-gen-dependency-async-wrapper/ " ,
" /async-wrapped-dependency-async-wrapper/ " ,
" /async-wrapped-gen-dependency-async-wrapper/ " ,
" /wrapped-class-instance-dependency-async-wrapper/ " ,
" /wrapped-class-instance-async-dependency-async-wrapper/ " ,
" /wrapped-class-dependency-async-wrapper/ " ,
" /wrapped-endpoint-async-wrapper/ " ,
" /async-wrapped-endpoint-async-wrapper/ " ,
] ,
] ,
)
)
def test_class_dependency ( route ) :
def test_class_dependency ( route ) :