Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

swagger_extra_fields should be allowed even when we don't call get_schema #142

Merged
merged 7 commits into from
Jun 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,18 @@ Changelog
#########


*********
**1.9.0**
*********

*Release date: Jun 16, 2018*

- **ADDED:** added ``DEFAULT_GENERATOR_CLASS`` setting and ``--generator-clas`` argument to the ``generate_swagger``
management command (:issue:`140`)
- **FIXED:** fixed wrongly required ``'count'`` response field on ``CursorPagination`` (:issue:`141`)
- **FIXED:** fixed crash when encountering ``coreapi.Fields``\ s without a ``schema`` (:issue:`143`)


*********
**1.8.0**
*********
Expand Down
10 changes: 9 additions & 1 deletion docs/settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ The possible settings and their default values are as follows:
Default classes
===============

DEFAULT_GENERATOR_CLASS
-------------------------

:class:`~.generators.OpenAPISchemaGenerator` subclass that will be used by default for generating the final
:class:`.Schema` object. Can be overriden by the ``generator_class`` argument to :func:`.get_schema_view`.

**Default**: :class:`drf_yasg.generators.OpenAPISchemaGenerator`

DEFAULT_AUTO_SCHEMA_CLASS
-------------------------

Expand Down Expand Up @@ -102,7 +110,7 @@ DEFAULT_INFO
------------

An import string to an :class:`.openapi.Info` object. This will be used when running the ``generate_swagger``
management command, or if no ``info`` argument is passed to ``get_schema_view``.
management command, or if no ``info`` argument is passed to :func:`.get_schema_view`.

**Default**: :python:`None`

Expand Down
2 changes: 2 additions & 0 deletions src/drf_yasg/app_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from rest_framework.settings import perform_import

SWAGGER_DEFAULTS = {
'DEFAULT_GENERATOR_CLASS': 'drf_yasg.generators.OpenAPISchemaGenerator',
'DEFAULT_AUTO_SCHEMA_CLASS': 'drf_yasg.inspectors.SwaggerAutoSchema',

'DEFAULT_FIELD_INSPECTORS': [
Expand Down Expand Up @@ -68,6 +69,7 @@
}

IMPORT_STRINGS = [
'DEFAULT_GENERATOR_CLASS',
'DEFAULT_AUTO_SCHEMA_CLASS',
'DEFAULT_FIELD_INSPECTORS',
'DEFAULT_FILTER_INSPECTORS',
Expand Down
9 changes: 5 additions & 4 deletions src/drf_yasg/inspectors/field.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,7 @@ def add_manual_fields(self, serializer, schema):
setattr(schema, attr, val)

def get_schema(self, serializer):
result = self.probe_field_inspectors(serializer, openapi.Schema, self.use_definitions)
schema = openapi.resolve_ref(result, self.components)
self.add_manual_fields(serializer, schema)
return result
return self.probe_field_inspectors(serializer, openapi.Schema, self.use_definitions)

def add_manual_parameters(self, serializer, parameters):
"""Add/replace parameters from the given list of automatically generated request parameters. This method
Expand Down Expand Up @@ -117,6 +114,10 @@ def make_schema_definition():
# but is visually displayed like the model name, which is confusing
# it is better to just remove title from inline models
del result.title

# Provide an option to add manual paremeters to a schema
# for example, to add examples
self.add_manual_fields(field, result)
return result

if not ref_name or not use_references:
Expand Down
7 changes: 5 additions & 2 deletions src/drf_yasg/inspectors/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def coreapi_field_to_parameter(self, field):
in_=location_to_in[field.location],
type=coreapi_types.get(type(field.schema), openapi.TYPE_STRING),
required=field.required,
description=field.schema.description,
description=field.schema.description if field.schema else None,
)


Expand All @@ -70,7 +70,10 @@ def get_paginated_response(self, paginator, response_schema):
('previous', openapi.Schema(type=openapi.TYPE_STRING, format=openapi.FORMAT_URI)),
('results', response_schema),
)),
required=['count', 'results']
required=['results']
)

if has_count:
paged_schema.required.insert(0, 'count')

return paged_schema
22 changes: 19 additions & 3 deletions src/drf_yasg/management/commands/generate_swagger.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import logging
import os
from collections import OrderedDict
from importlib import import_module

from django.contrib.auth.models import User
from django.core.exceptions import ImproperlyConfigured
Expand All @@ -12,7 +13,15 @@
from ... import openapi
from ...app_settings import swagger_settings
from ...codecs import OpenAPICodecJson, OpenAPICodecYaml
from ...generators import OpenAPISchemaGenerator


def import_class(import_string):
if not import_string:
return None

module_path, class_name = import_string.rsplit('.', 1)
module = import_module(module_path)
return getattr(module, class_name)


class Command(BaseCommand):
Expand Down Expand Up @@ -64,6 +73,11 @@ def add_arguments(self, parser):
'OpenAPISchemaGenerator.get_schema().\n'
'This option implies --mock-request.'
)
parser.add_argument(
'-g', '--generator-class', dest='generator_class_name',
default='',
help='Import string pointing to an OpenAPISchemaGenerator subclass to use for schema generation.'
)

def write_schema(self, schema, stream, format):
if format == 'json':
Expand All @@ -89,7 +103,8 @@ def get_mock_request(self, url, format, user=None):
request = APIView().initialize_request(request)
return request

def handle(self, output_file, overwrite, format, api_url, mock, user, private, *args, **options):
def handle(self, output_file, overwrite, format, api_url, mock, user, private, generator_class_name,
*args, **kwargs):
# disable logs of WARNING and below
logging.disable(logging.WARNING)

Expand Down Expand Up @@ -117,7 +132,8 @@ def handle(self, output_file, overwrite, format, api_url, mock, user, private, *

request = self.get_mock_request(api_url, format, user) if mock else None

generator = OpenAPISchemaGenerator(
generator_class = import_class(generator_class_name) or swagger_settings.DEFAULT_GENERATOR_CLASS
generator = generator_class(
info=info,
url=api_url
)
Expand Down
3 changes: 1 addition & 2 deletions src/drf_yasg/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
from rest_framework.views import APIView

from .app_settings import swagger_settings
from .generators import OpenAPISchemaGenerator
from .renderers import OpenAPIRenderer, ReDocRenderer, SwaggerJSONRenderer, SwaggerUIRenderer, SwaggerYAMLRenderer

SPEC_RENDERERS = (SwaggerYAMLRenderer, SwaggerJSONRenderer, OpenAPIRenderer)
Expand Down Expand Up @@ -46,7 +45,7 @@ def callback(response):


def get_schema_view(info=None, url=None, patterns=None, urlconf=None, public=False, validators=None,
generator_class=OpenAPISchemaGenerator,
generator_class=swagger_settings.DEFAULT_GENERATOR_CLASS,
authentication_classes=api_settings.DEFAULT_AUTHENTICATION_CLASSES,
permission_classes=api_settings.DEFAULT_PERMISSION_CLASSES):
"""Create a SchemaView class with default renderers and generators.
Expand Down
2 changes: 1 addition & 1 deletion testproj/todo/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@
urlpatterns = router.urls

urlpatterns += [
url(r'^(?P<todo_id>\d+)/yetanother/(?P<yetanother_id>\d+)/$',
url(r'^(?P<todo_id>\d+)/yetanothers/(?P<yetanother_id>\d+)/$',
views.NestedTodoView.as_view(), ),
]
4 changes: 2 additions & 2 deletions tests/reference.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -697,9 +697,9 @@ paths:
description: A unique integer value identifying this todo.
required: true
type: integer
/todo/{todo_id}/yetanother/{yetanother_id}/:
/todo/{todo_id}/yetanothers/{yetanother_id}/:
get:
operationId: todo_yetanother_read
operationId: todo_yetanothers_read
description: ''
parameters: []
responses:
Expand Down
20 changes: 16 additions & 4 deletions tests/test_management.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,18 @@
from django.contrib.auth.models import User
from django.core.management import call_command

from drf_yasg import openapi
from drf_yasg.codecs import yaml_sane_load
from drf_yasg.generators import OpenAPISchemaGenerator


def call_generate_swagger(output_file='-', overwrite=False, format='', api_url='',
mock=False, user='', private=False, **kwargs):
mock=False, user='', private=False, generator_class_name='', **kwargs):
out = StringIO()
call_command(
'generate_swagger', stdout=out,
output_file=output_file, overwrite=overwrite, format=format,
api_url=api_url, mock=mock, user=user, private=private,
**kwargs
output_file=output_file, overwrite=overwrite, format=format, api_url=api_url, mock=mock, user=user,
private=private, generator_class_name=generator_class_name, **kwargs
)
return out.getvalue()

Expand All @@ -46,6 +47,17 @@ def test_no_mock(db):
assert len(output_schema['paths']) > 0


class EmptySchemaGenerator(OpenAPISchemaGenerator):
def get_paths(self, endpoints, components, request, public):
return openapi.Paths(paths={}), ''


def test_generator_class(db):
output = call_generate_swagger(generator_class_name='test_management.EmptySchemaGenerator')
output_schema = json.loads(output, object_pairs_hook=OrderedDict)
assert len(output_schema['paths']) == 0


def silentremove(filename):
try:
os.remove(filename)
Expand Down