Show warning on ref_name collisions

Closes #156
openapi3
Cristi Vîjdea 2018-08-06 20:00:20 +03:00
parent 3f2d2871f0
commit 5cd642c9a0
4 changed files with 41 additions and 7 deletions

View File

@ -31,8 +31,7 @@ class EndpointEnumerator(_EndpointEnumerator):
def get_path_from_regex(self, path_regex):
if path_regex.endswith(')'):
logger.warning("url pattern does not end in $ ('%s') - unexpected things might happen",
path_regex)
logger.warning("url pattern does not end in $ ('%s') - unexpected things might happen", path_regex)
return self.unescape_path(super(EndpointEnumerator, self).get_path_from_regex(path_regex))
def should_include_endpoint(self, path, callback, app_name='', namespace='', url_name=None):

View File

@ -13,7 +13,7 @@ from rest_framework.settings import api_settings as rest_framework_settings
from .. import openapi
from ..errors import SwaggerGenerationError
from ..utils import decimal_as_float, filter_none, get_serializer_ref_name
from ..utils import decimal_as_float, filter_none, get_serializer_ref_name, get_serializer_class
from .base import FieldInspector, NotHandled, SerializerInspector
try:
@ -107,7 +107,7 @@ class InlineSerializerInspector(SerializerInspector):
)
if not ref_name and 'title' in result:
# on an inline model, the title is derived from the field name
# but is visually displayed like the model name, which is confusing
# but is visno coverually displayed like the model name, which is confusing
# it is better to just remove title from inline models
del result.title
@ -117,7 +117,13 @@ class InlineSerializerInspector(SerializerInspector):
return make_schema_definition()
definitions = self.components.with_scope(openapi.SCHEMA_DEFINITIONS)
definitions.setdefault(ref_name, make_schema_definition)
actual_schema = definitions.setdefault(ref_name, make_schema_definition)
actual_serializer = get_serializer_class(getattr(actual_schema, '_serializer', None))
this_serializer = get_serializer_class(field)
if actual_serializer and actual_serializer != this_serializer: # pragma: no cover
logger.warning("Schema for %s will override distinct serializer %s because they "
"share the same ref_name", actual_serializer, this_serializer)
return openapi.SchemaRef(definitions, ref_name)
return NotHandled

View File

@ -1,3 +1,4 @@
import logging
import re
from collections import OrderedDict
@ -7,6 +8,8 @@ from inflection import camelize
from .utils import filter_none
logger = logging.getLogger(__name__)
TYPE_OBJECT = "object" #:
TYPE_STRING = "string" #:
TYPE_NUMBER = "number" #:
@ -628,8 +631,13 @@ class ReferenceResolver(object):
ret = self.getdefault(name, None, scope)
if ret is None:
ret = maker()
value = self.getdefault(name, None, scope)
assert ret is not None, "maker returned None; referenced objects cannot be None/null"
if value is None:
self.set(name, ret, scope)
elif value != ret:
logger.debug("during setdefault, maker for %s inserted a value and returned a different value", name)
ret = value
return ret

View File

@ -274,6 +274,7 @@ def force_serializer_instance(serializer):
:param serializer: serializer class or instance
:return: serializer instance
:rtype: serializers.BaseSerializer
"""
if inspect.isclass(serializer):
assert issubclass(serializer, serializers.BaseSerializer), "Serializer required, not %s" % serializer.__name__
@ -284,6 +285,26 @@ def force_serializer_instance(serializer):
return serializer
def get_serializer_class(serializer):
"""Given a ``Serializer`` class or intance, return the ``Serializer`` class. If `serializer` is not a ``Serializer``
class or instance, raises an assertion error.
:param serializer: serializer class or instance, or ``None``
:return: serializer class
:rtype: type[serializers.BaseSerializer]
"""
if serializer is None:
return None
if inspect.isclass(serializer):
assert issubclass(serializer, serializers.BaseSerializer), "Serializer required, not %s" % serializer.__name__
return serializer
assert isinstance(serializer, serializers.BaseSerializer), \
"Serializer class or instance required, not %s" % type(serializer).__name__
return type(serializer)
def get_consumes(parser_classes):
"""Extract ``consumes`` MIME types from a list of parser classes.
@ -336,7 +357,7 @@ def get_serializer_ref_name(serializer):
if hasattr(serializer_meta, 'ref_name'):
ref_name = serializer_meta.ref_name
elif serializer_name == 'NestedSerializer' and isinstance(serializer, serializers.ModelSerializer):
logger.debug("Forcing inline output for ModelSerializer named 'NestedSerializer': " + str(serializer))
logger.debug("Forcing inline output for ModelSerializer named 'NestedSerializer':\n" + str(serializer))
ref_name = None
else:
ref_name = serializer_name