Skip to content

Commit 45e058d

Browse files
apragacztomchristie
authored andcommitted
Fix unhandled Http404, PermissionDenied in schema generation (encode#4645) (encode#4646)
1 parent 2bf082a commit 45e058d

File tree

2 files changed

+70
-2
lines changed

2 files changed

+70
-2
lines changed

rest_framework/schemas.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
from django.conf import settings
66
from django.contrib.admindocs.views import simplify_regex
7+
from django.core.exceptions import PermissionDenied
8+
from django.http import Http404
79
from django.utils import six
810
from django.utils.encoding import force_text, smart_text
911

@@ -339,7 +341,7 @@ def has_view_permissions(self, path, method, view):
339341

340342
try:
341343
view.check_permissions(view.request)
342-
except exceptions.APIException:
344+
except (exceptions.APIException, Http404, PermissionDenied):
343345
return False
344346
return True
345347

tests/test_schemas.py

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
import unittest
22

33
from django.conf.urls import include, url
4+
from django.core.exceptions import PermissionDenied
5+
from django.http import Http404
46
from django.test import TestCase, override_settings
57

68
from rest_framework import filters, pagination, permissions, serializers
79
from rest_framework.compat import coreapi
810
from rest_framework.decorators import detail_route, list_route
11+
from rest_framework.request import Request
912
from rest_framework.routers import DefaultRouter
1013
from rest_framework.schemas import SchemaGenerator, get_schema_view
11-
from rest_framework.test import APIClient
14+
from rest_framework.test import APIClient, APIRequestFactory
1215
from rest_framework.views import APIView
1316
from rest_framework.viewsets import ModelViewSet
1417

18+
factory = APIRequestFactory()
19+
1520

1621
class MockUser(object):
1722
def is_authenticated(self):
@@ -215,6 +220,32 @@ def test_authenticated_request(self):
215220
self.assertEqual(response.data, expected)
216221

217222

223+
class DenyAllUsingHttp404(permissions.BasePermission):
224+
225+
def has_permission(self, request, view):
226+
raise Http404()
227+
228+
def has_object_permission(self, request, view, obj):
229+
raise Http404()
230+
231+
232+
class DenyAllUsingPermissionDenied(permissions.BasePermission):
233+
234+
def has_permission(self, request, view):
235+
raise PermissionDenied()
236+
237+
def has_object_permission(self, request, view, obj):
238+
raise PermissionDenied()
239+
240+
241+
class Http404ExampleViewSet(ExampleViewSet):
242+
permission_classes = [DenyAllUsingHttp404]
243+
244+
245+
class PermissionDeniedExampleViewSet(ExampleViewSet):
246+
permission_classes = [DenyAllUsingPermissionDenied]
247+
248+
218249
class ExampleListView(APIView):
219250
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
220251

@@ -337,6 +368,41 @@ def test_schema_for_regular_views(self):
337368
self.assertEqual(schema, expected)
338369

339370

371+
@unittest.skipUnless(coreapi, 'coreapi is not installed')
372+
class TestSchemaGeneratorWithRestrictedViewSets(TestCase):
373+
def setUp(self):
374+
router = DefaultRouter()
375+
router.register('example1', Http404ExampleViewSet, base_name='example1')
376+
router.register('example2', PermissionDeniedExampleViewSet, base_name='example2')
377+
self.patterns = [
378+
url('^example/?$', ExampleListView.as_view()),
379+
url(r'^', include(router.urls))
380+
]
381+
382+
def test_schema_for_regular_views(self):
383+
"""
384+
Ensure that schema generation works for ViewSet classes
385+
with permission classes raising exceptions.
386+
"""
387+
generator = SchemaGenerator(title='Example API', patterns=self.patterns)
388+
request = factory.get('/')
389+
schema = generator.get_schema(Request(request))
390+
expected = coreapi.Document(
391+
url='',
392+
title='Example API',
393+
content={
394+
'example': {
395+
'list': coreapi.Link(
396+
url='/example/',
397+
action='get',
398+
fields=[]
399+
),
400+
},
401+
}
402+
)
403+
self.assertEqual(schema, expected)
404+
405+
340406
@unittest.skipUnless(coreapi, 'coreapi is not installed')
341407
class Test4605Regression(TestCase):
342408
def test_4605_regression(self):

0 commit comments

Comments
 (0)