Compare commits
15 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
728c02356c | |
|
|
9ccf24c27a | |
|
|
8aa255cf56 | |
|
|
7491d330a8 | |
|
|
ebe21b77c6 | |
|
|
17da098940 | |
|
|
a872eb66d6 | |
|
|
6a1166deb5 | |
|
|
b700191f46 | |
|
|
5c25ecd8f2 | |
|
|
8fd27664f1 | |
|
|
456b697ca2 | |
|
|
9966297f87 | |
|
|
27007a9cf4 | |
|
|
a72e5b2899 |
|
|
@ -1,10 +1,8 @@
|
||||||
language: python
|
language: python
|
||||||
python:
|
python:
|
||||||
- '2.7'
|
|
||||||
- '3.5'
|
|
||||||
- '3.6'
|
- '3.6'
|
||||||
- '3.7'
|
- '3.7'
|
||||||
- '3.8-dev'
|
- '3.8'
|
||||||
|
|
||||||
dist: xenial
|
dist: xenial
|
||||||
|
|
||||||
|
|
@ -39,7 +37,6 @@ matrix:
|
||||||
allow_failures:
|
allow_failures:
|
||||||
- env: TOXENV=lint
|
- env: TOXENV=lint
|
||||||
- env: TOXENV=djmaster
|
- env: TOXENV=djmaster
|
||||||
- python: '3.8-dev'
|
|
||||||
|
|
||||||
fast_finish: true
|
fast_finish: true
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ You want to contribute some code? Great! Here are a few steps to get you started
|
||||||
|
|
||||||
.. code:: console
|
.. code:: console
|
||||||
|
|
||||||
(venv) $ python testproj/manage.py generate_swagger ../tests/reference.yaml --overwrite --user admin --url http://test.local:8002/
|
(venv) $ python testproj/manage.py generate_swagger tests/reference.yaml --overwrite --user admin --url http://test.local:8002/
|
||||||
|
|
||||||
After checking the git diff to verify that no unexpected changes appeared, you should commit the new
|
After checking the git diff to verify that no unexpected changes appeared, you should commit the new
|
||||||
``reference.yaml`` together with your changes.
|
``reference.yaml`` together with your changes.
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,9 @@ Generate **real** Swagger/OpenAPI 2.0 specifications from a Django Rest Framewor
|
||||||
|
|
||||||
Compatible with
|
Compatible with
|
||||||
|
|
||||||
- **Django Rest Framework**: 3.8, 3.9, 3.10
|
- **Django Rest Framework**: 3.8, 3.9, 3.10, 3.11
|
||||||
- **Django**: 1.11, 2.1, 2.2
|
- **Django**: 1.11, 2.2, 3.0
|
||||||
- **Python**: 2.7, 3.5, 3.6, 3.7
|
- **Python**: 2.7, 3.6, 3.7, 3.8
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,18 @@
|
||||||
Changelog
|
Changelog
|
||||||
#########
|
#########
|
||||||
|
|
||||||
|
|
||||||
|
**********
|
||||||
|
**1.17.1**
|
||||||
|
**********
|
||||||
|
|
||||||
|
*Release date: Feb 17, 2020*
|
||||||
|
|
||||||
|
- **FIXED:** fixed compatibility issue with CurrentUserDefault in Django Rest Framework 3.11
|
||||||
|
- **FIXED:** respect `USERNAME_FIELD` in `generate_swagger` command (:pr:`486`)
|
||||||
|
|
||||||
|
**Support was dropped for Python 3.5, Django 2.0, Django 2.1, DRF 3.7**
|
||||||
|
|
||||||
**********
|
**********
|
||||||
**1.17.0**
|
**1.17.0**
|
||||||
**********
|
**********
|
||||||
|
|
|
||||||
|
|
@ -212,7 +212,8 @@ Schema generation of ``serializers.SerializerMethodField`` is supported in two w
|
||||||
Serializer ``Meta`` nested class
|
Serializer ``Meta`` nested class
|
||||||
********************************
|
********************************
|
||||||
|
|
||||||
You can define some per-serializer options by adding a ``Meta`` class to your serializer, e.g.:
|
You can define some per-serializer or per-field options by adding a ``Meta`` class to your ``Serializer`` or
|
||||||
|
serializer ``Field``, e.g.:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
|
@ -236,6 +237,64 @@ The available options are:
|
||||||
which are converted to Swagger ``Schema`` attribute names according to :func:`.make_swagger_name`.
|
which are converted to Swagger ``Schema`` attribute names according to :func:`.make_swagger_name`.
|
||||||
Attribute names and values must conform to the `OpenAPI 2.0 specification <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#schemaObject>`_.
|
Attribute names and values must conform to the `OpenAPI 2.0 specification <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#schemaObject>`_.
|
||||||
|
|
||||||
|
Suppose you wanted to model an email using a `JSONField` to store the subject and body for performance reasons:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from django.contrib.postgres.fields import JSONField
|
||||||
|
|
||||||
|
class Email(models.Model):
|
||||||
|
# Store data as JSON, but the data should be made up of
|
||||||
|
# an object that has two properties, "subject" and "body"
|
||||||
|
# Example:
|
||||||
|
# {
|
||||||
|
# "subject": "My Title",
|
||||||
|
# "body": "The body of the message.",
|
||||||
|
# }
|
||||||
|
message = JSONField()
|
||||||
|
|
||||||
|
To instruct ``drf-yasg`` to output an OpenAPI schema that matches this, create a custom ``JSONField``:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
class EmailMessageField(serializers.JSONField):
|
||||||
|
class Meta:
|
||||||
|
swagger_schema_fields = {
|
||||||
|
"type": openapi.TYPE_OBJECT,
|
||||||
|
"title": "Email",
|
||||||
|
"properties": {
|
||||||
|
"subject": openapi.Schema(
|
||||||
|
title="Email subject",
|
||||||
|
type=openapi.TYPE_STRING,
|
||||||
|
),
|
||||||
|
"body": openapi.Schema(
|
||||||
|
title="Email body",
|
||||||
|
type=openapi.TYPE_STRING,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
"required": ["subject", "body"],
|
||||||
|
}
|
||||||
|
|
||||||
|
class EmailSerializer(ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Email
|
||||||
|
fields = "__all__"
|
||||||
|
|
||||||
|
message = EmailMessageField()
|
||||||
|
|
||||||
|
.. Warning::
|
||||||
|
|
||||||
|
Overriding a default ``Field`` generated by a ``ModelSerializer`` will also override automatically
|
||||||
|
generated validators for that ``Field``. To add ``Serializer`` validation back in manually, see the relevant
|
||||||
|
`DRF Validators`_ and `DRF Fields`_ documentation.
|
||||||
|
|
||||||
|
One example way to do this is to set the ``default_validators`` attribute on a field.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
class EmailMessageField(serializers.JSONField):
|
||||||
|
default_validators = [my_custom_email_validator]
|
||||||
|
...
|
||||||
|
|
||||||
*************************
|
*************************
|
||||||
Subclassing and extending
|
Subclassing and extending
|
||||||
|
|
@ -389,3 +448,5 @@ A second example, of a :class:`~.inspectors.FieldInspector` that removes the ``t
|
||||||
|
|
||||||
|
|
||||||
.. _Python 3 type hinting: https://docs.python.org/3/library/typing.html
|
.. _Python 3 type hinting: https://docs.python.org/3/library/typing.html
|
||||||
|
.. _DRF Validators: https://www.django-rest-framework.org/api-guide/validators/
|
||||||
|
.. _DRF Fields: https://www.django-rest-framework.org/api-guide/fields/#validators
|
||||||
|
|
|
||||||
|
|
@ -4,3 +4,4 @@
|
||||||
-r lint.txt
|
-r lint.txt
|
||||||
|
|
||||||
tox-battery>=0.5
|
tox-battery>=0.5
|
||||||
|
django-oauth-toolkit
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,8 @@
|
||||||
Pillow>=4.3.0
|
Pillow>=4.3.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.5"
|
django-filter>=1.1.0; python_version >= "3.5"
|
||||||
#djangorestframework-camel-case>=0.2.0
|
djangorestframework-camel-case>=1.1.2
|
||||||
# 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
|
||||||
|
django-cors-headers
|
||||||
|
|
|
||||||
2
setup.py
2
setup.py
|
|
@ -19,7 +19,7 @@ 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)
|
py3_supported_range = (5, 8)
|
||||||
|
|
||||||
# convert inclusive range to exclusive range
|
# convert inclusive range to exclusive range
|
||||||
py3_supported_range = (py3_supported_range[0], py3_supported_range[1] + 1)
|
py3_supported_range = (py3_supported_range[0], py3_supported_range[1] + 1)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from six import raise_from
|
from six import binary_type, raise_from, text_type
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
import json
|
import json
|
||||||
|
|
@ -176,7 +176,14 @@ class SaneYamlDumper(yaml.SafeDumper):
|
||||||
node.flow_style = best_style
|
node.flow_style = best_style
|
||||||
return node
|
return node
|
||||||
|
|
||||||
|
def represent_text(self, text):
|
||||||
|
if "\n" in text:
|
||||||
|
return self.represent_scalar('tag:yaml.org,2002:str', text, style='|')
|
||||||
|
return self.represent_scalar('tag:yaml.org,2002:str', text)
|
||||||
|
|
||||||
|
|
||||||
|
SaneYamlDumper.add_representer(binary_type, SaneYamlDumper.represent_text)
|
||||||
|
SaneYamlDumper.add_representer(text_type, SaneYamlDumper.represent_text)
|
||||||
SaneYamlDumper.add_representer(OrderedDict, SaneYamlDumper.represent_odict)
|
SaneYamlDumper.add_representer(OrderedDict, SaneYamlDumper.represent_odict)
|
||||||
SaneYamlDumper.add_multi_representer(OrderedDict, SaneYamlDumper.represent_odict)
|
SaneYamlDumper.add_multi_representer(OrderedDict, SaneYamlDumper.represent_odict)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -382,8 +382,21 @@ def find_limits(field):
|
||||||
def decimal_field_type(field):
|
def decimal_field_type(field):
|
||||||
return openapi.TYPE_NUMBER if decimal_as_float(field) else openapi.TYPE_STRING
|
return openapi.TYPE_NUMBER if decimal_as_float(field) else openapi.TYPE_STRING
|
||||||
|
|
||||||
|
def recurse_one_to_one(field, visited_set=None):
|
||||||
|
if visited_set is None:
|
||||||
|
visited_set = set()
|
||||||
|
if field in visited_set:
|
||||||
|
return None #cycle?
|
||||||
|
if isinstance(field, models.OneToOneField):
|
||||||
|
tgt = field.target_field
|
||||||
|
visited_set.add(field)
|
||||||
|
return recurse_one_to_one(tgt, visited_set=visited_set)
|
||||||
|
else:
|
||||||
|
tmp = get_basic_type_info(field)
|
||||||
|
return tmp['type']
|
||||||
|
|
||||||
model_field_to_basic_type = [
|
model_field_to_basic_type = [
|
||||||
|
(models.OneToOneField, (recurse_one_to_one, None)),
|
||||||
(models.AutoField, (openapi.TYPE_INTEGER, None)),
|
(models.AutoField, (openapi.TYPE_INTEGER, None)),
|
||||||
(models.BinaryField, (openapi.TYPE_STRING, openapi.FORMAT_BINARY)),
|
(models.BinaryField, (openapi.TYPE_STRING, openapi.FORMAT_BINARY)),
|
||||||
(models.BooleanField, (openapi.TYPE_BOOLEAN, None)),
|
(models.BooleanField, (openapi.TYPE_BOOLEAN, None)),
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ class Command(BaseCommand):
|
||||||
if user:
|
if user:
|
||||||
# Only call get_user_model if --user was passed in order to
|
# Only call get_user_model if --user was passed in order to
|
||||||
# avoid crashing if auth is not configured in the project
|
# avoid crashing if auth is not configured in the project
|
||||||
user = get_user_model().objects.get(username=user)
|
user = get_user_model().objects.get(**{get_user_model().USERNAME_FIELD: user})
|
||||||
|
|
||||||
mock = mock or private or (user is not None) or (api_version is not None)
|
mock = mock or private or (user is not None) or (api_version is not None)
|
||||||
if mock and not api_url:
|
if mock and not api_url:
|
||||||
|
|
|
||||||
|
|
@ -470,7 +470,7 @@ class Schema(SwaggerDict):
|
||||||
:type properties: dict[str,Schema or SchemaRef]
|
:type properties: dict[str,Schema or SchemaRef]
|
||||||
:param additional_properties: allow wildcard properties not listed in `properties`
|
:param additional_properties: allow wildcard properties not listed in `properties`
|
||||||
:type additional_properties: bool or Schema or SchemaRef
|
:type additional_properties: bool or Schema or SchemaRef
|
||||||
:param list[str] required: list of requried property names
|
:param list[str] required: list of required property names
|
||||||
:param items: type of array items, only valid if `type` is ``array``
|
:param items: type of array items, only valid if `type` is ``array``
|
||||||
:type items: Schema or SchemaRef
|
:type items: Schema or SchemaRef
|
||||||
:param default: only valid when insider another ``Schema``\\ 's ``properties``;
|
:param default: only valid when insider another ``Schema``\\ 's ``properties``;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import inspect
|
import inspect
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
|
import textwrap
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
|
|
@ -95,8 +96,8 @@ def swagger_auto_schema(method=None, methods=None, auto_schema=unset, request_bo
|
||||||
* a ``Serializer`` class or instance will be converted into a :class:`.Schema` and treated as above
|
* a ``Serializer`` class or instance will be converted into a :class:`.Schema` and treated as above
|
||||||
* a :class:`.Response` object will be used as-is; however if its ``schema`` attribute is a ``Serializer``,
|
* a :class:`.Response` object will be used as-is; however if its ``schema`` attribute is a ``Serializer``,
|
||||||
it will automatically be converted into a :class:`.Schema`
|
it will automatically be converted into a :class:`.Schema`
|
||||||
:type responses: dict[str,(drf_yasg.openapi.Schema or drf_yasg.openapi.SchemaRef or drf_yasg.openapi.Response or
|
:type responses: dict[int or str, (drf_yasg.openapi.Schema or drf_yasg.openapi.SchemaRef or
|
||||||
str or rest_framework.serializers.Serializer)]
|
drf_yasg.openapi.Response or str or rest_framework.serializers.Serializer)]
|
||||||
|
|
||||||
:param list[type[drf_yasg.inspectors.FieldInspector]] field_inspectors: extra serializer and field inspectors; these
|
:param list[type[drf_yasg.inspectors.FieldInspector]] field_inspectors: extra serializer and field inspectors; these
|
||||||
will be tried before :attr:`.ViewInspector.field_inspectors` on the :class:`.inspectors.SwaggerAutoSchema`
|
will be tried before :attr:`.ViewInspector.field_inspectors` on the :class:`.inspectors.SwaggerAutoSchema`
|
||||||
|
|
@ -374,10 +375,16 @@ def get_consumes(parser_classes):
|
||||||
parser_classes = [pc for pc in parser_classes if not issubclass(pc, FileUploadParser)]
|
parser_classes = [pc for pc in parser_classes if not issubclass(pc, FileUploadParser)]
|
||||||
media_types = [parser.media_type for parser in parser_classes or []]
|
media_types = [parser.media_type for parser in parser_classes or []]
|
||||||
non_form_media_types = [encoding for encoding in media_types if not is_form_media_type(encoding)]
|
non_form_media_types = [encoding for encoding in media_types if not is_form_media_type(encoding)]
|
||||||
|
# Because swagger Parameter objects don't support complex data types (nested objects, arrays),
|
||||||
|
# we can't use those unless we are sure the view *only* accepts form data
|
||||||
|
# This means that a view won't support file upload in swagger unless it explicitly
|
||||||
|
# sets its parser classes to include only form parsers
|
||||||
if len(non_form_media_types) == 0:
|
if len(non_form_media_types) == 0:
|
||||||
return media_types
|
return media_types
|
||||||
else:
|
|
||||||
return non_form_media_types
|
# If the form accepts both form data and another type, like json (which is the default config),
|
||||||
|
# we will render its input as a Schema and thus it file parameters will be read-only
|
||||||
|
return non_form_media_types
|
||||||
|
|
||||||
|
|
||||||
def get_produces(renderer_classes):
|
def get_produces(renderer_classes):
|
||||||
|
|
@ -438,6 +445,9 @@ def force_real_str(s, encoding='utf-8', strings_only=False, errors='strict'):
|
||||||
if type(s) != str:
|
if type(s) != str:
|
||||||
s = '' + s
|
s = '' + s
|
||||||
|
|
||||||
|
# Remove common indentation to get the correct Markdown rendering
|
||||||
|
s = textwrap.dedent(s)
|
||||||
|
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -473,7 +483,10 @@ def get_field_default(field):
|
||||||
try:
|
try:
|
||||||
if hasattr(default, 'set_context'):
|
if hasattr(default, 'set_context'):
|
||||||
default.set_context(field)
|
default.set_context(field)
|
||||||
default = default()
|
if getattr(default, 'requires_context', False):
|
||||||
|
default = default(field)
|
||||||
|
else:
|
||||||
|
default = default()
|
||||||
except Exception: # pragma: no cover
|
except Exception: # pragma: no cover
|
||||||
logger.warning("default for %s is callable but it raised an exception when "
|
logger.warning("default for %s is callable but it raised an exception when "
|
||||||
"called; 'default' will not be set on schema", field, exc_info=True)
|
"called; 'default' will not be set on schema", field, exc_info=True)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from articles.models import Article, ArticleGroup
|
from articles.models import Article, ArticleGroup
|
||||||
|
|
|
||||||
|
|
@ -193,16 +193,6 @@ LOGGING = {
|
||||||
'propagate': False,
|
'propagate': False,
|
||||||
},
|
},
|
||||||
'django': {
|
'django': {
|
||||||
'handlers': ['console_log'],
|
|
||||||
'level': 'DEBUG',
|
|
||||||
'propagate': False,
|
|
||||||
},
|
|
||||||
'django.db.backends': {
|
|
||||||
'handlers': ['console_log'],
|
|
||||||
'level': 'INFO',
|
|
||||||
'propagate': False,
|
|
||||||
},
|
|
||||||
'django.template': {
|
|
||||||
'handlers': ['console_log'],
|
'handlers': ['console_log'],
|
||||||
'level': 'INFO',
|
'level': 'INFO',
|
||||||
'propagate': False,
|
'propagate': False,
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,9 @@ swagger_info = openapi.Info(
|
||||||
default_version='v1',
|
default_version='v1',
|
||||||
description="""This is a demo project for the [drf-yasg](https://github.com/axnsan12/drf-yasg) Django Rest Framework library.
|
description="""This is a demo project for the [drf-yasg](https://github.com/axnsan12/drf-yasg) Django Rest Framework library.
|
||||||
|
|
||||||
The `swagger-ui` view can be found [here](/cached/swagger).
|
The `swagger-ui` view can be found [here](/cached/swagger).
|
||||||
The `ReDoc` view can be found [here](/cached/redoc).
|
The `ReDoc` view can be found [here](/cached/redoc).
|
||||||
The swagger YAML document can be found [here](/cached/swagger.yaml).
|
The swagger YAML document can be found [here](/cached/swagger.yaml).
|
||||||
|
|
||||||
You can log in using the pre-existing `admin` user with password `passwordadmin`.""", # noqa
|
You can log in using the pre-existing `admin` user with password `passwordadmin`.""", # noqa
|
||||||
terms_of_service="https://www.google.com/policies/terms/",
|
terms_of_service="https://www.google.com/policies/terms/",
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import sys
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.hashers import make_password
|
from django.contrib.auth.hashers import make_password
|
||||||
from django.db import migrations, IntegrityError
|
from django.db import migrations, IntegrityError, transaction
|
||||||
|
|
||||||
|
|
||||||
def add_default_user(apps, schema_editor):
|
def add_default_user(apps, schema_editor):
|
||||||
|
|
@ -13,14 +13,15 @@ def add_default_user(apps, schema_editor):
|
||||||
User = apps.get_model(settings.AUTH_USER_MODEL)
|
User = apps.get_model(settings.AUTH_USER_MODEL)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
admin = User(
|
with transaction.atomic():
|
||||||
username=username,
|
admin = User(
|
||||||
email=email,
|
username=username,
|
||||||
password=make_password(password),
|
email=email,
|
||||||
is_superuser=True,
|
password=make_password(password),
|
||||||
is_staff=True
|
is_superuser=True,
|
||||||
)
|
is_staff=True
|
||||||
admin.save()
|
)
|
||||||
|
admin.save()
|
||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
sys.stdout.write(" User '%s <%s>' already exists..." % (username, email))
|
sys.stdout.write(" User '%s <%s>' already exists..." % (username, email))
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
swagger: '2.0'
|
swagger: '2.0'
|
||||||
info:
|
info:
|
||||||
title: Snippets API
|
title: Snippets API
|
||||||
description: "This is a demo project for the [drf-yasg](https://github.com/axnsan12/drf-yasg)\
|
description: |-
|
||||||
\ Django Rest Framework library.\n\nThe `swagger-ui` view can be found [here](/cached/swagger).\
|
This is a demo project for the [drf-yasg](https://github.com/axnsan12/drf-yasg) Django Rest Framework library.
|
||||||
\ \nThe `ReDoc` view can be found [here](/cached/redoc). \nThe swagger YAML\
|
|
||||||
\ document can be found [here](/cached/swagger.yaml). \n\nYou can log in using\
|
The `swagger-ui` view can be found [here](/cached/swagger).
|
||||||
\ the pre-existing `admin` user with password `passwordadmin`."
|
The `ReDoc` view can be found [here](/cached/redoc).
|
||||||
|
The swagger YAML document can be found [here](/cached/swagger.yaml).
|
||||||
|
|
||||||
|
You can log in using the pre-existing `admin` user with password `passwordadmin`.
|
||||||
termsOfService: https://www.google.com/policies/terms/
|
termsOfService: https://www.google.com/policies/terms/
|
||||||
contact:
|
contact:
|
||||||
email: contact@snippets.local
|
email: contact@snippets.local
|
||||||
|
|
@ -1502,7 +1505,9 @@ definitions:
|
||||||
readOnly: true
|
readOnly: true
|
||||||
help_text_example_3:
|
help_text_example_3:
|
||||||
title: Help text example 3
|
title: Help text example 3
|
||||||
description: "\n docstring is set so should appear in swagger as fallback\n\
|
description: |2
|
||||||
\ :return:\n "
|
|
||||||
|
docstring is set so should appear in swagger as fallback
|
||||||
|
:return:
|
||||||
type: integer
|
type: integer
|
||||||
readOnly: true
|
readOnly: true
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,11 @@ from django.conf.urls import url
|
||||||
from django.contrib.postgres import fields as postgres_fields
|
from django.contrib.postgres import fields as postgres_fields
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.inspect import get_func_args
|
from django.utils.inspect import get_func_args
|
||||||
|
from django_fake_model import models as fake_models
|
||||||
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
|
||||||
|
|
@ -334,3 +334,21 @@ def test_optional_return_type(py_type, expected_type):
|
||||||
swagger = generator.get_schema(None, True)
|
swagger = generator.get_schema(None, True)
|
||||||
property_schema = swagger["definitions"]["OptionalMethod"]["properties"]["x"]
|
property_schema = swagger["definitions"]["OptionalMethod"]["properties"]["x"]
|
||||||
assert property_schema == openapi.Schema(title='X', type=expected_type, readOnly=True)
|
assert property_schema == openapi.Schema(title='X', type=expected_type, readOnly=True)
|
||||||
|
|
||||||
|
|
||||||
|
EXPECTED_DESCRIPTION = """\
|
||||||
|
description: |-
|
||||||
|
This is a demo project for the [drf-yasg](https://github.com/axnsan12/drf-yasg) Django Rest Framework library.
|
||||||
|
|
||||||
|
The `swagger-ui` view can be found [here](/cached/swagger).
|
||||||
|
The `ReDoc` view can be found [here](/cached/redoc).
|
||||||
|
The swagger YAML document can be found [here](/cached/swagger.yaml).
|
||||||
|
|
||||||
|
You can log in using the pre-existing `admin` user with password `passwordadmin`.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def test_multiline_strings(call_generate_swagger):
|
||||||
|
output = call_generate_swagger(format='yaml')
|
||||||
|
print("|\n|".join(output.splitlines()[:20]))
|
||||||
|
assert EXPECTED_DESCRIPTION in output
|
||||||
|
|
|
||||||
16
tox.ini
16
tox.ini
|
|
@ -5,11 +5,9 @@ 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 =
|
||||||
py27-django111-drf39-typing,
|
py36-django{111,22}-drf{38,39},
|
||||||
py27-django111-drf{38,39},
|
py37-django22-drf{38,39,310,311},
|
||||||
py{35,36}-django{111,21,22}-drf{38,39},
|
py38-django{22,3}-drf{310,311},
|
||||||
py37-django{21,22}-drf{38,39,310},
|
|
||||||
py38-django22-drf310,
|
|
||||||
djmaster, lint, docs
|
djmaster, lint, docs
|
||||||
skip_missing_interpreters = true
|
skip_missing_interpreters = true
|
||||||
|
|
||||||
|
|
@ -20,21 +18,21 @@ deps =
|
||||||
[testenv]
|
[testenv]
|
||||||
deps =
|
deps =
|
||||||
django111: Django>=1.11,<2.0
|
django111: Django>=1.11,<2.0
|
||||||
django111: django-cors-headers>=2.1.0
|
|
||||||
django111: django-oauth-toolkit>=1.1.0,<1.2.0
|
django111: django-oauth-toolkit>=1.1.0,<1.2.0
|
||||||
|
|
||||||
django21: Django>=2.1,<2.2
|
django21: Django>=2.1,<2.2
|
||||||
django21: django-cors-headers>=2.1.0
|
|
||||||
django21: django-oauth-toolkit>=1.2.0
|
django21: django-oauth-toolkit>=1.2.0
|
||||||
|
|
||||||
django22: Django>=2.2,<2.3
|
django22: Django>=2.2,<2.3
|
||||||
django22: django-cors-headers>=2.1.0
|
|
||||||
django22: django-oauth-toolkit>=1.2.0
|
django22: django-oauth-toolkit>=1.2.0
|
||||||
|
|
||||||
|
django3: Django>=2.2,<2.3
|
||||||
|
django3: django-oauth-toolkit>=1.2.0
|
||||||
|
|
||||||
drf38: djangorestframework>=3.8,<3.9
|
drf38: djangorestframework>=3.8,<3.9
|
||||||
drf39: djangorestframework>=3.9,<3.10
|
drf39: djangorestframework>=3.9,<3.10
|
||||||
drf310: djangorestframework>=3.10
|
drf310: djangorestframework>=3.10,<3.11
|
||||||
|
drf311: djangorestframework>=3.11,<3.12
|
||||||
|
|
||||||
typing: typing>=3.6.6
|
typing: typing>=3.6.6
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue