diff --git a/drf_spectacular/openapi.py b/drf_spectacular/openapi.py index d6a25f39..11c69f86 100644 --- a/drf_spectacular/openapi.py +++ b/drf_spectacular/openapi.py @@ -17,8 +17,8 @@ from rest_framework.schemas.utils import get_pk_description, is_list_view from drf_spectacular.app_settings import spectacular_settings -from drf_spectacular.plumbing import resolve_basic_type, warn, anyisinstance, force_instance, is_serializer, follow_field_source, is_field -from drf_spectacular.types import OpenApiTypes, PYTHON_TYPE_MAPPING, OPENAPI_TYPE_MAPPING +from drf_spectacular.plumbing import resolve_basic_type, warn, anyisinstance, force_instance, is_serializer, follow_field_source, is_field, is_basic_type +from drf_spectacular.types import OpenApiTypes from drf_spectacular.utils import PolymorphicProxySerializer AUTHENTICATION_SCHEMES = { @@ -378,7 +378,7 @@ def _map_model_field(self, field): def _map_serializer_field(self, method, field): if hasattr(field, '_spectacular_annotation'): - if field._spectacular_annotation in OPENAPI_TYPE_MAPPING or field._spectacular_annotation in PYTHON_TYPE_MAPPING: + if is_basic_type(field._spectacular_annotation): return resolve_basic_type(field._spectacular_annotation) else: return self._map_serializer_field(method, field._spectacular_annotation) @@ -640,7 +640,7 @@ def _map_type_hint(self, method): if is_serializer(hint) or is_field(hint): return self._map_serializer_field(method, force_instance(hint)) - elif hint in PYTHON_TYPE_MAPPING or hint in OPENAPI_TYPE_MAPPING: + elif is_basic_type(hint): return resolve_basic_type(hint) else: warn(f'type hint for function "{method.__name__}" is unknown. defaulting to string.') diff --git a/drf_spectacular/plumbing.py b/drf_spectacular/plumbing.py index 250ab878..d8ae4d8c 100644 --- a/drf_spectacular/plumbing.py +++ b/drf_spectacular/plumbing.py @@ -1,3 +1,4 @@ +import collections import inspect import sys @@ -38,18 +39,24 @@ def is_field(obj): return isinstance(force_instance(obj), fields.Field) and not is_serializer(obj) -def resolve_basic_type(type_): +def is_basic_type(obj): + if not isinstance(obj, collections.Hashable): + return False + return obj in OPENAPI_TYPE_MAPPING or obj in PYTHON_TYPE_MAPPING + + +def resolve_basic_type(obj): """ resolve either enum or actual type and yield schema template for modification """ - if type_ in OPENAPI_TYPE_MAPPING: - return dict(OPENAPI_TYPE_MAPPING[type_]) - elif type_ in PYTHON_TYPE_MAPPING: - return dict(OPENAPI_TYPE_MAPPING[PYTHON_TYPE_MAPPING[type_]]) - elif type_ is None or type(type_) is None: + if obj in OPENAPI_TYPE_MAPPING: + return dict(OPENAPI_TYPE_MAPPING[obj]) + elif obj in PYTHON_TYPE_MAPPING: + return dict(OPENAPI_TYPE_MAPPING[PYTHON_TYPE_MAPPING[obj]]) + elif obj is None or type(obj) is None: return dict(OPENAPI_TYPE_MAPPING[OpenApiTypes.NONE]) else: - warn(f'could not resolve type "{type_}". defaulting to "string"') + warn(f'could not resolve type "{obj}". defaulting to "string"') return dict(OPENAPI_TYPE_MAPPING[OpenApiTypes.STR])