Compare commits

...

11 Commits

Author SHA1 Message Date
Cristi Vîjdea d2dc09cb3c Fix changelog markup 2018-04-25 23:04:43 +03:00
Cristi Vîjdea 36992072ca Add 1.6.2 changelog 2018-04-25 22:58:02 +03:00
Cristi Vîjdea aa90723703 Switch to redoc 2.0 alpha
Update redoc to 2.0.0-alpha.17
2018-04-25 22:55:25 +03:00
Cristi Vîjdea 301511bebc Update swagger-ui to 3.13.6 2018-04-25 22:44:49 +03:00
Cristi Vîjdea c0f37f6ec1 Avoid crash when hitting unknown model fields
Fixes #102
2018-04-25 22:41:06 +03:00
Tobias Krönke 5e684549a1 Correct values in swagger-ui docs (#108) 2018-04-25 17:53:22 +03:00
John Carter 322971f3e7 Make parameters order stable for multi-parameter URLs (#106)
Fixes #105

* Added intermittently failing test for #105
* Make parameter order stable for urls with multiple params
2018-04-23 19:16:22 +03:00
Cristi Vîjdea 6dd8ded05d Update swagger-ui to 3.13.3 2018-04-09 13:55:17 +03:00
Cristi Vîjdea 7270154828 Test with Django Rest Framework 3.8 (#96)
* Add djangorestframework 3.8 to tox and travis
* Add @action tests
* Limit tox to <3.0.0
2018-04-04 22:59:57 +03:00
Cristi Vîjdea 6f7d14fdb2 Add 1.6.1 changelog 2018-04-01 12:08:14 +03:00
shahha 941ec8fdaf Added SUPPORTED_SUBMIT_METHODS swagger ui setting (#91) 2018-03-26 11:15:28 +03:00
28 changed files with 2577 additions and 227 deletions
+2
View File
@@ -159,3 +159,5 @@ com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
\.pytest_cache/
+2
View File
@@ -8,6 +8,7 @@
<option name="manageScript" value="manage.py" />
<option name="environment" value="&lt;map/&gt;" />
<option name="doNotUseTestRunner" value="false" />
<option name="trackFilePattern" value="migrations" />
</configuration>
</facet>
</component>
@@ -15,6 +16,7 @@
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/testproj" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/docs/_build" />
<excludeFolder url="file://$MODULE_DIR$/venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.6 (drf-yasg)" jdkType="Python SDK" />
+2 -1
View File
@@ -10,11 +10,12 @@
<inspection_tool class="PyCompatibilityInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ourVersions">
<value>
<list size="4">
<list size="5">
<item index="0" class="java.lang.String" itemvalue="2.7" />
<item index="1" class="java.lang.String" itemvalue="3.4" />
<item index="2" class="java.lang.String" itemvalue="3.5" />
<item index="3" class="java.lang.String" itemvalue="3.6" />
<item index="4" class="java.lang.String" itemvalue="3.7" />
</list>
</value>
</option>
+3
View File
@@ -70,4 +70,7 @@
</LinkMapSettings>
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6 (drf-yasg)" project-jdk-type="Python SDK" />
<component name="PythonCompatibilityInspectionAdvertiser">
<option name="version" value="3" />
</component>
</project>
+1
View File
@@ -9,6 +9,7 @@ python:
env:
- DRF=3.7
- DRF=3.8
jobs:
include:
+1 -1
View File
@@ -11,7 +11,7 @@ Generate **real** Swagger/OpenAPI 2.0 specifications from a Django Rest Framewor
Compatible with
- **Django Rest Framework**: 3.7.7
- **Django Rest Framework**: 3.7.7, 3.8.x
- **Django**: 1.11.x, 2.0.x
- **Python**: 2.7, 3.4, 3.5, 3.6
+19
View File
@@ -3,6 +3,25 @@ Changelog
#########
*********
**1.6.2**
*********
*Release date: Apr 25, 2018*
- **IMPROVED:** updated ``swagger-ui`` to version 3.13.6
- **IMPROVED:** switched ``ReDoc`` to version 2.0.0-alpha.17 (was 1.21.2); fixes :issue:`107`
- **FIXED:** made documentation ordering of parameters stable for urls with multiple parameters (:issue:`105`, :pr:`106`)
- **FIXED:** fixed crash when using a model ``ChoiceField`` of unknown child type
*********
**1.6.1**
*********
*Release date: Apr 01, 2018*
- **ADDED:** added ``SUPPORTED_SUBMIT_METHODS`` ``swagger-ui`` setting
*********
**1.6.0**
*********
+4 -4
View File
@@ -87,8 +87,8 @@ Where you can use the :func:`@swagger_auto_schema <.swagger_auto_schema>` decora
* for ``ViewSet``, ``GenericViewSet``, ``ModelViewSet``, because each viewset corresponds to multiple **paths**, you have
to decorate the *action methods*, i.e. ``list``, ``create``, ``retrieve``, etc. |br|
Additionally, ``@list_route``\ s or ``@detail_route``\ s defined on the viewset, like function based api views, can
respond to multiple HTTP methods and thus have multiple operations that must be decorated separately:
Additionally, ``@action``\ s, `@list_route``\ s or ``@detail_route``\ s defined on the viewset, like function based
api views, can respond to multiple HTTP methods and thus have multiple operations that must be decorated separately:
.. code-block:: python
@@ -96,13 +96,13 @@ Where you can use the :func:`@swagger_auto_schema <.swagger_auto_schema>` decora
class ArticleViewSet(viewsets.ModelViewSet):
# method or 'methods' can be skipped because the list_route only handles a single method (GET)
@swagger_auto_schema(operation_description='GET /articles/today/')
@list_route(methods=['get'])
@action(detail=False, methods=['get'])
def today(self, request):
...
@swagger_auto_schema(method='get', operation_description="GET /articles/{id}/image/")
@swagger_auto_schema(method='post', operation_description="POST /articles/{id}/image/")
@detail_route(methods=['get', 'post'], parser_classes=(MultiPartParser,))
@action(detail=True, methods=['get', 'post'], parser_classes=(MultiPartParser,))
def image(self, request, id=None):
...
+17 -8
View File
@@ -190,8 +190,8 @@ OPERATIONS_SORTER
Sorting order for the operation list of each tag.
* :python:`None`: show in the order returned by the server
* :python:`alpha`: sort alphabetically by path
* :python:`method`: sort by HTTP method
* :python:`'alpha'`: sort alphabetically by path
* :python:`'method'`: sort by HTTP method
**Default**: :python:`None` |br|
*Maps to parameter*: ``operationsSorter``
@@ -202,7 +202,7 @@ TAGS_SORTER
Sorting order for tagged operation groups.
* :python:`None`: Swagger UI default ordering
* :python:`alpha`: sort alphabetically
* :python:`'alpha'`: sort alphabetically
**Default**: :python:`None` |br|
*Maps to parameter*: ``tagsSorter``
@@ -212,9 +212,9 @@ DOC_EXPANSION
Controls the default expansion setting for the operations and tags.
* :python:`None`: everything is collapsed
* :python:`list`: only tags are expanded
* :python:`full`: all operations are expanded
* :python:`'none'`: everything is collapsed
* :python:`'list'`: only tags are expanded
* :python:`'full'`: all operations are expanded
**Default**: :python:`'list'` |br|
*Maps to parameter*: ``docExpansion``
@@ -240,8 +240,8 @@ DEFAULT_MODEL_RENDERING
Controls whether operations show the model structure or the example value by default.
* :python:`model`: show the model fields by default
* :python:`example`: show the example value by default
* :python:`'model'`: show the model fields by default
* :python:`'example'`: show the example value by default
**Default**: :python:`'model'` |br|
*Maps to parameter*: ``defaultModelRendering``
@@ -276,6 +276,15 @@ to the ``SwaggerUIBundle#initOAuth`` method, and must be a dictionary. See
**Default**: :python:`{}`
SUPPORTED_SUBMIT_METHODS
------------------------
List of HTTP methods that have the Try it out feature enabled. An empty array disables Try it out for all operations.
This does not filter the operations from the display.
**Default**: :python:`['get','put','post','delete','options','head','patch','trace']` |br|
*Maps to parameter*: ``supportedSubmitMethods``
******************
``REDOC_SETTINGS``
******************
+2261 -155
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -1,8 +1,8 @@
{
"name": "drf-yasg",
"dependencies": {
"redoc": "^1.21.2",
"swagger-ui-dist": "^3.13.0"
"redoc": "^2.0.0-alpha.17",
"swagger-ui-dist": "^3.13.6"
},
"repository": {
"type": "git",
+1 -1
View File
@@ -1,5 +1,5 @@
# requirements for building and running tox
tox>=2.9.1
tox>=2.9.1,<3.0.0
detox>=0.11
-r setup.txt
+10
View File
@@ -46,6 +46,16 @@ SWAGGER_DEFAULTS = {
'DEFAULT_MODEL_DEPTH': 3,
'OAUTH2_REDIRECT_URL': None,
'OAUTH2_CONFIG': {},
'SUPPORTED_SUBMIT_METHODS': [
'get',
'put',
'post',
'delete',
'options',
'head',
'patch',
'trace'
],
}
REDOC_DEFAULTS = {
+1 -1
View File
@@ -403,7 +403,7 @@ class OpenAPISchemaGenerator(object):
queryset = getattr(view_cls, 'queryset', None)
model = getattr(getattr(view_cls, 'queryset', None), 'model', None)
for variable in uritemplate.variables(path):
for variable in sorted(uritemplate.variables(path)):
model, model_field = get_queryset_field(queryset, variable)
attrs = get_basic_type_info(model_field) or {'type': openapi.TYPE_STRING}
if getattr(view_cls, 'lookup_field', None) == variable and attrs['type'] == openapi.TYPE_STRING:
+3 -1
View File
@@ -410,7 +410,9 @@ class ChoiceFieldInspector(FieldInspector):
model = getattr(getattr(serializer, 'Meta'), 'model')
model_field = get_model_field(model, field.source)
if model_field:
enum_type = get_basic_type_info(model_field).get('type', enum_type)
model_type = get_basic_type_info(model_field)
if model_type:
enum_type = model_type.get('type', enum_type)
if isinstance(field, serializers.MultipleChoiceField):
return SwaggerType(
+1
View File
@@ -94,6 +94,7 @@ class _UIRenderer(BaseRenderer):
'defaultModelExpandDepth': swagger_settings.DEFAULT_MODEL_DEPTH,
'defaultModelsExpandDepth': swagger_settings.DEFAULT_MODEL_DEPTH,
'oauth2RedirectUrl': swagger_settings.OAUTH2_REDIRECT_URL,
'supportedSubmitMethods': swagger_settings.SUPPORTED_SUBMIT_METHODS,
}
data = {k: v for k, v in data.items() if v is not None}
if swagger_settings.VALIDATOR_URL != '':
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+9 -8
View File
@@ -114,7 +114,7 @@ def swagger_auto_schema(method=None, methods=None, auto_schema=unset, request_bo
# no overrides to set, no use in doing more work
return
# if the method is a detail_route or list_route, it will have a bind_to_methods attribute
# if the method is an @action, it will have a bind_to_methods attribute
bind_to_methods = getattr(view_method, 'bind_to_methods', [])
# if the method is actually a function based view (@api_view), it will have a 'cls' attribute
view_cls = getattr(view_method, 'cls', None)
@@ -126,7 +126,7 @@ def swagger_auto_schema(method=None, methods=None, auto_schema=unset, request_bo
_methods = methods
if methods or method:
assert available_methods or http_method_names, "`method` or `methods` can only be specified " \
"on @detail_route or @api_view views"
"on @action or @api_view views"
assert bool(methods) != bool(method), "specify either method or methods"
assert not isinstance(methods, str), "`methods` expects to receive a list of methods;" \
" use `method` for a single argument"
@@ -138,13 +138,13 @@ def swagger_auto_schema(method=None, methods=None, auto_schema=unset, request_bo
assert not any(mth in existing_data for mth in _methods), "http method defined multiple times"
if available_methods:
# detail_route, list_route or api_view
# action or api_view
assert bool(http_method_names) != bool(bind_to_methods), "this should never happen"
if len(available_methods) > 1:
assert _methods, \
"on multi-method api_view, detail_route or list_route, you must specify swagger_auto_schema on " \
"a per-method basis using one of the `method` or `methods` arguments"
"on multi-method api_view, action, detail_route or list_route, you must specify " \
"swagger_auto_schema on a per-method basis using one of the `method` or `methods` arguments"
else:
# for a single-method view we assume that single method as the decorator target
_methods = _methods or available_methods
@@ -156,8 +156,9 @@ def swagger_auto_schema(method=None, methods=None, auto_schema=unset, request_bo
view_method._swagger_auto_schema = existing_data
else:
assert not _methods, \
"the methods argument should only be specified when decorating a detail_route or list_route; you " \
"should also ensure that you put the swagger_auto_schema decorator AFTER (above) the _route decorator"
"the methods argument should only be specified when decorating an action, detail_route or " \
"list_route; you should also ensure that you put the swagger_auto_schema decorator " \
"AFTER (above) the _route decorator"
assert not existing_data, "swagger_auto_schema applied twice to method"
view_method._swagger_auto_schema = data
@@ -183,7 +184,7 @@ def is_list_view(path, method, view):
return True
if action in ('retrieve', 'update', 'partial_update', 'destroy') or detail is True or suffix == 'Instance':
# a detail_route is surely not a list route
# a detail action is surely not a list route
return False
# for GenericAPIView, if it's a detail view it can't also be a list view
+42 -16
View File
@@ -3,6 +3,7 @@ import datetime
from django.utils.decorators import method_decorator
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import viewsets
# noinspection PyDeprecation
from rest_framework.decorators import detail_route, list_route
from rest_framework.filters import OrderingFilter
from rest_framework.pagination import LimitOffsetPagination
@@ -89,23 +90,48 @@ class ArticleViewSet(viewsets.ModelViewSet):
swagger_schema = NoTitleAutoSchema
@swagger_auto_schema(auto_schema=NoPagingAutoSchema, filter_inspectors=[DjangoFilterDescriptionInspector])
@list_route(methods=['get'])
def today(self, request):
today_min = datetime.datetime.combine(datetime.date.today(), datetime.time.min)
today_max = datetime.datetime.combine(datetime.date.today(), datetime.time.max)
articles = self.get_queryset().filter(date_created__range=(today_min, today_max)).all()
serializer = self.serializer_class(articles, many=True)
return Response(serializer.data)
try:
from rest_framework.decorators import action
@swagger_auto_schema(method='get', operation_description="image GET description override")
@swagger_auto_schema(method='post', request_body=serializers.ImageUploadSerializer)
@detail_route(methods=['get', 'post'], parser_classes=(MultiPartParser,))
def image(self, request, slug=None):
"""
image method docstring
"""
pass
@swagger_auto_schema(auto_schema=NoPagingAutoSchema, filter_inspectors=[DjangoFilterDescriptionInspector])
@action(detail=False, methods=['get'])
def today(self, request):
today_min = datetime.datetime.combine(datetime.date.today(), datetime.time.min)
today_max = datetime.datetime.combine(datetime.date.today(), datetime.time.max)
articles = self.get_queryset().filter(date_created__range=(today_min, today_max)).all()
serializer = self.serializer_class(articles, many=True)
return Response(serializer.data)
@swagger_auto_schema(method='get', operation_description="image GET description override")
@swagger_auto_schema(method='post', request_body=serializers.ImageUploadSerializer)
@action(detail=True, methods=['get', 'post'], parser_classes=(MultiPartParser,))
def image(self, request, slug=None):
"""
image method docstring
"""
pass
except ImportError:
action = None
# noinspection PyDeprecation
@swagger_auto_schema(auto_schema=NoPagingAutoSchema, filter_inspectors=[DjangoFilterDescriptionInspector])
@list_route(methods=['get'])
def today(self, request):
today_min = datetime.datetime.combine(datetime.date.today(), datetime.time.min)
today_max = datetime.datetime.combine(datetime.date.today(), datetime.time.max)
articles = self.get_queryset().filter(date_created__range=(today_min, today_max)).all()
serializer = self.serializer_class(articles, many=True)
return Response(serializer.data)
# noinspection PyDeprecation
@swagger_auto_schema(method='get', operation_description="image GET description override")
@swagger_auto_schema(method='post', request_body=serializers.ImageUploadSerializer)
@detail_route(methods=['get', 'post'], parser_classes=(MultiPartParser,))
def image(self, request, slug=None):
"""
image method docstring
"""
pass
def update(self, request, *args, **kwargs):
"""update method docstring"""
+6
View File
@@ -1,3 +1,4 @@
from django.conf.urls import url
from rest_framework import routers
from todo import views
@@ -8,3 +9,8 @@ router.register(r'another', views.TodoAnotherViewSet)
router.register(r'yetanother', views.TodoYetAnotherViewSet)
urlpatterns = router.urls
urlpatterns += [
url(r'^(?P<todo_id>\d+)/yetanother/(?P<yetanother_id>\d+)/$',
views.NestedTodoView.as_view(),),
]
+5
View File
@@ -1,4 +1,5 @@
from rest_framework import viewsets
from rest_framework.generics import RetrieveAPIView
from .models import Todo, TodoAnother, TodoYetAnother
from .serializer import TodoAnotherSerializer, TodoSerializer, TodoYetAnotherSerializer
@@ -20,3 +21,7 @@ class TodoAnotherViewSet(viewsets.ReadOnlyModelViewSet):
class TodoYetAnotherViewSet(viewsets.ReadOnlyModelViewSet):
queryset = TodoYetAnother.objects.all()
serializer_class = TodoYetAnotherSerializer
class NestedTodoView(RetrieveAPIView):
serializer_class = TodoYetAnotherSerializer
+21
View File
@@ -546,6 +546,27 @@ paths:
description: A unique integer value identifying this todo.
required: true
type: integer
/todo/{todo_id}/yetanother/{yetanother_id}/:
get:
operationId: todo_yetanother_read
description: ''
parameters: []
responses:
'200':
description: ''
schema:
$ref: '#/definitions/TodoYetAnother'
tags:
- todo
parameters:
- name: todo_id
in: path
required: true
type: string
- name: yetanother_id
in: path
required: true
type: string
/users/:
get:
operationId: users_list
+3 -1
View File
@@ -1,13 +1,14 @@
[tox]
envlist =
py27-django111-drf37,
py{34,35,36}-django{111,20}-drf37,
py{34,35,36}-django{111,20}-drf{37,38},
py36-django20-drfmaster,
lint, docs
[travis:env]
DRF =
3.7: drf37
3.8: drf38
master: drfmaster
[testenv]
@@ -16,6 +17,7 @@ deps =
django20: Django>=2.0,<2.1
drf37: djangorestframework>=3.7.7,<3.8
drf38: djangorestframework>=3.8.0,<3.9
# test with the latest build of django-rest-framework to get early warning of compatibility issues
drfmaster: https://github.com/encode/django-rest-framework/archive/master.tar.gz
+1 -1
View File
@@ -2,7 +2,7 @@
set -ev
npm update
cp node_modules/redoc/dist/redoc.min.js src/drf_yasg/static/drf-yasg/redoc/
cp node_modules/redoc/bundles/redoc.standalone.js src/drf_yasg/static/drf-yasg/redoc/redoc.min.js
cp -r node_modules/swagger-ui-dist src/drf_yasg/static/drf-yasg/
pushd src/drf_yasg/static/drf-yasg/swagger-ui-dist/ >/dev/null
rm -f package.json .npmignore README.md