Skip to content

Commit

Permalink
If available, use docstrings from properties for field descriptions (#…
Browse files Browse the repository at this point in the history
…954)

* Use dosctrings from properties for field descriptions if available

* add test, modify impl details of #698

---------

Co-authored-by: Luke Plant <[email protected]>
Co-authored-by: T. Franzel <[email protected]>
  • Loading branch information
tfranzel and spookylukey authored Mar 4, 2023
1 parent adb6a8e commit 704ed7d
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 1 deletion.
11 changes: 10 additions & 1 deletion drf_spectacular/openapi.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import copy
import functools
import re
import typing
from collections import defaultdict
Expand Down Expand Up @@ -1099,14 +1100,22 @@ def _map_response_type_hint(self, method):
return hint

try:
return resolve_type_hint(hint)
schema = resolve_type_hint(hint)
except UnableToProceedError:
warn(
f'unable to resolve type hint for function "{method.__name__}". Consider '
f'using a type hint or @extend_schema_field. Defaulting to string.'
)
return build_basic_type(OpenApiTypes.STR)

description = get_doc(
method.func if isinstance(method, functools.partial) else method
)
if description:
schema['description'] = description

return schema

def _get_paginator(self):
pagination_class = getattr(self.view, 'pagination_class', None)
if pagination_class:
Expand Down
1 change: 1 addition & 0 deletions tests/test_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def __init__(self, instance):

@property
def calculated(self) -> int:
""" My calculated property """
return self._instance.field_int

@property
Expand Down
7 changes: 7 additions & 0 deletions tests/test_fields.yml
Original file line number Diff line number Diff line change
Expand Up @@ -191,33 +191,40 @@ components:
additionalProperties: {}
field_sub_object_calculated:
type: integer
description: My calculated property
readOnly: true
field_sub_object_nested_calculated:
type: integer
description: My calculated property
readOnly: true
field_sub_object_model_int:
type: integer
readOnly: true
field_sub_object_cached_calculated:
type: integer
description: My calculated property
readOnly: true
field_sub_object_cached_nested_calculated:
type: integer
description: My calculated property
readOnly: true
field_sub_object_cached_model_int:
type: integer
readOnly: true
field_sub_object_py_cached_calculated:
type: integer
description: My calculated property
readOnly: true
field_sub_object_py_cached_nested_calculated:
type: integer
description: My calculated property
readOnly: true
field_sub_object_py_cached_model_int:
type: integer
readOnly: true
field_optional_sub_object_calculated:
type: integer
description: My calculated property
readOnly: true
nullable: true
field_sub_object_optional_int:
Expand Down
31 changes: 31 additions & 0 deletions tests/test_regressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3071,3 +3071,34 @@ class XViewset(viewsets.ModelViewSet):
'field_related': {'type': 'integer', 'default': 1},
'field_related_slug': {'type': 'string', 'default': 'foo'},
}


def test_serializer_method_docstring_precedence(no_warnings):
class XSerializer(serializers.Serializer):
field_method1 = serializers.SerializerMethodField()
field_method2 = serializers.SerializerMethodField(help_text='help_text 2')
field_method3 = serializers.SerializerMethodField()

def get_field_method1(self) -> str:
""" docstring 1 """
return '' # pragma: no cover

def get_field_method2(self) -> int:
""" docstring 2 """
return 1 # pragma: no cover

@extend_schema_field(OpenApiTypes.DATETIME)
def get_field_method3(self):
""" docstring 3 """
pass # pragma: no cover

class XViewset(viewsets.ModelViewSet):
serializer_class = XSerializer
queryset = SimpleModel.objects.all()

schema = generate_schema('/x', XViewset)
assert schema['components']['schemas']['X']['properties'] == {
'field_method1': {'type': 'string', 'description': 'docstring 1', 'readOnly': True},
'field_method2': {'type': 'integer', 'description': 'help_text 2', 'readOnly': True},
'field_method3': {'type': 'string', 'description': 'docstring 3', 'format': 'date-time', 'readOnly': True},
}

0 comments on commit 704ed7d

Please sign in to comment.