Compare commits

...

30 Commits

Author SHA1 Message Date
Cristi Vîjdea 27e38101a4 Add customization blocks to ui templates
Closes #178.
2018-09-10 02:41:02 +03:00
Cristi Vîjdea 4bac38e67b Update ReDoc settings 2018-09-10 01:39:57 +03:00
Cristi Vîjdea 10abf46597 Merge pull request #204 from axnsan12/release-1.10.1
Lotsa fixes. Sorry for the long time no see 😄
2018-09-10 01:00:26 +03:00
Cristi Vîjdea 42841e3092 Add 1.10.1 changelog 2018-09-10 00:42:45 +03:00
Cristi Vîjdea 0654aefe58 Update swagger-ui to 3.18.2 and ReDoc to 2.0.0-alpha.37 2018-09-10 00:13:39 +03:00
Cristi Vîjdea 41b1ca4483 Do not bail on response when request body is formData 2018-09-10 00:02:39 +03:00
Cristi Vîjdea b109d4c847 Fix bad test for no_body 2018-09-09 23:14:09 +03:00
Cristi Vîjdea 591c12f1a7 Fix request_body=no_body handling
Fixes #188, #199.
2018-09-09 23:14:09 +03:00
Cristi Vîjdea 271918a678 Fix empty swagger_auto_schema return value 2018-09-09 23:14:09 +03:00
Cristi Vîjdea c5c40e31c4 Log regex compilation failure in find_regex
Closes #193.
2018-09-09 22:33:13 +03:00
Cristi Vîjdea 3ac6c9ec3a Remove dependency on future
Sole use was raise_from. 

six.raise_from loses exception detail on Python 2, so god help the programmers of the past.

Fixes #196.
2018-09-09 22:29:11 +03:00
Cristi Vîjdea 5fa35d5b81 Check for None before calling to_representation
Django REST Framework also does this in serializers.

https://github.com/encode/django-rest-framework/issues/2299
https://github.com/encode/django-rest-framework/blob/4d57d46bf89f54f276909219ee06f0a2bf112f9f/rest_framework/serializers.py#L518

Fixes #203.
2018-09-09 22:22:58 +03:00
Terence D. Honles f9b215deab Fix missing backslashes found via pytest 3.8 (#202)
See: https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals

Changed in version 3.6: Unrecognized escape sequences produce a DeprecationWarning

Closes #202.
2018-09-09 22:17:04 +03:00
Nour Chawich 0837873f55 Add missing overrides to swagger_auto_schema (#194)
Add missing `operation_summary` and `deprecated` to `swagger_auto_schema` decorator data. The previous PR missed adding these to extra overrides.

- Added tests
- Updated reference.yaml

Refs #149, #173.
Closes #194, #198.
2018-09-09 22:15:50 +03:00
Julian Bez 02b8848912 Fix error when using typing classes (#195)
Closes #195.
2018-09-09 22:11:29 +03:00
Cristi Vîjdea 6e39a58b2d Defer settings imports to avoid ImportErrors 2018-09-09 21:56:26 +03:00
Cristi Vîjdea e146a9712e Remove minor version from PyCharm python interpreter name
This allows for conflictless development on any supproted python version
2018-09-09 21:56:26 +03:00
Cristi Vîjdea ec7529399e Fix swagger-ui style when session auth is disabled 2018-09-09 21:56:26 +03:00
Cristi Vîjdea 824baf7e9d Update PyCharm interpreter to python 3.7 2018-08-14 09:54:05 +03:00
Cristi Vîjdea dd50eb5e12 Remove unused requirement 2018-08-14 09:53:47 +03:00
Cristi Vîjdea 9b56e1a4c8 Avoid invalid usage of readOnly 2018-08-09 04:27:08 +03:00
Cristi Vîjdea 608abaf0e1 Fuck this test 2018-08-09 04:02:35 +03:00
Cristi Vîjdea 64e13a94da Remove tox-battery from CI requirements 2018-08-09 03:54:35 +03:00
Cristi Vîjdea 5051f91c97 Don't cache .tox on travis 2018-08-09 03:52:18 +03:00
Cristi Vîjdea d1ae81a27e Fix relative imports 2018-08-09 03:52:09 +03:00
Cristi Vîjdea 1ca401959c Fix tests 2018-08-09 03:40:35 +03:00
Cristi Vîjdea cd4bd4a18e Add SPEC_URL setting 2018-08-09 03:32:04 +03:00
Cristi Vîjdea 8a69f08c29 Update ReDoc to 2.0.0-alpha.34 2018-08-09 03:15:08 +03:00
Cristi Vîjdea e533b0827a Add ReDoc 1.x.x renderer 2018-08-09 03:14:08 +03:00
Cristi Vîjdea dc78dfdad8 Shrink tox envlist 2018-08-08 01:53:24 +03:00
42 changed files with 469 additions and 302 deletions
+7 -3
View File
@@ -16,10 +16,14 @@
<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$/.pytest_cache" />
<excludeFolder url="file://$MODULE_DIR$/dist" />
<excludeFolder url="file://$MODULE_DIR$/docs/_build" />
<excludeFolder url="file://$MODULE_DIR$/htmlcov" />
<excludeFolder url="file://$MODULE_DIR$/src/drf_yasg.egg-info" />
<excludeFolder url="file://$MODULE_DIR$/venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.6 (drf-yasg)" jdkType="Python SDK" />
<orderEntry type="jdk" jdkName="Python 3 (drf-yasg)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="TemplatesService">
@@ -31,7 +35,7 @@
</option>
</component>
<component name="TestRunnerService">
<option name="projectConfiguration" value="py.test" />
<option name="PROJECT_TEST_RUNNER" value="py.test" />
<option name="projectConfiguration" value="pytest" />
<option name="PROJECT_TEST_RUNNER" value="pytest" />
</component>
</module>
+1 -1
View File
@@ -69,7 +69,7 @@
<textMaps />
</LinkMapSettings>
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6 (drf-yasg)" project-jdk-type="Python SDK" />
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3 (drf-yasg)" project-jdk-type="Python SDK" />
<component name="PythonCompatibilityInspectionAdvertiser">
<option name="version" value="3" />
</component>
+1 -7
View File
@@ -6,13 +6,7 @@ python:
- '3.5'
- '3.6'
cache:
directories:
- $HOME/.cache/pip
- .tox
before_cache:
- rm -f $HOME/.cache/pip/log/debug.log
- rm -fr .tox/log/ .tox/*/log/ .tox/*/tmp/ .tox/dist .tox/*/lib/*/site-packages/drf_yasg*
cache: pip
jobs:
include:
+20
View File
@@ -3,6 +3,26 @@ Changelog
#########
**********
**1.10.1**
**********
*Release date: Sep 10, 2018*
- **ADDED:** added the ``SPEC_URL`` setting for controlling the download link in ``swagger-ui`` and ``ReDoc``
- **ADDED:** updated ``ReDoc`` settings (added ``NATIVE_SCROLLBARS`` and ``REQUIRED_PROPS_FIRST``)
- **ADDED:** added ``extra_styles`` and ``extra_scripts`` blocks to ui templates (:issue:`178`)
- **IMPROVED:** updated ``swagger-ui`` to version 3.18.2
- **IMPROVED:** updated ``ReDoc`` to version 2.0.0-alpha.37
- **FIXED:** stopped generating invalid OpenAPI by improper placement of ``readOnly`` Schemas
- **FIXED:** fixed broken CSS when ``USE_SESSION_AUTH=False``
- **FIXED:** fixed implementation of ``operation_summary`` and ``deprecated`` (:pr:`194`, :pr:`198`)
- **FIXED:** fixed a bug related to nested ``typing`` hints (:pr:`195`)
- **FIXED:** removed dependency on ``future`` (:issue:`196`)
- **FIXED:** removed exceptions loged for fields with ``default=None`` (:issue:`203`)
- **FIXED:** fixed ``request_body=no_body`` handling and related tests (:issue:`188`, :issue:`199`)
**********
**1.10.0**
**********
+14 -3
View File
@@ -2,6 +2,17 @@
Customizing the web UI
######################
There is currently no pluggable way of customizing the web UI apart from the settings available in
:ref:`swagger-ui-settings` and :ref:`redoc-ui-settings`. If you really need to, you can override one of the
``drf-yasg/swagger-ui.html`` or ``drf-yasg/redoc.html`` templates that are used for rendering.
The web UI can be customized using the settings available in :ref:`swagger-ui-settings` and :ref:`redoc-ui-settings`.
You can also extend one of the ``drf-yasg/swagger-ui.html`` or ``drf-yasg/redoc.html`` templates that are used for
rendering. The customizable blocks are currently limited to:
{% block extra_styles %}
additional stylesheets
{% block extra_scripts %}
additional scripts
{% block user_context_message %}
*(swagger-ui session auth only)*
logged in user message
+56 -13
View File
@@ -27,16 +27,27 @@ Example:
}
REDOC_SETTINGS = {
'LAZY_RENDERING': True,
'LAZY_RENDERING': False,
...
}
.. _url-settings:
All settings which configure URLs (``LOGIN_URL``, ``SPEC_URL``, ``VALIDATOR_URL``, etc.) can accept several forms of
input:
* A view name: `urls.reverse()` will be used to reverse-resolve the name
* A 2-tuple of ``(view_name, kwargs)```: `urls.reverse()` will be used to reverse-resolve the name using the given
`kwargs`; `kwargs` must be a dict
* A 3-tuple of ``(view_name, args, kwargs)```: `urls.reverse()` will be used to reverse-resolve the name using the given
`args` and `kwargs`; `args`, `kwargs` must be a tuple/list and a dict respectively
* A URL, which will be used as-is
The possible settings and their default values are as follows:
********************
``SWAGGER_SETTINGS``
********************
****************
SWAGGER_SETTINGS
****************
.. _default-class-settings:
@@ -192,6 +203,15 @@ Swagger UI settings
Swagger UI configuration settings. |br|
See https://github.com/swagger-api/swagger-ui/blob/112bca906553a937ac67adc2e500bdeed96d067b/docs/usage/configuration.md#parameters.
SPEC_URL
--------
URL pointing to a swagger document for use by swagger-ui. The default behaviour is to append ``?format=openapi`` to the
URL which serves the UI; see :ref:`note on URL settings <url-settings>` above.
**Default**: :python:`None` |br|
*Maps to parameter*: ``url``
VALIDATOR_URL
-------------
@@ -312,9 +332,9 @@ 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``
******************
**************
REDOC_SETTINGS
**************
.. _redoc-ui-settings:
@@ -324,29 +344,52 @@ ReDoc UI settings
ReDoc UI configuration settings. |br|
See https://github.com/Rebilly/ReDoc#configuration.
SPEC_URL
--------
URL pointing to a swagger document for use by ReDoc. The default behaviour is to append ``?format=openapi`` to the
URL which serves the UI; see :ref:`note on URL settings <url-settings>` above.
**Default**: :python:`None` |br|
*Maps to attribute*: ``spec-url``
LAZY_RENDERING
--------------
**Default**: :python:`True` |br|
*Maps to attribute*: ``lazy-rendering``
**NOTE:** this feature might be removed in future versions of ReDoc (see https://github.com/Rebilly/ReDoc/issues/475)
**Default**: :python:`False` |br|
*Maps to attribute*: ``lazyRendering``
HIDE_HOSTNAME
-------------
**Default**: :python:`False` |br|
*Maps to attribute*: ``hide-hostname``
*Maps to attribute*: ``hideHostname``
EXPAND_RESPONSES
----------------
**Default**: :python:`'all'` |br|
*Maps to attribute*: ``expand-responses``
*Maps to attribute*: ``expandResponses``
PATH_IN_MIDDLE
--------------
**Default**: :python:`False` |br|
*Maps to attribute*: ``path-in-middle-panel``
*Maps to attribute*: ``pathInMiddlePanel``
NATIVE_SCROLLBARS
-----------------
**Default**: :python:`False` |br|
*Maps to attribute*: ``nativeScrollbars``
REQUIRED_PROPS_FIRST
--------------------
**Default**: :python:`False` |br|
*Maps to attribute*: ``requiredPropsFirst``
.. _FORCE_SCRIPT_NAME: https://docs.djangoproject.com/en/2.0/ref/settings/#force-script-name
+61 -61
View File
@@ -22,9 +22,9 @@
"integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw=="
},
"buffer": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.0.tgz",
"integrity": "sha512-nUJyfChH7PMJy75eRDCCKtszSEFokUNXC1hNVSe+o+VdcgvDPLs20k3v8UXI8ruRYAJiYtyRea8mYyqPxoHWDw==",
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz",
"integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==",
"requires": {
"base64-js": "^1.0.2",
"ieee754": "^1.1.4"
@@ -96,9 +96,9 @@
"integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg="
},
"dompurify": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-1.0.7.tgz",
"integrity": "sha512-1xK0JEda/jvIm3SgqHXKvRCh3AbEKCyBbUAGpNCMVIljBD145cPvBR66JSj3O4SdscFUx5NXsDkJpz6vDT8KLg=="
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-1.0.8.tgz",
"integrity": "sha512-vetRFbN1SXSPfP3ClIiYnxTrXquSqakBEOoB5JESn0SVcSYzpu6ougjakpKnskGctYdlNpwf+riUHSkG7d4XUw=="
},
"encoding": {
"version": "0.1.12",
@@ -176,9 +176,9 @@
"integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw=="
},
"iconv-lite": {
"version": "0.4.23",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
"integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
}
@@ -225,14 +225,14 @@
}
},
"json-schema-ref-parser": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-5.1.2.tgz",
"integrity": "sha512-gP0mSqqkG99xNeA4F6bf2pXQYv5fFqe9SybbKO9qSMmyzzfFFIqd16s9Y65mRWKzZ0muTjyEtcSE/hLZLvIjZw==",
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-5.1.3.tgz",
"integrity": "sha512-CpDFlBwz/6la78hZxyB9FECVKGYjIIl3Ms3KLqFj99W7IIb7D00/RDgc++IGB4BBALl0QRhh5m4q5WNSopvLtQ==",
"requires": {
"call-me-maybe": "^1.0.1",
"debug": "^3.1.0",
"js-yaml": "^3.12.0",
"ono": "^4.0.5"
"ono": "^4.0.6"
}
},
"loose-envify": {
@@ -244,9 +244,9 @@
}
},
"lunr": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.1.tgz",
"integrity": "sha1-ETYWorYC3cEJMqe/ik5uV+v+zfI="
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.3.tgz",
"integrity": "sha512-rlAEsgU9Bnavca2w1WJ6+6cdeHMXNyadcersyk3ZpuhgWb5HBNj8l4WwJz9PjksAhYDlpQffCVXPctOn+wCIVA=="
},
"mark.js": {
"version": "8.11.1",
@@ -259,9 +259,9 @@
"integrity": "sha512-49i2QYhfULqaXzNZpxC808PisuCTGT2fgG0zrzdCI9N3rIfAWfW0nggvbXr6zvpynZdOG5+9xNxdzP0kwZnERw=="
},
"memoize-one": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-4.0.0.tgz",
"integrity": "sha512-wdpOJ4XBejprGn/xhd1i2XR8Dv1A25FJeIvR7syQhQlz9eXsv+06llcvcmBxlWVGv4C73QBsWA8kxvZozzNwiQ=="
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-4.0.2.tgz",
"integrity": "sha512-ucx2DmXTeZTsS4GPPUZCbULAN7kdPT1G+H49Y34JjbQ5ESc6OGhVxKvb1iKhr9v19ZB9OtnHwNnhUnNR/7Wteg=="
},
"min-document": {
"version": "2.19.0",
@@ -272,9 +272,9 @@
}
},
"mobx-react": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/mobx-react/-/mobx-react-5.2.3.tgz",
"integrity": "sha512-OuSlF2nJEa1PGookZcZnINbvEK4iWNNYiqUh6aebk2AkWxj3sG8OafDOQMcMYApQALTHRsrBIjOx/K8TFxcz7w==",
"version": "5.2.6",
"resolved": "https://registry.npmjs.org/mobx-react/-/mobx-react-5.2.6.tgz",
"integrity": "sha512-AGo3m/ICzN2SEbtNi8ZdF1ShDcAOnEKonZFc3mm8uuF2obDXg6rXqV5mtkr9ZHPYizGp51kT/vRg0TlGzok+CA==",
"requires": {
"hoist-non-react-statics": "^2.5.0",
"react-lifecycles-compat": "^3.0.2"
@@ -300,17 +300,17 @@
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"ono": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/ono/-/ono-4.0.5.tgz",
"integrity": "sha512-ZVNuV9kJbr/2tWs83I2snrYo+WIS0DISF/xUfX9p9b6GyDD6F5N9PzHjW+p/dep6IGwSYylf1HCub5I/nM0R5Q==",
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/ono/-/ono-4.0.7.tgz",
"integrity": "sha512-FJiGEETwfSVyOwVTwQZD7XN69FRekvgtlobtvPwtilc7PxIHg3gKUykdNP7E9mC/VTF2cxqKZxUZfNKA3MuQLA==",
"requires": {
"format-util": "^1.0.3"
}
},
"openapi-sampler": {
"version": "1.0.0-beta.13",
"resolved": "https://registry.npmjs.org/openapi-sampler/-/openapi-sampler-1.0.0-beta.13.tgz",
"integrity": "sha512-NReKJh92NlUmY9CDo86L1Skkx3DMDeWmiLoqMxQSX7xBpoSx8WJ1JdTb7nEwz6M7S+WDPrQsEfS5BaIW27nMrQ==",
"version": "1.0.0-beta.14",
"resolved": "https://registry.npmjs.org/openapi-sampler/-/openapi-sampler-1.0.0-beta.14.tgz",
"integrity": "sha512-NNmH9YAN5AaCE4w6MQXdCrmsOJJQTswHVSp075+h+iiG+OTonpZE8HzwocozovD2imx4lamkuxGLs4E4bO4Z+g==",
"requires": {
"json-pointer": "^0.6.0"
}
@@ -361,17 +361,17 @@
}
},
"react-dropdown": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/react-dropdown/-/react-dropdown-1.5.0.tgz",
"integrity": "sha512-rRv3a7NiP++yC1rzdjzkviC5ujq759i4SRa0M3C0Cr7loYT4Z3+JhSPekv1/04JiZNXX46cV3/g6A9kS7rkI4Q==",
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/react-dropdown/-/react-dropdown-1.6.2.tgz",
"integrity": "sha512-6RpKAFEVZLr53y91qnxC9rAWcoDvq8A9YstmeSV2AQgJxNFRcsreN1mJNRUctSvIwm0Hph07ouMvDc2GvfQBsA==",
"requires": {
"classnames": "^2.2.3"
}
},
"react-hot-loader": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/react-hot-loader/-/react-hot-loader-4.3.4.tgz",
"integrity": "sha512-LlKjtHq+RhDq9xm6crXojbkzrEvli5F4/RaeJ//XtDWrwwsAHDjEqKfZZiPCxv7gWV2cxE3YE8TXeE9BDzLqOA==",
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/react-hot-loader/-/react-hot-loader-4.3.6.tgz",
"integrity": "sha512-iuBeBkLz7tdkKmKduNww9o5JY4ZH1XI0TWwkWToHIqfOSh1xMCqLMSYXUasWfgZWykWWa9IkueYab+cDq2jyWg==",
"requires": {
"fast-levenshtein": "^2.0.6",
"global": "^4.3.0",
@@ -382,9 +382,9 @@
}
},
"react-is": {
"version": "16.4.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.4.2.tgz",
"integrity": "sha512-rI3cGFj/obHbBz156PvErrS5xc6f1eWyTwyV4mo0vF2lGgXgS+mm7EKD5buLJq6jNgIagQescGSVG2YzgXt8Yg=="
"version": "16.5.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.5.0.tgz",
"integrity": "sha512-kpkCGLsChXTEQJVmowQqHpCjHKJFwB4SIChYaaaiAkq8OtE2aBg5pQe8/xnFlGmz9KmMx1H4oQRUyxP7qC9v5A=="
},
"react-lifecycles-compat": {
"version": "3.0.4",
@@ -392,41 +392,41 @@
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
},
"react-tabs": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/react-tabs/-/react-tabs-2.2.2.tgz",
"integrity": "sha512-jZGAAoq1yknr/XF60/2kH5X3UJdR1X8ItcsLZ1mJnHfoniKcCr3shT2TK5wiS2sO0LOmqwX2BtJQX3snKd50sg==",
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/react-tabs/-/react-tabs-2.3.0.tgz",
"integrity": "sha512-pYaefgVy76/36AMEP+B8YuVVzDHa3C5UFZ3REU78zolk0qMxEhKvUFofvDCXyLZwf0RZjxIfiwok1BEb18nHyA==",
"requires": {
"classnames": "^2.2.0",
"prop-types": "^15.5.0"
}
},
"redoc": {
"version": "2.0.0-alpha.32",
"resolved": "https://registry.npmjs.org/redoc/-/redoc-2.0.0-alpha.32.tgz",
"integrity": "sha512-hqQlQ8lnXszLOJGyrRCLtCH+yPJfS22FjbqJ9X6/KM3U46UXk7rv3jZG/quV0IIRhcyehRm6h8a6Eu18KRupng==",
"version": "2.0.0-alpha.37",
"resolved": "https://registry.npmjs.org/redoc/-/redoc-2.0.0-alpha.37.tgz",
"integrity": "sha512-yuT8sTT+oNzg8G9PfsUhu8Jhd9rWYJCTSQnbgaq9KzAFcJ2O0XfvlstkGXDK1zmtSSBBe5cy9Z/1XcQGDiGYug==",
"requires": {
"classnames": "^2.2.6",
"decko": "^1.2.0",
"dompurify": "^1.0.6",
"dompurify": "^1.0.7",
"eventemitter3": "^3.0.0",
"json-pointer": "^0.6.0",
"json-schema-ref-parser": "^5.1.1",
"lunr": "^2.3.0",
"json-schema-ref-parser": "^5.1.2",
"lunr": "^2.3.2",
"mark.js": "^8.11.1",
"marked": "0.3.18",
"memoize-one": "^4.0.0",
"mobx-react": "^5.2.3",
"openapi-sampler": "1.0.0-beta.13",
"mobx-react": "^5.2.5",
"openapi-sampler": "1.0.0-beta.14",
"perfect-scrollbar": "^1.4.0",
"polished": "^1.9.3",
"prismjs": "^1.15.0",
"prop-types": "^15.6.2",
"react-dropdown": "^1.3.0",
"react-hot-loader": "^4.3.3",
"react-dropdown": "^1.6.1",
"react-hot-loader": "^4.3.4",
"react-tabs": "^2.0.0",
"slugify": "^1.2.1",
"slugify": "^1.3.1",
"stickyfill": "^1.1.1",
"styled-components": "^3.3.3",
"styled-components": "^3.4.2",
"tslib": "^1.9.3"
}
},
@@ -452,9 +452,9 @@
"integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ=="
},
"slugify": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/slugify/-/slugify-1.3.0.tgz",
"integrity": "sha512-vvz+9ANt7CtdTHwJpfrsHOnGkgxky+CUPnvtzDZBZYFo/H/CdZkd5lJL7z7RqtH/x9QW/ItYYfHlcGf38CBK1w=="
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/slugify/-/slugify-1.3.1.tgz",
"integrity": "sha512-6BwyhjF5tG5P8s+0DPNyJmBSBePG6iMyhjvIW5zGdA3tFik9PtK+yNkZgTeiroCRGZYgkHftFA62tGVK1EI9Kw=="
},
"sprintf-js": {
"version": "1.0.3",
@@ -467,9 +467,9 @@
"integrity": "sha1-OUE/7p0CXHSn5ZzuyyN4TMDxfwI="
},
"styled-components": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/styled-components/-/styled-components-3.4.0.tgz",
"integrity": "sha1-0lb7RmfmwRWn7WGrePEgKDtD3QA=",
"version": "3.4.5",
"resolved": "https://registry.npmjs.org/styled-components/-/styled-components-3.4.5.tgz",
"integrity": "sha512-/4c4/72+QAZ8LO+VIzTcitdjMcJleOln1laK9HZr166O+OmGpKZYt3+hRn0YhYPytwDGfx9J5c7WhU7Oys+nSw==",
"requires": {
"buffer": "^5.0.3",
"css-to-react-native": "^2.0.3",
@@ -501,9 +501,9 @@
}
},
"swagger-ui-dist": {
"version": "3.18.0",
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.18.0.tgz",
"integrity": "sha512-AwFwmd9pf4XJb/IwLvpZ6Bl6wDhjidwjgBiqGv3/kXHp1hbVWi5ZKGSwKjdJ9att6MDJFhgp0+Dvd/Zqb7uySA=="
"version": "3.18.2",
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.18.2.tgz",
"integrity": "sha512-pWAEiKkgWUJvjmLW9AojudnutJ+NTn5g6OdNLj1iIJWwCkoy40K3Upwa24DqFbmIE4vLX4XplND61hp2L+s5vg=="
},
"tiny-emitter": {
"version": "2.0.2",
+2 -2
View File
@@ -1,8 +1,8 @@
{
"name": "drf-yasg",
"dependencies": {
"redoc": "^2.0.0-alpha.32",
"swagger-ui-dist": "^3.18.0"
"redoc": "^2.0.0-alpha.37",
"swagger-ui-dist": "^3.18.2"
},
"repository": {
"type": "git",
-2
View File
@@ -1,9 +1,7 @@
coreapi>=2.3.3
coreschema>=0.0.4
openapi_codec>=1.3.2
ruamel.yaml>=0.15.34
inflection>=0.3.1
future>=0.16.0
six>=1.10.0
uritemplate>=3.0.0
+2
View File
@@ -2,3 +2,5 @@
-r tox.txt
-r test.txt
-r lint.txt
tox-battery>=0.5
-1
View File
@@ -1,5 +1,4 @@
# requirements for building and running tox
tox>=3.1.2
tox-battery>=0.5
-r setup.txt
+5 -1
View File
@@ -40,6 +40,7 @@ SWAGGER_DEFAULTS = {
'SECURITY_REQUIREMENTS': None,
'LOGIN_URL': getattr(settings, 'LOGIN_URL', None),
'LOGOUT_URL': getattr(settings, 'LOGOUT_URL', None),
'SPEC_URL': None,
'VALIDATOR_URL': '',
'OPERATIONS_SORTER': None,
@@ -65,10 +66,13 @@ SWAGGER_DEFAULTS = {
}
REDOC_DEFAULTS = {
'LAZY_RENDERING': True,
'SPEC_URL': None,
'LAZY_RENDERING': False,
'HIDE_HOSTNAME': False,
'EXPAND_RESPONSES': 'all',
'PATH_IN_MIDDLE': False,
'NATIVE_SCROLLBARS': False,
'REQUIRED_PROPS_FIRST': False,
}
IMPORT_STRINGS = [
+1 -1
View File
@@ -1,4 +1,4 @@
from future.utils import raise_from
from six import raise_from
import copy
import json
+1 -1
View File
@@ -134,7 +134,7 @@ class EndpointEnumerator(_EndpointEnumerator):
"""Remove backslashe escapes from all path components outside {parameters}. This is needed because
``simplify_regex`` does not handle this correctly - note however that this implementation is
**NOTE:** this might destructively affect some url regex patterns that contain metacharacters (e.g. \w, \d)
**NOTE:** this might destructively affect some url regex patterns that contain metacharacters (e.g. \\w, \\d)
outside path parameter groups; if you are in this category, God help you
:param str path: path possibly containing
+2 -2
View File
@@ -258,7 +258,7 @@ class SerializerInspector(FieldInspector):
return NotHandled
def get_request_parameters(self, serializer, in_):
"""Convert a DRF serializer into a list of :class:`.Parameter`\ s.
"""Convert a DRF serializer into a list of :class:`.Parameter`\\ s.
Should return :data:`.NotHandled` if this inspector does not know how to handle the given `serializer`.
@@ -372,7 +372,7 @@ class ViewInspector(BaseInspector):
)
def serializer_to_parameters(self, serializer, in_):
"""Convert a serializer to a possibly empty list of :class:`.Parameter`\ s.
"""Convert a serializer to a possibly empty list of :class:`.Parameter`\\ s.
:param serializers.BaseSerializer serializer: the ``Serializer`` instance
:param str in_: the location of the parameters, one of the `openapi.IN_*` constants
+14 -4
View File
@@ -5,6 +5,7 @@ import operator
import uuid
from collections import OrderedDict
from decimal import Decimal
from inspect import isclass
from django.core import validators
from django.db import models
@@ -118,6 +119,8 @@ class InlineSerializerInspector(SerializerInspector):
definitions = self.components.with_scope(openapi.SCHEMA_DEFINITIONS)
actual_schema = definitions.setdefault(ref_name, make_schema_definition)
actual_schema._remove_read_only()
actual_serializer = get_serializer_class(getattr(actual_schema, '_serializer', None))
this_serializer = get_serializer_class(field)
if actual_serializer and actual_serializer != this_serializer: # pragma: no cover
@@ -194,7 +197,7 @@ def get_related_model(model, source):
class RelatedFieldInspector(FieldInspector):
"""Provides conversions for ``RelatedField``\ s."""
"""Provides conversions for ``RelatedField``\\ s."""
def field_to_swagger_object(self, field, swagger_object_type, use_references, **kwargs):
SwaggerType, ChildSwaggerType = self._get_partial_types(field, swagger_object_type, use_references, **kwargs)
@@ -259,7 +262,12 @@ def find_regex(regex_field):
regex_validator = validator
# regex_validator.regex should be a compiled re object...
pattern = getattr(getattr(regex_validator, 'regex', None), 'pattern', None)
try:
pattern = getattr(getattr(regex_validator, 'regex', None), 'pattern', None)
except Exception: # pragma: no cover
logger.warning('failed to compile regex validator of ' + str(regex_field), exc_info=True)
return None
if pattern:
# attempt some basic cleanup to remove regex constructs not supported by JavaScript
# -- swagger uses javascript-style regexes - see https://github.com/swagger-api/swagger-editor/issues/1601
@@ -509,7 +517,9 @@ class SerializerMethodFieldInspector(FieldInspector):
# look for Python 3.5+ style type hinting of the return value
hint_class = inspect.signature(method).return_annotation
if not issubclass(hint_class, inspect._empty):
if not isclass(hint_class) and hasattr(hint_class, '__args__'):
hint_class = hint_class.__args__[0]
if isclass(hint_class) and not issubclass(hint_class, inspect._empty):
type_info = get_basic_type_info_from_hint(hint_class)
if type_info is not None:
@@ -568,7 +578,7 @@ class ChoiceFieldInspector(FieldInspector):
class FileFieldInspector(FieldInspector):
"""Provides conversions for ``FileField``\ s."""
"""Provides conversions for ``FileField``\\ s."""
def field_to_swagger_object(self, field, swagger_object_type, use_references, **kwargs):
SwaggerType, ChildSwaggerType = self._get_partial_types(field, swagger_object_type, use_references, **kwargs)
+2 -3
View File
@@ -3,14 +3,13 @@ from collections import OrderedDict
import coreschema
from rest_framework.pagination import CursorPagination, LimitOffsetPagination, PageNumberPagination
from drf_yasg.utils import force_real_str
from .. import openapi
from ..utils import force_real_str
from .base import FilterInspector, PaginatorInspector
class CoreAPICompatInspector(PaginatorInspector, FilterInspector):
"""Converts ``coreapi.Field``\ s to :class:`.openapi.Parameter`\ s for filters and paginators that implement a
"""Converts ``coreapi.Field``\\ s to :class:`.openapi.Parameter`\\ s for filters and paginators that implement a
``get_schema_fields`` method.
"""
+12 -7
View File
@@ -63,7 +63,7 @@ class SwaggerAutoSchema(ViewInspector):
- a list of primitive Parameters parsed as form data
:param list[str] consumes: a list of accepted MIME types as returned by :meth:`.get_consumes`
:return: a (potentially empty) list of :class:`.Parameter`\ s either ``in: body`` or ``in: formData``
:return: a (potentially empty) list of :class:`.Parameter`\\ s either ``in: body`` or ``in: formData``
:rtype: list[openapi.Parameter]
"""
serializer = self.get_request_serializer()
@@ -106,7 +106,7 @@ class SwaggerAutoSchema(ViewInspector):
if body_override is not None:
if body_override is no_body:
return None
return no_body
if self.method not in self.body_methods:
raise SwaggerGenerationError("request_body can only be applied to (" + ','.join(self.body_methods) +
"); are you looking for query_serializer or manual_parameters?")
@@ -126,10 +126,13 @@ class SwaggerAutoSchema(ViewInspector):
if body_override is None and self.method in self.implicit_body_methods:
return self.get_view_serializer()
if body_override is no_body:
return None
return body_override
def get_request_form_parameters(self, serializer):
"""Given a Serializer, return a list of ``in: formData`` :class:`.Parameter`\ s.
"""Given a Serializer, return a list of ``in: formData`` :class:`.Parameter`\\ s.
:param serializer: the view's request serializer as returned by :meth:`.get_request_serializer`
:rtype: list[openapi.Parameter]
@@ -192,7 +195,11 @@ class SwaggerAutoSchema(ViewInspector):
:return: response serializer, :class:`.Schema`, :class:`.SchemaRef`, ``None``
"""
return self._get_request_body_override() or self.get_view_serializer()
body_override = self._get_request_body_override()
if body_override and body_override is not no_body:
return body_override
return self.get_view_serializer()
def get_default_responses(self):
"""Get the default responses determined for this view from the request serializer and request method.
@@ -207,8 +214,6 @@ class SwaggerAutoSchema(ViewInspector):
default_schema = self.get_default_response_serializer()
default_schema = default_schema or ''
if any(is_form_media_type(encoding) for encoding in self.get_consumes()):
default_schema = ''
if default_schema and not isinstance(default_schema, openapi.Schema):
default_schema = self.serializer_to_schema(default_schema) or ''
@@ -223,7 +228,7 @@ class SwaggerAutoSchema(ViewInspector):
def get_response_serializers(self):
"""Return the response codes that this view is expected to return, and the serializer for each response body.
The return value should be a dict where the keys are possible status codes, and values are either strings,
``Serializer``\ s, :class:`.Schema`, :class:`.SchemaRef` or :class:`.Response` objects. See
``Serializer``\\ s, :class:`.Schema`, :class:`.SchemaRef` or :class:`.Response` objects. See
:func:`@swagger_auto_schema <.swagger_auto_schema>` for more details.
:return: the response serializers
+16 -7
View File
@@ -387,8 +387,6 @@ class Parameter(SwaggerDict):
:param default: default value if the parameter is not provided; must conform to parameter type
"""
super(Parameter, self).__init__(**extra)
if (not schema and not type) or (schema and type):
raise AssertionError("either schema or type are required for Parameter object!")
self.name = name
self.in_ = in_
self.description = description
@@ -401,6 +399,10 @@ class Parameter(SwaggerDict):
self.items = items
self.default = default
self._insert_extras__()
if (not schema and not type) or (schema and type):
raise AssertionError("either schema or type are required for Parameter object (not both)!")
if schema and isinstance(schema, Schema):
schema._remove_read_only()
if self['in'] == IN_PATH:
# path parameters must always be required
assert required is not False, "path parameter cannot be optional"
@@ -432,9 +434,9 @@ class Schema(SwaggerDict):
:param bool,.Schema,.SchemaRef additional_properties: allow wildcard properties not listed in `properties`
:param list[str] required: list of requried property names
:param .Schema,.SchemaRef items: type of array items, only valid if `type` is ``array``
:param default: only valid when insider another ``Schema``\ 's ``properties``;
:param default: only valid when insider another ``Schema``\\ 's ``properties``;
the default value of this property if it is not provided, must conform to the type of this Schema
:param read_only: only valid when insider another ``Schema``\ 's ``properties``;
:param read_only: only valid when insider another ``Schema``\\ 's ``properties``;
declares the property as read only - it must only be sent as part of responses, never in requests
"""
super(Schema, self).__init__(**extra)
@@ -465,6 +467,11 @@ class Schema(SwaggerDict):
if pattern and type != TYPE_STRING:
raise AssertionError("pattern can only be used when type is string")
def _remove_read_only(self):
# readOnly is only valid for Schemas inside another Schema's properties;
# when placing Schema elsewhere we must take care to remove the readOnly flag
self.pop('readOnly', '')
class _Ref(SwaggerDict):
ref_name_re = re.compile(r"#/(?P<scope>.+)/(?P<name>[^/]+)$")
@@ -497,12 +504,12 @@ class _Ref(SwaggerDict):
ref_match = self.ref_name_re.match(self.ref)
return resolver.get(ref_match.group('name'), scope=ref_match.group('scope'))
def __setitem__(self, key, value, **kwargs):
def __setitem__(self, key, value):
if key == "$ref":
return super(_Ref, self).__setitem__(key, value, **kwargs)
return super(_Ref, self).__setitem__(key, value)
raise NotImplementedError("only $ref can be set on Reference objects (not %s)" % key)
def __delitem__(self, key, **kwargs):
def __delitem__(self, key):
raise NotImplementedError("cannot delete property of Reference object")
@@ -560,6 +567,8 @@ class Response(SwaggerDict):
self.schema = schema
self.examples = examples
self._insert_extras__()
if schema and isinstance(schema, Schema):
schema._remove_read_only()
class ReferenceResolver(object):
+70 -39
View File
@@ -1,11 +1,15 @@
import warnings
import six
from django.shortcuts import render, resolve_url
from rest_framework.renderers import BaseRenderer, JSONRenderer, TemplateHTMLRenderer
from rest_framework.utils import json
from drf_yasg.openapi import Swagger
from .app_settings import redoc_settings, swagger_settings
from .codecs import VALIDATORS, OpenAPICodecJson, OpenAPICodecYaml
from .openapi import Swagger
from .utils import filter_none
class _SpecRenderer(BaseRenderer):
@@ -74,23 +78,52 @@ class _UIRenderer(BaseRenderer):
def set_context(self, renderer_context, swagger):
renderer_context['title'] = swagger.info.title
renderer_context['version'] = swagger.info.version
renderer_context['swagger_settings'] = json.dumps(self.get_swagger_ui_settings())
renderer_context['redoc_settings'] = json.dumps(self.get_redoc_settings())
renderer_context['oauth2_config'] = json.dumps(self.get_oauth2_config())
renderer_context['USE_SESSION_AUTH'] = swagger_settings.USE_SESSION_AUTH
renderer_context.update(self.get_auth_urls())
def get_auth_urls(self):
urls = {}
if swagger_settings.LOGIN_URL is not None:
urls['LOGIN_URL'] = resolve_url(swagger_settings.LOGIN_URL)
if swagger_settings.LOGOUT_URL is not None:
urls['LOGOUT_URL'] = resolve_url(swagger_settings.LOGOUT_URL)
def resolve_url(self, to):
if to is None:
return None
return urls
args, kwargs = None, None
if not isinstance(to, six.string_types):
if len(to) > 2:
to, args, kwargs = to
elif len(to) == 2:
to, kwargs = to
args = args or ()
kwargs = kwargs or {}
return resolve_url(to, *args, **kwargs)
def get_auth_urls(self):
urls = {
'LOGIN_URL': self.resolve_url(swagger_settings.LOGIN_URL),
'LOGOUT_URL': self.resolve_url(swagger_settings.LOGOUT_URL),
}
return filter_none(urls)
def get_oauth2_config(self):
data = swagger_settings.OAUTH2_CONFIG
assert isinstance(data, dict), "OAUTH2_CONFIG must be a dict"
return data
class SwaggerUIRenderer(_UIRenderer):
"""Renders a swagger-ui web interface for schema browisng."""
template = 'drf-yasg/swagger-ui.html'
format = 'swagger'
def set_context(self, renderer_context, swagger):
super(SwaggerUIRenderer, self).set_context(renderer_context, swagger)
renderer_context['swagger_settings'] = json.dumps(self.get_swagger_ui_settings())
def get_swagger_ui_settings(self):
data = {
'url': self.resolve_url(swagger_settings.SPEC_URL),
'operationsSorter': swagger_settings.OPERATIONS_SORTER,
'tagsSorter': swagger_settings.TAGS_SORTER,
'docExpansion': swagger_settings.DOC_EXPANSION,
@@ -103,39 +136,37 @@ class _UIRenderer(BaseRenderer):
'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}
data = filter_none(data)
if swagger_settings.VALIDATOR_URL != '':
data['validatorUrl'] = swagger_settings.VALIDATOR_URL
data['validatorUrl'] = self.resolve_url(swagger_settings.VALIDATOR_URL)
return data
def get_redoc_settings(self):
data = {
'lazyRendering': redoc_settings.LAZY_RENDERING,
'hideHostname': redoc_settings.HIDE_HOSTNAME,
'expandResponses': redoc_settings.EXPAND_RESPONSES,
'pathInMiddle': redoc_settings.PATH_IN_MIDDLE,
}
return data
def get_oauth2_config(self):
data = swagger_settings.OAUTH2_CONFIG
assert isinstance(data, dict), "OAUTH2_CONFIG must be a dict"
return data
class SwaggerUIRenderer(_UIRenderer):
"""Renders a swagger-ui web interface for schema browisng.
Also requires :class:`.OpenAPIRenderer` as an available renderer on the same view.
"""
template = 'drf-yasg/swagger-ui.html'
format = 'swagger'
class ReDocRenderer(_UIRenderer):
"""Renders a ReDoc web interface for schema browisng.
Also requires :class:`.OpenAPIRenderer` as an available renderer on the same view.
"""
"""Renders a ReDoc web interface for schema browisng."""
template = 'drf-yasg/redoc.html'
format = 'redoc'
def set_context(self, renderer_context, swagger):
super(ReDocRenderer, self).set_context(renderer_context, swagger)
renderer_context['redoc_settings'] = json.dumps(self.get_redoc_settings())
def get_redoc_settings(self):
data = {
'url': self.resolve_url(redoc_settings.SPEC_URL),
'lazyRendering': redoc_settings.LAZY_RENDERING,
'hideHostname': redoc_settings.HIDE_HOSTNAME,
'expandResponses': redoc_settings.EXPAND_RESPONSES,
'pathInMiddlePanel': redoc_settings.PATH_IN_MIDDLE,
'nativeScrollbars': redoc_settings.NATIVE_SCROLLBARS,
'requiredPropsFirst': redoc_settings.REQUIRED_PROPS_FIRST,
}
return filter_none(data)
class ReDocOldRenderer(ReDocRenderer):
"""Renders a ReDoc 1.x.x web interface for schema browisng."""
template = 'drf-yasg/redoc-old.html'
+15 -8
View File
@@ -3,19 +3,26 @@
var currentPath = window.location.protocol + "//" + window.location.host + window.location.pathname;
var specURL = currentPath + '?format=openapi';
var redoc = document.createElement("redoc");
redoc.setAttribute("spec-url", specURL);
var redocSettings = JSON.parse(document.getElementById('redoc-settings').innerHTML);
if (redocSettings.lazyRendering) {
redoc.setAttribute("lazy-rendering", '');
if (redocSettings.url) {
specURL = redocSettings.url;
delete redocSettings.url;
}
if (redocSettings.pathInMiddle) {
redoc.setAttribute("path-in-middle-panel", '');
redoc.setAttribute("spec-url", specURL);
function camelToKebab(str) {
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
}
if (redocSettings.hideHostname) {
redoc.setAttribute("hide-hostname", '');
for (var p in redocSettings) {
if (redocSettings.hasOwnProperty(p)) {
if (redocSettings[p] !== null && redocSettings[p] !== undefined && redocSettings[p] !== false) {
redoc.setAttribute(camelToKebab(p), redocSettings[p].toString());
}
}
}
redoc.setAttribute("expand-responses", redocSettings.expandResponses);
document.body.appendChild(redoc);
function hideEmptyVersion() {
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-4
View File
@@ -19,10 +19,6 @@ body.swagger-body {
background: #fafafa;
}
#django-session-auth {
margin-right: 8px;
}
.hidden {
display: none;
}
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
@@ -6,6 +6,11 @@ function patchSwaggerUi() {
var authWrapper = document.querySelector('.auth-wrapper');
var authorizeButton = document.querySelector('.auth-wrapper .authorize');
var djangoSessionAuth = document.querySelector('#django-session-auth');
if (!djangoSessionAuth) {
console.log("WARNING: session auth disabled");
return;
}
if (document.querySelector('.auth-wrapper #django-session-auth')) {
console.log("WARNING: session auth already patched; skipping patchSwaggerUi()");
return;
@@ -57,7 +62,7 @@ function initSwaggerUi() {
}
}
console.log(swaggerSettings);
console.log('swaggerSettings', swaggerSettings);
for (var p in swaggerSettings) {
if (swaggerSettings.hasOwnProperty(p)) {
swaggerConfig[p] = swaggerSettings[p];
@@ -66,7 +71,7 @@ function initSwaggerUi() {
window.ui = SwaggerUIBundle(swaggerConfig);
var oauth2Config = JSON.parse(document.getElementById('oauth2-config').innerHTML);
console.log(oauth2Config);
console.log('oauth2Config', oauth2Config);
window.ui.initOAuth(oauth2Config);
}
@@ -0,0 +1,18 @@
{% load static %}
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="{% static 'drf-yasg/style.css' %}"/>
</head>
<body>
<script id="redoc-settings" type="application/json">{{ redoc_settings | safe }}</script>
<script src="{% static 'drf-yasg/insQ.min.js' %}"></script>
<script src="{% static 'drf-yasg/redoc-init.js' %}"> </script>
<script src="{% static 'drf-yasg/redoc-old/redoc.min.js' %}"></script>
</body>
</html>
+10 -4
View File
@@ -7,12 +7,18 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="{% static 'drf-yasg/style.css' %}"/>
{% block extra_styles %}
{# -- Add any additional CSS scripts here -- #}
{% endblock %}
</head>
<body>
<script id="redoc-settings" type="application/json">{{ redoc_settings | safe }}</script>
<script id="redoc-settings" type="application/json">{{ redoc_settings | safe }}</script>
<script src="{% static 'drf-yasg/insQ.min.js' %}"></script>
<script src="{% static 'drf-yasg/redoc-init.js' %}"> </script>
<script src="{% static 'drf-yasg/redoc/redoc.min.js' %}"></script>
<script src="{% static 'drf-yasg/insQ.min.js' %}"></script>
<script src="{% static 'drf-yasg/redoc-init.js' %}"></script>
<script src="{% static 'drf-yasg/redoc/redoc.min.js' %}"></script>
{% block extra_scripts %}
{# -- Add any additional scripts here -- #}
{% endblock %}
</body>
</html>
+24 -53
View File
@@ -11,53 +11,14 @@
<link rel="stylesheet" type="text/css" href="{% static 'drf-yasg/swagger-ui-dist/swagger-ui.css' %}">
<link rel="icon" type="image/png" href="{% static 'drf-yasg/swagger-ui-dist/favicon-32x32.png' %}" sizes="32x32"/>
<link rel="icon" type="image/png" href="{% static 'drf-yasg/swagger-ui-dist/favicon-16x16.png' %}" sizes="16x16"/>
{% block extra_styles %}
{# -- Add any additional CSS scripts here -- #}
{% endblock %}
</head>
<body class="swagger-body">
<svg class="swagger-defs" xmlns="http://www.w3.org/2000/svg">
<defs>
<symbol viewBox="0 0 20 20" id="unlocked">
<path
d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V6h2v-.801C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8z"></path>
</symbol>
<symbol viewBox="0 0 20 20" id="locked">
<path
d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8zM12 8H8V5.199C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8z"></path>
</symbol>
<symbol viewBox="0 0 20 20" id="close">
<path
d="M14.348 14.849c-.469.469-1.229.469-1.697 0L10 11.819l-2.651 3.029c-.469.469-1.229.469-1.697 0-.469-.469-.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-.469-.469-.469-1.228 0-1.697.469-.469 1.228-.469 1.697 0L10 8.183l2.651-3.031c.469-.469 1.228-.469 1.697 0 .469.469.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c.469.469.469 1.229 0 1.698z"></path>
</symbol>
<symbol viewBox="0 0 20 20" id="large-arrow">
<path
d="M13.25 10L6.109 2.58c-.268-.27-.268-.707 0-.979.268-.27.701-.27.969 0l7.83 7.908c.268.271.268.709 0 .979l-7.83 7.908c-.268.271-.701.27-.969 0-.268-.269-.268-.707 0-.979L13.25 10z"></path>
</symbol>
<symbol viewBox="0 0 20 20" id="large-arrow-down">
<path
d="M17.418 6.109c.272-.268.709-.268.979 0s.271.701 0 .969l-7.908 7.83c-.27.268-.707.268-.979 0l-7.908-7.83c-.27-.268-.27-.701 0-.969.271-.268.709-.268.979 0L10 13.25l7.418-7.141z"></path>
</symbol>
<symbol viewBox="0 0 24 24" id="jump-to">
<path d="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z"></path>
</symbol>
<symbol viewBox="0 0 24 24" id="expand">
<path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"></path>
</symbol>
</defs>
</svg>
<div id="swagger-ui"></div>
<div id="spec-error" class="hidden alert alert-danger"></div>
<script id="swagger-settings" type="application/json">{{ swagger_settings | safe }}</script>
<script id="oauth2-config" type="application/json">{{ oauth2_config | safe }}</script>
@@ -66,33 +27,43 @@
<script src="{% static 'drf-yasg/swagger-ui-dist/swagger-ui-standalone-preset.js' %}"></script>
<script src="{% static 'drf-yasg/insQ.min.js' %}"></script>
<script src="{% static 'drf-yasg/swagger-ui-init.js' %}"></script>
{% block extra_scripts %}
{# -- Add any additional scripts here -- #}
{% endblock %}
<a id="oauth2-redirect-url" href="{% static 'drf-yasg/swagger-ui-dist/oauth2-redirect.html' %}" class="hidden"></a>
<div id="django-session-auth" class="hidden">
{% if USE_SESSION_AUTH %}
{% if USE_SESSION_AUTH %}
<div id="django-session-auth" class="hidden">
{% csrf_token %}
{% if request.user.is_authenticated %}
<div class="hello">
<span class="django-session">Django</span> <span class="label label-primary">{{ request.user }}</span>
</div>
{% endif %}
{% block user_context_message %}
{% if request.user.is_authenticated %}
<div class="hello">
<span class="django-session">Django</span> <span class="label label-primary">{{ request.user }}</span>
</div>
{% endif %}
{% endblock %}
{% if request.user.is_authenticated %}
<div class='btn authorize'>
<a id="auth" class="header__btn" href="{{ LOGOUT_URL }}?next={{ request.path }}" data-sw-translate>
Django Logout
{% block django_logout_message %}
Django Logout
{% endblock %}
</a>
</div>
{% else %}
<div class='btn authorize'>
<a id="auth" class="header__btn" href="{{ LOGIN_URL }}?next={{ request.path }}" data-sw-translate>
Django Login
{% block django_login_message %}
Django Login
{% endblock %}
</a>
</div>
{% endif %}
{% endif %}
</div>
</div>
{% endif %}
</body>
</html>
+7 -5
View File
@@ -11,7 +11,7 @@ from rest_framework.settings import api_settings as rest_framework_settings
from rest_framework.utils import encoders, json
from rest_framework.views import APIView
from drf_yasg.app_settings import swagger_settings
from .app_settings import swagger_settings
logger = logging.getLogger(__name__)
@@ -50,7 +50,7 @@ def swagger_auto_schema(method=None, methods=None, auto_schema=unset, request_bo
the `manual_parameters` argument.
If a ``Serializer`` class or instance is given, it will be automatically converted into a :class:`.Schema`
used as a ``body`` :class:`.Parameter`, or into a list of ``form`` :class:`.Parameter`\ s, as appropriate.
used as a ``body`` :class:`.Parameter`, or into a list of ``form`` :class:`.Parameter`\\ s, as appropriate.
:param .Serializer query_serializer: if you use a ``Serializer`` to parse query parameters, you can pass it here
and have :class:`.Parameter` objects be generated automatically from it.
@@ -63,7 +63,7 @@ def swagger_auto_schema(method=None, methods=None, auto_schema=unset, request_bo
:param list[.Parameter] manual_parameters: a list of manual parameters to override the automatically generated ones
:class:`.Parameter`\ s are identified by their (``name``, ``in``) combination, and any parameters given
:class:`.Parameter`\\ s are identified by their (``name``, ``in``) combination, and any parameters given
here will fully override automatically generated parameters if they collide.
It is an error to supply ``form`` parameters when the request does not consume form-data.
@@ -107,6 +107,8 @@ def swagger_auto_schema(method=None, methods=None, auto_schema=unset, request_bo
'query_serializer': query_serializer,
'manual_parameters': manual_parameters,
'operation_id': operation_id,
'operation_summary': operation_summary,
'deprecated': deprecated,
'operation_description': operation_description,
'security': security,
'responses': responses,
@@ -120,7 +122,7 @@ def swagger_auto_schema(method=None, methods=None, auto_schema=unset, request_bo
data.update(extra_overrides)
if not data: # pragma: no cover
# no overrides to set, no use in doing more work
return
return view_method
# if the method is an @action, it will have a bind_to_methods attribute, or a mapping attribute for drf>3.8
bind_to_methods = getattr(view_method, 'bind_to_methods', [])
@@ -402,7 +404,7 @@ def get_field_default(field):
"called; 'default' will not be set on schema", field, exc_info=True)
default = serializers.empty
if default is not serializers.empty:
if default is not serializers.empty and default is not None:
try:
default = field.to_representation(default)
# JSON roundtrip ensures that the value is valid JSON;
+10 -5
View File
@@ -11,12 +11,15 @@ from rest_framework.settings import api_settings
from rest_framework.views import APIView
from .app_settings import swagger_settings
from .renderers import OpenAPIRenderer, ReDocRenderer, SwaggerJSONRenderer, SwaggerUIRenderer, SwaggerYAMLRenderer
from .renderers import (
OpenAPIRenderer, ReDocOldRenderer, ReDocRenderer, SwaggerJSONRenderer, SwaggerUIRenderer, SwaggerYAMLRenderer
)
SPEC_RENDERERS = (SwaggerYAMLRenderer, SwaggerJSONRenderer, OpenAPIRenderer)
UI_RENDERERS = {
'swagger': (SwaggerUIRenderer, ReDocRenderer),
'redoc': (ReDocRenderer, SwaggerUIRenderer),
'redoc-old': (ReDocOldRenderer, ReDocRenderer, SwaggerUIRenderer),
}
@@ -45,9 +48,7 @@ def deferred_never_cache(view_func):
def get_schema_view(info=None, url=None, patterns=None, urlconf=None, public=False, validators=None,
generator_class=swagger_settings.DEFAULT_GENERATOR_CLASS,
authentication_classes=api_settings.DEFAULT_AUTHENTICATION_CLASSES,
permission_classes=api_settings.DEFAULT_PERMISSION_CLASSES):
generator_class=None, authentication_classes=None, permission_classes=None):
"""Create a SchemaView class with default renderers and generators.
:param .Info info: information about the API; if omitted, defaults to :ref:`DEFAULT_INFO <default-swagger-settings>`
@@ -63,9 +64,13 @@ def get_schema_view(info=None, url=None, patterns=None, urlconf=None, public=Fal
:rtype: type[.SchemaView]
"""
_public = public
_generator_class = generator_class
_generator_class = generator_class or swagger_settings.DEFAULT_GENERATOR_CLASS
_auth_classes = authentication_classes
if _auth_classes is None:
_auth_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
_perm_classes = permission_classes
if _perm_classes is None:
_perm_classes = api_settings.DEFAULT_PERMISSION_CLASSES
info = info or swagger_settings.DEFAULT_INFO
validators = validators or []
_spec_renderers = tuple(renderer.with_validators(validators) for renderer in SPEC_RENDERERS)
+4 -2
View File
@@ -15,7 +15,7 @@ from articles.models import Article
from drf_yasg import openapi
from drf_yasg.app_settings import swagger_settings
from drf_yasg.inspectors import CoreAPICompatInspector, FieldInspector, NotHandled, SwaggerAutoSchema
from drf_yasg.utils import swagger_auto_schema
from drf_yasg.utils import no_body, swagger_auto_schema
class DjangoFilterDescriptionInspector(CoreAPICompatInspector):
@@ -133,11 +133,13 @@ class ArticleViewSet(viewsets.ModelViewSet):
"""
pass
@swagger_auto_schema(request_body=no_body, operation_id='no_body_test')
def update(self, request, *args, **kwargs):
"""update method docstring"""
return super(ArticleViewSet, self).update(request, *args, **kwargs)
@swagger_auto_schema(operation_description="partial_update description override", responses={404: 'slug not found'})
@swagger_auto_schema(operation_description="partial_update description override", responses={404: 'slug not found'},
operation_summary='partial_update summary', deprecated=True)
def partial_update(self, request, *args, **kwargs):
"""partial_update method docstring"""
return super(ArticleViewSet, self).partial_update(request, *args, **kwargs)
+4
View File
@@ -108,6 +108,10 @@ SWAGGER_SETTINGS = {
}
}
REDOC_SETTINGS = {
'SPEC_URL': ('schema-json', {'format': '.json'}),
}
# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/
+1
View File
@@ -51,6 +51,7 @@ urlpatterns = [
url(r'^swagger(?P<format>.json|.yaml)$', SchemaView.without_ui(cache_timeout=0), name='schema-json'),
url(r'^swagger/$', SchemaView.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
url(r'^redoc/$', SchemaView.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
url(r'^redoc-old/$', SchemaView.with_ui('redoc-old', cache_timeout=0), name='schema-redoc-old'),
url(r'^cached/swagger(?P<format>.json|.yaml)$', SchemaView.without_ui(cache_timeout=None), name='cschema-json'),
url(r'^cached/swagger/$', SchemaView.with_ui('swagger', cache_timeout=None), name='cschema-swagger-ui'),
+2 -2
View File
@@ -6,7 +6,7 @@ from rest_framework.response import Response
from rest_framework.views import APIView
from drf_yasg import openapi
from drf_yasg.utils import no_body, swagger_auto_schema
from drf_yasg.utils import swagger_auto_schema
from users.serializers import UserListQuerySerializer, UserSerializerrr
@@ -36,7 +36,7 @@ class UserList(APIView):
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
@swagger_auto_schema(request_body=no_body, operation_id="users_dummy", operation_description="dummy operation")
@swagger_auto_schema(operation_id="users_dummy", operation_description="dummy operation")
def patch(self, request):
pass
+34 -8
View File
@@ -134,14 +134,9 @@ paths:
tags:
- articles
put:
operationId: articles_update
operationId: no_body_test
description: update method docstring
parameters:
- name: data
in: body
required: true
schema:
$ref: '#/definitions/Article'
parameters: []
responses:
'200':
description: ''
@@ -151,6 +146,7 @@ paths:
- articles
patch:
operationId: articles_partial_update
summary: partial_update summary
description: partial_update description override
parameters:
- name: data
@@ -167,6 +163,7 @@ paths:
description: slug not found
tags:
- articles
deprecated: true
delete:
operationId: articles_delete
description: destroy method docstring
@@ -192,6 +189,8 @@ paths:
responses:
'200':
description: ''
schema:
$ref: '#/definitions/Article'
consumes:
- multipart/form-data
tags:
@@ -228,6 +227,8 @@ paths:
responses:
'201':
description: ''
schema:
$ref: '#/definitions/ImageUpload'
consumes:
- multipart/form-data
tags:
@@ -890,6 +891,32 @@ definitions:
type: string
format: uuid
readOnly: true
ImageUpload:
required:
- image_styles
type: object
properties:
what_am_i_doing:
description: test
type: string
pattern: ^69$
default: '69'
minLength: 1
image_styles:
description: Parameter with Items
type: array
items:
type: string
enum:
- wide
- tall
- thumb
- social
upload:
description: image serializer help_text
type: string
readOnly: true
format: uri
Identity:
title: Identity
type: object
@@ -1599,7 +1626,6 @@ definitions:
title: Foo
type: string
minLength: 1
readOnly: true
MethodFieldExample:
title: Hint example
type: object
+2 -2
View File
@@ -25,8 +25,8 @@ def test_validator_url(swagger_settings, swagger):
swagger_settings['VALIDATOR_URL'] = None
_check_swagger_setting(swagger, 'validatorUrl', None)
swagger_settings['VALIDATOR_URL'] = 'not none'
_check_swagger_setting(swagger, 'validatorUrl', 'not none')
swagger_settings['VALIDATOR_URL'] = 'http://not.none/'
_check_swagger_setting(swagger, 'validatorUrl', 'http://not.none/')
with pytest.raises(KeyError):
swagger_settings['VALIDATOR_URL'] = ''
+4 -7
View File
@@ -1,12 +1,9 @@
[tox]
# https://docs.djangoproject.com/en/dev/faq/install/#what-python-version-can-i-use-with-django
envlist =
py{27,34,35,36}-django111-drf37,
py{27,34,35,36}-django111-drf38,
py{34,35,36,37}-django20-drf37,
py{34,35,36,37}-django20-drf38,
py{35,36,37}-django21-drf37,
py{35,36,37}-django21-drf38,
py{27,34,35,36}-django111-drf{37,38},
py{34,35,36,37}-django20-drf{37,38},
py{35,36,37}-django21-drf{37,38},
djmaster, lint, docs
[testenv]
@@ -63,7 +60,7 @@ not_skip = __init__.py
atomic = true
multi_line_output = 5
line_length = 120
known_future_library = future,six
known_future_library = six
known_standard_library =
collections,copy,distutils,functools,inspect,io,json,logging,operator,os,pkg_resources,re,setuptools,sys,
types,warnings
+2
View File
@@ -3,6 +3,8 @@ set -ev
npm update
cp node_modules/redoc/bundles/redoc.standalone.js src/drf_yasg/static/drf-yasg/redoc/redoc.min.js
wget https://rebilly.github.io/ReDoc/releases/v1.x.x/redoc.min.js -O src/drf_yasg/static/drf-yasg/redoc-old/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