Skip to content

Commit

Permalink
Migration to drf_spectacular (#4210)
Browse files Browse the repository at this point in the history
  • Loading branch information
Marishka17 authored Feb 12, 2022
1 parent dd4a78d commit d098e42
Show file tree
Hide file tree
Showing 16 changed files with 834 additions and 414 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Different resources (tasks, projects) are not visible anymore for all CVAT instance users by default (<https://github.com/openvinotoolkit/cvat/pull/3788>)
- API versioning scheme: using accept header versioning instead of namespace versioning (<https://github.com/openvinotoolkit/cvat/pull/4239>)
- Replaced 'django_sendfile' with 'django_sendfile2' (<https://github.com/openvinotoolkit/cvat/pull/4267>)
- Use drf-spectacular instead of drf-yasg for swagger documentation (<https://github.com/openvinotoolkit/cvat/pull/4210>)

### Deprecated
- Job field "status" is not used in UI anymore, but it has not been removed from the database yet (<https://github.com/openvinotoolkit/cvat/pull/3788>)
Expand Down
4 changes: 4 additions & 0 deletions cvat/apps/engine/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ class StatusChoice(str, Enum):
def choices(cls):
return tuple((x.value, x.name) for x in cls)

@classmethod
def list(cls):
return list(map(lambda x: x.value, cls))

def __str__(self):
return self.value

Expand Down
69 changes: 67 additions & 2 deletions cvat/apps/engine/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
from cvat.apps.engine.log import slogger
from cvat.apps.engine.utils import parse_specific_attributes

from drf_spectacular.utils import OpenApiExample, extend_schema_serializer

class BasicUserSerializer(serializers.ModelSerializer):
def validate(self, data):
if hasattr(self, 'initial_data'):
Expand Down Expand Up @@ -849,15 +851,78 @@ def to_internal_value(self, data):
def to_representation(self, instance):
return instance.filename if instance else instance

class BaseCloudStorageSerializer(serializers.ModelSerializer):
class CloudStorageReadSerializer(serializers.ModelSerializer):
owner = BasicUserSerializer(required=False)
manifests = ManifestSerializer(many=True, default=[])
class Meta:
model = models.CloudStorage
exclude = ['credentials']
read_only_fields = ('created_date', 'updated_date', 'owner', 'organization')

class CloudStorageSerializer(serializers.ModelSerializer):
@extend_schema_serializer(
examples=[
OpenApiExample(
'Create AWS S3 cloud storage with credentials',
description='',
value={
'provider_type': models.CloudProviderChoice.AWS_S3,
'resource': 'somebucket',
'display_name': 'Bucket',
'credentials_type': models.CredentialsTypeChoice.KEY_SECRET_KEY_PAIR,
'specific_attributes': 'region=eu-central-1',
'description': 'Some description',
'manifests': [
'manifest.jsonl'
],
},
request_only=True,
),
OpenApiExample(
'Create AWS S3 cloud storage without credentials',
value={
'provider_type': models.CloudProviderChoice.AWS_S3,
'resource': 'somebucket',
'display_name': 'Bucket',
'credentials_type': models.CredentialsTypeChoice.ANONYMOUS_ACCESS,
'manifests': [
'manifest.jsonl'
],
},
request_only=True,
),
OpenApiExample(
'Create Azure cloud storage',
value={
'provider_type': models.CloudProviderChoice.AZURE_CONTAINER,
'resource': 'sonecontainer',
'display_name': 'Container',
'credentials_type': models.CredentialsTypeChoice.ACCOUNT_NAME_TOKEN_PAIR,
'account_name': 'someaccount',
'session_token': 'xxx',
'manifests': [
'manifest.jsonl'
],
},
request_only=True,
),
OpenApiExample(
'Create GCS',
value={
'provider_type': models.CloudProviderChoice.GOOGLE_CLOUD_STORAGE,
'resource': 'somebucket',
'display_name': 'Bucket',
'credentials_type': models.CredentialsTypeChoice.KEY_FILE_PATH,
'key_file': 'file',
'manifests': [
'manifest.jsonl'
],
},
request_only=True,
)
]
)
class CloudStorageWriteSerializer(serializers.ModelSerializer):
owner = BasicUserSerializer(required=False)
session_token = serializers.CharField(max_length=440, allow_blank=True, required=False)
key = serializers.CharField(max_length=20, allow_blank=True, required=False)
Expand Down
43 changes: 5 additions & 38 deletions cvat/apps/engine/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,42 +6,12 @@
from django.urls import path, include
from . import views
from rest_framework import routers
from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi

from django.views.generic import RedirectView
from django.conf import settings
from cvat.apps.restrictions.views import RestrictionsViewSet
from cvat.apps.iam.decorators import login_required

schema_view = get_schema_view(
openapi.Info(
title="CVAT REST API",
default_version='v1',
description="REST API for Computer Vision Annotation Tool (CVAT)",
terms_of_service="https://www.google.com/policies/terms/",
contact=openapi.Contact(email="nikita.manovich@intel.com"),
license=openapi.License(name="MIT License"),
),
public=True,
permission_classes=(permissions.IsAuthenticated,),
)

# drf-yasg component doesn't handle correctly URL_FORMAT_OVERRIDE and
# send requests with ?format=openapi suffix instead of ?scheme=openapi.
# We map the required parameter explicitly and add it into query arguments
# on the server side.
def wrap_swagger(view):
@login_required
def _map_format_to_schema(request, scheme=None):
if 'format' in request.GET:
request.GET = request.GET.copy()
format_alias = settings.REST_FRAMEWORK['URL_FORMAT_OVERRIDE']
request.GET[format_alias] = request.GET['format']

return view(request, format=scheme)

return _map_format_to_schema
from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView

router = routers.DefaultRouter(trailing_slash=False)
router.register('projects', views.ProjectViewSet)
Expand All @@ -60,12 +30,9 @@ def _map_format_to_schema(request, scheme=None):
query_string=True)),

# documentation for API
path('api/swagger<str:scheme>', wrap_swagger(
schema_view.without_ui(cache_timeout=0)), name='schema-json'),
path('api/swagger/', wrap_swagger(
schema_view.with_ui('swagger', cache_timeout=0)), name='schema-swagger-ui'),
path('api/docs/', wrap_swagger(
schema_view.with_ui('redoc', cache_timeout=0)), name='schema-redoc'),
path('api/schema/', SpectacularAPIView.as_view(api_version='2.0'), name='schema'),
path('api/swagger/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger'),
path('api/docs/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'),

# entry point for API
path('api/', include('cvat.apps.iam.urls')),
Expand Down
Loading

0 comments on commit d098e42

Please sign in to comment.