mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-07-27 16:40:03 +03:00
Check extra action's func.__name__
This commit is contained in:
parent
20a811dbda
commit
ed733b7d4c
|
@ -33,6 +33,15 @@ def _is_extra_action(attr):
|
|||
return hasattr(attr, 'mapping') and isinstance(attr.mapping, MethodMapper)
|
||||
|
||||
|
||||
def _check_attr_name(func, name):
|
||||
assert func.__name__ == name, (
|
||||
f'Expected function (`{func.__name__}`) to match its attribute name '
|
||||
f'(`{name}`). If using a decorator, ensure the inner function is '
|
||||
f'decorated with `functools.wraps`, or that `{func.__name__}.__name__` '
|
||||
f'is otherwise set to `{name}`.')
|
||||
return func
|
||||
|
||||
|
||||
class ViewSetMixin:
|
||||
"""
|
||||
This is the magic.
|
||||
|
@ -164,7 +173,9 @@ class ViewSetMixin:
|
|||
"""
|
||||
Get the methods that are marked as an extra ViewSet `@action`.
|
||||
"""
|
||||
return [method for _, method in getmembers(cls, _is_extra_action)]
|
||||
return [_check_attr_name(method, name)
|
||||
for name, method
|
||||
in getmembers(cls, _is_extra_action)]
|
||||
|
||||
def get_extra_action_url_map(self):
|
||||
"""
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from collections import OrderedDict
|
||||
from functools import wraps
|
||||
|
||||
import pytest
|
||||
from django.conf.urls import include, url
|
||||
|
@ -34,6 +35,7 @@ class Action(models.Model):
|
|||
|
||||
|
||||
def decorate(fn):
|
||||
@wraps(fn)
|
||||
def wrapper(self, request, *args, **kwargs):
|
||||
return fn(self, request, *args, **kwargs)
|
||||
return wrapper
|
||||
|
@ -222,9 +224,35 @@ class GetExtraActionsTests(TestCase):
|
|||
'detail_action',
|
||||
'list_action',
|
||||
'unresolvable_detail_action',
|
||||
'wrapped_detail_action',
|
||||
'wrapped_list_action',
|
||||
]
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_attr_name_check(self):
|
||||
def decorate(fn):
|
||||
def wrapper(self, request, *args, **kwargs):
|
||||
return fn(self, request, *args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
class ActionViewSet(GenericViewSet):
|
||||
queryset = Action.objects.all()
|
||||
|
||||
@action(detail=False)
|
||||
@decorate
|
||||
def wrapped_list_action(self, request, *args, **kwargs):
|
||||
raise NotImplementedError
|
||||
|
||||
view = ActionViewSet()
|
||||
with pytest.raises(AssertionError) as excinfo:
|
||||
view.get_extra_actions()
|
||||
|
||||
assert str(excinfo.value) == (
|
||||
'Expected function (`wrapper`) to match its attribute name '
|
||||
'(`wrapped_list_action`). If using a decorator, ensure the inner '
|
||||
'function is decorated with `functools.wraps`, or that '
|
||||
'`wrapper.__name__` is otherwise set to `wrapped_list_action`.')
|
||||
|
||||
|
||||
@override_settings(ROOT_URLCONF='tests.test_viewsets')
|
||||
class GetExtraActionUrlMapTests(TestCase):
|
||||
|
|
Loading…
Reference in New Issue
Block a user