Skip to content

Commit

Permalink
higher order hints for @extend_schema_field (case 2) #1174 #1212
Browse files Browse the repository at this point in the history
  • Loading branch information
tfranzel committed Mar 31, 2024
1 parent 580bee1 commit ba1fecf
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 3 deletions.
2 changes: 2 additions & 0 deletions drf_spectacular/openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,8 @@ def _map_serializer_field(self, field, direction, bypass_extensions=False):
schema = build_basic_type(override)
if schema is None:
return None
elif is_higher_order_type_hint(override):
schema = resolve_type_hint(override)
elif isinstance(override, dict):
schema = override
else:
Expand Down
3 changes: 1 addition & 2 deletions drf_spectacular/plumbing.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
else:
from typing_extensions import TypeGuard # noqa: F401


import inflection
import uritemplate
from django.apps import apps
Expand Down Expand Up @@ -1366,7 +1365,7 @@ def resolve_type_hint(hint):
elif origin is collections.abc.Iterable:
return build_array_type(resolve_type_hint(args[0]))
else:
raise UnableToProceedError()
raise UnableToProceedError(hint)


def whitelisted(obj: object, classes: Optional[List[Type[object]]], exact=False) -> bool:
Expand Down
2 changes: 1 addition & 1 deletion drf_spectacular/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ def get_external_docs(self):


def extend_schema_field(
field: Union[_SerializerType, _FieldType, OpenApiTypes, _SchemaType],
field: Union[_SerializerType, _FieldType, OpenApiTypes, _SchemaType, _KnownPythonTypes],
component_name: Optional[str] = None
) -> Callable[[F], F]:
"""
Expand Down
37 changes: 37 additions & 0 deletions tests/test_regressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3348,3 +3348,40 @@ def favorite(self, request, pk=None):
schema = generate_schema('m', XViewSet)

assert list(schema['paths'].keys()) == ['/m/', '/m/{id}/', '/m/{id}/favorite/']


def test_extend_schema_field_with_types(no_warnings):
@extend_schema_field(int)
class CustomField(serializers.CharField):
pass # pragma: no cover

@extend_schema_field(typing.List[int]) # this is the new case
class CustomField2(serializers.CharField):
pass # pragma: no cover

class XSerializer(serializers.Serializer):
foo = serializers.SerializerMethodField()
bar = serializers.SerializerMethodField()
baz = CustomField()
qux = CustomField2()

@extend_schema_field(int)
def get_foo(self, field, extra_param):
return 'foo' # pragma: no cover

@extend_schema_field(typing.List[int])
def get_bar(self, field, extra_param):
return 1 # pragma: no cover

@extend_schema(request=XSerializer, responses=XSerializer)
@api_view(['POST'])
def view_func(request, format=None):
pass # pragma: no cover

schema = generate_schema('/x/', view_function=view_func)
assert schema['components']['schemas']['X']['properties'] == {
'foo': {'readOnly': True, 'type': 'integer'},
'bar': {'items': {'type': 'integer'}, 'readOnly': True, 'type': 'array'},
'baz': {'type': 'integer'},
'qux': {'items': {'type': 'integer'}, 'type': 'array'}
}

0 comments on commit ba1fecf

Please sign in to comment.