From a780e80debac0d12bb62fbb0ed98635e601e76de Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Wed, 15 Dec 2021 15:16:38 +0000 Subject: [PATCH] Revert "Make api_view respect standard wrapper assignments (#8291)" (#8297) This reverts commit 9c97946531b85858fcee5df56240de6d29571da2. --- rest_framework/decorators.py | 20 ++++++++++++++++---- tests/test_decorators.py | 10 ---------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/rest_framework/decorators.py b/rest_framework/decorators.py index 7ba43d37c..30b9d84d4 100644 --- a/rest_framework/decorators.py +++ b/rest_framework/decorators.py @@ -7,7 +7,6 @@ based views, as well as the `@action` decorator, which is used to annotate methods on viewsets that should be included by routers. """ import types -from functools import update_wrapper from django.forms.utils import pretty_name @@ -23,8 +22,18 @@ def api_view(http_method_names=None): def decorator(func): - class WrappedAPIView(APIView): - pass + WrappedAPIView = type( + 'WrappedAPIView', + (APIView,), + {'__doc__': func.__doc__} + ) + + # Note, the above allows us to set the docstring. + # It is the equivalent of: + # + # class WrappedAPIView(APIView): + # pass + # WrappedAPIView.__doc__ = func.doc <--- Not possible to do this # api_view applied without (method_names) assert not(isinstance(http_method_names, types.FunctionType)), \ @@ -43,6 +52,9 @@ def api_view(http_method_names=None): for method in http_method_names: setattr(WrappedAPIView, method.lower(), handler) + WrappedAPIView.__name__ = func.__name__ + WrappedAPIView.__module__ = func.__module__ + WrappedAPIView.renderer_classes = getattr(func, 'renderer_classes', APIView.renderer_classes) @@ -61,7 +73,7 @@ def api_view(http_method_names=None): WrappedAPIView.schema = getattr(func, 'schema', APIView.schema) - return update_wrapper(WrappedAPIView.as_view(), func) + return WrappedAPIView.as_view() return decorator diff --git a/tests/test_decorators.py b/tests/test_decorators.py index 116d6f1be..99ba13e60 100644 --- a/tests/test_decorators.py +++ b/tests/test_decorators.py @@ -162,16 +162,6 @@ class DecoratorTestCase(TestCase): assert isinstance(view.cls.schema, CustomSchema) - def test_wrapper_assignments(self): - @api_view(["GET"]) - def test_view(request): - """example docstring""" - pass - - assert test_view.__name__ == "test_view" - assert test_view.__doc__ == "example docstring" - assert test_view.__qualname__ == "DecoratorTestCase.test_wrapper_assignments..test_view" - class ActionDecoratorTestCase(TestCase):