Initial Refactor Step

* Add descriptor class
* call from generator
* proxy back to generator for implementation.
This commit is contained in:
Carlton Gibson 2017-08-23 10:11:04 +02:00
parent 9aaea2586b
commit 8f13e9c143
2 changed files with 62 additions and 2 deletions

View File

@ -256,6 +256,38 @@ class EndpointInspector(object):
] ]
class APIViewSchemaDescriptor(object):
"""
Descriptor class on APIView.
Responsible for per-view instrospection and schema generation.
"""
def __get__(self, instance, owner):
# ???: Is this TOO simple? (Option is to return a new instance each time.)
self.view = instance
return self
def get_link(self, path, method, generator):
"""
Generate `coreapi.Link` for view.
This is the main _public_ access point.
"""
assert self.view is not None, "Schema generation REQUIRES a view instance. (Hint: you accessed `schema` from the view CLASS rather than an instance.)"
view = self.view
# TEMP: now we proxy back to the generator
link = generator.get_link(path, method, view)
return link
# TODO: Where should this live?
# - We import APIView here. So we can't import the descriptor into `views`
# - APIView is only used by SchemaView.
# - ???: Make `schemas` a package and move SchemaView to `schema.views`
APIView.schema = APIViewSchemaDescriptor()
class SchemaGenerator(object): class SchemaGenerator(object):
# Map HTTP methods onto actions. # Map HTTP methods onto actions.
default_mapping = { default_mapping = {
@ -341,7 +373,7 @@ class SchemaGenerator(object):
for path, method, view in view_endpoints: for path, method, view in view_endpoints:
if not self.has_view_permissions(path, method, view): if not self.has_view_permissions(path, method, view):
continue continue
link = self.get_link(path, method, view) link = self.get_link_proxy(path, method, view)
subpath = path[len(prefix):] subpath = path[len(prefix):]
keys = self.get_keys(subpath, method, view) keys = self.get_keys(subpath, method, view)
insert_into(links, keys, link) insert_into(links, keys, link)
@ -434,6 +466,18 @@ class SchemaGenerator(object):
return path.replace('{pk}', '{%s}' % field_name) return path.replace('{pk}', '{%s}' % field_name)
# Methods for generating each individual `Link` instance... # Methods for generating each individual `Link` instance...
def get_link_proxy(self, path, method, view):
"""
Proxy to view's descriptor for link
TEMPORARY NAME at least.
"""
schema = view.schema
# To begin we pass generator — we still need its methods.
link = schema.get_link(path, method, self)
return link
def get_link(self, path, method, view): def get_link(self, path, method, view):
""" """

View File

@ -1,5 +1,6 @@
import unittest import unittest
import pytest
from django.conf.urls import include, url from django.conf.urls import include, url
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.http import Http404 from django.http import Http404
@ -10,7 +11,9 @@ from rest_framework.compat import coreapi, coreschema
from rest_framework.decorators import detail_route, list_route from rest_framework.decorators import detail_route, list_route
from rest_framework.request import Request from rest_framework.request import Request
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
from rest_framework.schemas import SchemaGenerator, get_schema_view from rest_framework.schemas import (
APIViewSchemaDescriptor, SchemaGenerator, get_schema_view
)
from rest_framework.test import APIClient, APIRequestFactory from rest_framework.test import APIClient, APIRequestFactory
from rest_framework.views import APIView from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
@ -496,3 +499,16 @@ class Test4605Regression(TestCase):
'/auth/convert-token/' '/auth/convert-token/'
]) ])
assert prefix == '/' assert prefix == '/'
class TestDescriptor(TestCase):
def test_apiview_schema_descriptor(self):
view = APIView()
assert hasattr(view, 'schema')
assert isinstance(view.schema, APIViewSchemaDescriptor)
def test_get_link_requires_instance(self):
descriptor = APIView.schema # Accessed from class
with pytest.raises(AssertionError):
descriptor.get_link(None, None, None) # ???: Do the dummy arguments require a tighter assert?