Prepare for 1.1.0 (#30)
* refactor the view inspection process to be more modular and allow recursive customization * add operation_id argument to @swagger_auto_ * add inspections for min/max validators * add support for URLPathVersioning and NamespaceVersioning * integrate with djangorestframework-camel-case * fix bugs, improve tests and documentation
This commit is contained in:
Vendored
+18
@@ -0,0 +1,18 @@
|
||||
.versionadded, .versionchanged, .deprecated {
|
||||
font-family: "Roboto", Corbel, Avenir, "Lucida Grande", "Lucida Sans", sans-serif;
|
||||
padding: 10px 13px;
|
||||
border: 1px solid rgb(137, 191, 4);
|
||||
border-radius: 4px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.versionmodified {
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.versionadded p, .versionchanged p, .deprecated p,
|
||||
/*override fucking !important by being more specific */
|
||||
.rst-content dl .versionadded p, .rst-content dl .versionchanged p {
|
||||
margin: 0 !important;
|
||||
}
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
{% extends "!layout.html" %}
|
||||
{% block extrahead %}
|
||||
<meta name="google-site-verification" content="saewLzcrUS1lAAgNVIikKWc3DUbFcE-TWtpyw3AW8CA" />
|
||||
{% endblock %}
|
||||
@@ -3,6 +3,21 @@ Changelog
|
||||
#########
|
||||
|
||||
|
||||
*********
|
||||
**1.1.0**
|
||||
*********
|
||||
|
||||
- **ADDED:** added support for APIs versioned with ``URLPathVersioning`` or ``NamespaceVersioning``
|
||||
- **ADDED:** added ability to recursively customize schema generation
|
||||
:ref:`using pluggable inspector classes <custom-spec-inspectors>`
|
||||
- **ADDED:** added ``operation_id`` parameter to :func:`@swagger_auto_schema <.swagger_auto_schema>`
|
||||
- **ADDED:** integration with `djangorestframework-camel-case
|
||||
<https://github.com/vbabiy/djangorestframework-camel-case>`_ (:issue:`28`)
|
||||
- **IMPROVED:** strings, arrays and integers will now have min/max validation attributes inferred from the
|
||||
field-level validators
|
||||
- **FIXED:** fixed a bug that caused ``title`` to never be generated for Schemas; ``title`` is now correctly
|
||||
populated from the field's ``label`` property
|
||||
|
||||
*********
|
||||
**1.0.6**
|
||||
*********
|
||||
|
||||
+44
-3
@@ -3,6 +3,7 @@
|
||||
#
|
||||
# drf-yasg documentation build configuration file, created by
|
||||
# sphinx-quickstart on Sun Dec 10 15:20:34 2017.
|
||||
import inspect
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
@@ -68,9 +69,6 @@ pygments_style = 'sphinx'
|
||||
|
||||
modindex_common_prefix = ['drf_yasg.']
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = False
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
@@ -186,18 +184,23 @@ nitpick_ignore = [
|
||||
('py:obj', 'callable'),
|
||||
('py:obj', 'type'),
|
||||
('py:obj', 'OrderedDict'),
|
||||
('py:obj', 'None'),
|
||||
|
||||
('py:obj', 'coreapi.Field'),
|
||||
('py:obj', 'BaseFilterBackend'),
|
||||
('py:obj', 'BasePagination'),
|
||||
('py:obj', 'Request'),
|
||||
('py:obj', 'rest_framework.request.Request'),
|
||||
('py:obj', 'rest_framework.serializers.Field'),
|
||||
('py:obj', 'serializers.Field'),
|
||||
('py:obj', 'serializers.BaseSerializer'),
|
||||
('py:obj', 'Serializer'),
|
||||
('py:obj', 'BaseSerializer'),
|
||||
('py:obj', 'APIView'),
|
||||
]
|
||||
|
||||
# TODO: inheritance aliases in sphinx 1.7
|
||||
|
||||
# even though the package should be already installed, the sphinx build on RTD
|
||||
# for some reason needs the sources dir to be in the path in order for viewcode to work
|
||||
sys.path.insert(0, os.path.abspath('../src'))
|
||||
@@ -215,6 +218,40 @@ import drf_yasg.views # noqa: E402
|
||||
|
||||
drf_yasg.views.SchemaView = drf_yasg.views.get_schema_view(None)
|
||||
|
||||
# monkey patch to stop sphinx from trying to find classes by their real location instead of the
|
||||
# top-level __init__ alias; this allows us to document only `drf_yasg.inspectors` and avoid broken references or
|
||||
# double documenting
|
||||
|
||||
import drf_yasg.inspectors # noqa: E402
|
||||
|
||||
|
||||
def redirect_cls(cls):
|
||||
if cls.__module__.startswith('drf_yasg.inspectors'):
|
||||
return getattr(drf_yasg.inspectors, cls.__name__)
|
||||
return cls
|
||||
|
||||
|
||||
for cls_name in drf_yasg.inspectors.__all__:
|
||||
# first pass - replace all classes' module with the top level module
|
||||
real_cls = getattr(drf_yasg.inspectors, cls_name)
|
||||
if not inspect.isclass(real_cls):
|
||||
continue
|
||||
|
||||
patched_dict = dict(real_cls.__dict__)
|
||||
patched_dict.update({'__module__': 'drf_yasg.inspectors'})
|
||||
patched_cls = type(cls_name, real_cls.__bases__, patched_dict)
|
||||
setattr(drf_yasg.inspectors, cls_name, patched_cls)
|
||||
|
||||
for cls_name in drf_yasg.inspectors.__all__:
|
||||
# second pass - replace the inheritance bases for all classes to point to the new clean classes
|
||||
real_cls = getattr(drf_yasg.inspectors, cls_name)
|
||||
if not inspect.isclass(real_cls):
|
||||
continue
|
||||
|
||||
patched_bases = tuple(redirect_cls(base) for base in real_cls.__bases__)
|
||||
patched_cls = type(cls_name, patched_bases, dict(real_cls.__dict__))
|
||||
setattr(drf_yasg.inspectors, cls_name, patched_cls)
|
||||
|
||||
# custom interpreted role for linking to GitHub issues and pull requests
|
||||
# use as :issue:`14` or :pr:`17`
|
||||
gh_issue_uri = "https://github.com/axnsan12/drf-yasg/issues/{}"
|
||||
@@ -273,3 +310,7 @@ def role_github_pull_request_or_issue(name, rawtext, text, lineno, inliner, opti
|
||||
roles.register_local_role('pr', role_github_pull_request_or_issue)
|
||||
roles.register_local_role('issue', role_github_pull_request_or_issue)
|
||||
roles.register_local_role('ghuser', role_github_user)
|
||||
|
||||
|
||||
def setup(app):
|
||||
app.add_stylesheet('css/style.css')
|
||||
|
||||
+136
-3
@@ -249,15 +249,63 @@ Where you can use the :func:`@swagger_auto_schema <.swagger_auto_schema>` decora
|
||||
However, do note that both of the methods above can lead to unexpected (and maybe surprising) results by
|
||||
replacing/decorating methods on the base class itself.
|
||||
|
||||
|
||||
********************************
|
||||
Serializer ``Meta`` nested class
|
||||
********************************
|
||||
|
||||
You can define some per-serializer options by adding a ``Meta`` class to your serializer, e.g.:
|
||||
|
||||
.. code:: python
|
||||
|
||||
class WhateverSerializer(Serializer):
|
||||
...
|
||||
|
||||
class Meta:
|
||||
... options here ...
|
||||
|
||||
Currently, the only option you can add here is
|
||||
|
||||
* ``ref_name`` - a string which will be used as the model definition name for this serializer class; setting it to
|
||||
``None`` will force the serializer to be generated as an inline model everywhere it is used
|
||||
|
||||
*************************
|
||||
Subclassing and extending
|
||||
*************************
|
||||
|
||||
For more advanced control you can subclass :class:`.SwaggerAutoSchema` - see the documentation page for a list of
|
||||
methods you can override.
|
||||
|
||||
---------------------
|
||||
``SwaggerAutoSchema``
|
||||
---------------------
|
||||
|
||||
For more advanced control you can subclass :class:`~.inspectors.SwaggerAutoSchema` - see the documentation page
|
||||
for a list of methods you can override.
|
||||
|
||||
You can put your custom subclass to use by setting it on a view method using the
|
||||
:func:`@swagger_auto_schema <.swagger_auto_schema>` decorator described above.
|
||||
:ref:`@swagger_auto_schema <custom-spec-swagger-auto-schema>` decorator described above, by setting it as a
|
||||
class-level attribute named ``swagger_schema`` on the view class, or
|
||||
:ref:`globally via settings <default-class-settings>`.
|
||||
|
||||
For example, to generate all operation IDs as camel case, you could do:
|
||||
|
||||
.. code:: python
|
||||
|
||||
from inflection import camelize
|
||||
|
||||
class CamelCaseOperationIDAutoSchema(SwaggerAutoSchema):
|
||||
def get_operation_id(self, operation_keys):
|
||||
operation_id = super(CamelCaseOperationIDAutoSchema, self).get_operation_id(operation_keys)
|
||||
return camelize(operation_id, uppercase_first_letter=False)
|
||||
|
||||
|
||||
SWAGGER_SETTINGS = {
|
||||
'DEFAULT_AUTO_SCHEMA_CLASS': 'path.to.CamelCaseOperationIDAutoSchema',
|
||||
...
|
||||
}
|
||||
|
||||
--------------------------
|
||||
``OpenAPISchemaGenerator``
|
||||
--------------------------
|
||||
|
||||
If you need to control things at a higher level than :class:`.Operation` objects (e.g. overall document structure,
|
||||
vendor extensions in metadata) you can also subclass :class:`.OpenAPISchemaGenerator` - again, see the documentation
|
||||
@@ -265,3 +313,88 @@ page for a list of its methods.
|
||||
|
||||
This custom generator can be put to use by setting it as the :attr:`.generator_class` of a :class:`.SchemaView` using
|
||||
:func:`.get_schema_view`.
|
||||
|
||||
.. _custom-spec-inspectors:
|
||||
|
||||
---------------------
|
||||
``Inspector`` classes
|
||||
---------------------
|
||||
|
||||
.. versionadded:: 1.1
|
||||
|
||||
For customizing behavior related to specific field, serializer, filter or paginator classes you can implement the
|
||||
:class:`~.inspectors.FieldInspector`, :class:`~.inspectors.SerializerInspector`, :class:`~.inspectors.FilterInspector`,
|
||||
:class:`~.inspectors.PaginatorInspector` classes and use them with
|
||||
:ref:`@swagger_auto_schema <custom-spec-swagger-auto-schema>` or one of the
|
||||
:ref:`related settings <default-class-settings>`.
|
||||
|
||||
A :class:`~.inspectors.FilterInspector` that adds a description to all ``DjangoFilterBackend`` parameters could be
|
||||
implemented like so:
|
||||
|
||||
.. code:: python
|
||||
|
||||
class DjangoFilterDescriptionInspector(CoreAPICompatInspector):
|
||||
def get_filter_parameters(self, filter_backend):
|
||||
if isinstance(filter_backend, DjangoFilterBackend):
|
||||
result = super(DjangoFilterDescriptionInspector, self).get_filter_parameters(filter_backend)
|
||||
for param in result:
|
||||
if not param.get('description', ''):
|
||||
param.description = "Filter the returned list by {field_name}".format(field_name=param.name)
|
||||
|
||||
return result
|
||||
|
||||
return NotHandled
|
||||
|
||||
@method_decorator(name='list', decorator=swagger_auto_schema(
|
||||
filter_inspectors=[DjangoFilterDescriptionInspector]
|
||||
))
|
||||
class ArticleViewSet(viewsets.ModelViewSet):
|
||||
filter_backends = (DjangoFilterBackend,)
|
||||
filter_fields = ('title',)
|
||||
...
|
||||
|
||||
|
||||
A second example, of a :class:`~.inspectors.FieldInspector` that removes the ``title`` attribute from all generated
|
||||
:class:`.Schema` objects:
|
||||
|
||||
.. code:: python
|
||||
|
||||
class NoSchemaTitleInspector(FieldInspector):
|
||||
def process_result(self, result, method_name, obj, **kwargs):
|
||||
# remove the `title` attribute of all Schema objects
|
||||
if isinstance(result, openapi.Schema.OR_REF):
|
||||
# traverse any references and alter the Schema object in place
|
||||
schema = openapi.resolve_ref(result, self.components)
|
||||
schema.pop('title', None)
|
||||
|
||||
# no ``return schema`` here, because it would mean we always generate
|
||||
# an inline `object` instead of a definition reference
|
||||
|
||||
# return back the same object that we got - i.e. a reference if we got a reference
|
||||
return result
|
||||
|
||||
|
||||
class NoTitleAutoSchema(SwaggerAutoSchema):
|
||||
field_inspectors = [NoSchemaTitleInspector] + swagger_settings.DEFAULT_FIELD_INSPECTORS
|
||||
|
||||
class ArticleViewSet(viewsets.ModelViewSet):
|
||||
swagger_schema = NoTitleAutoSchema
|
||||
...
|
||||
|
||||
|
||||
.. Note::
|
||||
|
||||
A note on references - :class:`.Schema` objects are sometimes output by reference (:class:`.SchemaRef`); in fact,
|
||||
that is how named models are implemented in OpenAPI:
|
||||
|
||||
- in the output swagger document there is a ``definitions`` section containing :class:`.Schema` objects for all
|
||||
models
|
||||
- every usage of a model refers to that single :class:`.Schema` object - for example, in the ArticleViewSet
|
||||
above, all requests and responses containg an ``Article`` model would refer to the same schema definition by a
|
||||
``'$ref': '#/definitions/Article'``
|
||||
|
||||
This is implemented by only generating **one** :class:`.Schema` object for every serializer **class** encountered.
|
||||
|
||||
This means that you should generally avoid view or method-specific ``FieldInspector``\ s if you are dealing with
|
||||
references (a.k.a named models), because you can never know which view will be the first to generate the schema
|
||||
for a given serializer.
|
||||
|
||||
+3
-9
@@ -1,14 +1,6 @@
|
||||
drf\_yasg package
|
||||
====================
|
||||
|
||||
drf\_yasg\.app\_settings
|
||||
----------------------------------
|
||||
|
||||
.. automodule:: drf_yasg.app_settings
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
drf\_yasg\.codecs
|
||||
---------------------------
|
||||
|
||||
@@ -16,7 +8,7 @@ drf\_yasg\.codecs
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
:exclude-members: SaneYamlDumper
|
||||
:exclude-members: SaneYamlDumper,SaneYamlLoader
|
||||
|
||||
drf\_yasg\.errors
|
||||
---------------------------
|
||||
@@ -37,6 +29,8 @@ drf\_yasg\.generators
|
||||
drf\_yasg\.inspectors
|
||||
-------------------------------
|
||||
|
||||
.. autodata:: drf_yasg.inspectors.NotHandled
|
||||
|
||||
.. automodule:: drf_yasg.inspectors
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
@@ -37,6 +37,60 @@ The possible settings and their default values are as follows:
|
||||
``SWAGGER_SETTINGS``
|
||||
********************
|
||||
|
||||
|
||||
.. _default-class-settings:
|
||||
|
||||
Default classes
|
||||
===============
|
||||
|
||||
DEFAULT_AUTO_SCHEMA_CLASS
|
||||
-------------------------
|
||||
|
||||
:class:`~.inspectors.ViewInspector` subclass that will be used by default for generating :class:`.Operation`
|
||||
objects when iterating over endpoints. Can be overriden by using the `auto_schema` argument of
|
||||
:func:`@swagger_auto_schema <.swagger_auto_schema>` or by a ``swagger_schema`` attribute on the view class.
|
||||
|
||||
**Default**: :class:`drf_yasg.inspectors.SwaggerAutoSchema`
|
||||
|
||||
DEFAULT_FIELD_INSPECTORS
|
||||
------------------------
|
||||
|
||||
List of :class:`~.inspectors.FieldInspector` subclasses that will be used by default for inspecting serializers and
|
||||
serializer fields. Field inspectors given to :func:`@swagger_auto_schema <.swagger_auto_schema>` will be prepended
|
||||
to this list.
|
||||
|
||||
**Default**: ``[`` |br| \
|
||||
:class:`'drf_yasg.inspectors.CamelCaseJSONFilter' <.inspectors.CamelCaseJSONFilter>`, |br| \
|
||||
:class:`'drf_yasg.inspectors.ReferencingSerializerInspector' <.inspectors.ReferencingSerializerInspector>`, |br| \
|
||||
:class:`'drf_yasg.inspectors.RelatedFieldInspector' <.inspectors.RelatedFieldInspector>`, |br| \
|
||||
:class:`'drf_yasg.inspectors.ChoiceFieldInspector' <.inspectors.ChoiceFieldInspector>`, |br| \
|
||||
:class:`'drf_yasg.inspectors.FileFieldInspector' <.inspectors.FileFieldInspector>`, |br| \
|
||||
:class:`'drf_yasg.inspectors.DictFieldInspector' <.inspectors.DictFieldInspector>`, |br| \
|
||||
:class:`'drf_yasg.inspectors.SimpleFieldInspector' <.inspectors.SimpleFieldInspector>`, |br| \
|
||||
:class:`'drf_yasg.inspectors.StringDefaultFieldInspector' <.inspectors.StringDefaultFieldInspector>`, |br| \
|
||||
``]``
|
||||
|
||||
DEFAULT_FILTER_INSPECTORS
|
||||
-------------------------
|
||||
|
||||
List of :class:`~.inspectors.FilterInspector` subclasses that will be used by default for inspecting filter backends.
|
||||
Filter inspectors given to :func:`@swagger_auto_schema <.swagger_auto_schema>` will be prepended to this list.
|
||||
|
||||
**Default**: ``[`` |br| \
|
||||
:class:`'drf_yasg.inspectors.CoreAPICompatInspector' <.inspectors.CoreAPICompatInspector>`, |br| \
|
||||
``]``
|
||||
|
||||
DEFAULT_PAGINATOR_INSPECTORS
|
||||
----------------------------
|
||||
|
||||
List of :class:`~.inspectors.PaginatorInspector` subclasses that will be used by default for inspecting paginators.
|
||||
Paginator inspectors given to :func:`@swagger_auto_schema <.swagger_auto_schema>` will be prepended to this list.
|
||||
|
||||
**Default**: ``[`` |br| \
|
||||
:class:`'drf_yasg.inspectors.DjangoRestResponsePagination' <.inspectors.DjangoRestResponsePagination>`, |br| \
|
||||
:class:`'drf_yasg.inspectors.CoreAPICompatInspector' <.inspectors.CoreAPICompatInspector>`, |br| \
|
||||
``]``
|
||||
|
||||
Authorization
|
||||
=============
|
||||
|
||||
|
||||
Reference in New Issue
Block a user