Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bc931677dc | |||
| 1904b0499e | |||
| 1e380fe68b | |||
| 6417bb3770 | |||
| e9f27442fc | |||
| cf8b912c10 | |||
| 3a37c4a019 | |||
| 8acab171ea | |||
| acc204e4ea | |||
| 1635e5e095 | |||
| 753be1a8bd | |||
| 2656696a0f | |||
| a083d3cf7c | |||
| eed8a8d3ec | |||
| d04f27f40f | |||
| db154d196a | |||
| 60e1346150 | |||
| 69b628a7af | |||
| 64d9d42aa9 | |||
| e9d5344de3 | |||
| b5aba7243d | |||
| 91ef83e830 | |||
| 0991c806c7 | |||
| 59e86ff72f |
@@ -3,6 +3,7 @@ testproj/db.sqlite3
|
|||||||
testproj/staticfiles
|
testproj/staticfiles
|
||||||
\.pytest_cache/
|
\.pytest_cache/
|
||||||
docs/\.doctrees/
|
docs/\.doctrees/
|
||||||
|
pip-wheel-metadata/
|
||||||
|
|
||||||
# Created by .ignore support plugin (hsz.mobi)
|
# Created by .ignore support plugin (hsz.mobi)
|
||||||
### Python template
|
### Python template
|
||||||
|
|||||||
Generated
+2
-1
@@ -19,6 +19,7 @@
|
|||||||
<excludeFolder url="file://$MODULE_DIR$/.cache" />
|
<excludeFolder url="file://$MODULE_DIR$/.cache" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/.eggs" />
|
<excludeFolder url="file://$MODULE_DIR$/.eggs" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/.pytest_cache" />
|
<excludeFolder url="file://$MODULE_DIR$/.pytest_cache" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.tox" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/dist" />
|
<excludeFolder url="file://$MODULE_DIR$/dist" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/docs/.doctrees" />
|
<excludeFolder url="file://$MODULE_DIR$/docs/.doctrees" />
|
||||||
@@ -44,4 +45,4 @@
|
|||||||
<option name="projectConfiguration" value="pytest" />
|
<option name="projectConfiguration" value="pytest" />
|
||||||
<option name="PROJECT_TEST_RUNNER" value="pytest" />
|
<option name="PROJECT_TEST_RUNNER" value="pytest" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
language: python
|
language: python
|
||||||
python:
|
python:
|
||||||
- '2.7'
|
- '2.7'
|
||||||
- '3.4'
|
|
||||||
- '3.5'
|
- '3.5'
|
||||||
- '3.6'
|
- '3.6'
|
||||||
- '3.7'
|
- '3.7'
|
||||||
|
|||||||
+1
-1
@@ -95,7 +95,7 @@ You want to contribute some code? Great! Here are a few steps to get you started
|
|||||||
|
|
||||||
#. **Your code must pass all the required travis jobs before it is merged**
|
#. **Your code must pass all the required travis jobs before it is merged**
|
||||||
|
|
||||||
As of now, this consists of running on Python 2.7, 3.4, 3.5 and 3.6, and building the docs succesfully.
|
As of now, this consists of running on Python 2.7, 3.5, 3.6 and 3.7, and building the docs succesfully.
|
||||||
|
|
||||||
******************
|
******************
|
||||||
Maintainer's notes
|
Maintainer's notes
|
||||||
|
|||||||
+4
-4
@@ -13,9 +13,9 @@ Generate **real** Swagger/OpenAPI 2.0 specifications from a Django Rest Framewor
|
|||||||
|
|
||||||
Compatible with
|
Compatible with
|
||||||
|
|
||||||
- **Django Rest Framework**: 3.7.7, 3.8, 3.9
|
- **Django Rest Framework**: 3.8, 3.9
|
||||||
- **Django**: 1.11, 2.0, 2.1
|
- **Django**: 1.11, 2.1, 2.2
|
||||||
- **Python**: 2.7, 3.4, 3.5, 3.6, 3.7
|
- **Python**: 2.7, 3.5, 3.6, 3.7
|
||||||
|
|
||||||
Only the latest patch version of each ``major.minor`` series of Python, Django and Django REST Framework is supported.
|
Only the latest patch version of each ``major.minor`` series of Python, Django and Django REST Framework is supported.
|
||||||
|
|
||||||
@@ -235,7 +235,7 @@ Offline
|
|||||||
^^^^^^^
|
^^^^^^^
|
||||||
|
|
||||||
If your schema is not accessible from the internet, you can run a local copy of
|
If your schema is not accessible from the internet, you can run a local copy of
|
||||||
`swagger-validator <https://hub.docker.com/r/swaggerapi/swagger-validator/>`_ and set the `VALIDATOR_URL` accordingly:
|
`swagger-validator <https://hub.docker.com/r/swaggerapi/swagger-validator/>`_ and set the ``VALIDATOR_URL`` accordingly:
|
||||||
|
|
||||||
.. code:: python
|
.. code:: python
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,38 @@ Changelog
|
|||||||
#########
|
#########
|
||||||
|
|
||||||
|
|
||||||
|
**********
|
||||||
|
**1.16.1**
|
||||||
|
**********
|
||||||
|
|
||||||
|
*Release date: Jul 16, 2019*
|
||||||
|
|
||||||
|
- **FIXED:** fixed DRF 3.10 compatibility (:pr:`408`, :issue:`410`, :issue:`411`)
|
||||||
|
- **IMPROVED:** better enum type detection for nested `ChoiceField`s (:pr:`400`)
|
||||||
|
|
||||||
|
**********
|
||||||
|
**1.16.0**
|
||||||
|
**********
|
||||||
|
|
||||||
|
*Release date: Jun 13, 2019*
|
||||||
|
|
||||||
|
- **ADDED:** added `reference_resolver_class` attribute hook to `SwaggerAutoSchema` (:pr:`350`)
|
||||||
|
- **ADDED:** added `operation_keys` attribute to `SwaggerAutoSchema`, along with `__init__` parameter (:pr:`355`)
|
||||||
|
- **FIXED:** fixed potential crash on `issubclass` check without `isclass` check
|
||||||
|
|
||||||
|
**********
|
||||||
|
**1.15.1**
|
||||||
|
**********
|
||||||
|
|
||||||
|
*Release date: Jun 13, 2019*
|
||||||
|
|
||||||
|
- **IMPROVED:** updated ``swagger-ui`` to version 3.22.3
|
||||||
|
- **IMPROVED:** updated ``ReDoc`` to version 2.0.0-rc.8-1
|
||||||
|
- **FIXED:** fixed an issue with inspection of typing hints on Python 2.7 (:issue:`363`)
|
||||||
|
- **FIXED:** fixed an issue with inspection of typing hints on Python 3.7 (:issue:`371`)
|
||||||
|
|
||||||
|
**Python 3.4 support has been dropped!**
|
||||||
|
|
||||||
**********
|
**********
|
||||||
**1.15.0**
|
**1.15.0**
|
||||||
**********
|
**********
|
||||||
|
|||||||
@@ -87,14 +87,14 @@ 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
|
* 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|
|
to decorate the *action methods*, i.e. ``list``, ``create``, ``retrieve``, etc. |br|
|
||||||
Additionally, ``@action``\ s, ``@list_route``\ s or ``@detail_route``\ s defined on the viewset, like function based
|
Additionally, ``@action``\ s defined on the viewset, like function based api views, can respond to multiple HTTP
|
||||||
api views, can respond to multiple HTTP methods and thus have multiple operations that must be decorated separately:
|
methods and thus have multiple operations that must be decorated separately:
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
class ArticleViewSet(viewsets.ModelViewSet):
|
class ArticleViewSet(viewsets.ModelViewSet):
|
||||||
# method or 'methods' can be skipped because the list_route only handles a single method (GET)
|
# method or 'methods' can be skipped because the action only handles a single method (GET)
|
||||||
@swagger_auto_schema(operation_description='GET /articles/today/')
|
@swagger_auto_schema(operation_description='GET /articles/today/')
|
||||||
@action(detail=False, methods=['get'])
|
@action(detail=False, methods=['get'])
|
||||||
def today(self, request):
|
def today(self, request):
|
||||||
|
|||||||
+2
-2
@@ -340,7 +340,7 @@ values for Parameters.
|
|||||||
OAUTH2_REDIRECT_URL
|
OAUTH2_REDIRECT_URL
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
Used when OAuth2 authenitcation of API requests via swagger-ui is desired. If ``None`` is passed, the
|
Used when OAuth2 authentication of API requests via swagger-ui is desired. If ``None`` is passed, the
|
||||||
``oauth2RedirectUrl`` parameter will be set to ``{% static 'drf-yasg/swagger-ui-dist/oauth2-redirect.html' %}``. This
|
``oauth2RedirectUrl`` parameter will be set to ``{% static 'drf-yasg/swagger-ui-dist/oauth2-redirect.html' %}``. This
|
||||||
is the default `https://github.com/swagger-api/swagger-ui/blob/master/dist/oauth2-redirect.html <oauth2-redirect>`_
|
is the default `https://github.com/swagger-api/swagger-ui/blob/master/dist/oauth2-redirect.html <oauth2-redirect>`_
|
||||||
file provided by ``swagger-ui``.
|
file provided by ``swagger-ui``.
|
||||||
@@ -351,7 +351,7 @@ file provided by ``swagger-ui``.
|
|||||||
OAUTH2_CONFIG
|
OAUTH2_CONFIG
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
Used when OAuth2 authenitcation of API requests via swagger-ui is desired. Provides OAuth2 configuration parameters
|
Used when OAuth2 authentication of API requests via swagger-ui is desired. Provides OAuth2 configuration parameters
|
||||||
to the ``SwaggerUIBundle#initOAuth`` method, and must be a dictionary. See
|
to the ``SwaggerUIBundle#initOAuth`` method, and must be a dictionary. See
|
||||||
`OAuth2 configuration <https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/oauth2.md>`_.
|
`OAuth2 configuration <https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/oauth2.md>`_.
|
||||||
|
|
||||||
|
|||||||
Generated
+203
-203
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "drf-yasg",
|
"name": "drf-yasg",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"redoc": "^2.0.0-rc.4",
|
"redoc": "^2.0.0-rc.8-1",
|
||||||
"swagger-ui-dist": "^3.22.0"
|
"swagger-ui-dist": "^3.22.3"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
@@ -5,5 +5,5 @@ inflection>=0.3.1
|
|||||||
six>=1.10.0
|
six>=1.10.0
|
||||||
uritemplate>=3.0.0
|
uritemplate>=3.0.0
|
||||||
|
|
||||||
djangorestframework>=3.7.7
|
djangorestframework>=3.8
|
||||||
Django>=1.11.7
|
Django>=1.11.7
|
||||||
|
|||||||
@@ -5,5 +5,7 @@ pytest-cov>=2.6.0
|
|||||||
pytest-xdist>=1.25.0
|
pytest-xdist>=1.25.0
|
||||||
pytest-django>=3.4.4
|
pytest-django>=3.4.4
|
||||||
datadiff==2.0.0
|
datadiff==2.0.0
|
||||||
|
psycopg2-binary==2.8.3
|
||||||
|
django-fake-model==0.1.4
|
||||||
|
|
||||||
-r testproj.txt
|
-r testproj.txt
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
# test project requirements
|
# test project requirements
|
||||||
Pillow>=4.3.0
|
Pillow>=4.3.0
|
||||||
pygments>=2.2.0
|
|
||||||
django-cors-headers>=2.1.0
|
django-cors-headers>=2.1.0
|
||||||
django-filter>=1.1.0,<2.0; python_version == "2.7"
|
django-filter>=1.1.0,<2.0; python_version == "2.7"
|
||||||
django-filter>=1.1.0; python_version >= "3.4"
|
django-filter>=1.1.0; python_version >= "3.5"
|
||||||
djangorestframework-camel-case>=0.2.0
|
#djangorestframework-camel-case>=0.2.0
|
||||||
|
# tempory replacement of broken lib
|
||||||
|
-e git+https://github.com/tfranzel/djangorestframework-camel-case.git@bd556d38fa7382acadfe91d93d92d99c663248a9#egg=djangorestframework_camel_case
|
||||||
djangorestframework-recursive>=0.1.2
|
djangorestframework-recursive>=0.1.2
|
||||||
dj-database-url>=0.4.2
|
dj-database-url>=0.4.2
|
||||||
user_agents>=1.1.0
|
user_agents>=1.1.0
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
python-3.7.1
|
python-3.7.3
|
||||||
|
|||||||
@@ -19,6 +19,18 @@ with io.open('README.rst', encoding='utf-8') as readme:
|
|||||||
requirements = read_req('base.txt')
|
requirements = read_req('base.txt')
|
||||||
requirements_validation = read_req('validation.txt')
|
requirements_validation = read_req('validation.txt')
|
||||||
|
|
||||||
|
py3_supported_range = (5, 7)
|
||||||
|
|
||||||
|
# convert inclusive range to exclusive range
|
||||||
|
py3_supported_range = (py3_supported_range[0], py3_supported_range[1] + 1)
|
||||||
|
python_requires = ", ".join([">=2.7"] + ["!=3.{}.*".format(v) for v in range(0, py3_supported_range[0])])
|
||||||
|
python_classifiers = [
|
||||||
|
'Programming Language :: Python',
|
||||||
|
'Programming Language :: Python :: 2',
|
||||||
|
'Programming Language :: Python :: 2.7',
|
||||||
|
'Programming Language :: Python :: 3',
|
||||||
|
] + ['Programming Language :: Python :: 3.{}'.format(v) for v in range(*py3_supported_range)]
|
||||||
|
|
||||||
|
|
||||||
def drf_yasg_setup(**kwargs):
|
def drf_yasg_setup(**kwargs):
|
||||||
setup(
|
setup(
|
||||||
@@ -38,28 +50,21 @@ def drf_yasg_setup(**kwargs):
|
|||||||
author_email='cristi@cvjd.me',
|
author_email='cristi@cvjd.me',
|
||||||
keywords='drf django django-rest-framework schema swagger openapi codegen swagger-codegen '
|
keywords='drf django django-rest-framework schema swagger openapi codegen swagger-codegen '
|
||||||
'documentation drf-yasg django-rest-swagger drf-openapi',
|
'documentation drf-yasg django-rest-swagger drf-openapi',
|
||||||
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*",
|
python_requires=python_requires,
|
||||||
classifiers=[
|
classifiers=[
|
||||||
'Intended Audience :: Developers',
|
'Intended Audience :: Developers',
|
||||||
'License :: OSI Approved :: BSD License',
|
'License :: OSI Approved :: BSD License',
|
||||||
'Development Status :: 5 - Production/Stable',
|
'Development Status :: 5 - Production/Stable',
|
||||||
'Operating System :: OS Independent',
|
'Operating System :: OS Independent',
|
||||||
'Environment :: Web Environment',
|
'Environment :: Web Environment',
|
||||||
'Programming Language :: Python',
|
|
||||||
'Programming Language :: Python :: 2',
|
|
||||||
'Programming Language :: Python :: 2.7',
|
|
||||||
'Programming Language :: Python :: 3',
|
|
||||||
'Programming Language :: Python :: 3.4',
|
|
||||||
'Programming Language :: Python :: 3.5',
|
|
||||||
'Programming Language :: Python :: 3.6',
|
|
||||||
'Programming Language :: Python :: 3.7',
|
|
||||||
'Framework :: Django',
|
'Framework :: Django',
|
||||||
'Framework :: Django :: 1.11',
|
'Framework :: Django :: 1.11',
|
||||||
'Framework :: Django :: 2.0',
|
'Framework :: Django :: 2.0',
|
||||||
'Framework :: Django :: 2.1',
|
'Framework :: Django :: 2.1',
|
||||||
|
'Framework :: Django :: 2.2',
|
||||||
'Topic :: Documentation',
|
'Topic :: Documentation',
|
||||||
'Topic :: Software Development :: Code Generators',
|
'Topic :: Software Development :: Code Generators',
|
||||||
],
|
] + python_classifiers,
|
||||||
**kwargs
|
**kwargs
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -4,14 +4,23 @@ import re
|
|||||||
from collections import OrderedDict, defaultdict
|
from collections import OrderedDict, defaultdict
|
||||||
|
|
||||||
import uritemplate
|
import uritemplate
|
||||||
|
import rest_framework
|
||||||
from coreapi.compat import urlparse
|
from coreapi.compat import urlparse
|
||||||
from rest_framework import versioning
|
from rest_framework import versioning
|
||||||
from rest_framework.compat import URLPattern, URLResolver, get_original_route
|
from rest_framework.compat import URLPattern, URLResolver, get_original_route
|
||||||
from rest_framework.schemas.generators import EndpointEnumerator as _EndpointEnumerator
|
from rest_framework.schemas.generators import EndpointEnumerator as _EndpointEnumerator
|
||||||
from rest_framework.schemas.generators import SchemaGenerator, endpoint_ordering, get_pk_name
|
from rest_framework.schemas.generators import endpoint_ordering, get_pk_name
|
||||||
from rest_framework.schemas.inspectors import get_pk_description
|
|
||||||
from rest_framework.settings import api_settings
|
from rest_framework.settings import api_settings
|
||||||
|
|
||||||
|
from packaging.version import Version
|
||||||
|
if Version(rest_framework.__version__) < Version('3.10'):
|
||||||
|
from rest_framework.schemas.generators import SchemaGenerator
|
||||||
|
from rest_framework.schemas.inspectors import get_pk_description
|
||||||
|
else:
|
||||||
|
from rest_framework.schemas import SchemaGenerator
|
||||||
|
from rest_framework.schemas.utils import get_pk_description
|
||||||
|
|
||||||
from . import openapi
|
from . import openapi
|
||||||
from .app_settings import swagger_settings
|
from .app_settings import swagger_settings
|
||||||
from .errors import SwaggerGenerationError
|
from .errors import SwaggerGenerationError
|
||||||
@@ -160,6 +169,7 @@ class OpenAPISchemaGenerator(object):
|
|||||||
Method implementations shamelessly stolen and adapted from rest-framework ``SchemaGenerator``.
|
Method implementations shamelessly stolen and adapted from rest-framework ``SchemaGenerator``.
|
||||||
"""
|
"""
|
||||||
endpoint_enumerator_class = EndpointEnumerator
|
endpoint_enumerator_class = EndpointEnumerator
|
||||||
|
reference_resolver_class = ReferenceResolver
|
||||||
|
|
||||||
def __init__(self, info, version='', url=None, patterns=None, urlconf=None):
|
def __init__(self, info, version='', url=None, patterns=None, urlconf=None):
|
||||||
"""
|
"""
|
||||||
@@ -238,7 +248,7 @@ class OpenAPISchemaGenerator(object):
|
|||||||
:rtype: openapi.Swagger
|
:rtype: openapi.Swagger
|
||||||
"""
|
"""
|
||||||
endpoints = self.get_endpoints(request)
|
endpoints = self.get_endpoints(request)
|
||||||
components = ReferenceResolver(openapi.SCHEMA_DEFINITIONS, force_init=True)
|
components = self.reference_resolver_class(openapi.SCHEMA_DEFINITIONS, force_init=True)
|
||||||
self.consumes = get_consumes(api_settings.DEFAULT_PARSER_CLASSES)
|
self.consumes = get_consumes(api_settings.DEFAULT_PARSER_CLASSES)
|
||||||
self.produces = get_produces(api_settings.DEFAULT_RENDERER_CLASSES)
|
self.produces = get_produces(api_settings.DEFAULT_RENDERER_CLASSES)
|
||||||
paths, prefix = self.get_paths(endpoints, components, request, public)
|
paths, prefix = self.get_paths(endpoints, components, request, public)
|
||||||
@@ -440,7 +450,7 @@ class OpenAPISchemaGenerator(object):
|
|||||||
if view_inspector_cls is None:
|
if view_inspector_cls is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
view_inspector = view_inspector_cls(view, path, method, components, request, overrides)
|
view_inspector = view_inspector_cls(view, path, method, components, request, overrides, operation_keys)
|
||||||
operation = view_inspector.get_operation(operation_keys)
|
operation = view_inspector.get_operation(operation_keys)
|
||||||
if operation is None:
|
if operation is None:
|
||||||
return None
|
return None
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import datetime
|
|||||||
import inspect
|
import inspect
|
||||||
import logging
|
import logging
|
||||||
import operator
|
import operator
|
||||||
|
import sys
|
||||||
import uuid
|
import uuid
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
@@ -489,6 +490,10 @@ hinting_type_info = [
|
|||||||
(datetime.date, (openapi.TYPE_STRING, openapi.FORMAT_DATE)),
|
(datetime.date, (openapi.TYPE_STRING, openapi.FORMAT_DATE)),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if sys.version_info < (3, 0):
|
||||||
|
# noinspection PyUnresolvedReferences
|
||||||
|
hinting_type_info.append((unicode, (openapi.TYPE_STRING, None))) # noqa: F821
|
||||||
|
|
||||||
if typing:
|
if typing:
|
||||||
def inspect_collection_hint_class(hint_class):
|
def inspect_collection_hint_class(hint_class):
|
||||||
args = hint_class.__args__
|
args = hint_class.__args__
|
||||||
@@ -527,11 +532,14 @@ def get_basic_type_info_from_hint(hint_class):
|
|||||||
:rtype: OrderedDict
|
:rtype: OrderedDict
|
||||||
"""
|
"""
|
||||||
union_types = _get_union_types(hint_class)
|
union_types = _get_union_types(hint_class)
|
||||||
|
|
||||||
if typing and union_types:
|
if typing and union_types:
|
||||||
# Optional is implemented as Union[T, None]
|
# Optional is implemented as Union[T, None]
|
||||||
if len(union_types) == 2 and isinstance(None, union_types[1]):
|
if len(union_types) == 2 and isinstance(None, union_types[1]):
|
||||||
result = get_basic_type_info_from_hint(union_types[0])
|
result = get_basic_type_info_from_hint(union_types[0])
|
||||||
result['x-nullable'] = True
|
if result:
|
||||||
|
result['x-nullable'] = True
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
return None
|
return None
|
||||||
@@ -602,8 +610,6 @@ class SerializerMethodFieldInspector(FieldInspector):
|
|||||||
# look for Python 3.5+ style type hinting of the return value
|
# look for Python 3.5+ style type hinting of the return value
|
||||||
hint_class = inspect_signature(method).return_annotation
|
hint_class = inspect_signature(method).return_annotation
|
||||||
|
|
||||||
if not inspect.isclass(hint_class) and hasattr(hint_class, '__args__'):
|
|
||||||
hint_class = hint_class.__args__[0]
|
|
||||||
if inspect.isclass(hint_class) and not issubclass(hint_class, inspect._empty):
|
if inspect.isclass(hint_class) and not issubclass(hint_class, inspect._empty):
|
||||||
type_info = get_basic_type_info_from_hint(hint_class)
|
type_info = get_basic_type_info_from_hint(hint_class)
|
||||||
|
|
||||||
@@ -650,7 +656,11 @@ class ChoiceFieldInspector(FieldInspector):
|
|||||||
serializer = get_parent_serializer(field)
|
serializer = get_parent_serializer(field)
|
||||||
if isinstance(serializer, serializers.ModelSerializer):
|
if isinstance(serializer, serializers.ModelSerializer):
|
||||||
model = getattr(getattr(serializer, 'Meta'), 'model')
|
model = getattr(getattr(serializer, 'Meta'), 'model')
|
||||||
model_field = get_model_field(model, field.source)
|
# Use the parent source for nested fields
|
||||||
|
model_field = get_model_field(model, field.source or field.parent.source)
|
||||||
|
# If the field has a base_field its type must be used
|
||||||
|
if getattr(model_field, "base_field", None):
|
||||||
|
model_field = model_field.base_field
|
||||||
if model_field:
|
if model_field:
|
||||||
model_type = get_basic_type_info(model_field)
|
model_type = get_basic_type_info(model_field)
|
||||||
if model_type:
|
if model_type:
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from .. import openapi
|
|||||||
from ..errors import SwaggerGenerationError
|
from ..errors import SwaggerGenerationError
|
||||||
from ..utils import (
|
from ..utils import (
|
||||||
filter_none, force_real_str, force_serializer_instance, get_consumes, get_produces, guess_response_status,
|
filter_none, force_real_str, force_serializer_instance, get_consumes, get_produces, guess_response_status,
|
||||||
is_list_view, merge_params, no_body, param_list_to_odict
|
merge_params, no_body, param_list_to_odict
|
||||||
)
|
)
|
||||||
from .base import ViewInspector, call_view_method
|
from .base import ViewInspector, call_view_method
|
||||||
|
|
||||||
@@ -17,12 +17,15 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class SwaggerAutoSchema(ViewInspector):
|
class SwaggerAutoSchema(ViewInspector):
|
||||||
def __init__(self, view, path, method, components, request, overrides):
|
def __init__(self, view, path, method, components, request, overrides, operation_keys=None):
|
||||||
super(SwaggerAutoSchema, self).__init__(view, path, method, components, request, overrides)
|
super(SwaggerAutoSchema, self).__init__(view, path, method, components, request, overrides)
|
||||||
self._sch = AutoSchema()
|
self._sch = AutoSchema()
|
||||||
self._sch.view = view
|
self._sch.view = view
|
||||||
|
self.operation_keys = operation_keys
|
||||||
|
|
||||||
|
def get_operation(self, operation_keys=None):
|
||||||
|
operation_keys = operation_keys or self.operation_keys
|
||||||
|
|
||||||
def get_operation(self, operation_keys):
|
|
||||||
consumes = self.get_consumes()
|
consumes = self.get_consumes()
|
||||||
produces = self.get_produces()
|
produces = self.get_produces()
|
||||||
|
|
||||||
@@ -300,7 +303,7 @@ class SwaggerAutoSchema(ViewInspector):
|
|||||||
|
|
||||||
return natural_parameters + serializer_parameters
|
return natural_parameters + serializer_parameters
|
||||||
|
|
||||||
def get_operation_id(self, operation_keys):
|
def get_operation_id(self, operation_keys=None):
|
||||||
"""Return an unique ID for this operation. The ID must be unique across
|
"""Return an unique ID for this operation. The ID must be unique across
|
||||||
all :class:`.Operation` objects in the API.
|
all :class:`.Operation` objects in the API.
|
||||||
|
|
||||||
@@ -308,6 +311,8 @@ class SwaggerAutoSchema(ViewInspector):
|
|||||||
of this view in the API; e.g. ``('snippets', 'list')``, ``('snippets', 'retrieve')``, etc.
|
of this view in the API; e.g. ``('snippets', 'list')``, ``('snippets', 'retrieve')``, etc.
|
||||||
:rtype: str
|
:rtype: str
|
||||||
"""
|
"""
|
||||||
|
operation_keys = operation_keys or self.operation_keys
|
||||||
|
|
||||||
operation_id = self.overrides.get('operation_id', '')
|
operation_id = self.overrides.get('operation_id', '')
|
||||||
if not operation_id:
|
if not operation_id:
|
||||||
operation_id = '_'.join(operation_keys)
|
operation_id = '_'.join(operation_keys)
|
||||||
@@ -369,7 +374,7 @@ class SwaggerAutoSchema(ViewInspector):
|
|||||||
"""
|
"""
|
||||||
return self.overrides.get('deprecated', None)
|
return self.overrides.get('deprecated', None)
|
||||||
|
|
||||||
def get_tags(self, operation_keys):
|
def get_tags(self, operation_keys=None):
|
||||||
"""Get a list of tags for this operation. Tags determine how operations relate with each other, and in the UI
|
"""Get a list of tags for this operation. Tags determine how operations relate with each other, and in the UI
|
||||||
each tag will show as a group containing the operations that use it. If not provided in overrides,
|
each tag will show as a group containing the operations that use it. If not provided in overrides,
|
||||||
tags will be inferred from the operation url.
|
tags will be inferred from the operation url.
|
||||||
@@ -378,6 +383,8 @@ class SwaggerAutoSchema(ViewInspector):
|
|||||||
of this view in the API; e.g. ``('snippets', 'list')``, ``('snippets', 'retrieve')``, etc.
|
of this view in the API; e.g. ``('snippets', 'list')``, ``('snippets', 'retrieve')``, etc.
|
||||||
:rtype: list[str]
|
:rtype: list[str]
|
||||||
"""
|
"""
|
||||||
|
operation_keys = operation_keys or self.operation_keys
|
||||||
|
|
||||||
tags = self.overrides.get('tags')
|
tags = self.overrides.get('tags')
|
||||||
if not tags:
|
if not tags:
|
||||||
tags = [operation_keys[0]]
|
tags = [operation_keys[0]]
|
||||||
|
|||||||
+14
-14
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
@@ -166,7 +166,7 @@ def swagger_auto_schema(method=None, methods=None, auto_schema=unset, request_bo
|
|||||||
|
|
||||||
if len(available_http_methods) > 1:
|
if len(available_http_methods) > 1:
|
||||||
assert _methods, \
|
assert _methods, \
|
||||||
"on multi-method api_view, action, detail_route or list_route, you must specify " \
|
"on multi-method api_view or action, you must specify " \
|
||||||
"swagger_auto_schema on a per-method basis using one of the `method` or `methods` arguments"
|
"swagger_auto_schema on a per-method basis using one of the `method` or `methods` arguments"
|
||||||
else:
|
else:
|
||||||
# for a single-method view we assume that single method as the decorator target
|
# for a single-method view we assume that single method as the decorator target
|
||||||
@@ -179,8 +179,8 @@ def swagger_auto_schema(method=None, methods=None, auto_schema=unset, request_bo
|
|||||||
view_method._swagger_auto_schema = existing_data
|
view_method._swagger_auto_schema = existing_data
|
||||||
else:
|
else:
|
||||||
assert not _methods, \
|
assert not _methods, \
|
||||||
"the methods argument should only be specified when decorating an action, detail_route or " \
|
"the methods argument should only be specified when decorating an action; " \
|
||||||
"list_route; you should also ensure that you put the swagger_auto_schema decorator " \
|
"you should also ensure that you put the swagger_auto_schema decorator " \
|
||||||
"AFTER (above) the _route decorator"
|
"AFTER (above) the _route decorator"
|
||||||
assert not existing_data, "swagger_auto_schema applied twice to method"
|
assert not existing_data, "swagger_auto_schema applied twice to method"
|
||||||
view_method._swagger_auto_schema = data
|
view_method._swagger_auto_schema = data
|
||||||
@@ -215,7 +215,7 @@ def is_list_view(path, method, view):
|
|||||||
:param APIView view: target view
|
:param APIView view: target view
|
||||||
:rtype: bool
|
:rtype: bool
|
||||||
"""
|
"""
|
||||||
# for ViewSets, it could be the default 'list' action, or a list_route
|
# for ViewSets, it could be the default 'list' action, or an @action(detail=False)
|
||||||
action = getattr(view, 'action', '')
|
action = getattr(view, 'action', '')
|
||||||
method = getattr(view, action, None) or method
|
method = getattr(view, action, None) or method
|
||||||
detail = getattr(method, 'detail', None)
|
detail = getattr(method, 'detail', None)
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import functools
|
|
||||||
|
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django_filters.rest_framework import DjangoFilterBackend
|
from django_filters.rest_framework import DjangoFilterBackend
|
||||||
from rest_framework import viewsets
|
from rest_framework import viewsets
|
||||||
# noinspection PyDeprecation
|
|
||||||
from rest_framework.filters import OrderingFilter
|
from rest_framework.filters import OrderingFilter
|
||||||
from rest_framework.pagination import LimitOffsetPagination
|
from rest_framework.pagination import LimitOffsetPagination
|
||||||
from rest_framework.parsers import FileUploadParser, MultiPartParser
|
from rest_framework.parsers import FileUploadParser, MultiPartParser
|
||||||
@@ -93,17 +91,10 @@ class ArticleViewSet(viewsets.ModelViewSet):
|
|||||||
|
|
||||||
swagger_schema = NoTitleAutoSchema
|
swagger_schema = NoTitleAutoSchema
|
||||||
|
|
||||||
try:
|
from rest_framework.decorators import action
|
||||||
from rest_framework.decorators import action
|
|
||||||
list_route = functools.partial(action, detail=False)
|
|
||||||
detail_route = functools.partial(action, detail=True)
|
|
||||||
except ImportError:
|
|
||||||
# TODO: remove when dropping support for DRF 3.7
|
|
||||||
action = None
|
|
||||||
from rest_framework.decorators import list_route, detail_route
|
|
||||||
|
|
||||||
@swagger_auto_schema(auto_schema=NoPagingAutoSchema, filter_inspectors=[DjangoFilterDescriptionInspector])
|
@swagger_auto_schema(auto_schema=NoPagingAutoSchema, filter_inspectors=[DjangoFilterDescriptionInspector])
|
||||||
@list_route(methods=['get'])
|
@action(detail=False, methods=['get'])
|
||||||
def today(self, request):
|
def today(self, request):
|
||||||
today_min = datetime.datetime.combine(datetime.date.today(), datetime.time.min)
|
today_min = datetime.datetime.combine(datetime.date.today(), datetime.time.min)
|
||||||
today_max = datetime.datetime.combine(datetime.date.today(), datetime.time.max)
|
today_max = datetime.datetime.combine(datetime.date.today(), datetime.time.max)
|
||||||
@@ -118,7 +109,7 @@ class ArticleViewSet(viewsets.ModelViewSet):
|
|||||||
type=openapi.TYPE_INTEGER,
|
type=openapi.TYPE_INTEGER,
|
||||||
description="this should not crash (form parameter on DELETE method)"
|
description="this should not crash (form parameter on DELETE method)"
|
||||||
)])
|
)])
|
||||||
@detail_route(methods=['get', 'post', 'delete'], parser_classes=(MultiPartParser, FileUploadParser))
|
@action(detail=True, methods=['get', 'post', 'delete'], parser_classes=(MultiPartParser, FileUploadParser))
|
||||||
def image(self, request, slug=None):
|
def image(self, request, slug=None):
|
||||||
"""
|
"""
|
||||||
image method docstring
|
image method docstring
|
||||||
|
|||||||
@@ -1,13 +1,19 @@
|
|||||||
from rest_framework import viewsets
|
from rest_framework import viewsets
|
||||||
|
from rest_framework.pagination import BasePagination
|
||||||
|
|
||||||
from .models import Identity, Person
|
from .models import Identity, Person
|
||||||
from .serializers import IdentitySerializer, PersonSerializer
|
from .serializers import IdentitySerializer, PersonSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class UnknownPagination(BasePagination):
|
||||||
|
paginator_query_args = ['unknown_paginator']
|
||||||
|
|
||||||
|
|
||||||
class PersonViewSet(viewsets.ModelViewSet):
|
class PersonViewSet(viewsets.ModelViewSet):
|
||||||
model = Person
|
model = Person
|
||||||
queryset = Person.objects
|
queryset = Person.objects
|
||||||
serializer_class = PersonSerializer
|
serializer_class = PersonSerializer
|
||||||
|
pagination_class = UnknownPagination
|
||||||
|
|
||||||
|
|
||||||
class IdentityViewSet(viewsets.ModelViewSet):
|
class IdentityViewSet(viewsets.ModelViewSet):
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 2.2.2 on 2019-06-12 22:54
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('snippets', '0003_snippetviewer'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='snippet',
|
||||||
|
name='language',
|
||||||
|
field=models.CharField(choices=[('cpp', 'cpp'), ('js', 'js'), ('python', 'python')], default='python', max_length=100),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='snippet',
|
||||||
|
name='style',
|
||||||
|
field=models.CharField(choices=[('monokai', 'monokai'), ('solarized-dark', 'solarized-dark'), ('vim', 'vim')], default='solarized-dark', max_length=100),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -1,10 +1,7 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from pygments.lexers import get_all_lexers
|
|
||||||
from pygments.styles import get_all_styles
|
|
||||||
|
|
||||||
LEXERS = [item for item in get_all_lexers() if item[1]]
|
LANGUAGE_CHOICES = sorted((item, item) for item in ('cpp', 'python', 'js'))
|
||||||
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
|
STYLE_CHOICES = sorted((item, item) for item in ('solarized-dark', 'monokai', 'vim'))
|
||||||
STYLE_CHOICES = sorted((item, item) for item in get_all_styles())
|
|
||||||
|
|
||||||
|
|
||||||
class Snippet(models.Model):
|
class Snippet(models.Model):
|
||||||
@@ -14,7 +11,7 @@ class Snippet(models.Model):
|
|||||||
code = models.TextField(help_text="code model help text")
|
code = models.TextField(help_text="code model help text")
|
||||||
linenos = models.BooleanField(default=False)
|
linenos = models.BooleanField(default=False)
|
||||||
language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)
|
language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)
|
||||||
style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)
|
style = models.CharField(choices=STYLE_CHOICES, default='solarized-dark', max_length=100)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('created',)
|
ordering = ('created',)
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
|
import rest_framework
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
|
from packaging.version import Version
|
||||||
|
if Version(rest_framework.__version__) < Version('3.10'):
|
||||||
|
from rest_framework.compat import MaxLengthValidator, MinValueValidator
|
||||||
|
else:
|
||||||
|
from django.core.validators import MaxLengthValidator, MinValueValidator
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.compat import MaxLengthValidator, MinValueValidator
|
|
||||||
|
|
||||||
from snippets.models import LANGUAGE_CHOICES, STYLE_CHOICES, Snippet, SnippetViewer
|
from snippets.models import LANGUAGE_CHOICES, STYLE_CHOICES, Snippet, SnippetViewer
|
||||||
|
|
||||||
@@ -17,7 +22,7 @@ class LanguageSerializer(serializers.Serializer):
|
|||||||
|
|
||||||
|
|
||||||
class ExampleProjectSerializer(serializers.Serializer):
|
class ExampleProjectSerializer(serializers.Serializer):
|
||||||
project_name = serializers.CharField(help_text='Name of the project')
|
project_name = serializers.CharField(label='project name custom title', help_text='Name of the project')
|
||||||
github_repo = serializers.CharField(required=True, help_text='Github repository of the project')
|
github_repo = serializers.CharField(required=True, help_text='Github repository of the project')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@@ -69,7 +74,7 @@ class SnippetSerializer(serializers.Serializer):
|
|||||||
tags = serializers.ListField(child=serializers.CharField(min_length=2), min_length=3, max_length=15)
|
tags = serializers.ListField(child=serializers.CharField(min_length=2), min_length=3, max_length=15)
|
||||||
linenos = serializers.BooleanField(required=False)
|
linenos = serializers.BooleanField(required=False)
|
||||||
language = LanguageSerializer(help_text="Sample help text for language")
|
language = LanguageSerializer(help_text="Sample help text for language")
|
||||||
styles = serializers.MultipleChoiceField(choices=STYLE_CHOICES, default=['friendly'])
|
styles = serializers.MultipleChoiceField(choices=STYLE_CHOICES, default=['solarized-dark'])
|
||||||
lines = serializers.ListField(child=serializers.IntegerField(), allow_empty=True, allow_null=True, required=False)
|
lines = serializers.ListField(child=serializers.IntegerField(), allow_empty=True, allow_null=True, required=False)
|
||||||
example_projects = serializers.ListSerializer(child=ExampleProjectSerializer(), read_only=True,
|
example_projects = serializers.ListSerializer(child=ExampleProjectSerializer(), read_only=True,
|
||||||
validators=[MaxLengthValidator(100)])
|
validators=[MaxLengthValidator(100)])
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
from drf_yasg import openapi
|
||||||
|
from drf_yasg.inspectors import NotHandled, PaginatorInspector
|
||||||
|
|
||||||
|
|
||||||
|
class UnknownPaginatorInspector(PaginatorInspector):
|
||||||
|
def get_paginator_parameters(self, paginator):
|
||||||
|
if hasattr(paginator, 'paginator_query_args'):
|
||||||
|
return [openapi.Parameter(name=arg, in_=openapi.IN_QUERY, type=openapi.TYPE_STRING)
|
||||||
|
for arg in getattr(paginator, 'paginator_query_args')]
|
||||||
|
|
||||||
|
return NotHandled
|
||||||
@@ -140,7 +140,12 @@ SWAGGER_SETTINGS = {
|
|||||||
'clientId': OAUTH2_CLIENT_ID,
|
'clientId': OAUTH2_CLIENT_ID,
|
||||||
'clientSecret': OAUTH2_CLIENT_SECRET,
|
'clientSecret': OAUTH2_CLIENT_SECRET,
|
||||||
'appName': OAUTH2_APP_NAME,
|
'appName': OAUTH2_APP_NAME,
|
||||||
}
|
},
|
||||||
|
"DEFAULT_PAGINATOR_INSPECTORS": [
|
||||||
|
'testproj.inspectors.UnknownPaginatorInspector',
|
||||||
|
'drf_yasg.inspectors.DjangoRestResponsePagination',
|
||||||
|
'drf_yasg.inspectors.CoreAPICompatInspector',
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
REDOC_SETTINGS = {
|
REDOC_SETTINGS = {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
@@ -6,7 +8,10 @@ from snippets.models import Snippet
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
import typing # noqa: F401
|
import typing # noqa: F401
|
||||||
from .method_serializers_with_typing import MethodFieldExampleSerializer
|
if sys.version_info >= (3, 4):
|
||||||
|
from .method_serializers_with_typing import MethodFieldExampleSerializer
|
||||||
|
else:
|
||||||
|
from .method_serializers_without_typing import MethodFieldExampleSerializer
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from .method_serializers_without_typing import MethodFieldExampleSerializer
|
from .method_serializers_without_typing import MethodFieldExampleSerializer
|
||||||
|
|
||||||
|
|||||||
+7
-464
@@ -276,7 +276,10 @@ paths:
|
|||||||
get:
|
get:
|
||||||
operationId: people_list
|
operationId: people_list
|
||||||
description: ''
|
description: ''
|
||||||
parameters: []
|
parameters:
|
||||||
|
- name: unknown_paginator
|
||||||
|
in: query
|
||||||
|
type: string
|
||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
description: ''
|
description: ''
|
||||||
@@ -1110,7 +1113,7 @@ definitions:
|
|||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
projectName:
|
projectName:
|
||||||
title: Project name
|
title: project name custom title
|
||||||
description: Name of the project
|
description: Name of the project
|
||||||
type: string
|
type: string
|
||||||
minLength: 1
|
minLength: 1
|
||||||
@@ -1176,443 +1179,9 @@ definitions:
|
|||||||
description: The name of the programming language
|
description: The name of the programming language
|
||||||
type: string
|
type: string
|
||||||
enum:
|
enum:
|
||||||
- abap
|
|
||||||
- abnf
|
|
||||||
- ada
|
|
||||||
- adl
|
|
||||||
- agda
|
|
||||||
- aheui
|
|
||||||
- ahk
|
|
||||||
- alloy
|
|
||||||
- ampl
|
|
||||||
- antlr
|
|
||||||
- antlr-as
|
|
||||||
- antlr-cpp
|
|
||||||
- antlr-csharp
|
|
||||||
- antlr-java
|
|
||||||
- antlr-objc
|
|
||||||
- antlr-perl
|
|
||||||
- antlr-python
|
|
||||||
- antlr-ruby
|
|
||||||
- apacheconf
|
|
||||||
- apl
|
|
||||||
- applescript
|
|
||||||
- arduino
|
|
||||||
- as
|
|
||||||
- as3
|
|
||||||
- aspectj
|
|
||||||
- aspx-cs
|
|
||||||
- aspx-vb
|
|
||||||
- asy
|
|
||||||
- at
|
|
||||||
- autoit
|
|
||||||
- awk
|
|
||||||
- basemake
|
|
||||||
- bash
|
|
||||||
- bat
|
|
||||||
- bbcode
|
|
||||||
- bc
|
|
||||||
- befunge
|
|
||||||
- bib
|
|
||||||
- blitzbasic
|
|
||||||
- blitzmax
|
|
||||||
- bnf
|
|
||||||
- boo
|
|
||||||
- boogie
|
|
||||||
- brainfuck
|
|
||||||
- bro
|
|
||||||
- bst
|
|
||||||
- bugs
|
|
||||||
- c
|
|
||||||
- c-objdump
|
|
||||||
- ca65
|
|
||||||
- cadl
|
|
||||||
- camkes
|
|
||||||
- capdl
|
|
||||||
- capnp
|
|
||||||
- cbmbas
|
|
||||||
- ceylon
|
|
||||||
- cfc
|
|
||||||
- cfengine3
|
|
||||||
- cfm
|
|
||||||
- cfs
|
|
||||||
- chai
|
|
||||||
- chapel
|
|
||||||
- cheetah
|
|
||||||
- cirru
|
|
||||||
- clay
|
|
||||||
- clean
|
|
||||||
- clojure
|
|
||||||
- clojurescript
|
|
||||||
- cmake
|
|
||||||
- cobol
|
|
||||||
- cobolfree
|
|
||||||
- coffee-script
|
|
||||||
- common-lisp
|
|
||||||
- componentpascal
|
|
||||||
- console
|
|
||||||
- control
|
|
||||||
- coq
|
|
||||||
- cpp
|
- cpp
|
||||||
- cpp-objdump
|
|
||||||
- cpsa
|
|
||||||
- cr
|
|
||||||
- crmsh
|
|
||||||
- croc
|
|
||||||
- cryptol
|
|
||||||
- csharp
|
|
||||||
- csound
|
|
||||||
- csound-document
|
|
||||||
- csound-score
|
|
||||||
- css
|
|
||||||
- css+django
|
|
||||||
- css+erb
|
|
||||||
- css+genshitext
|
|
||||||
- css+lasso
|
|
||||||
- css+mako
|
|
||||||
- css+mozpreproc
|
|
||||||
- css+myghty
|
|
||||||
- css+php
|
|
||||||
- css+smarty
|
|
||||||
- cucumber
|
|
||||||
- cuda
|
|
||||||
- cypher
|
|
||||||
- cython
|
|
||||||
- d
|
|
||||||
- d-objdump
|
|
||||||
- dart
|
|
||||||
- delphi
|
|
||||||
- dg
|
|
||||||
- diff
|
|
||||||
- django
|
|
||||||
- docker
|
|
||||||
- doscon
|
|
||||||
- dpatch
|
|
||||||
- dtd
|
|
||||||
- duel
|
|
||||||
- dylan
|
|
||||||
- dylan-console
|
|
||||||
- dylan-lid
|
|
||||||
- earl-grey
|
|
||||||
- easytrieve
|
|
||||||
- ebnf
|
|
||||||
- ec
|
|
||||||
- ecl
|
|
||||||
- eiffel
|
|
||||||
- elixir
|
|
||||||
- elm
|
|
||||||
- emacs
|
|
||||||
- erb
|
|
||||||
- erl
|
|
||||||
- erlang
|
|
||||||
- evoque
|
|
||||||
- extempore
|
|
||||||
- ezhil
|
|
||||||
- factor
|
|
||||||
- fan
|
|
||||||
- fancy
|
|
||||||
- felix
|
|
||||||
- fennel
|
|
||||||
- fish
|
|
||||||
- flatline
|
|
||||||
- forth
|
|
||||||
- fortran
|
|
||||||
- fortranfixed
|
|
||||||
- foxpro
|
|
||||||
- fsharp
|
|
||||||
- gap
|
|
||||||
- gas
|
|
||||||
- genshi
|
|
||||||
- genshitext
|
|
||||||
- glsl
|
|
||||||
- gnuplot
|
|
||||||
- go
|
|
||||||
- golo
|
|
||||||
- gooddata-cl
|
|
||||||
- gosu
|
|
||||||
- groff
|
|
||||||
- groovy
|
|
||||||
- gst
|
|
||||||
- haml
|
|
||||||
- handlebars
|
|
||||||
- haskell
|
|
||||||
- haxeml
|
|
||||||
- hexdump
|
|
||||||
- hlsl
|
|
||||||
- hsail
|
|
||||||
- html
|
|
||||||
- html+cheetah
|
|
||||||
- html+django
|
|
||||||
- html+evoque
|
|
||||||
- html+genshi
|
|
||||||
- html+handlebars
|
|
||||||
- html+lasso
|
|
||||||
- html+mako
|
|
||||||
- html+myghty
|
|
||||||
- html+ng2
|
|
||||||
- html+php
|
|
||||||
- html+smarty
|
|
||||||
- html+twig
|
|
||||||
- html+velocity
|
|
||||||
- http
|
|
||||||
- hx
|
|
||||||
- hybris
|
|
||||||
- hylang
|
|
||||||
- i6t
|
|
||||||
- idl
|
|
||||||
- idris
|
|
||||||
- iex
|
|
||||||
- igor
|
|
||||||
- inform6
|
|
||||||
- inform7
|
|
||||||
- ini
|
|
||||||
- io
|
|
||||||
- ioke
|
|
||||||
- irc
|
|
||||||
- isabelle
|
|
||||||
- j
|
|
||||||
- jags
|
|
||||||
- jasmin
|
|
||||||
- java
|
|
||||||
- javascript+mozpreproc
|
|
||||||
- jcl
|
|
||||||
- jlcon
|
|
||||||
- js
|
- js
|
||||||
- js+cheetah
|
|
||||||
- js+django
|
|
||||||
- js+erb
|
|
||||||
- js+genshitext
|
|
||||||
- js+lasso
|
|
||||||
- js+mako
|
|
||||||
- js+myghty
|
|
||||||
- js+php
|
|
||||||
- js+smarty
|
|
||||||
- jsgf
|
|
||||||
- json
|
|
||||||
- json-object
|
|
||||||
- jsonld
|
|
||||||
- jsp
|
|
||||||
- julia
|
|
||||||
- juttle
|
|
||||||
- kal
|
|
||||||
- kconfig
|
|
||||||
- koka
|
|
||||||
- kotlin
|
|
||||||
- lagda
|
|
||||||
- lasso
|
|
||||||
- lcry
|
|
||||||
- lean
|
|
||||||
- less
|
|
||||||
- lhs
|
|
||||||
- lidr
|
|
||||||
- lighty
|
|
||||||
- limbo
|
|
||||||
- liquid
|
|
||||||
- live-script
|
|
||||||
- llvm
|
|
||||||
- logos
|
|
||||||
- logtalk
|
|
||||||
- lsl
|
|
||||||
- lua
|
|
||||||
- make
|
|
||||||
- mako
|
|
||||||
- maql
|
|
||||||
- mask
|
|
||||||
- mason
|
|
||||||
- mathematica
|
|
||||||
- matlab
|
|
||||||
- matlabsession
|
|
||||||
- md
|
|
||||||
- minid
|
|
||||||
- modelica
|
|
||||||
- modula2
|
|
||||||
- monkey
|
|
||||||
- monte
|
|
||||||
- moocode
|
|
||||||
- moon
|
|
||||||
- mozhashpreproc
|
|
||||||
- mozpercentpreproc
|
|
||||||
- mql
|
|
||||||
- mscgen
|
|
||||||
- mupad
|
|
||||||
- mxml
|
|
||||||
- myghty
|
|
||||||
- mysql
|
|
||||||
- nasm
|
|
||||||
- ncl
|
|
||||||
- nemerle
|
|
||||||
- nesc
|
|
||||||
- newlisp
|
|
||||||
- newspeak
|
|
||||||
- ng2
|
|
||||||
- nginx
|
|
||||||
- nim
|
|
||||||
- nit
|
|
||||||
- nixos
|
|
||||||
- nsis
|
|
||||||
- numpy
|
|
||||||
- nusmv
|
|
||||||
- objdump
|
|
||||||
- objdump-nasm
|
|
||||||
- objective-c
|
|
||||||
- objective-c++
|
|
||||||
- objective-j
|
|
||||||
- ocaml
|
|
||||||
- octave
|
|
||||||
- odin
|
|
||||||
- ooc
|
|
||||||
- opa
|
|
||||||
- openedge
|
|
||||||
- pacmanconf
|
|
||||||
- pan
|
|
||||||
- parasail
|
|
||||||
- pawn
|
|
||||||
- perl
|
|
||||||
- perl6
|
|
||||||
- php
|
|
||||||
- pig
|
|
||||||
- pike
|
|
||||||
- pkgconfig
|
|
||||||
- plpgsql
|
|
||||||
- postgresql
|
|
||||||
- postscript
|
|
||||||
- pot
|
|
||||||
- pov
|
|
||||||
- powershell
|
|
||||||
- praat
|
|
||||||
- prolog
|
|
||||||
- properties
|
|
||||||
- protobuf
|
|
||||||
- ps1con
|
|
||||||
- psql
|
|
||||||
- pug
|
|
||||||
- puppet
|
|
||||||
- py3tb
|
|
||||||
- pycon
|
|
||||||
- pypylog
|
|
||||||
- pytb
|
|
||||||
- python
|
- python
|
||||||
- python3
|
|
||||||
- qbasic
|
|
||||||
- qml
|
|
||||||
- qvto
|
|
||||||
- racket
|
|
||||||
- ragel
|
|
||||||
- ragel-c
|
|
||||||
- ragel-cpp
|
|
||||||
- ragel-d
|
|
||||||
- ragel-em
|
|
||||||
- ragel-java
|
|
||||||
- ragel-objc
|
|
||||||
- ragel-ruby
|
|
||||||
- raw
|
|
||||||
- rb
|
|
||||||
- rbcon
|
|
||||||
- rconsole
|
|
||||||
- rd
|
|
||||||
- rebol
|
|
||||||
- red
|
|
||||||
- redcode
|
|
||||||
- registry
|
|
||||||
- resource
|
|
||||||
- rexx
|
|
||||||
- rhtml
|
|
||||||
- rnc
|
|
||||||
- roboconf-graph
|
|
||||||
- roboconf-instances
|
|
||||||
- robotframework
|
|
||||||
- rql
|
|
||||||
- rsl
|
|
||||||
- rst
|
|
||||||
- rts
|
|
||||||
- rust
|
|
||||||
- sas
|
|
||||||
- sass
|
|
||||||
- sc
|
|
||||||
- scala
|
|
||||||
- scaml
|
|
||||||
- scheme
|
|
||||||
- scilab
|
|
||||||
- scss
|
|
||||||
- shen
|
|
||||||
- silver
|
|
||||||
- slim
|
|
||||||
- smali
|
|
||||||
- smalltalk
|
|
||||||
- smarty
|
|
||||||
- sml
|
|
||||||
- snobol
|
|
||||||
- snowball
|
|
||||||
- sourceslist
|
|
||||||
- sp
|
|
||||||
- sparql
|
|
||||||
- spec
|
|
||||||
- splus
|
|
||||||
- sql
|
|
||||||
- sqlite3
|
|
||||||
- squidconf
|
|
||||||
- ssp
|
|
||||||
- stan
|
|
||||||
- stata
|
|
||||||
- swift
|
|
||||||
- swig
|
|
||||||
- systemverilog
|
|
||||||
- tads3
|
|
||||||
- tap
|
|
||||||
- tasm
|
|
||||||
- tcl
|
|
||||||
- tcsh
|
|
||||||
- tcshcon
|
|
||||||
- tea
|
|
||||||
- termcap
|
|
||||||
- terminfo
|
|
||||||
- terraform
|
|
||||||
- tex
|
|
||||||
- text
|
|
||||||
- thrift
|
|
||||||
- todotxt
|
|
||||||
- trac-wiki
|
|
||||||
- treetop
|
|
||||||
- ts
|
|
||||||
- tsql
|
|
||||||
- turtle
|
|
||||||
- twig
|
|
||||||
- typoscript
|
|
||||||
- typoscriptcssdata
|
|
||||||
- typoscripthtmldata
|
|
||||||
- urbiscript
|
|
||||||
- vala
|
|
||||||
- vb.net
|
|
||||||
- vcl
|
|
||||||
- vclsnippets
|
|
||||||
- vctreestatus
|
|
||||||
- velocity
|
|
||||||
- verilog
|
|
||||||
- vgl
|
|
||||||
- vhdl
|
|
||||||
- vim
|
|
||||||
- wdiff
|
|
||||||
- whiley
|
|
||||||
- x10
|
|
||||||
- xml
|
|
||||||
- xml+cheetah
|
|
||||||
- xml+django
|
|
||||||
- xml+erb
|
|
||||||
- xml+evoque
|
|
||||||
- xml+lasso
|
|
||||||
- xml+mako
|
|
||||||
- xml+myghty
|
|
||||||
- xml+php
|
|
||||||
- xml+smarty
|
|
||||||
- xml+velocity
|
|
||||||
- xorg.conf
|
|
||||||
- xquery
|
|
||||||
- xslt
|
|
||||||
- xtend
|
|
||||||
- xul+mozpreproc
|
|
||||||
- yaml
|
|
||||||
- yaml+jinja
|
|
||||||
- zephir
|
|
||||||
default: python
|
default: python
|
||||||
readOnlyNullable:
|
readOnlyNullable:
|
||||||
title: Read only nullable
|
title: Read only nullable
|
||||||
@@ -1625,37 +1194,11 @@ definitions:
|
|||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
enum:
|
enum:
|
||||||
- abap
|
|
||||||
- algol
|
|
||||||
- algol_nu
|
|
||||||
- arduino
|
|
||||||
- autumn
|
|
||||||
- borland
|
|
||||||
- bw
|
|
||||||
- colorful
|
|
||||||
- default
|
|
||||||
- emacs
|
|
||||||
- friendly
|
|
||||||
- fruity
|
|
||||||
- igor
|
|
||||||
- lovelace
|
|
||||||
- manni
|
|
||||||
- monokai
|
- monokai
|
||||||
- murphy
|
- solarized-dark
|
||||||
- native
|
|
||||||
- paraiso-dark
|
|
||||||
- paraiso-light
|
|
||||||
- pastie
|
|
||||||
- perldoc
|
|
||||||
- rainbow_dash
|
|
||||||
- rrt
|
|
||||||
- tango
|
|
||||||
- trac
|
|
||||||
- vim
|
- vim
|
||||||
- vs
|
|
||||||
- xcode
|
|
||||||
default:
|
default:
|
||||||
- friendly
|
- solarized-dark
|
||||||
lines:
|
lines:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
|
|||||||
@@ -3,11 +3,14 @@ from collections import OrderedDict
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
|
from django.contrib.postgres import fields as postgres_fields
|
||||||
|
from django.db import models
|
||||||
from django.utils.inspect import get_func_args
|
from django.utils.inspect import get_func_args
|
||||||
from rest_framework import routers, serializers, viewsets
|
from rest_framework import routers, serializers, viewsets
|
||||||
from rest_framework.decorators import api_view
|
from rest_framework.decorators import api_view
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
|
from django_fake_model import models as fake_models
|
||||||
from drf_yasg import codecs, openapi
|
from drf_yasg import codecs, openapi
|
||||||
from drf_yasg.codecs import yaml_sane_load
|
from drf_yasg.codecs import yaml_sane_load
|
||||||
from drf_yasg.errors import SwaggerGenerationError
|
from drf_yasg.errors import SwaggerGenerationError
|
||||||
@@ -204,6 +207,7 @@ def test_action_mapping():
|
|||||||
|
|
||||||
@pytest.mark.parametrize('choices, expected_type', [
|
@pytest.mark.parametrize('choices, expected_type', [
|
||||||
(['A', 'B'], openapi.TYPE_STRING),
|
(['A', 'B'], openapi.TYPE_STRING),
|
||||||
|
([u'A', u'B'], openapi.TYPE_STRING),
|
||||||
([123, 456], openapi.TYPE_INTEGER),
|
([123, 456], openapi.TYPE_INTEGER),
|
||||||
([1.2, 3.4], openapi.TYPE_NUMBER),
|
([1.2, 3.4], openapi.TYPE_NUMBER),
|
||||||
(['A', 456], openapi.TYPE_STRING)
|
(['A', 456], openapi.TYPE_STRING)
|
||||||
@@ -229,3 +233,43 @@ def test_choice_field(choices, expected_type):
|
|||||||
property_schema = swagger['definitions']['Detail']['properties']['detail']
|
property_schema = swagger['definitions']['Detail']['properties']['detail']
|
||||||
|
|
||||||
assert property_schema == openapi.Schema(title='Detail', type=expected_type, enum=choices)
|
assert property_schema == openapi.Schema(title='Detail', type=expected_type, enum=choices)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('choices, field, expected_type', [
|
||||||
|
([1, 2, 3], models.IntegerField, openapi.TYPE_INTEGER),
|
||||||
|
(["A", "B"], models.CharField, openapi.TYPE_STRING),
|
||||||
|
])
|
||||||
|
def test_nested_choice_in_array_field(choices, field, expected_type):
|
||||||
|
|
||||||
|
# Create a model class on the fly to avoid warnings about using the several
|
||||||
|
# model class name several times
|
||||||
|
model_class = type(
|
||||||
|
"%sModel" % field.__name__,
|
||||||
|
(fake_models.FakeModel,),
|
||||||
|
{
|
||||||
|
"array": postgres_fields.ArrayField(
|
||||||
|
field(choices=((i, "choice %s" % i) for i in choices))
|
||||||
|
),
|
||||||
|
"__module__": "test_models",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
class ArraySerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = model_class
|
||||||
|
fields = ("array",)
|
||||||
|
|
||||||
|
class ArrayViewSet(viewsets.ModelViewSet):
|
||||||
|
serializer_class = ArraySerializer
|
||||||
|
|
||||||
|
router = routers.DefaultRouter()
|
||||||
|
router.register(r'arrays', ArrayViewSet, **_basename_or_base_name('arrays'))
|
||||||
|
|
||||||
|
generator = OpenAPISchemaGenerator(
|
||||||
|
info=openapi.Info(title='Test array model generator', default_version='v1'),
|
||||||
|
patterns=router.urls
|
||||||
|
)
|
||||||
|
|
||||||
|
swagger = generator.get_schema(None, True)
|
||||||
|
property_schema = swagger['definitions']['Array']['properties']['array']['items']
|
||||||
|
assert property_schema == openapi.Schema(title='Array', type=expected_type, enum=choices)
|
||||||
|
|||||||
@@ -5,9 +5,11 @@ isolated_build_env = .package
|
|||||||
|
|
||||||
# https://docs.djangoproject.com/en/dev/faq/install/#what-python-version-can-i-use-with-django
|
# https://docs.djangoproject.com/en/dev/faq/install/#what-python-version-can-i-use-with-django
|
||||||
envlist =
|
envlist =
|
||||||
py{27,34,35,36}-django111-drf{37,38,39},
|
py27-django111-drf39-typing,
|
||||||
py{34,35,36,37}-django20-drf{37,38,39},
|
py27-django111-drf{38,39},
|
||||||
py{35,36,37}-django21-drf{37,38,39},
|
py{35,36}-django{111,21,22}-drf{38,39},
|
||||||
|
py37-django{21,22}-drf{38,39},
|
||||||
|
py37-django{21,22}-drf310,
|
||||||
djmaster, lint, docs
|
djmaster, lint, docs
|
||||||
|
|
||||||
[testenv:.package]
|
[testenv:.package]
|
||||||
@@ -17,12 +19,14 @@ deps =
|
|||||||
[testenv]
|
[testenv]
|
||||||
deps =
|
deps =
|
||||||
django111: Django>=1.11,<2.0
|
django111: Django>=1.11,<2.0
|
||||||
django20: Django>=2.0,<2.1
|
|
||||||
django21: Django>=2.1,<2.2
|
django21: Django>=2.1,<2.2
|
||||||
|
django22: Django>=2.2,<2.3
|
||||||
|
|
||||||
drf37: djangorestframework>=3.7.7,<3.8
|
drf38: djangorestframework>=3.8,<3.9
|
||||||
drf38: djangorestframework>=3.8.0,<3.9
|
|
||||||
drf39: djangorestframework>=3.9,<3.10
|
drf39: djangorestframework>=3.9,<3.10
|
||||||
|
drf310: djangorestframework>=3.10
|
||||||
|
|
||||||
|
typing: typing>=3.6.6
|
||||||
|
|
||||||
# test with the latest build of django-rest-framework to get early warning of compatibility issues
|
# test with the latest build of django-rest-framework to get early warning of compatibility issues
|
||||||
djmaster: https://github.com/encode/django-rest-framework/archive/master.tar.gz
|
djmaster: https://github.com/encode/django-rest-framework/archive/master.tar.gz
|
||||||
@@ -72,6 +76,6 @@ known_standard_library =
|
|||||||
types,warnings
|
types,warnings
|
||||||
known_third_party =
|
known_third_party =
|
||||||
coreapi,coreschema,datadiff,dj_database_url,django,django_filters,djangorestframework_camel_case,
|
coreapi,coreschema,datadiff,dj_database_url,django,django_filters,djangorestframework_camel_case,
|
||||||
rest_framework_recursive,flex,gunicorn,inflection,pygments,pytest,rest_framework,ruamel,setuptools_scm,
|
rest_framework_recursive,flex,gunicorn,inflection,pytest,rest_framework,ruamel,setuptools_scm,
|
||||||
swagger_spec_validator,uritemplate,user_agents,whitenoise,oauth2_provider
|
swagger_spec_validator,uritemplate,user_agents,whitenoise,oauth2_provider
|
||||||
known_first_party = drf_yasg,testproj,articles,people,snippets,todo,users,urlconfs
|
known_first_party = drf_yasg,testproj,articles,people,snippets,todo,users,urlconfs
|
||||||
|
|||||||
Reference in New Issue
Block a user