  from rest_framework.reverse import reverse
  
  
  class ViewSetMixin(object):
      """
      This is the magic.
  
      Overrides `.as_view()` so that it takes an `actions` keyword that performs
 
</s> remove     Ensure `@detail_route` decorator raises an except when applied
 </s> add     Ensure `@action` decorator raises an except when applied </s> remove from rest_framework.decorators import detail_route, list_route
 </s> add from rest_framework.decorators import action </s> remove from rest_framework.decorators import detail_route, list_route
 </s> add from rest_framework.decorators import action
def _is_extra_action(attr):
    return hasattr(attr, 'bind_to_methods')


  from rest_framework.reverse import reverse
  
  
def _is_extra_action(attr):
    return hasattr(attr, 'bind_to_methods')


  class ViewSetMixin(object):
      """
      This is the magic.
  
      Overrides `.as_view()` so that it takes an `actions` keyword that performs
keep keep add keep keep keep keep keep
 Rework dynamic list/detail actions (#5705)

* Merge list/detail route decorators into 'action'

* Merge dynamic routes, add 'detail' attribute

* Add 'ViewSet.get_extra_actions()'

* Refactor dynamic route checking & collection

* Refactor dynamic route generation

* Add 'ViewSet.detail' initkwarg

* Fixup schema test

* Add release notes for dynamic action changes

* Replace list/detail route decorators in tests

* Convert tabs to spaces in router docs

* Update docs

* Make 'detail' a required argument of 'action'

* Improve router docs 
rest_framework/viewsets.py