Permalink
Browse files

Allows decorator list to apply to memembers prior to response generat…

…ion. Adds decorator list testing
  • Loading branch information...
incognick committed May 17, 2016
1 parent edaa910 commit 686be6ef6fd09d9c1719fa89763ad09baddf7fd0
Showing with 196 additions and 4 deletions.
  1. +15 −4 flask_classful.py
  2. +81 −0 test_classful/test_decorators.py
  3. +100 −0 test_classful/view_classes.py
View
@@ -180,6 +180,21 @@ def make_proxy_method(cls, name):
i = cls()
view = getattr(i, name)
# Since the view is a bound instance method, first make it an actual function
# So function attributes work correctly
def make_func(fn):
@functools.wraps(fn)
def inner(*args, **kwargs):
return fn(*args, **kwargs)
return inner
view = make_func(view)
# Now apply the class decorator list in reverse order
# to match memeber decorator order
if cls.decorators:
for decorator in reversed(cls.decorators):
view = decorator(view)
@functools.wraps(view)
def proxy(**forgettable_view_args):
# Always use the global request object's view_args, because they
@@ -234,10 +249,6 @@ def proxy(**forgettable_view_args):
return response
# Decorate the proxy which is a function rather than the view which is a bound instance method
if cls.decorators:
for decorator in cls.decorators:
proxy = decorator(proxy)
return proxy
@@ -1,9 +1,19 @@
from flask import Flask, url_for
from .view_classes import DecoratedView
from .view_classes import DecoratedBoldListView
from .view_classes import DecoratedBoldItalicsListView
from .view_classes import DecoratedListMemberView
from .view_classes import DecoratedListFunctionAttributesView
from .view_classes import DecoratedListMemberFunctionAttributesView
from nose.tools import *
app = Flask("decorated")
DecoratedView.register(app)
DecoratedBoldListView.register(app)
DecoratedBoldItalicsListView.register(app)
DecoratedListMemberView.register(app)
DecoratedListFunctionAttributesView.register(app)
DecoratedListMemberFunctionAttributesView.register(app)
client = app.test_client()
@@ -51,9 +61,80 @@ def test_params_decorator():
resp = client.get('/decorated/params_decorator_method/')
eq_(b"Params Decorator", resp.data)
def test_params_decorator_delete():
resp = client.delete('/decorated/1234')
eq_(b"Params Decorator Delete 1234", resp.data)
def test_decorator_bold_list_get():
resp = client.get('/decorated_bold_list_view/1234')
ok_(b'<b>' in resp.data)
ok_(b'</b>' in resp.data)
def test_decorator_bold_list_index():
resp = client.get('/decorated_bold_list_view/')
ok_(b'<b>' in resp.data)
ok_(b'</b>' in resp.data)
def test_decorator_bold_italics_list_get():
resp = client.get('/decorated_bold_italics_list_view/1234')
ok_(b'<i>' in resp.data)
ok_(b'</i>' in resp.data)
ok_(b'<b>' in resp.data)
ok_(b'</b>' in resp.data)
def test_decorator_bold_italics_list_index():
resp = client.get('/decorated_bold_italics_list_view/')
ok_(b'<i>' in resp.data)
ok_(b'</i>' in resp.data)
ok_(b'<b>' in resp.data)
ok_(b'</b>' in resp.data)
def test_decorator_list_member_index():
resp = client.get('/decorated_list_member_view/')
ok_(b'<i>' in resp.data)
ok_(b'</i>' in resp.data)
ok_(b'<b>' in resp.data)
ok_(b'</b>' in resp.data)
ok_(b'<p>' not in resp.data)
ok_(b'</p>' not in resp.data)
def test_decorator_list_member_get():
resp = client.get('/decorated_list_member_view/1234')
# The order should match how functions are decorated
eq_(b'<b>', resp.data[:3])
eq_(b'<i>', resp.data[3:6])
eq_(b'<p>', resp.data[6:9])
eq_(b'</p>', resp.data[-12:-8])
eq_(b'</i>', resp.data[-8:-4])
eq_(b'</b>', resp.data[-4:])
# Verify list of decorators with attributes modify all functions in FlaskView
def test_decorator_list_function_attributes_get():
ok_(hasattr(app.view_functions['DecoratedListFunctionAttributesView:get'], '_eggs'))
eq_('scrambled', app.view_functions['DecoratedListFunctionAttributesView:get']._eggs)
# Verify list of decorators with attributes modify all functions in FlaskView
def test_decorator_list_function_attributes_index():
ok_(hasattr(app.view_functions['DecoratedListFunctionAttributesView:index'], '_eggs'))
eq_('scrambled', app.view_functions['DecoratedListFunctionAttributesView:index']._eggs)
# Verify decorator with attributes does not modify other members
def test_decorator_list_member_function_attributes_get():
eq_(hasattr(app.view_functions['DecoratedListMemberFunctionAttributesView:get'], '_eggs'), False)
# Verify decorator with attributes modify decorated memeber functions
def test_decorator_list_member_function_attributes_index():
eq_(hasattr(app.view_functions['DecoratedListMemberFunctionAttributesView:index'], '_eggs'), True)
eq_('scrambled', app.view_functions['DecoratedListMemberFunctionAttributesView:index']._eggs)
@@ -1,3 +1,4 @@
from flask import Response
from flask_classful import FlaskView, route
from functools import wraps
@@ -334,4 +335,103 @@ def index(self):
return "Index"
def make_bold_decorator(fn):
@wraps(fn)
def inner(*args, **kwargs):
return '<b>' + fn(*args, **kwargs) + '</b>'
return inner
def make_italics_decorator(fn):
@wraps(fn)
def inner(*args, **kwargs):
return '<i>' + fn(*args, **kwargs) + '</i>'
return inner
def make_paragraph_decorator(fn):
@wraps(fn)
def inner(*args, **kwargs):
return '<p>' + fn(*args, **kwargs) + '</p>'
return inner
class DecoratedBoldListView(FlaskView):
route_base = '/decorated_bold_list_view/'
decorators = [make_bold_decorator]
def get(self, id):
return 'Get %s'%id
def index(self):
return 'Index'
class DecoratedBoldItalicsListView(FlaskView):
route_base = '/decorated_bold_italics_list_view/'
decorators = [make_bold_decorator, make_italics_decorator]
def get(self, id):
return 'Get %s'%id
def index(self):
return 'Index'
class DecoratedListMemberView(FlaskView):
route_base = '/decorated_list_member_view/'
decorators = [
# Third Decorator
make_bold_decorator,
# Second Decorator
make_italics_decorator
]
# First decorator
@make_paragraph_decorator
def get(self, id):
return 'Get %s'%id
def index(self):
return 'Index'
def eggs_attribute_decorator(eggs_style):
def decorator(f):
# Apply the style to the function
f._eggs = eggs_style
@wraps(f)
def decorated_function(*args, **kwargs):
return f(*args, **kwargs)
return decorated_function
return decorator
class DecoratedListFunctionAttributesView(FlaskView):
route_base = '/decorated_list_function_attributes_view/'
decorators = [
make_italics_decorator,
eggs_attribute_decorator('scrambled')
]
@make_bold_decorator
def get(self, id):
return 'Get %s'%id
def index(self):
return 'Index'
class DecoratedListMemberFunctionAttributesView(FlaskView):
route_base = '/decorated_list_member_function_attributes_view/'
decorators = [make_italics_decorator]
@make_bold_decorator
def get(self, id):
return 'Get %s'%id
@eggs_attribute_decorator('scrambled')
def index(self):
return 'Index'

0 comments on commit 686be6e

Please sign in to comment.