1
1
from collections import OrderedDict
2
+ from functools import wraps
2
3
3
4
import pytest
4
5
from django .conf .urls import include , url
@@ -33,6 +34,13 @@ class Action(models.Model):
33
34
pass
34
35
35
36
37
+ def decorate (fn ):
38
+ @wraps (fn )
39
+ def wrapper (self , request , * args , ** kwargs ):
40
+ return fn (self , request , * args , ** kwargs )
41
+ return wrapper
42
+
43
+
36
44
class ActionViewSet (GenericViewSet ):
37
45
queryset = Action .objects .all ()
38
46
@@ -68,6 +76,16 @@ def custom_detail_action(self, request, *args, **kwargs):
68
76
def unresolvable_detail_action (self , request , * args , ** kwargs ):
69
77
raise NotImplementedError
70
78
79
+ @action (detail = False )
80
+ @decorate
81
+ def wrapped_list_action (self , request , * args , ** kwargs ):
82
+ raise NotImplementedError
83
+
84
+ @action (detail = True )
85
+ @decorate
86
+ def wrapped_detail_action (self , request , * args , ** kwargs ):
87
+ raise NotImplementedError
88
+
71
89
72
90
class ActionNamesViewSet (GenericViewSet ):
73
91
@@ -191,6 +209,8 @@ def test_extra_actions(self):
191
209
'detail_action' ,
192
210
'list_action' ,
193
211
'unresolvable_detail_action' ,
212
+ 'wrapped_detail_action' ,
213
+ 'wrapped_list_action' ,
194
214
]
195
215
196
216
self .assertEqual (actual , expected )
@@ -204,9 +224,35 @@ def test_should_only_return_decorated_methods(self):
204
224
'detail_action' ,
205
225
'list_action' ,
206
226
'unresolvable_detail_action' ,
227
+ 'wrapped_detail_action' ,
228
+ 'wrapped_list_action' ,
207
229
]
208
230
self .assertEqual (actual , expected )
209
231
232
+ def test_attr_name_check (self ):
233
+ def decorate (fn ):
234
+ def wrapper (self , request , * args , ** kwargs ):
235
+ return fn (self , request , * args , ** kwargs )
236
+ return wrapper
237
+
238
+ class ActionViewSet (GenericViewSet ):
239
+ queryset = Action .objects .all ()
240
+
241
+ @action (detail = False )
242
+ @decorate
243
+ def wrapped_list_action (self , request , * args , ** kwargs ):
244
+ raise NotImplementedError
245
+
246
+ view = ActionViewSet ()
247
+ with pytest .raises (AssertionError ) as excinfo :
248
+ view .get_extra_actions ()
249
+
250
+ assert str (excinfo .value ) == (
251
+ 'Expected function (`wrapper`) to match its attribute name '
252
+ '(`wrapped_list_action`). If using a decorator, ensure the inner '
253
+ 'function is decorated with `functools.wraps`, or that '
254
+ '`wrapper.__name__` is otherwise set to `wrapped_list_action`.' )
255
+
210
256
211
257
@override_settings (ROOT_URLCONF = 'tests.test_viewsets' )
212
258
class GetExtraActionUrlMapTests (TestCase ):
@@ -218,6 +264,7 @@ def test_list_view(self):
218
264
expected = OrderedDict ([
219
265
('Custom list action' , 'http://testserver/api/actions/custom_list_action/' ),
220
266
('List action' , 'http://testserver/api/actions/list_action/' ),
267
+ ('Wrapped list action' , 'http://testserver/api/actions/wrapped_list_action/' ),
221
268
])
222
269
223
270
self .assertEqual (view .get_extra_action_url_map (), expected )
@@ -229,6 +276,7 @@ def test_detail_view(self):
229
276
expected = OrderedDict ([
230
277
('Custom detail action' , 'http://testserver/api/actions/1/custom_detail_action/' ),
231
278
('Detail action' , 'http://testserver/api/actions/1/detail_action/' ),
279
+ ('Wrapped detail action' , 'http://testserver/api/actions/1/wrapped_detail_action/' ),
232
280
# "Unresolvable detail action" excluded, since it's not resolvable
233
281
])
234
282
0 commit comments