From 5d61a2027c57c7f58a501156a9c2a92153fcccec Mon Sep 17 00:00:00 2001 From: Rollo Konig Brock Date: Fri, 24 Apr 2020 15:29:03 +0100 Subject: [PATCH 1/2] Decorated view test --- flask_injector/tests.py | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/flask_injector/tests.py b/flask_injector/tests.py index 6e70fcd..bf12410 100644 --- a/flask_injector/tests.py +++ b/flask_injector/tests.py @@ -1,7 +1,7 @@ import gc import json import warnings -from functools import partial +from functools import partial, wraps from typing import NewType import flask_restful @@ -284,6 +284,36 @@ def dispatch_request(self, dispatch_arg): eq_(response.data, b'aaa bbb') +def test_view_decoration_works(): + + def decorator(view): + @wraps(view) + def wrapper(*args, **kwargs): + return view(*args, **kwargs) + + return wrapper + + class MyView(View): + decorators = [decorator] + + def __init__(self, class_arg): + self.class_arg = class_arg + + def dispatch_request(self, dispatch_arg): + return '%s %s' % (self.class_arg, dispatch_arg) + + + app = Flask(__name__) + app.add_url_rule('/', view_func=MyView.as_view('view', class_arg='aaa')) + + FlaskInjector(app=app) + + client = app.test_client() + response = client.get('/bbb') + print(response.data) + eq_(response.data, b'aaa bbb') + + def test_flask_restful_integration_works(): class HelloWorld(flask_restful.Resource): @inject From b0326681def498dd12becb95f514bbe5d92a84a7 Mon Sep 17 00:00:00 2001 From: Rollo Konig Brock Date: Fri, 24 Apr 2020 16:13:12 +0100 Subject: [PATCH 2/2] Fix for decorated view - breaks other things --- flask_injector/__init__.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/flask_injector/__init__.py b/flask_injector/__init__.py index 0a77f97..7c91ad3 100644 --- a/flask_injector/__init__.py +++ b/flask_injector/__init__.py @@ -53,6 +53,20 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: return wrapper # type: ignore +def _resolve_wraped_function(func: Callable) -> Callable: + """ + Decorators that use functools wraps will not have + a func.__code__ object that matches what View.as_view + creates breaking code. + + This gets the original undecorated function. + """ + if hasattr(func, '__wrapped__'): + return _resolve_wraped_function(func.__wrapped__) + else: + return func + + def wrap_fun(fun: T, injector: Injector) -> T: if isinstance(fun, LocalProxy): return fun # type: ignore @@ -101,6 +115,7 @@ def wrap_class_based_view(fun: Callable, injector: Injector) -> Callable: cls = cast(Any, fun).view_class name = fun.__name__ + fun = _resolve_wraped_function(fun) closure_contents = (c.cell_contents for c in cast(Any, fun).__closure__) fun_closure = dict(zip(fun.__code__.co_freevars, closure_contents)) try: