is_request_stream for CompositionView and HTTPMethodView
This commit is contained in:
		
							
								
								
									
										13
									
								
								sanic/app.py
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								sanic/app.py
									
									
									
									
									
								
							| @@ -131,6 +131,7 @@ class Sanic: | ||||
|             self.is_request_stream = True | ||||
|  | ||||
|         def response(handler): | ||||
|             if stream: | ||||
|                 handler.is_stream = stream | ||||
|             self.router.add(uri=uri, methods=methods, handler=handler, | ||||
|                             host=host, strict_slashes=strict_slashes) | ||||
| @@ -187,20 +188,28 @@ class Sanic: | ||||
|         :param host: | ||||
|         :return: function or class instance | ||||
|         """ | ||||
|         stream = False | ||||
|         # Handle HTTPMethodView differently | ||||
|         if hasattr(handler, 'view_class'): | ||||
|             methods = set() | ||||
|  | ||||
|             for method in HTTP_METHODS: | ||||
|                 if getattr(handler.view_class, method.lower(), None): | ||||
|                 _handler = getattr(handler.view_class, method.lower(), None) | ||||
|                 if _handler: | ||||
|                     methods.add(method) | ||||
|                     if hasattr(_handler, 'is_stream'): | ||||
|                         stream = True | ||||
|  | ||||
|         # handle composition view differently | ||||
|         if isinstance(handler, CompositionView): | ||||
|             methods = handler.handlers.keys() | ||||
|             for _handler in handler.handlers.values(): | ||||
|                 if hasattr(_handler, 'is_stream'): | ||||
|                     stream = True | ||||
|                     break | ||||
|  | ||||
|         self.route(uri=uri, methods=methods, host=host, | ||||
|                    strict_slashes=strict_slashes)(handler) | ||||
|                    strict_slashes=strict_slashes, stream=stream)(handler) | ||||
|         return handler | ||||
|  | ||||
|     # Decorator | ||||
|   | ||||
| @@ -355,4 +355,4 @@ class Router: | ||||
|         if (hasattr(handler, 'view_class') and | ||||
|                 hasattr(handler.view_class, request.method.lower())): | ||||
|             handler = getattr(handler.view_class, request.method.lower()) | ||||
|         return hasattr(handler, 'is_stream') and handler.is_stream | ||||
|         return hasattr(handler, 'is_stream') | ||||
|   | ||||
| @@ -89,6 +89,7 @@ class CompositionView: | ||||
|         self.handlers = {} | ||||
|  | ||||
|     def add(self, methods, handler, stream=False): | ||||
|         if stream: | ||||
|             handler.is_stream = stream | ||||
|         for method in methods: | ||||
|             if method not in HTTP_METHODS: | ||||
|   | ||||
| @@ -17,10 +17,12 @@ def test_bp(): | ||||
|  | ||||
|     @bp.route('/') | ||||
|     def handler(request): | ||||
|         assert request.stream is None | ||||
|         return text('Hello') | ||||
|  | ||||
|     app.blueprint(bp) | ||||
|     request, response = app.test_client.get('/') | ||||
|     assert app.is_request_stream is False | ||||
|  | ||||
|     assert response.text == 'Hello' | ||||
|  | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| import asyncio | ||||
| from sanic import Sanic | ||||
| from sanic.blueprints import Blueprint | ||||
| from sanic.views import CompositionView | ||||
| @@ -5,17 +6,23 @@ from sanic.views import HTTPMethodView | ||||
| from sanic.views import stream as stream_decorator | ||||
| from sanic.response import stream, text | ||||
|  | ||||
| bp = Blueprint('test_blueprint_request_stream') | ||||
| app = Sanic('test_request_stream') | ||||
| data = "abc" * 100000 | ||||
|  | ||||
|  | ||||
| class SimpleView(HTTPMethodView): | ||||
| def test_request_stream_method_view(): | ||||
|     '''for self.is_request_stream = True''' | ||||
|  | ||||
|     app = Sanic('test_request_stream_method_view') | ||||
|  | ||||
|     class SimpleView(HTTPMethodView): | ||||
|  | ||||
|         def get(self, request): | ||||
|             assert request.stream is None | ||||
|             return text('OK') | ||||
|  | ||||
|         @stream_decorator | ||||
|         async def post(self, request): | ||||
|             assert isinstance(request.stream, asyncio.Queue) | ||||
|             result = '' | ||||
|             while True: | ||||
|                 body = await request.stream.get() | ||||
| @@ -24,9 +31,28 @@ class SimpleView(HTTPMethodView): | ||||
|                 result += body.decode('utf-8') | ||||
|             return text(result) | ||||
|  | ||||
|     app.add_route(SimpleView.as_view(), '/method_view') | ||||
|  | ||||
|     assert app.is_request_stream is True | ||||
|  | ||||
|     request, response = app.test_client.get('/method_view') | ||||
|     assert response.status == 200 | ||||
|     assert response.text == 'OK' | ||||
|  | ||||
|     request, response = app.test_client.post('/method_view', data=data) | ||||
|     assert response.status == 200 | ||||
|     assert response.text == data | ||||
|  | ||||
|  | ||||
| def test_request_stream_app(): | ||||
|     '''for self.is_request_stream = True''' | ||||
|  | ||||
|     app = Sanic('test_request_stream_app') | ||||
|  | ||||
|     @app.stream('/stream') | ||||
|     async def handler(request): | ||||
|         assert isinstance(request.stream, asyncio.Queue) | ||||
|  | ||||
| @app.stream('/stream') | ||||
| async def handler(request): | ||||
|         async def streaming(response): | ||||
|             while True: | ||||
|                 body = await request.stream.get() | ||||
| @@ -35,14 +61,31 @@ async def handler(request): | ||||
|                 response.write(body.decode('utf-8')) | ||||
|         return stream(streaming) | ||||
|  | ||||
|  | ||||
| @app.get('/get') | ||||
| async def get(request): | ||||
|     @app.get('/get') | ||||
|     async def get(request): | ||||
|         assert request.stream is None | ||||
|         return text('OK') | ||||
|  | ||||
|     assert app.is_request_stream is True | ||||
|  | ||||
| @bp.stream('/bp_stream') | ||||
| async def bp_stream(request): | ||||
|     request, response = app.test_client.get('/get') | ||||
|     assert response.status == 200 | ||||
|     assert response.text == 'OK' | ||||
|  | ||||
|     request, response = app.test_client.post('/stream', data=data) | ||||
|     assert response.status == 200 | ||||
|     assert response.text == data | ||||
|  | ||||
|  | ||||
| def test_request_stream_blueprint(): | ||||
|     '''for self.is_request_stream = True''' | ||||
|  | ||||
|     app = Sanic('test_request_stream_blueprint') | ||||
|     bp = Blueprint('test_blueprint_request_stream_blueprint') | ||||
|  | ||||
|     @bp.stream('/bp_stream') | ||||
|     async def bp_stream(request): | ||||
|         assert isinstance(request.stream, asyncio.Queue) | ||||
|         result = '' | ||||
|         while True: | ||||
|             body = await request.stream.get() | ||||
| @@ -51,17 +94,35 @@ async def bp_stream(request): | ||||
|             result += body.decode('utf-8') | ||||
|         return text(result) | ||||
|  | ||||
|  | ||||
| @bp.get('/bp_get') | ||||
| async def bp_get(request): | ||||
|     @bp.get('/bp_get') | ||||
|     async def bp_get(request): | ||||
|         assert request.stream is None | ||||
|         return text('OK') | ||||
|  | ||||
|     app.blueprint(bp) | ||||
|  | ||||
| def get_handler(request): | ||||
|     assert app.is_request_stream is True | ||||
|  | ||||
|     request, response = app.test_client.get('/bp_get') | ||||
|     assert response.status == 200 | ||||
|     assert response.text == 'OK' | ||||
|  | ||||
|     request, response = app.test_client.post('/bp_stream', data=data) | ||||
|     assert response.status == 200 | ||||
|     assert response.text == data | ||||
|  | ||||
|  | ||||
| def test_request_stream_composition_view(): | ||||
|     '''for self.is_request_stream = True''' | ||||
|  | ||||
|     app = Sanic('test_request_stream__composition_view') | ||||
|  | ||||
|     def get_handler(request): | ||||
|         assert request.stream is None | ||||
|         return text('OK') | ||||
|  | ||||
|  | ||||
| async def post_handler(request): | ||||
|     async def post_handler(request): | ||||
|         assert isinstance(request.stream, asyncio.Queue) | ||||
|         result = '' | ||||
|         while True: | ||||
|             body = await request.stream.get() | ||||
| @@ -70,20 +131,103 @@ async def post_handler(request): | ||||
|             result += body.decode('utf-8') | ||||
|         return text(result) | ||||
|  | ||||
|     view = CompositionView() | ||||
|     view.add(['GET'], get_handler) | ||||
|     view.add(['POST'], post_handler, stream=True) | ||||
|     app.add_route(view, '/composition_view') | ||||
|  | ||||
| app.add_route(SimpleView.as_view(), '/method_view') | ||||
|     assert app.is_request_stream is True | ||||
|  | ||||
| view = CompositionView() | ||||
| view.add(['GET'], get_handler) | ||||
| view.add(['POST'], post_handler, stream=True) | ||||
|     request, response = app.test_client.get('/composition_view') | ||||
|     assert response.status == 200 | ||||
|     assert response.text == 'OK' | ||||
|  | ||||
| app.blueprint(bp) | ||||
|  | ||||
| app.add_route(view, '/composition_view') | ||||
|     request, response = app.test_client.post('/composition_view', data=data) | ||||
|     assert response.status == 200 | ||||
|     assert response.text == data | ||||
|  | ||||
|  | ||||
| def test_request_stream(): | ||||
|     data = "abc" * 100000 | ||||
|     '''test for complex application''' | ||||
|  | ||||
|     bp = Blueprint('test_blueprint_request_stream') | ||||
|     app = Sanic('test_request_stream') | ||||
|  | ||||
|     class SimpleView(HTTPMethodView): | ||||
|  | ||||
|         def get(self, request): | ||||
|             assert request.stream is None | ||||
|             return text('OK') | ||||
|  | ||||
|         @stream_decorator | ||||
|         async def post(self, request): | ||||
|             assert isinstance(request.stream, asyncio.Queue) | ||||
|             result = '' | ||||
|             while True: | ||||
|                 body = await request.stream.get() | ||||
|                 if body is None: | ||||
|                     break | ||||
|                 result += body.decode('utf-8') | ||||
|             return text(result) | ||||
|  | ||||
|     @app.stream('/stream') | ||||
|     async def handler(request): | ||||
|         assert isinstance(request.stream, asyncio.Queue) | ||||
|  | ||||
|         async def streaming(response): | ||||
|             while True: | ||||
|                 body = await request.stream.get() | ||||
|                 if body is None: | ||||
|                     break | ||||
|                 response.write(body.decode('utf-8')) | ||||
|         return stream(streaming) | ||||
|  | ||||
|     @app.get('/get') | ||||
|     async def get(request): | ||||
|         assert request.stream is None | ||||
|         return text('OK') | ||||
|  | ||||
|     @bp.stream('/bp_stream') | ||||
|     async def bp_stream(request): | ||||
|         assert isinstance(request.stream, asyncio.Queue) | ||||
|         result = '' | ||||
|         while True: | ||||
|             body = await request.stream.get() | ||||
|             if body is None: | ||||
|                 break | ||||
|             result += body.decode('utf-8') | ||||
|         return text(result) | ||||
|  | ||||
|     @bp.get('/bp_get') | ||||
|     async def bp_get(request): | ||||
|         assert request.stream is None | ||||
|         return text('OK') | ||||
|  | ||||
|     def get_handler(request): | ||||
|         assert request.stream is None | ||||
|         return text('OK') | ||||
|  | ||||
|     async def post_handler(request): | ||||
|         assert isinstance(request.stream, asyncio.Queue) | ||||
|         result = '' | ||||
|         while True: | ||||
|             body = await request.stream.get() | ||||
|             if body is None: | ||||
|                 break | ||||
|             result += body.decode('utf-8') | ||||
|         return text(result) | ||||
|  | ||||
|     app.add_route(SimpleView.as_view(), '/method_view') | ||||
|  | ||||
|     view = CompositionView() | ||||
|     view.add(['GET'], get_handler) | ||||
|     view.add(['POST'], post_handler, stream=True) | ||||
|  | ||||
|     app.blueprint(bp) | ||||
|  | ||||
|     app.add_route(view, '/composition_view') | ||||
|  | ||||
|     assert app.is_request_stream is True | ||||
|  | ||||
|     request, response = app.test_client.get('/method_view') | ||||
|     assert response.status == 200 | ||||
|   | ||||
| @@ -28,12 +28,15 @@ def test_route_strict_slash(): | ||||
|  | ||||
|     @app.get('/get', strict_slashes=True) | ||||
|     def handler(request): | ||||
|         assert request.stream is None | ||||
|         return text('OK') | ||||
|  | ||||
|     @app.post('/post/', strict_slashes=True) | ||||
|     def handler(request): | ||||
|         return text('OK') | ||||
|  | ||||
|     assert app.is_request_stream is False | ||||
|  | ||||
|     request, response = app.test_client.get('/get') | ||||
|     assert response.text == 'OK' | ||||
|  | ||||
|   | ||||
| @@ -16,6 +16,7 @@ def test_methods(method): | ||||
|     class DummyView(HTTPMethodView): | ||||
|  | ||||
|         async def get(self, request): | ||||
|             assert request.stream is None | ||||
|             return text('', headers={'method': 'GET'}) | ||||
|  | ||||
|         def post(self, request): | ||||
| @@ -37,6 +38,7 @@ def test_methods(method): | ||||
|             return text('', headers={'method': 'DELETE'}) | ||||
|  | ||||
|     app.add_route(DummyView.as_view(), '/') | ||||
|     assert app.is_request_stream is False | ||||
|  | ||||
|     request, response = getattr(app.test_client, method.lower())('/') | ||||
|     assert response.headers['method'] == method | ||||
| @@ -79,6 +81,7 @@ def test_with_bp(): | ||||
|     class DummyView(HTTPMethodView): | ||||
|  | ||||
|         def get(self, request): | ||||
|             assert request.stream is None | ||||
|             return text('I am get method') | ||||
|  | ||||
|     bp.add_route(DummyView.as_view(), '/') | ||||
| @@ -86,6 +89,7 @@ def test_with_bp(): | ||||
|     app.blueprint(bp) | ||||
|     request, response = app.test_client.get('/') | ||||
|  | ||||
|     assert app.is_request_stream is False | ||||
|     assert response.text == 'I am get method' | ||||
|  | ||||
|  | ||||
| @@ -227,10 +231,15 @@ def test_composition_view_runs_methods_as_expected(method): | ||||
|     app = Sanic('test_composition_view') | ||||
|  | ||||
|     view = CompositionView() | ||||
|     view.add(['GET', 'POST', 'PUT'], lambda x: text('first method')) | ||||
|  | ||||
|     def first(request): | ||||
|         assert request.stream is None | ||||
|         return text('first method') | ||||
|     view.add(['GET', 'POST', 'PUT'], first) | ||||
|     view.add(['DELETE', 'PATCH'], lambda x: text('second method')) | ||||
|  | ||||
|     app.add_route(view, '/') | ||||
|     assert app.is_request_stream is False | ||||
|  | ||||
|     if method in ['GET', 'POST', 'PUT']: | ||||
|         request, response = getattr(app.test_client, method.lower())('/') | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 38elements
					38elements