Use method type annotation to determine schema type for method field

This commit is contained in:
Erwin Junge 2021-03-22 17:17:10 +01:00
parent 71e6c30034
commit 5f4e262edc
No known key found for this signature in database
GPG Key ID: 6BB40CCFB5157446
2 changed files with 35 additions and 0 deletions

View File

@ -1,3 +1,4 @@
import inspect
import re
import warnings
from collections import OrderedDict
@ -359,6 +360,16 @@ class AutoSchema(ViewInspector):
return mapping
def map_field(self, field):
if isinstance(field, serializers.SerializerMethodField) and field.parent and field.method_name:
return_type = inspect.signature(
getattr(field.parent, field.method_name)
).return_annotation
if issubclass(return_type, bool):
return {'type': 'boolean'}
if issubclass(return_type, float):
return {'type': 'number'}
if issubclass(return_type, int):
return {'type': 'integer'}
# Nested Serializers, `many` or not.
if isinstance(field, serializers.ListSerializer):

View File

@ -54,6 +54,25 @@ class TestFieldMapping(TestCase):
uuid1 = uuid.uuid4()
uuid2 = uuid.uuid4()
inspector = AutoSchema()
class TestSerializer(serializers.Serializer):
unannotated = serializers.SerializerMethodField()
annotated_int = serializers.SerializerMethodField()
annotated_float = serializers.SerializerMethodField()
annotated_bool = serializers.SerializerMethodField()
def get_unannotated(self):
return 'blub'
def get_annotated_int(self) -> int:
return 1
def get_annotated_float(self) -> float:
return 1.0
def get_annotated_bool(self) -> bool:
return True
cases = [
(serializers.ListField(), {'items': {}, 'type': 'array'}),
(serializers.ListField(child=serializers.BooleanField()), {'items': {'type': 'boolean'}, 'type': 'array'}),
@ -83,6 +102,11 @@ class TestFieldMapping(TestCase):
{'items': {'enum': [1, 2, 3], 'type': 'integer'}, 'type': 'array'}),
(serializers.IntegerField(min_value=2147483648),
{'type': 'integer', 'minimum': 2147483648, 'format': 'int64'}),
(serializers.SerializerMethodField(), {'type': 'string'}),
(TestSerializer().fields['unannotated'], {'type': 'string'}),
(TestSerializer().fields['annotated_int'], {'type': 'integer'}),
(TestSerializer().fields['annotated_float'], {'type': 'number'}),
(TestSerializer().fields['annotated_bool'], {'type': 'boolean'}),
]
for field, mapping in cases:
with self.subTest(field=field):