Commits

Mark Lavin committed c7959f9

Rewrite mixins as class decorators.

Comments (0)

Files changed (2)

selectable/base.py

+import functools
 import operator
 import re
 
 __all__ = (
     'LookupBase',
     'ModelLookup',
-    'AjaxRequiredMixin',
-    'LoginRequiredMixin',
-    'StaffRequiredMixin',
+    'ajax_required',
+    'login_required',
+    'staff_member_required',
 )
 
 
         return self.model(**data)
 
 
-class AjaxRequiredMixin(object):
-    "Lookup extension to require AJAX calls to the lookup view."
+def ajax_required(lookup_cls):
+    "Lookup decorator to require AJAX calls to the lookup view."
 
-    def results(self, request):
+    func = lookup_cls.results
+
+    @functools.wraps(func)
+    def wrapper(self, request):
+        "Wrapped results function."
         if not request.is_ajax():
-            return http.HttpResponseBadRequest()   
-        return super(AjaxRequiredMixin, self).results(request)
+            return http.HttpResponseBadRequest()
+        return func(self, request)
 
+    lookup_cls.results = wrapper
+    return lookup_cls
 
-class LoginRequiredMixin(object):
-    "Lookup extension to require the user to be authenticated."
 
-    def results(self, request):
+def login_required(lookup_cls):
+    "Lookup decorator to require the user to be authenticated."
+
+    func = lookup_cls.results
+
+    @functools.wraps(func)
+    def wrapper(self, request):
+        "Wrapped results function."
         user = getattr(request, 'user', None)
         if user is None or not user.is_authenticated():
-            return http.HttpResponse(status=401) # Unauthorized   
-        return super(LoginRequiredMixin, self).results(request)
+            return http.HttpResponse(status=401) # Unauthorized
+        return func(self, request)
 
+    lookup_cls.results = wrapper
+    return lookup_cls
 
-class StaffRequiredMixin(object):
-    "Lookup extension to require the user is a staff member."
 
-    def results(self, request):
+def staff_member_required(lookup_cls):
+    "Lookup decorator to require the user is a staff member."
+    func = lookup_cls.results
+
+    @functools.wraps(func)
+    def wrapper(self, request):
+        "Wrapped results function."
         user = getattr(request, 'user', None)
         if user is None or not user.is_authenticated():
             return http.HttpResponse(status=401) # Unauthorized
         elif not user.is_staff:
             return http.HttpResponseForbidden()
-        return super(StaffRequiredMixin, self).results(request)
+        return func(self, request)
 
+    lookup_cls.results = wrapper
+    return lookup_cls

selectable/tests/base.py

 from django.test import TestCase
 
 from mock import Mock
-from selectable.base import ModelLookup, AjaxRequiredMixin
-from selectable.base import LoginRequiredMixin, StaffRequiredMixin
+from selectable.base import ModelLookup
+from selectable.base import ajax_required, login_required, staff_member_required
 from selectable.tests import Thing
 
 __all__ = (
         self.assertTrue(other_thing.pk in qs.values_list('id', flat=True))
 
 
-class LookupMixinTest(object):
-    "Helper for constructing lookups using a particular mixin."
+class AjaxRequiredLookupTestCase(BaseSelectableTestCase):
 
-    lookup_mixin = object
-
-    def create_lookup_class(self):
-        return type('TestLookup', (self.lookup_mixin, self.lookup_cls), {})
-
-
-class AjaxRequiredLookupTestCase(BaseSelectableTestCase, LookupMixinTest):
-    
-    lookup_cls = SimpleModelLookup
-    lookup_mixin = AjaxRequiredMixin
-    
     def setUp(self):
-        self.lookup = self.create_lookup_class()()
+        self.lookup = ajax_required(SimpleModelLookup)()
 
     def test_ajax_call(self):
         "Ajax call should yield a successful response."
         self.assertEqual(response.status_code, 400)
 
 
-class LoginRequiredLookupTestCase(BaseSelectableTestCase, LookupMixinTest):
-    
-    lookup_cls = SimpleModelLookup
-    lookup_mixin = LoginRequiredMixin
+class LoginRequiredLookupTestCase(BaseSelectableTestCase):
 
     def setUp(self):
-        self.lookup = self.create_lookup_class()()
+        self.lookup = login_required(SimpleModelLookup)()
     
     def test_authenicated_call(self):
         "Authenicated call should yield a successful response."
         self.assertEqual(response.status_code, 401)
 
 
-class StaffRequiredLookupTestCase(BaseSelectableTestCase, LookupMixinTest):
-
-    lookup_cls = SimpleModelLookup
-    lookup_mixin = StaffRequiredMixin
+class StaffRequiredLookupTestCase(BaseSelectableTestCase):
 
     def setUp(self):
-        self.lookup = self.create_lookup_class()()
+        self.lookup = staff_member_required(SimpleModelLookup)()
 
     def test_staff_member_call(self):
         "Staff member call should yield a successful response."
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.