Repository: encode/django-rest-framework

Issue:
Subclasses of BrowsableAPIRenderer should not be output in schema
https://github.com/encode/django-rest-framework/blob/5ce237e00471d885f05e6d979ec777552809b3b1/rest_framework/schemas/openapi.py#L598

A popular library djangorestframework-camel-case defines a subclass of BrowsableAPIRenderer called CamelCaseBrowsableAPIRenderer. This equality check should use issubclass() to determine type hierarchy as opposed to a strict equality comparison of types.


Discussion:
Hi @jordmantheman. Thanks for the report. Yes, that sounds reasonable. A PR would be very timely there. 

There's a `test_renderer_mapping` that could be fleshed out. I'd suggest ensure that neither the base class, nor any subclasses are included. :+1:

Resolving patch:
diff --git a/rest_framework/schemas/openapi.py b/rest_framework/schemas/openapi.py
--- a/rest_framework/schemas/openapi.py
+++ b/rest_framework/schemas/openapi.py
@@ -595,7 +595,7 @@ def map_renderers(self, path, method):
         media_types = []
         for renderer in self.view.renderer_classes:
             # BrowsableAPIRenderer not relevant to OpenAPI spec
-            if renderer == renderers.BrowsableAPIRenderer:
+            if issubclass(renderer, renderers.BrowsableAPIRenderer):
                 continue
             media_types.append(renderer.media_type)
         return media_types


Test patch:
diff --git a/tests/schemas/test_openapi.py b/tests/schemas/test_openapi.py
--- a/tests/schemas/test_openapi.py
+++ b/tests/schemas/test_openapi.py
@@ -10,7 +10,9 @@
 from rest_framework.authtoken.views import obtain_auth_token
 from rest_framework.compat import uritemplate
 from rest_framework.parsers import JSONParser, MultiPartParser
-from rest_framework.renderers import JSONRenderer, OpenAPIRenderer
+from rest_framework.renderers import (
+    BaseRenderer, BrowsableAPIRenderer, JSONRenderer, OpenAPIRenderer
+)
 from rest_framework.request import Request
 from rest_framework.schemas.openapi import AutoSchema, SchemaGenerator
 
@@ -507,9 +509,16 @@ def test_renderer_mapping(self):
         path = '/{id}/'
         method = 'GET'
 
+        class CustomBrowsableAPIRenderer(BrowsableAPIRenderer):
+            media_type = 'image/jpeg'  # that's a wild API renderer
+
+        class TextRenderer(BaseRenderer):
+            media_type = 'text/plain'
+            format = 'text'
+
         class View(generics.CreateAPIView):
             serializer_class = views.ExampleSerializer
-            renderer_classes = [JSONRenderer]
+            renderer_classes = [JSONRenderer, TextRenderer, BrowsableAPIRenderer, CustomBrowsableAPIRenderer]
 
         view = create_view(
             View,
@@ -524,8 +533,8 @@ class View(generics.CreateAPIView):
         # schema support is there
         success_response = responses['200']
 
-        assert len(success_response['content'].keys()) == 1
-        assert 'application/json' in success_response['content']
+        # Check that the API renderers aren't included, but custom renderers are
+        assert set(success_response['content']) == {'application/json', 'text/plain'}
 
     def test_openapi_yaml_rendering_without_aliases(self):
         renderer = OpenAPIRenderer()