33import ssl
44import sys
55import time
6- from typing import TYPE_CHECKING , Any , Callable , Dict , List , Mapping , Optional , Union
6+ from typing import TYPE_CHECKING , Any , Callable , Dict , List , Mapping , Optional , Tuple , Union
77
88import certifi
99import httpx
4747_DEFAULT_TIMEOUT = httpx .Timeout (timeout = 5.0 , connect = 5.0 )
4848
4949
50+ def _prepare_request_data_and_content (
51+ data : Optional [Union [dict , str , bytes ]] = None ,
52+ content : Any = None ,
53+ ) -> Tuple [Optional [Union [dict , Mapping ]], Any ]:
54+ """
55+ Helper function to route data/content parameters correctly for httpx requests
56+
57+ This prevents httpx DeprecationWarnings that cause memory leaks.
58+
59+ Background:
60+ - httpx shows a DeprecationWarning when you pass bytes/str to `data=`
61+ - It wants you to use `content=` instead for bytes/str
62+ - The warning itself leaks memory when triggered repeatedly
63+
64+ Solution:
65+ - Move bytes/str from `data=` to `content=` before calling build_request
66+ - Keep dicts in `data=` (that's still the correct parameter for dicts)
67+
68+ Args:
69+ data: Request data (can be dict, str, or bytes)
70+ content: Request content (raw bytes/str)
71+
72+ Returns:
73+ Tuple of (request_data, request_content) properly routed for httpx
74+ """
75+ request_data = None
76+ request_content = content
77+
78+ if data is not None :
79+ if isinstance (data , (bytes , str )):
80+ # Bytes/strings belong in content= (only if not already provided)
81+ if content is None :
82+ request_content = data
83+ else :
84+ # dict/Mapping stays in data= parameter
85+ request_data = data
86+
87+ return request_data , request_content
88+
89+
5090def get_ssl_configuration (
5191 ssl_verify : Optional [VerifyTypes ] = None ,
5292) -> Union [bool , str , ssl .SSLContext ]:
@@ -301,17 +341,20 @@ async def post(
301341 if timeout is None :
302342 timeout = self .timeout
303343
344+ # Prepare data/content parameters to prevent httpx DeprecationWarning (memory leak fix)
345+ request_data , request_content = _prepare_request_data_and_content (data , content )
346+
304347 req = self .client .build_request (
305348 "POST" ,
306349 url ,
307- data = data , # type: ignore
350+ data = request_data ,
308351 json = json ,
309352 params = params ,
310353 headers = headers ,
311354 timeout = timeout ,
312355 files = files ,
313- content = content ,
314- )
356+ content = request_content ,
357+ )
315358 response = await self .client .send (req , stream = stream )
316359 response .raise_for_status ()
317360 return response
@@ -364,19 +407,23 @@ async def post(
364407 async def put (
365408 self ,
366409 url : str ,
367- data : Optional [Union [dict , str ]] = None , # type: ignore
410+ data : Optional [Union [dict , str , bytes ]] = None , # type: ignore
368411 json : Optional [dict ] = None ,
369412 params : Optional [dict ] = None ,
370413 headers : Optional [dict ] = None ,
371414 timeout : Optional [Union [float , httpx .Timeout ]] = None ,
372415 stream : bool = False ,
416+ content : Any = None ,
373417 ):
374418 try :
375419 if timeout is None :
376420 timeout = self .timeout
377421
422+ # Prepare data/content parameters to prevent httpx DeprecationWarning (memory leak fix)
423+ request_data , request_content = _prepare_request_data_and_content (data , content )
424+
378425 req = self .client .build_request (
379- "PUT" , url , data = data , json = json , params = params , headers = headers , timeout = timeout # type: ignore
426+ "PUT" , url , data = request_data , json = json , params = params , headers = headers , timeout = timeout , content = request_content # type: ignore
380427 )
381428 response = await self .client .send (req )
382429 response .raise_for_status ()
@@ -424,19 +471,23 @@ async def put(
424471 async def patch (
425472 self ,
426473 url : str ,
427- data : Optional [Union [dict , str ]] = None , # type: ignore
474+ data : Optional [Union [dict , str , bytes ]] = None , # type: ignore
428475 json : Optional [dict ] = None ,
429476 params : Optional [dict ] = None ,
430477 headers : Optional [dict ] = None ,
431478 timeout : Optional [Union [float , httpx .Timeout ]] = None ,
432479 stream : bool = False ,
480+ content : Any = None ,
433481 ):
434482 try :
435483 if timeout is None :
436484 timeout = self .timeout
437485
486+ # Prepare data/content parameters to prevent httpx DeprecationWarning (memory leak fix)
487+ request_data , request_content = _prepare_request_data_and_content (data , content )
488+
438489 req = self .client .build_request (
439- "PATCH" , url , data = data , json = json , params = params , headers = headers , timeout = timeout # type: ignore
490+ "PATCH" , url , data = request_data , json = json , params = params , headers = headers , timeout = timeout , content = request_content # type: ignore
440491 )
441492 response = await self .client .send (req )
442493 response .raise_for_status ()
@@ -484,18 +535,23 @@ async def patch(
484535 async def delete (
485536 self ,
486537 url : str ,
487- data : Optional [Union [dict , str ]] = None , # type: ignore
538+ data : Optional [Union [dict , str , bytes ]] = None , # type: ignore
488539 json : Optional [dict ] = None ,
489540 params : Optional [dict ] = None ,
490541 headers : Optional [dict ] = None ,
491542 timeout : Optional [Union [float , httpx .Timeout ]] = None ,
492543 stream : bool = False ,
544+ content : Any = None ,
493545 ):
494546 try :
495547 if timeout is None :
496548 timeout = self .timeout
549+
550+ # Prepare data/content parameters to prevent httpx DeprecationWarning (memory leak fix)
551+ request_data , request_content = _prepare_request_data_and_content (data , content )
552+
497553 req = self .client .build_request (
498- "DELETE" , url , data = data , json = json , params = params , headers = headers , timeout = timeout # type: ignore
554+ "DELETE" , url , data = request_data , json = json , params = params , headers = headers , timeout = timeout , content = request_content # type: ignore
499555 )
500556 response = await self .client .send (req , stream = stream )
501557 response .raise_for_status ()
@@ -543,8 +599,11 @@ async def single_connection_post_request(
543599
544600 Used for retrying connection client errors.
545601 """
602+ # Prepare data/content parameters to prevent httpx DeprecationWarning (memory leak fix)
603+ request_data , request_content = _prepare_request_data_and_content (data , content )
604+
546605 req = client .build_request (
547- "POST" , url , data = data , json = json , params = params , headers = headers , content = content # type: ignore
606+ "POST" , url , data = request_data , json = json , params = params , headers = headers , content = request_content # type: ignore
548607 )
549608 response = await client .send (req , stream = stream )
550609 response .raise_for_status ()
@@ -798,21 +857,24 @@ def post(
798857 logging_obj : Optional [LiteLLMLoggingObject ] = None ,
799858 ):
800859 try :
860+ # Prepare data/content parameters to prevent httpx DeprecationWarning (memory leak fix)
861+ request_data , request_content = _prepare_request_data_and_content (data , content )
862+
801863 if timeout is not None :
802864 req = self .client .build_request (
803865 "POST" ,
804866 url ,
805- data = data , # type: ignore
867+ data = request_data , # type: ignore
806868 json = json ,
807869 params = params ,
808870 headers = headers ,
809871 timeout = timeout ,
810872 files = files ,
811- content = content , # type: ignore
873+ content = request_content , # type: ignore
812874 )
813875 else :
814876 req = self .client .build_request (
815- "POST" , url , data = data , json = json , params = params , headers = headers , files = files , content = content # type: ignore
877+ "POST" , url , data = request_data , json = json , params = params , headers = headers , files = files , content = request_content # type: ignore
816878 )
817879 response = self .client .send (req , stream = stream )
818880 response .raise_for_status ()
@@ -840,21 +902,25 @@ def post(
840902 def patch (
841903 self ,
842904 url : str ,
843- data : Optional [Union [dict , str ]] = None ,
905+ data : Optional [Union [dict , str , bytes ]] = None ,
844906 json : Optional [Union [dict , str ]] = None ,
845907 params : Optional [dict ] = None ,
846908 headers : Optional [dict ] = None ,
847909 stream : bool = False ,
848910 timeout : Optional [Union [float , httpx .Timeout ]] = None ,
911+ content : Any = None ,
849912 ):
850913 try :
914+ # Prepare data/content parameters to prevent httpx DeprecationWarning (memory leak fix)
915+ request_data , request_content = _prepare_request_data_and_content (data , content )
916+
851917 if timeout is not None :
852918 req = self .client .build_request (
853- "PATCH" , url , data = data , json = json , params = params , headers = headers , timeout = timeout # type: ignore
919+ "PATCH" , url , data = request_data , json = json , params = params , headers = headers , timeout = timeout , content = request_content # type: ignore
854920 )
855921 else :
856922 req = self .client .build_request (
857- "PATCH" , url , data = data , json = json , params = params , headers = headers # type: ignore
923+ "PATCH" , url , data = request_data , json = json , params = params , headers = headers , content = request_content # type: ignore
858924 )
859925 response = self .client .send (req , stream = stream )
860926 response .raise_for_status ()
@@ -883,21 +949,25 @@ def patch(
883949 def put (
884950 self ,
885951 url : str ,
886- data : Optional [Union [dict , str ]] = None ,
952+ data : Optional [Union [dict , str , bytes ]] = None ,
887953 json : Optional [Union [dict , str ]] = None ,
888954 params : Optional [dict ] = None ,
889955 headers : Optional [dict ] = None ,
890956 stream : bool = False ,
891957 timeout : Optional [Union [float , httpx .Timeout ]] = None ,
958+ content : Any = None ,
892959 ):
893960 try :
961+ # Prepare data/content parameters to prevent httpx DeprecationWarning (memory leak fix)
962+ request_data , request_content = _prepare_request_data_and_content (data , content )
963+
894964 if timeout is not None :
895965 req = self .client .build_request (
896- "PUT" , url , data = data , json = json , params = params , headers = headers , timeout = timeout # type: ignore
966+ "PUT" , url , data = request_data , json = json , params = params , headers = headers , timeout = timeout , content = request_content # type: ignore
897967 )
898968 else :
899969 req = self .client .build_request (
900- "PUT" , url , data = data , json = json , params = params , headers = headers # type: ignore
970+ "PUT" , url , data = request_data , json = json , params = params , headers = headers , content = request_content # type: ignore
901971 )
902972 response = self .client .send (req , stream = stream )
903973 return response
@@ -913,21 +983,25 @@ def put(
913983 def delete (
914984 self ,
915985 url : str ,
916- data : Optional [Union [dict , str ]] = None , # type: ignore
986+ data : Optional [Union [dict , str , bytes ]] = None , # type: ignore
917987 json : Optional [dict ] = None ,
918988 params : Optional [dict ] = None ,
919989 headers : Optional [dict ] = None ,
920990 timeout : Optional [Union [float , httpx .Timeout ]] = None ,
921991 stream : bool = False ,
992+ content : Any = None ,
922993 ):
923994 try :
995+ # Prepare data/content parameters to prevent httpx DeprecationWarning (memory leak fix)
996+ request_data , request_content = _prepare_request_data_and_content (data , content )
997+
924998 if timeout is not None :
925999 req = self .client .build_request (
926- "DELETE" , url , data = data , json = json , params = params , headers = headers , timeout = timeout # type: ignore
1000+ "DELETE" , url , data = request_data , json = json , params = params , headers = headers , timeout = timeout , content = request_content # type: ignore
9271001 )
9281002 else :
9291003 req = self .client .build_request (
930- "DELETE" , url , data = data , json = json , params = params , headers = headers # type: ignore
1004+ "DELETE" , url , data = request_data , json = json , params = params , headers = headers , content = request_content # type: ignore
9311005 )
9321006 response = self .client .send (req , stream = stream )
9331007 response .raise_for_status ()
0 commit comments