@@ -361,6 +361,265 @@ async def fetch():
361361 return jsonify ({"error" : str (e )}), 500
362362
363363
364+ @app .route ("/test/streaming" , methods = ["GET" ])
365+ def test_streaming ():
366+ """Test 5: Streaming response using client.stream() context manager."""
367+ try :
368+ with httpx .Client () as client :
369+ with client .stream ("GET" , "https://jsonplaceholder.typicode.com/posts/6" ) as response :
370+ # Read the streaming response
371+ content = response .read ()
372+ data = response .json ()
373+ return jsonify (data )
374+ except Exception as e :
375+ return jsonify ({"error" : str (e )}), 500
376+
377+
378+ @app .route ("/test/toplevel-stream" , methods = ["GET" ])
379+ def test_toplevel_stream ():
380+ """Test 6: Top-level httpx.stream() context manager."""
381+ try :
382+ with httpx .stream ("GET" , "https://jsonplaceholder.typicode.com/posts/7" ) as response :
383+ content = response .read ()
384+ data = response .json ()
385+ return jsonify (data )
386+ except Exception as e :
387+ return jsonify ({"error" : str (e )}), 500
388+
389+
390+ @app .route ("/test/multipart-files" , methods = ["POST" ])
391+ def test_multipart_files ():
392+ """Test 7: Multipart file upload using files= parameter."""
393+ try :
394+ # Create in-memory file-like content
395+ files = {"file" : ("test.txt" , b"Hello, World!" , "text/plain" )}
396+ with httpx .Client () as client :
397+ # Use httpbin.org which echoes back file uploads
398+ response = client .post (
399+ "https://httpbin.org/post" ,
400+ files = files ,
401+ )
402+ result = response .json ()
403+ return jsonify ({"uploaded" : True , "files" : result .get ("files" , {})})
404+ except Exception as e :
405+ return jsonify ({"error" : str (e )}), 500
406+
407+
408+ @app .route ("/test/follow-redirects" , methods = ["GET" ])
409+ def test_follow_redirects ():
410+ """Test 12: Following HTTP redirects."""
411+ try :
412+ with httpx .Client (follow_redirects = True ) as client :
413+ # httpbin.org/redirect/2 will redirect twice before returning
414+ response = client .get ("https://httpbin.org/redirect/2" )
415+ return jsonify (
416+ {
417+ "final_url" : str (response .url ),
418+ "status_code" : response .status_code ,
419+ "redirect_count" : len (response .history ),
420+ }
421+ )
422+ except Exception as e :
423+ return jsonify ({"error" : str (e )}), 500
424+
425+
426+ @app .route ("/test/async-send" , methods = ["GET" ])
427+ def test_async_send ():
428+ """Test 14: AsyncClient.send() method - bypasses AsyncClient.request()."""
429+
430+ async def fetch ():
431+ async with httpx .AsyncClient () as client :
432+ req = client .build_request ("GET" , "https://jsonplaceholder.typicode.com/posts/10" )
433+ response = await client .send (req )
434+ return response .json ()
435+
436+ try :
437+ result = asyncio .run (fetch ())
438+ return jsonify (result )
439+ except Exception as e :
440+ return jsonify ({"error" : str (e )}), 500
441+
442+
443+ @app .route ("/test/async-stream" , methods = ["GET" ])
444+ def test_async_stream ():
445+ """Test 15: Async streaming response using AsyncClient.stream()."""
446+
447+ async def fetch ():
448+ async with httpx .AsyncClient () as client :
449+ async with client .stream ("GET" , "https://jsonplaceholder.typicode.com/posts/11" ) as response :
450+ await response .aread ()
451+ return response .json ()
452+
453+ try :
454+ result = asyncio .run (fetch ())
455+ return jsonify (result )
456+ except Exception as e :
457+ return jsonify ({"error" : str (e )}), 500
458+
459+
460+ @app .route ("/test/basic-auth" , methods = ["GET" ])
461+ def test_basic_auth ():
462+ try :
463+ with httpx .Client () as client :
464+ # httpbin.org/basic-auth/{user}/{passwd} returns 200 if auth succeeds
465+ response = client .get (
466+ "https://httpbin.org/basic-auth/testuser/testpass" ,
467+ auth = ("testuser" , "testpass" ),
468+ )
469+ return jsonify (response .json ())
470+ except Exception as e :
471+ return jsonify ({"error" : str (e )}), 500
472+
473+
474+ @app .route ("/test/event-hooks" , methods = ["GET" ])
475+ def test_event_hooks ():
476+ try :
477+ request_headers_captured = []
478+ response_headers_captured = []
479+
480+ def log_request (request ):
481+ request_headers_captured .append (dict (request .headers ))
482+ request .headers ["X-Hook-Added" ] = "true"
483+
484+ def log_response (response ):
485+ response_headers_captured .append (dict (response .headers ))
486+
487+ with httpx .Client (event_hooks = {"request" : [log_request ], "response" : [log_response ]}) as client :
488+ response = client .get ("https://httpbin.org/headers" )
489+ result = response .json ()
490+ return jsonify (
491+ {
492+ "hook_header_present" : "X-Hook-Added" in result .get ("headers" , {}),
493+ "request_captured" : len (request_headers_captured ) > 0 ,
494+ "response_captured" : len (response_headers_captured ) > 0 ,
495+ }
496+ )
497+ except Exception as e :
498+ return jsonify ({"error" : str (e )}), 500
499+
500+
501+ @app .route ("/test/response-hook-only" , methods = ["GET" ])
502+ def test_response_hook_only ():
503+ try :
504+ response_data_captured = []
505+
506+ def capture_response (response ):
507+ response_data_captured .append (
508+ {
509+ "status" : response .status_code ,
510+ "url" : str (response .url ),
511+ }
512+ )
513+
514+ with httpx .Client (event_hooks = {"response" : [capture_response ]}) as client :
515+ response = client .get ("https://httpbin.org/get" )
516+ return jsonify (
517+ {
518+ "captured" : len (response_data_captured ) > 0 ,
519+ "response_status" : response .status_code ,
520+ }
521+ )
522+ except Exception as e :
523+ return jsonify ({"error" : str (e )}), 500
524+
525+
526+ @app .route ("/test/request-hook-modify-url" , methods = ["GET" ])
527+ def test_request_hook_modify_url ():
528+ try :
529+
530+ def add_query_param (request ):
531+ request .headers ["X-Hook-Tried-Url-Modify" ] = "true"
532+ return request
533+
534+ with httpx .Client (event_hooks = {"request" : [add_query_param ]}) as client :
535+ response = client .get ("https://httpbin.org/get?original=param" )
536+ result = response .json ()
537+ return jsonify (
538+ {
539+ "headers" : result .get ("headers" , {}),
540+ "args" : result .get ("args" , {}),
541+ }
542+ )
543+ except Exception as e :
544+ return jsonify ({"error" : str (e )}), 500
545+
546+
547+ @app .route ("/test/digest-auth" , methods = ["GET" ])
548+ def test_digest_auth ():
549+ try :
550+ with httpx .Client () as client :
551+ auth = httpx .DigestAuth ("digestuser" , "digestpass" )
552+ response = client .get (
553+ "https://httpbin.org/digest-auth/auth/digestuser/digestpass" ,
554+ auth = auth ,
555+ )
556+ return jsonify (response .json ())
557+ except Exception as e :
558+ return jsonify ({"error" : str (e )}), 500
559+
560+
561+ @app .route ("/test/async-hooks" , methods = ["GET" ])
562+ def test_async_hooks ():
563+ """Test: AsyncClient with async event hooks."""
564+
565+ async def fetch ():
566+ request_count = [0 ]
567+ response_count = [0 ]
568+
569+ async def async_request_hook (request ):
570+ request_count [0 ] += 1
571+ request .headers ["X-Async-Hook" ] = "true"
572+
573+ async def async_response_hook (response ):
574+ response_count [0 ] += 1
575+
576+ async with httpx .AsyncClient (
577+ event_hooks = {
578+ "request" : [async_request_hook ],
579+ "response" : [async_response_hook ],
580+ }
581+ ) as client :
582+ response = await client .get ("https://httpbin.org/headers" )
583+ result = response .json ()
584+ return {
585+ "request_hook_called" : request_count [0 ] > 0 ,
586+ "response_hook_called" : response_count [0 ] > 0 ,
587+ "async_hook_header_present" : "X-Async-Hook" in result .get ("headers" , {}),
588+ }
589+
590+ try :
591+ result = asyncio .run (fetch ())
592+ return jsonify (result )
593+ except Exception as e :
594+ return jsonify ({"error" : str (e )}), 500
595+
596+
597+ @app .route ("/test/file-like-body" , methods = ["POST" ])
598+ def test_file_like_body ():
599+ """Test: Request body from file-like object (BytesIO)."""
600+ try :
601+ import io
602+
603+ file_content = b'{"title": "File Body", "body": "From BytesIO", "userId": 1}'
604+ file_obj = io .BytesIO (file_content )
605+
606+ with httpx .Client () as client :
607+ response = client .post (
608+ "https://httpbin.org/post" ,
609+ content = file_obj ,
610+ headers = {"Content-Type" : "application/json" },
611+ )
612+ result = response .json ()
613+ return jsonify (
614+ {
615+ "posted_data" : result .get ("data" , "" ),
616+ "content_type" : result .get ("headers" , {}).get ("Content-Type" , "" ),
617+ }
618+ )
619+ except Exception as e :
620+ return jsonify ({"error" : str (e )}), 500
621+
622+
364623if __name__ == "__main__" :
365624 sdk .mark_app_as_ready ()
366625 app .run (host = "0.0.0.0" , port = 8000 , debug = False )
0 commit comments