def scrape_endpoints(self): """ Iterate over the registered API endpoints for this version and generate path specs """ inspector = EndpointEnumerator() for path, http_method, func in inspector.get_api_endpoints(): http_method = http_method.lower() if not path.startswith('/api-auth/') and not path.startswith( "/{}/".format( self.version)): # skip if it doesnt match version continue method_func = getattr(func.cls, http_method, None) if self.has_apispec_wrapper(method_func): operation_spec = self.get_operation_spec(path, http_method, view_cls=func.cls) merged_spec = self.merge_specs( operation_spec, self.get_apispec_kwargs(method_func)) path_spec = { 'path': path, 'operations': { http_method: merged_spec } } self.add_path(**path_spec)
def test_deprecations(self): with pytest.warns(PendingDeprecationWarning) as record: @api_view(["GET"], exclude_from_schema=True) def view(request): pass assert len(record) == 1 assert str(record[0].message) == ( "The `exclude_from_schema` argument to `api_view` is pending " "deprecation. Use the `schema` decorator instead, passing `None`.") class OldFashionedExcludedView(APIView): exclude_from_schema = True def get(self, request, *args, **kwargs): pass patterns = [ url('^excluded-old-fashioned/$', OldFashionedExcludedView.as_view()), ] inspector = EndpointEnumerator(patterns) with pytest.warns(PendingDeprecationWarning) as record: inspector.get_api_endpoints() assert len(record) == 1 assert str(record[0].message) == ( "The `OldFashionedExcludedView.exclude_from_schema` attribute is " "pending deprecation. Set `schema = None` instead.")
def get_queryset(self): """ get: Return a list of all endpoints. """ endpoint_enumerator = EndpointEnumerator() if setting_url_base_path.value: url_index = 3 else: url_index = 2 # Extract the resource names from the API endpoint URLs parsed_urls = set() for entry in endpoint_enumerator.get_api_endpoints(): try: url = entry[0].split('/')[url_index] except IndexError: """An unknown or invalid URL""" else: parsed_urls.add(url) endpoints = [] for url in sorted(parsed_urls): if url: endpoints.append(Endpoint(label=url)) return endpoints
def test_deprecations(self): with pytest.warns(PendingDeprecationWarning) as record: @api_view(["GET"], exclude_from_schema=True) def view(request): pass assert len(record) == 1 assert str(record[0].message) == ( "The `exclude_from_schema` argument to `api_view` is pending " "deprecation. Use the `schema` decorator instead, passing `None`." ) class OldFashionedExcludedView(APIView): exclude_from_schema = True def get(self, request, *args, **kwargs): pass patterns = [ url('^excluded-old-fashioned/$', OldFashionedExcludedView.as_view()), ] inspector = EndpointEnumerator(patterns) with pytest.warns(PendingDeprecationWarning) as record: inspector.get_api_endpoints() assert len(record) == 1 assert str(record[0].message) == ( "The `OldFashionedExcludedView.exclude_from_schema` attribute is " "pending deprecation. Set `schema = None` instead." )
def test_endpoint_enumerator_excludes_correctly(self): """It is responsibility of EndpointEnumerator to exclude views""" inspector = EndpointEnumerator(self.patterns) endpoints = inspector.get_api_endpoints() assert len(endpoints) == 1 path, method, callback = endpoints[0] assert path == '/included-fbv/'
def scrape_endpoints_for_scopes(self): """ Iterate over the registered API endpoints output all the scopes """ inspector = EndpointEnumerator() all_scopes = set() for path, http_method, func in inspector.get_api_endpoints(): all_scopes |= set( self.valid_scopes_for_view(func.cls, method=http_method)) excluded_scopes = set(getattr(settings, 'API_DOCS_EXCLUDED_SCOPES', [])) return sorted(list(all_scopes ^ excluded_scopes))
def test_should_include_endpoint_excludes_correctly(self): """This is the specific method that should handle the exclusion""" inspector = EndpointEnumerator(self.patterns) # Not pretty. Mimics internals of EndpointEnumerator to put should_include_endpoint under test pairs = [(inspector.get_path_from_regex(get_regex_pattern(pattern)), pattern.callback) for pattern in self.patterns] should_include = [ inspector.should_include_endpoint(*pair) for pair in pairs ] expected = [False, False, True] assert should_include == expected
def get_paths() -> List[str]: """ Returns a list of endpoint paths. """ return list( set(endpoint[0] for endpoint in EndpointEnumerator().get_api_endpoints())) # noqa: C401
def get(self, request, format=None): """ get: Return a list of all endpoints. """ endpoint_enumerator = EndpointEnumerator() endpoints = [] for url in sorted( set([ entry[0].split('/')[2] for entry in endpoint_enumerator.get_api_endpoints() ])): if url: endpoints.append(Endpoint(label=url)) serializer = EndpointSerializer(endpoints, many=True) return Response(serializer.data)
def endpoints(self) -> List[str]: # pylint: disable=no-self-use """ Returns a list of endpoint paths. """ return list({ endpoint[0] for endpoint in EndpointEnumerator().get_api_endpoints() })
def usable_views(cls): api_endpoints = EndpointEnumerator().get_api_endpoints() generator = BaseSchemaGenerator() views = [] for endpoint in api_endpoints: _, method, view_callback = endpoint view = generator.create_view(view_callback, method) if cls._usable_viewset(view): if view.__class__ not in [v.__class__ for v in views]: views.append(view) return views
def test_head_and_options_methods_are_excluded(): """ Regression test for #5528 https://github.com/encode/django-rest-framework/issues/5528 Viewset OPTIONS actions were not being correctly excluded Initial cases here shown to be working as expected. """ @api_view(['options', 'get']) def fbv(request): pass inspector = EndpointEnumerator() path = '/a/path/' callback = fbv assert inspector.should_include_endpoint(path, callback) assert inspector.get_allowed_methods(callback) == ["GET"] class AnAPIView(APIView): def get(self, request, *args, **kwargs): pass def options(self, request, *args, **kwargs): pass callback = AnAPIView.as_view() assert inspector.should_include_endpoint(path, callback) assert inspector.get_allowed_methods(callback) == ["GET"] class AViewSet(ModelViewSet): @action(methods=['options', 'get'], detail=True) def custom_action(self, request, pk): pass callback = AViewSet.as_view({ "options": "custom_action", "get": "custom_action" }) assert inspector.should_include_endpoint(path, callback) assert inspector.get_allowed_methods(callback) == ["GET"]
def get_queryset(self): """ get: Return a list of all endpoints. """ endpoint_enumerator = EndpointEnumerator() if setting_url_base_path.value: index = 3 else: index = 2 # Extract the resource names from the API endpoint URLs parsed_urls = [] for entry in endpoint_enumerator.get_api_endpoints(): parsed_urls.append(entry[0].split('/')[index]) parsed_urls = sorted(set(parsed_urls)) endpoints = [] for url in parsed_urls: if url: endpoints.append(Endpoint(label=url)) return endpoints
def test_head_and_options_methods_are_excluded(): """ Regression test for #5528 https://github.com/encode/django-rest-framework/issues/5528 Viewset OPTIONS actions were not being correctly excluded Initial cases here shown to be working as expected. """ @api_view(['options', 'get']) def fbv(request): pass inspector = EndpointEnumerator() path = '/a/path/' callback = fbv assert inspector.should_include_endpoint(path, callback) assert inspector.get_allowed_methods(callback) == ["GET"] class AnAPIView(APIView): def get(self, request, *args, **kwargs): pass def options(self, request, *args, **kwargs): pass callback = AnAPIView.as_view() assert inspector.should_include_endpoint(path, callback) assert inspector.get_allowed_methods(callback) == ["GET"] class AViewSet(ModelViewSet): @detail_route(methods=['options', 'get']) def custom_action(self, request, pk): pass callback = AViewSet.as_view({ "options": "custom_action", "get": "custom_action" }) assert inspector.should_include_endpoint(path, callback) assert inspector.get_allowed_methods(callback) == ["GET"]
def get_endpoints_toggle(self): for endpoint in EndpointEnumerator().get_api_endpoints(): endpoint_name = endpoint[0].rsplit("{pk}")[0].rsplit("{uid}")[0] if ('{}|{}'.format(endpoint_name, endpoint[1])) not in self._keys: self.addnewkey(str('{}|{}'.format(endpoint_name, endpoint[1])), True)