diff --git a/src/drf_yasg/inspectors/field.py b/src/drf_yasg/inspectors/field.py index c18de72..fa80718 100644 --- a/src/drf_yasg/inspectors/field.py +++ b/src/drf_yasg/inspectors/field.py @@ -610,6 +610,8 @@ class SerializerMethodFieldInspector(FieldInspector): # look for Python 3.5+ style type hinting of the return value 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): type_info = get_basic_type_info_from_hint(hint_class) diff --git a/tests/test_schema_generator.py b/tests/test_schema_generator.py index 2400238..b232db1 100644 --- a/tests/test_schema_generator.py +++ b/tests/test_schema_generator.py @@ -1,4 +1,5 @@ import json +import sys from collections import OrderedDict import pytest @@ -17,6 +18,11 @@ from drf_yasg.errors import SwaggerGenerationError from drf_yasg.generators import OpenAPISchemaGenerator from drf_yasg.utils import swagger_auto_schema +try: + import typing +except ImportError: + typing = None + def test_schema_is_valid(swagger, codec_yaml): codec_yaml.encode(swagger) @@ -293,3 +299,38 @@ def test_json_field(): swagger = generator.get_schema(None, True) property_schema = swagger["definitions"]["TestJSONField"]["properties"]["json"] assert property_schema == openapi.Schema(title='Json', type=openapi.TYPE_OBJECT) + + +@pytest.mark.parametrize('py_type, expected_type', [ + (str, openapi.TYPE_STRING), + (int, openapi.TYPE_INTEGER), + (float, openapi.TYPE_NUMBER), + (bool, openapi.TYPE_BOOLEAN), +]) +@pytest.mark.skipif(typing is None or sys.version_info.major < 3, reason="typing not supported") +def test_optional_return_type(py_type, expected_type): + + class OptionalMethodSerializer(serializers.Serializer): + x = serializers.SerializerMethodField() + + def get_x(self, instance): + pass + + # Add the type annotation here in order to avoid a SyntaxError in py27 + get_x.__annotations__["return"] = typing.Optional[py_type] + + class OptionalMethodViewSet(viewsets.ViewSet): + @swagger_auto_schema(responses={200: openapi.Response("OK", OptionalMethodSerializer)}) + def retrieve(self, request, pk=None): + return Response({'optional': None}) + + router = routers.DefaultRouter() + router.register(r'optional', OptionalMethodViewSet, **_basename_or_base_name('optional')) + + generator = OpenAPISchemaGenerator( + info=openapi.Info(title='Test optional parameter', default_version='v1'), + patterns=router.urls + ) + swagger = generator.get_schema(None, True) + property_schema = swagger["definitions"]["OptionalMethod"]["properties"]["x"] + assert property_schema == openapi.Schema(title='X', type=expected_type, readOnly=True)