Skip to content

Commit b252a0d

Browse files
Handle annotations not available at runtime (#941)
* Add missing runtime annotations red test case * Update red test to use field_to_swagger_object * Add graceful fallback for get_type_hints NameError exceptions * Fix whitespace linter errors * Bump cmarkgfm * Bump cmarkgfm * Add missing commas
1 parent f8cb2db commit b252a0d

File tree

3 files changed

+53
-3
lines changed

3 files changed

+53
-3
lines changed

requirements/docs.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ sphinx_rtd_theme>=0.2.4
44
Pillow>=4.3.0
55
readme_renderer[md]>=24.0
66
twine>=1.12.1
7-
7+
cmarkgfm>=0.8.0,<0.9.0
88
Django>=2.0
99
djangorestframework_camel_case>=0.2.0

src/drf_yasg/inspectors/field.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from collections import OrderedDict
88
from contextlib import suppress
99
from decimal import Decimal
10+
from inspect import signature as inspect_signature
1011

1112
from django.core import validators
1213
from django.db import models
@@ -709,8 +710,22 @@ def field_to_swagger_object(
709710
serializer, swagger_object_type, use_references, read_only=True
710711
)
711712
else:
712-
# look for Python 3.5+ style type hinting of the return value
713-
hint_class = typing.get_type_hints(method).get("return")
713+
try:
714+
# look for Python 3.5+ style type hinting of the return value
715+
hint_class = typing.get_type_hints(method).get("return")
716+
717+
except NameError:
718+
hint_class = inspect_signature(method).return_annotation
719+
720+
if hint_class is not None and hint_class != inspect._empty:
721+
SwaggerType, _ = self._get_partial_types(
722+
field, swagger_object_type, use_references, **kwargs
723+
)
724+
725+
return SwaggerType(
726+
type=openapi.TYPE_STRING,
727+
description=f"Return type: {hint_class}",
728+
)
714729

715730
# annotations such as typing.Optional have an __instancecheck__
716731
# hook and will not look like classes, but `issubclass` needs

tests/test_annotations.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from typing import TYPE_CHECKING
2+
3+
from rest_framework import serializers
4+
5+
from drf_yasg import openapi
6+
from drf_yasg.inspectors.field import SerializerMethodFieldInspector
7+
from drf_yasg.openapi import ReferenceResolver
8+
9+
if TYPE_CHECKING:
10+
from uuid import UUID
11+
12+
13+
def test_missing_runtime_annotations():
14+
class UserSerializer(serializers.Serializer):
15+
uuid = serializers.SerializerMethodField()
16+
17+
def get_uuid(self, obj) -> "UUID":
18+
return obj.uuid
19+
20+
field = UserSerializer().fields["uuid"]
21+
components = ReferenceResolver("definitions", "parameters", force_init=True)
22+
23+
inspector = SerializerMethodFieldInspector(
24+
view=None,
25+
path="/",
26+
method="GET",
27+
components=components,
28+
request=None,
29+
field_inspectors=[],
30+
)
31+
32+
schema = inspector.field_to_swagger_object(field, openapi.Schema, True)
33+
34+
assert schema.type == "string"
35+
assert schema.description == "Return type: UUID"

0 commit comments

Comments
 (0)