Skip to content

Commit

Permalink
invert component exclusion logic (OpenApiSerializerExtension) #351 #391
Browse files Browse the repository at this point in the history
  • Loading branch information
tfranzel committed May 20, 2021
1 parent 48862bb commit 2227beb
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 11 deletions.
17 changes: 8 additions & 9 deletions drf_spectacular/openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -1179,16 +1179,15 @@ def resolve_serializer(self, serializer, direction) -> ResolvedComponent:

self.registry.register(component)
component.schema = self._map_serializer(serializer, direction)
# 4 cases:
# 1. polymorphic container component -> use
# 2. concrete component with properties -> use
# 3. concrete component without properties -> prob. transactional so discard
# 4. explicit list component -> demultiplexed at usage location so discard
keep_component = (
any(nest_tag in component.schema for nest_tag in ['oneOf', 'allOf', 'anyOf'])
or component.schema.get('properties', {})

discard_component = (
# components with empty schemas serve no purpose
not component.schema
# concrete component without properties are likely only transactional so discard
or (component.schema.get('type') == 'object' and not component.schema.get('properties'))
)
if not keep_component:

if discard_component:
del self.registry[component]
return ResolvedComponent(None, None) # sentinel
return component
30 changes: 28 additions & 2 deletions tests/test_regressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -864,7 +864,7 @@ class CustomAuth(TokenAuthentication):
pass

class XSerializer(serializers.Serializer):
field = serializers.IntegerField
field = serializers.IntegerField()

class XAPIView(APIView):
authentication_classes = [CustomAuth]
Expand Down Expand Up @@ -1238,7 +1238,7 @@ def view_func(request, format=None):

def test_basic_viewset_without_queryset_with_explicit_pk_typing(no_warnings):
class XSerializer(serializers.Serializer):
field = fields.IntegerField()
field = serializers.IntegerField()

class XViewset(viewsets.ViewSet):
serializer_class = XSerializer
Expand Down Expand Up @@ -1845,3 +1845,29 @@ def test_yaml_encoder_parity(no_warnings, value):
# rest_framework.encoders.JSONEncoder
assert OpenApiJsonRenderer().render(value)
assert OpenApiYamlRenderer().render(value)


@pytest.mark.parametrize('comp_schema', [
{'type': 'number'},
{'type': 'array', 'items': {'type': 'number'}},
])
def test_serializer_extension_with_non_object_schema(no_warnings, comp_schema):
class XSerializer(serializers.Serializer):
field = serializers.CharField()

class XExtension(OpenApiSerializerExtension):
target_class = XSerializer

def map_serializer(self, auto_schema, direction):
return comp_schema

class XAPIView(APIView):
@extend_schema(request=XSerializer, responses=XSerializer)
def post(self, request):
pass # pragma: no cover

schema = generate_schema('x', view=XAPIView)

operation = schema['paths']['/x']['post']
assert get_request_schema(operation)['$ref'] == '#/components/schemas/X'
assert schema['components']['schemas']['X'] == comp_schema

0 comments on commit 2227beb

Please sign in to comment.