@@ -214,3 +214,82 @@ def handler(name: str = "world", greeting: Annotated[str, Depends(get_greeting)]
214214 result = app (event , {})
215215 assert result ["statusCode" ] == 200
216216 assert json .loads (result ["body" ]) == {"message" : "hello, Lambda!" }
217+
218+
219+ class ArbitraryClient :
220+ """Stand-in for an arbitrary non-Pydantic type such as a boto3 client."""
221+
222+ def __init__ (self , name : str = "default" ):
223+ self .name = name
224+
225+
226+ def test_depends_with_arbitrary_return_type_and_validation ():
227+ """A dependency returning a non-Pydantic type must not crash under enable_validation (#8330)."""
228+ app = APIGatewayHttpResolver (enable_validation = True )
229+
230+ def get_client () -> ArbitraryClient :
231+ return ArbitraryClient (name = "orders" )
232+
233+ @app .get ("/items" )
234+ def handler (client : Annotated [ArbitraryClient , Depends (get_client )]):
235+ return {"client" : client .name }
236+
237+ event = {** API_GW_V2_EVENT }
238+ event ["rawPath" ] = "/items"
239+ event ["requestContext" ] = {
240+ ** event ["requestContext" ],
241+ "http" : {"method" : "GET" , "path" : "/items" },
242+ }
243+
244+ result = app (event , {})
245+ assert result ["statusCode" ] == 200
246+ assert json .loads (result ["body" ]) == {"client" : "orders" }
247+
248+
249+ def test_depends_nested_arbitrary_return_types_and_validation ():
250+ """A nested dependency chain of non-Pydantic return types must resolve (#8330).
251+
252+ Mirrors the reported chain: botocore session -> boto3 session -> dynamodb client.
253+ """
254+ app = APIGatewayHttpResolver (enable_validation = True )
255+
256+ def get_session () -> ArbitraryClient :
257+ return ArbitraryClient (name = "session" )
258+
259+ def get_client (session : Annotated [ArbitraryClient , Depends (get_session )]) -> ArbitraryClient :
260+ return ArbitraryClient (name = f"client-of-{ session .name } " )
261+
262+ @app .get ("/items" )
263+ def handler (client : Annotated [ArbitraryClient , Depends (get_client )]):
264+ return {"client" : client .name }
265+
266+ event = {** API_GW_V2_EVENT }
267+ event ["rawPath" ] = "/items"
268+ event ["requestContext" ] = {
269+ ** event ["requestContext" ],
270+ "http" : {"method" : "GET" , "path" : "/items" },
271+ }
272+
273+ result = app (event , {})
274+ assert result ["statusCode" ] == 200
275+ assert json .loads (result ["body" ]) == {"client" : "client-of-session" }
276+
277+
278+ def test_depends_arbitrary_return_type_excluded_from_openapi_schema ():
279+ """A non-Pydantic dependency return type must not appear in (or break) the OpenAPI schema (#8330)."""
280+ app = APIGatewayHttpResolver (enable_validation = True )
281+
282+ def get_client () -> ArbitraryClient :
283+ return ArbitraryClient ()
284+
285+ @app .get ("/items" )
286+ def handler (client : Annotated [ArbitraryClient , Depends (get_client )]):
287+ return {"ok" : True }
288+
289+ # Schema generation itself must not raise, and the dependency must not leak into params/body.
290+ schema = app .get_openapi_schema ()
291+ get_op = schema .paths ["/items" ].get
292+ param_names = [p .name for p in (get_op .parameters or [])]
293+
294+ assert "client" not in param_names
295+ assert get_op .requestBody is None
0 commit comments