Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 713c669e28 | |||
| 2545ae9657 | |||
| f03d9d71e9 | |||
| a993cba7aa | |||
| bfd88cbdb4 | |||
| 123a05c82c | |||
| 7065429d47 | |||
| bd727fbe88 | |||
| 698a175a1b | |||
| 5b225423ae | |||
| 209201b9a5 | |||
| ca00ed35be |
+3
-1
@@ -2,7 +2,6 @@ language: python
|
||||
cache: pip
|
||||
|
||||
python:
|
||||
- '2.7'
|
||||
- '3.4'
|
||||
- '3.5'
|
||||
- '3.6'
|
||||
@@ -14,6 +13,9 @@ env:
|
||||
jobs:
|
||||
include:
|
||||
- stage: test
|
||||
python: '2.7'
|
||||
env: DRF=3.7
|
||||
-
|
||||
python: '3.6'
|
||||
env: DRF=master
|
||||
-
|
||||
|
||||
@@ -3,6 +3,28 @@ Changelog
|
||||
#########
|
||||
|
||||
|
||||
*********
|
||||
**1.7.2**
|
||||
*********
|
||||
|
||||
*Release date: May 12, 2018*
|
||||
|
||||
- **FIXED:** fixed generation of default ``SECURITY_REQUIREMENTS`` to match documented behaviour
|
||||
- **FIXED:** ordering of ``SECURITY_REQUIREMENTS`` and ``SECURITY_DEFINITIONS`` is now stable
|
||||
|
||||
|
||||
*********
|
||||
**1.7.1**
|
||||
*********
|
||||
|
||||
*Release date: May 05, 2018*
|
||||
|
||||
- **IMPROVED:** updated ``swagger-ui`` to version 3.14.1
|
||||
- **IMPROVED:** set ``swagger-ui`` ``showCommonExtensions`` to ``True`` by default and add
|
||||
``SHOW_COMMON_EXTENSIONS`` setting key
|
||||
- **IMPROVED:** set ``min_length=1`` when ``allow_blank=False`` (:pr:`112`, thanks to :ghuser:`elnappo`)
|
||||
- **FIXED:** made documentation ordering of ``SwaggerDict`` extra attributes stable
|
||||
|
||||
*********
|
||||
**1.7.0**
|
||||
*********
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ Security requirements
|
||||
The second step is specifying, for each endpoint, which authentication mechanism can be used for interacting with it.
|
||||
See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#security-requirement-object for details.
|
||||
|
||||
By default, a top-level `security` that accepts all the declared security definitions is generated.
|
||||
By default, a top-level `security` that accepts any one of the declared security definitions is generated.
|
||||
For the example above, that would be :code:`[{'Basic': []}, {'Bearer': []}]`. This can be overriden using the
|
||||
:ref:`SECURITY_REQUIREMENTS <security-definitions-settings>` setting.
|
||||
|
||||
|
||||
@@ -255,6 +255,15 @@ Controls how many levels are expaned by default when showing nested models.
|
||||
**Default**: :python:`3` |br|
|
||||
*Maps to parameter*: ``defaultModelExpandDepth``
|
||||
|
||||
DEFAULT_MODEL_DEPTH
|
||||
-------------------
|
||||
|
||||
Controls the display of extensions (``pattern``, ``maxLength``, ``minLength``, ``maximum``, ```minimum``) fields and
|
||||
values for Parameters.
|
||||
|
||||
**Default**: :python:`True` |br|
|
||||
*Maps to parameter*: ``showCommonExtensions``
|
||||
|
||||
.. _oauth2-settings:
|
||||
|
||||
OAUTH2_REDIRECT_URL
|
||||
|
||||
Generated
+414
-414
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -2,7 +2,7 @@
|
||||
"name": "drf-yasg",
|
||||
"dependencies": {
|
||||
"redoc": "^2.0.0-alpha.17",
|
||||
"swagger-ui-dist": "^3.13.6"
|
||||
"swagger-ui-dist": "^3.14.1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -8,5 +8,4 @@ six>=1.10.0
|
||||
uritemplate>=3.0.0
|
||||
|
||||
djangorestframework>=3.7.7
|
||||
Django>=1.11.7,<2.0; python_version <= "2.7"
|
||||
Django>=1.11.7; python_version >= "3.4"
|
||||
Django>=1.11.7
|
||||
|
||||
@@ -3,8 +3,7 @@ pytest>=2.9
|
||||
pytest-pythonpath>=0.7.1
|
||||
pytest-cov>=2.5.1
|
||||
pytest-xdist>=1.22.0
|
||||
# latest pip version of pytest-django is more than a year old and does not support Django 2.0
|
||||
git+https://github.com/pytest-dev/pytest-django.git@94cccb956435dd7a719606744ee7608397e1eafb
|
||||
pytest-django>=3.2.0
|
||||
datadiff==2.0.0
|
||||
|
||||
-r testproj.txt
|
||||
|
||||
@@ -45,6 +45,7 @@ SWAGGER_DEFAULTS = {
|
||||
'SHOW_EXTENSIONS': True,
|
||||
'DEFAULT_MODEL_RENDERING': 'model',
|
||||
'DEFAULT_MODEL_DEPTH': 3,
|
||||
'SHOW_COMMON_EXTENSIONS': True,
|
||||
'OAUTH2_REDIRECT_URL': None,
|
||||
'OAUTH2_CONFIG': {},
|
||||
'SUPPORTED_SUBMIT_METHODS': [
|
||||
|
||||
@@ -204,9 +204,15 @@ class OpenAPISchemaGenerator(object):
|
||||
paths, prefix = self.get_paths(endpoints, components, request, public)
|
||||
|
||||
security_definitions = swagger_settings.SECURITY_DEFINITIONS
|
||||
if security_definitions is not None:
|
||||
security_definitions = OrderedDict(sorted([(key, OrderedDict(sorted(sd.items())))
|
||||
for key, sd in swagger_settings.SECURITY_DEFINITIONS.items()]))
|
||||
security_requirements = swagger_settings.SECURITY_REQUIREMENTS
|
||||
if security_requirements is None:
|
||||
security_requirements = [{security_scheme: [] for security_scheme in swagger_settings.SECURITY_DEFINITIONS}]
|
||||
security_requirements = [{security_scheme: []} for security_scheme in swagger_settings.SECURITY_DEFINITIONS]
|
||||
|
||||
security_requirements = sorted(security_requirements, key=lambda od: list(sorted(od)))
|
||||
security_requirements = [OrderedDict(sorted(sr.items())) for sr in security_requirements]
|
||||
|
||||
url = self.url
|
||||
if url is None and request is not None:
|
||||
@@ -401,7 +407,6 @@ class OpenAPISchemaGenerator(object):
|
||||
"""
|
||||
parameters = []
|
||||
queryset = getattr(view_cls, 'queryset', None)
|
||||
model = getattr(getattr(view_cls, 'queryset', None), 'model', None)
|
||||
|
||||
for variable in sorted(uritemplate.variables(path)):
|
||||
model, model_field = get_queryset_field(queryset, variable)
|
||||
|
||||
@@ -281,6 +281,10 @@ def find_limits(field):
|
||||
if attr not in limits or improves(limit_value, limits[attr]):
|
||||
limits[attr] = limit_value
|
||||
|
||||
if hasattr(field, "allow_blank") and not field.allow_blank:
|
||||
if limits.get('min_length', 0) < 1:
|
||||
limits['min_length'] = 1
|
||||
|
||||
return OrderedDict(sorted(limits.items()))
|
||||
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ class SwaggerDict(OrderedDict):
|
||||
which would result in the extra attributes being added first. For this reason, we defer the insertion of the
|
||||
attributes and require that subclasses call ._insert_extras__ at the end of their __init__ method.
|
||||
"""
|
||||
for attr, val in self._extras__.items():
|
||||
for attr, val in sorted(self._extras__.items()):
|
||||
setattr(self, attr, val)
|
||||
|
||||
@staticmethod
|
||||
@@ -221,7 +221,7 @@ class Swagger(SwaggerDict):
|
||||
:param str _prefix: api path prefix to use in setting basePath; this will be appended to the wsgi
|
||||
SCRIPT_NAME prefix or Django's FORCE_SCRIPT_NAME if applicable
|
||||
:param str _version: version string to override Info
|
||||
:param list[dict] security_definitions: list of supported authentication mechanisms
|
||||
:param dict[str,dict[str,str]] security_definitions: list of supported authentication mechanisms
|
||||
:param list[dict] security: authentication mechanisms accepted by default; can be overriden in Operation
|
||||
:param list[str] consumes: consumed MIME types; can be overriden in Operation
|
||||
:param list[str] produces: produced MIME types; can be overriden in Operation
|
||||
|
||||
@@ -93,6 +93,7 @@ class _UIRenderer(BaseRenderer):
|
||||
'defaultModelRendering': swagger_settings.DEFAULT_MODEL_RENDERING,
|
||||
'defaultModelExpandDepth': swagger_settings.DEFAULT_MODEL_DEPTH,
|
||||
'defaultModelsExpandDepth': swagger_settings.DEFAULT_MODEL_DEPTH,
|
||||
'showCommonExtensions': swagger_settings.SHOW_COMMON_EXTENSIONS,
|
||||
'oauth2RedirectUrl': swagger_settings.OAUTH2_REDIRECT_URL,
|
||||
'supportedSubmitMethods': swagger_settings.SUPPORTED_SUBMIT_METHODS,
|
||||
}
|
||||
|
||||
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
@@ -66,7 +66,7 @@ def swagger_auto_schema(method=None, methods=None, auto_schema=unset, request_bo
|
||||
|
||||
:param str operation_id: operation ID override; the operation ID must be unique accross the whole API
|
||||
:param str operation_description: operation description override
|
||||
:param str security: security requirements override; used to specify which authetication mechanism
|
||||
:param list[dict] security: security requirements override; used to specify which authetication mechanism
|
||||
is requried to call this API; an empty list marks the endpoint as unauthenticated (i.e. removes all accepted
|
||||
authentication schemes), and ``None`` will inherit the top-level secuirty requirements
|
||||
:param dict[str,(.Schema,.SchemaRef,.Response,str,Serializer)] responses: a dict of documented manual responses
|
||||
|
||||
@@ -94,7 +94,18 @@ SWAGGER_SETTINGS = {
|
||||
'LOGIN_URL': '/admin/login',
|
||||
'LOGOUT_URL': '/admin/logout',
|
||||
|
||||
'DEFAULT_INFO': 'testproj.urls.swagger_info'
|
||||
'DEFAULT_INFO': 'testproj.urls.swagger_info',
|
||||
|
||||
'SECURITY_DEFINITIONS': {
|
||||
'Basic': {
|
||||
'type': 'basic'
|
||||
},
|
||||
'Bearer': {
|
||||
'type': 'apiKey',
|
||||
'name': 'Authorization',
|
||||
'in': 'header'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Internationalization
|
||||
|
||||
+27
-2
@@ -21,10 +21,15 @@ consumes:
|
||||
produces:
|
||||
- application/json
|
||||
securityDefinitions:
|
||||
basic:
|
||||
Basic:
|
||||
type: basic
|
||||
Bearer:
|
||||
in: header
|
||||
name: Authorization
|
||||
type: apiKey
|
||||
security:
|
||||
- basic: []
|
||||
- Basic: []
|
||||
- Bearer: []
|
||||
paths:
|
||||
/articles/:
|
||||
get:
|
||||
@@ -202,6 +207,7 @@ paths:
|
||||
type: string
|
||||
pattern: ^69$
|
||||
default: '69'
|
||||
minLength: 1
|
||||
- name: image_styles
|
||||
in: formData
|
||||
description: Parameter with Items
|
||||
@@ -700,6 +706,7 @@ paths:
|
||||
description: this field is generated from a query_serializer
|
||||
required: false
|
||||
type: string
|
||||
minLength: 1
|
||||
- name: is_staff
|
||||
in: query
|
||||
description: this one too!
|
||||
@@ -800,6 +807,7 @@ definitions:
|
||||
description: title model help_text
|
||||
type: string
|
||||
maxLength: 255
|
||||
minLength: 1
|
||||
author:
|
||||
description: The ID of the user that created this article; if none is provided,
|
||||
defaults to the currently logged in user.
|
||||
@@ -809,6 +817,7 @@ definitions:
|
||||
description: body serializer help_text
|
||||
type: string
|
||||
maxLength: 5000
|
||||
minLength: 1
|
||||
slug:
|
||||
description: slug model help_text
|
||||
type: string
|
||||
@@ -830,6 +839,7 @@ definitions:
|
||||
description: but i needed to test these 2 fields somehow
|
||||
type: string
|
||||
format: uri
|
||||
minLength: 1
|
||||
readOnly: true
|
||||
uuid:
|
||||
description: should articles have UUIDs?
|
||||
@@ -872,10 +882,12 @@ definitions:
|
||||
title: FirstName
|
||||
type: string
|
||||
maxLength: 30
|
||||
minLength: 1
|
||||
lastName:
|
||||
title: LastName
|
||||
type: string
|
||||
maxLength: 30
|
||||
minLength: 1
|
||||
Person:
|
||||
required:
|
||||
- identity
|
||||
@@ -897,10 +909,12 @@ definitions:
|
||||
title: Project name
|
||||
description: Name of the project
|
||||
type: string
|
||||
minLength: 1
|
||||
githubRepo:
|
||||
title: Github repo
|
||||
description: Github repository of the project
|
||||
type: string
|
||||
minLength: 1
|
||||
Snippet:
|
||||
required:
|
||||
- code
|
||||
@@ -922,6 +936,7 @@ definitions:
|
||||
description: The ID of the user that created this snippet.
|
||||
type: string
|
||||
readOnly: true
|
||||
minLength: 1
|
||||
title: Owner as string
|
||||
title:
|
||||
title: Title
|
||||
@@ -930,6 +945,7 @@ definitions:
|
||||
code:
|
||||
title: Code
|
||||
type: string
|
||||
minLength: 1
|
||||
linenos:
|
||||
title: Linenos
|
||||
type: boolean
|
||||
@@ -1448,6 +1464,7 @@ definitions:
|
||||
title: Title
|
||||
type: string
|
||||
maxLength: 50
|
||||
minLength: 1
|
||||
TodoAnother:
|
||||
required:
|
||||
- title
|
||||
@@ -1458,6 +1475,7 @@ definitions:
|
||||
title: Title
|
||||
type: string
|
||||
maxLength: 50
|
||||
minLength: 1
|
||||
todo:
|
||||
$ref: '#/definitions/Todo'
|
||||
TodoRecursive:
|
||||
@@ -1473,6 +1491,7 @@ definitions:
|
||||
title: Title
|
||||
type: string
|
||||
maxLength: 50
|
||||
minLength: 1
|
||||
parent:
|
||||
$ref: '#/definitions/TodoRecursive'
|
||||
parent_id:
|
||||
@@ -1492,6 +1511,7 @@ definitions:
|
||||
title: Title
|
||||
type: string
|
||||
maxLength: 50
|
||||
minLength: 1
|
||||
children:
|
||||
type: array
|
||||
items:
|
||||
@@ -1505,6 +1525,7 @@ definitions:
|
||||
title: Title
|
||||
type: string
|
||||
maxLength: 50
|
||||
minLength: 1
|
||||
todo:
|
||||
required:
|
||||
- title
|
||||
@@ -1518,6 +1539,7 @@ definitions:
|
||||
title: Title
|
||||
type: string
|
||||
maxLength: 50
|
||||
minLength: 1
|
||||
todo:
|
||||
required:
|
||||
- title
|
||||
@@ -1531,6 +1553,7 @@ definitions:
|
||||
title: Title
|
||||
type: string
|
||||
maxLength: 50
|
||||
minLength: 1
|
||||
readOnly: true
|
||||
readOnly: true
|
||||
UserSerializerrr:
|
||||
@@ -1551,6 +1574,7 @@ definitions:
|
||||
type: string
|
||||
pattern: ^[\w.@+-]+$
|
||||
maxLength: 150
|
||||
minLength: 1
|
||||
email:
|
||||
title: Email address
|
||||
type: string
|
||||
@@ -1572,6 +1596,7 @@ definitions:
|
||||
type: string
|
||||
format: ipv4
|
||||
readOnly: true
|
||||
minLength: 1
|
||||
last_connected_at:
|
||||
title: Last connected at
|
||||
description: really?
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
from collections import OrderedDict
|
||||
from random import shuffle
|
||||
|
||||
from drf_yasg import openapi
|
||||
|
||||
|
||||
@@ -51,3 +54,15 @@ def test_trailing_underscore_stripped():
|
||||
del sd.in_
|
||||
assert 'in' not in sd
|
||||
assert not hasattr(sd, 'in__')
|
||||
|
||||
|
||||
def test_extra_ordering():
|
||||
"""Insertion order should also be consistent when setting undeclared parameters (kwargs) in SwaggerDict"""
|
||||
extras = [('beta', 1), ('alpha', 2), ('omega', 3), ('gamma', 4)]
|
||||
shuffled_extras = list(extras)
|
||||
shuffle(shuffled_extras)
|
||||
|
||||
s1 = openapi.SwaggerDict(**OrderedDict(extras))
|
||||
s2 = openapi.SwaggerDict(**OrderedDict(shuffled_extras))
|
||||
|
||||
assert list(s1.items()) == list(s2.items())
|
||||
|
||||
Reference in New Issue
Block a user