From fcae4a9f0a5217b3b5ea6495821a85773aa33c55 Mon Sep 17 00:00:00 2001 From: Anton Zhyrney Date: Sat, 7 Jan 2017 06:30:23 +0200 Subject: [PATCH 1/4] added as_view --- sanic/views.py | 25 ++++++++++++++++++++++++- tests/test_views.py | 14 +++++++------- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/sanic/views.py b/sanic/views.py index 9387bcf6..45a09ef1 100644 --- a/sanic/views.py +++ b/sanic/views.py @@ -28,12 +28,35 @@ class HTTPMethodView: To add the view into the routing you could use 1) app.add_route(DummyView(), '/') 2) app.route('/')(DummyView()) + + TODO: add doc about devorators """ - def __call__(self, request, *args, **kwargs): + decorators = () + + def dispatch_request(self, request, *args, **kwargs): handler = getattr(self, request.method.lower(), None) if handler: return handler(request, *args, **kwargs) raise InvalidUsage( 'Method {} not allowed for URL {}'.format( request.method, request.url), status_code=405) + + @classmethod + def as_view(cls, *class_args, **class_kwargs): + """ TODO: add docs + + """ + def view(*args, **kwargs): + self = view.view_class(*class_args, **class_kwargs) + return self.dispatch_request(*args, **kwargs) + + if cls.decorators: + view.__module__ = cls.__module__ + for decorator in cls.decorators: + view = decorator(view) + + view.view_class = cls + view.__doc__ = cls.__doc__ + view.__module__ = cls.__module__ + return view diff --git a/tests/test_views.py b/tests/test_views.py index 59acb847..af38277e 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -26,7 +26,7 @@ def test_methods(): def delete(self, request): return text('I am delete method') - app.add_route(DummyView(), '/') + app.add_route(DummyView.as_view(), '/') request, response = sanic_endpoint_test(app, method="get") assert response.text == 'I am get method' @@ -48,7 +48,7 @@ def test_unexisting_methods(): def get(self, request): return text('I am get method') - app.add_route(DummyView(), '/') + app.add_route(DummyView.as_view(), '/') request, response = sanic_endpoint_test(app, method="get") assert response.text == 'I am get method' request, response = sanic_endpoint_test(app, method="post") @@ -63,7 +63,7 @@ def test_argument_methods(): def get(self, request, my_param_here): return text('I am get method with %s' % my_param_here) - app.add_route(DummyView(), '/') + app.add_route(DummyView.as_view(), '/') request, response = sanic_endpoint_test(app, uri='/test123') @@ -79,7 +79,7 @@ def test_with_bp(): def get(self, request): return text('I am get method') - bp.add_route(DummyView(), '/') + bp.add_route(DummyView.as_view(), '/') app.blueprint(bp) request, response = sanic_endpoint_test(app) @@ -96,7 +96,7 @@ def test_with_bp_with_url_prefix(): def get(self, request): return text('I am get method') - bp.add_route(DummyView(), '/') + bp.add_route(DummyView.as_view(), '/') app.blueprint(bp) request, response = sanic_endpoint_test(app, uri='/test1/') @@ -112,7 +112,7 @@ def test_with_middleware(): def get(self, request): return text('I am get method') - app.add_route(DummyView(), '/') + app.add_route(DummyView.as_view(), '/') results = [] @@ -145,7 +145,7 @@ def test_with_middleware_response(): def get(self, request): return text('I am get method') - app.add_route(DummyView(), '/') + app.add_route(DummyView.as_view(), '/') request, response = sanic_endpoint_test(app) From 1317b1799ccf50f01d30b71c4b6c21a1c31dfc29 Mon Sep 17 00:00:00 2001 From: Anton Zhyrney Date: Sat, 7 Jan 2017 06:57:07 +0200 Subject: [PATCH 2/4] add docstrings&updated docs --- docs/class_based_views.md | 17 +++++++++++++++-- sanic/views.py | 13 +++++++------ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/docs/class_based_views.md b/docs/class_based_views.md index ee410b1d..27972e82 100644 --- a/docs/class_based_views.md +++ b/docs/class_based_views.md @@ -28,7 +28,7 @@ class SimpleView(HTTPMethodView): def delete(self, request): return text('I am delete method') -app.add_route(SimpleView(), '/') +app.add_route(SimpleView.as_view(), '/') ``` @@ -40,6 +40,19 @@ class NameView(HTTPMethodView): def get(self, request, name): return text('Hello {}'.format(name)) -app.add_route(NameView(), '/') +app.add_route(NameView.as_view(), '/') + +``` + +If you want to add decorator for class, you could set decorators variable + +``` +class ViewWithDecorator(HTTPMethodView): + decorators = (some_decorator_here) + + def get(self, request, name): + return text('Hello I have a decorator') + +app.add_route(ViewWithDecorator.as_view(), '/url') ``` diff --git a/sanic/views.py b/sanic/views.py index 45a09ef1..eeaa8d38 100644 --- a/sanic/views.py +++ b/sanic/views.py @@ -7,7 +7,7 @@ class HTTPMethodView: to every HTTP method you want to support. For example: - class DummyView(View): + class DummyView(HTTPMethodView): def get(self, request, *args, **kwargs): return text('I am get method') @@ -20,16 +20,16 @@ class HTTPMethodView: 405 response. If you need any url params just mention them in method definition: - class DummyView(View): + class DummyView(HTTPMethodView): def get(self, request, my_param_here, *args, **kwargs): return text('I am get method with %s' % my_param_here) To add the view into the routing you could use - 1) app.add_route(DummyView(), '/') - 2) app.route('/')(DummyView()) + 1) app.add_route(DummyView.as_view(), '/') + 2) app.route('/')(DummyView.as_view()) - TODO: add doc about devorators + To add any decorator you could set it into decorators variable """ decorators = () @@ -44,7 +44,8 @@ class HTTPMethodView: @classmethod def as_view(cls, *class_args, **class_kwargs): - """ TODO: add docs + """ Converts the class into an actual view function that can be used + with the routing system. """ def view(*args, **kwargs): From 47a4f34cdff4417a746f56ced29b698be7550fce Mon Sep 17 00:00:00 2001 From: Anton Zhyrney Date: Sat, 7 Jan 2017 07:13:49 +0200 Subject: [PATCH 3/4] tests&small update --- docs/class_based_views.md | 2 +- sanic/views.py | 2 +- tests/test_views.py | 41 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/docs/class_based_views.md b/docs/class_based_views.md index 27972e82..84a5b952 100644 --- a/docs/class_based_views.md +++ b/docs/class_based_views.md @@ -48,7 +48,7 @@ If you want to add decorator for class, you could set decorators variable ``` class ViewWithDecorator(HTTPMethodView): - decorators = (some_decorator_here) + decorators = [some_decorator_here] def get(self, request, name): return text('Hello I have a decorator') diff --git a/sanic/views.py b/sanic/views.py index eeaa8d38..0222b96f 100644 --- a/sanic/views.py +++ b/sanic/views.py @@ -32,7 +32,7 @@ class HTTPMethodView: To add any decorator you could set it into decorators variable """ - decorators = () + decorators = [] def dispatch_request(self, request, *args, **kwargs): handler = getattr(self, request.method.lower(), None) diff --git a/tests/test_views.py b/tests/test_views.py index af38277e..9447ab61 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -153,3 +153,44 @@ def test_with_middleware_response(): assert type(results[0]) is Request assert type(results[1]) is Request assert issubclass(type(results[2]), HTTPResponse) + + +def test_with_custom_class_methods(): + app = Sanic('test_with_custom_class_methods') + + class DummyView(HTTPMethodView): + global_var = 0 + + def _iternal_method(self): + self.global_var += 10 + + def get(self, request): + self._iternal_method() + return text('I am get method and global var is {}'.format(self.global_var)) + + app.add_route(DummyView.as_view(), '/') + request, response = sanic_endpoint_test(app, method="get") + assert response.text == 'I am get method and global var is 10' + + +def test_with_decorator(): + app = Sanic('test_with_decorator') + + results = [] + + def stupid_decorator(view): + def decorator(*args, **kwargs): + results.append(1) + return view(*args, **kwargs) + return decorator + + class DummyView(HTTPMethodView): + decorators = [stupid_decorator] + + def get(self, request): + return text('I am get method') + + app.add_route(DummyView.as_view(), '/') + request, response = sanic_endpoint_test(app, method="get", debug=True) + assert response.text == 'I am get method' + assert results[0] == 1 From 434fa74e67045ec397b5d7b5fdbdf2e25b9163a6 Mon Sep 17 00:00:00 2001 From: Anton Zhyrney Date: Sat, 7 Jan 2017 07:14:27 +0200 Subject: [PATCH 4/4] removed debug from test --- tests/test_views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_views.py b/tests/test_views.py index 9447ab61..592893a4 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -191,6 +191,6 @@ def test_with_decorator(): return text('I am get method') app.add_route(DummyView.as_view(), '/') - request, response = sanic_endpoint_test(app, method="get", debug=True) + request, response = sanic_endpoint_test(app, method="get") assert response.text == 'I am get method' assert results[0] == 1