Example #1
0
def test_customized_list_serializer():
    class X(models.Model):
        position = models.IntegerField()

    class XSerializer(serializers.ModelSerializer):
        class Meta:
            model = X
            fields = ("id", "position")

    class XListUpdateSerializer(serializers.ListSerializer):
        child = XSerializer()

    class XAPIView(generics.GenericAPIView):
        model = X
        serializer_class = XListUpdateSerializer

        def put(self, request, *args, **kwargs):
            pass  # pragma: no cover

    schema = generate_schema('x', view=XAPIView)
    operation = schema['paths']['/x']['put']
    comp = '#/components/schemas/X'

    assert get_request_schema(operation)['type'] == 'array'
    assert get_request_schema(operation)['items']['$ref'] == comp
    assert get_response_schema(operation)['type'] == 'array'
    assert get_response_schema(operation)['items']['$ref'] == comp

    assert operation['operationId'] == 'x_update'
    assert len(schema['components']
               ['schemas']) == 1 and 'X' in schema['components']['schemas']
def test_api_view_decorator_multi(no_warnings):

    @extend_schema(request=OpenApiTypes.FLOAT, responses=OpenApiTypes.INT, methods=['POST'])
    @extend_schema(responses=OpenApiTypes.FLOAT, methods=['GET'])
    @api_view(['GET', 'POST'])
    def pi(request):
        pass  # pragma: no cover

    schema = generate_schema('x', view_function=pi)
    operation = schema['paths']['/x']['get']
    assert get_response_schema(operation)['type'] == 'number'
    operation = schema['paths']['/x']['post']
    assert get_request_schema(operation)['type'] == 'number'
    assert get_response_schema(operation)['type'] == 'integer'
Example #3
0
def test_inline_serializer(no_warnings):
    @extend_schema(responses=inline_serializer(
        name='InlineOneOffSerializer',
        fields={
            'char':
            serializers.CharField(),
            'choice':
            serializers.ChoiceField(choices=(('A', 'A'), ('B', 'B'))),
            'nested_inline':
            inline_serializer(
                name='NestedInlineOneOffSerializer',
                fields={
                    'char': serializers.CharField(),
                    'int': serializers.IntegerField(),
                },
                allow_null=True,
            )
        }))
    @api_view(['GET'])
    def one_off(request, foo):
        pass  # pragma: no cover

    schema = generate_schema('x', view_function=one_off)
    assert get_response_schema(schema['paths']['/x']['get'])['$ref'] == (
        '#/components/schemas/InlineOneOff')
    assert len(schema['components']['schemas']) == 3

    one_off = schema['components']['schemas']['InlineOneOff']
    one_off_nested = schema['components']['schemas']['NestedInlineOneOff']

    assert len(one_off['properties']) == 3
    assert one_off['properties']['nested_inline']['nullable'] is True
    assert one_off['properties']['nested_inline']['allOf'][0]['$ref'] == (
        '#/components/schemas/NestedInlineOneOff')
    assert len(one_off_nested['properties']) == 2
Example #4
0
def test_many_polymorphic_serializer_extend_schema(no_warnings, explicit):
    if explicit:
        proxy_serializer = serializers.ListSerializer(
            child=PolymorphicProxySerializer(**PROXY_SERIALIZER_PARAMS))
    else:
        proxy_serializer = PolymorphicProxySerializer(**
                                                      PROXY_SERIALIZER_PARAMS,
                                                      many=True)

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

    schema = generate_schema('/x/', view_function=view_func)
    assert 'MetaPerson' in schema['components']['schemas']
    op = schema['paths']['/x/']['post']
    assert get_response_schema(op) == {
        'type': 'array',
        'items': {
            '$ref': '#/components/schemas/MetaPerson'
        }
    }
    assert get_request_schema(op) == {
        'type': 'array',
        'items': {
            '$ref': '#/components/schemas/MetaPerson'
        }
    }
Example #5
0
def test_lib_serializer_naming_collision_resolution(no_warnings):
    """ parity test in tests.test_warnings.test_serializer_name_reuse """
    def x_lib1():
        class XSerializer(serializers.Serializer):
            x = serializers.UUIDField()

        return XSerializer

    def x_lib2():
        class XSerializer(serializers.Serializer):
            x = serializers.IntegerField()

        return XSerializer

    x_lib1, x_lib2 = x_lib1(), x_lib2()

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

    class Lib2XSerializerRename(OpenApiSerializerExtension):
        target_class = x_lib2  # also accepts import strings

        def get_name(self):
            return 'RenamedLib2X'

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

    operation = schema['paths']['/x']['post']
    assert get_request_schema(operation)['$ref'] == '#/components/schemas/X'
    assert get_response_schema(
        operation)['$ref'] == '#/components/schemas/RenamedLib2X'
Example #6
0
def test_owned_serializer_naming_override_with_ref_name(no_warnings):
    def x_owned1():
        class XSerializer(serializers.Serializer):
            x = serializers.UUIDField()

        return XSerializer

    def x_owned2():
        class XSerializer(serializers.Serializer):
            x = serializers.IntegerField()

            class Meta:
                ref_name = 'Y'

        return XSerializer

    x_owned1, x_owned2 = x_owned1(), x_owned2()

    class XAPIView(APIView):
        @extend_schema(request=x_owned1, responses=x_owned2)
        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 get_response_schema(operation)['$ref'] == '#/components/schemas/Y'
Example #7
0
def test_schema_contains_only_urlpatterns_first_match(no_warnings):
    class XSerializer(serializers.Serializer):
        integer = serializers.IntegerField()

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

    class YSerializer(serializers.Serializer):
        integer = serializers.DateTimeField()

    class YAPIView(APIView):
        @extend_schema(responses=YSerializer)
        def get(self, request):
            pass  # pragma: no cover

    urlpatterns = [
        path('api/x/', XAPIView.as_view()),  # only first occurrence is used
        path('api/x/', YAPIView.as_view()),
    ]
    generator = SchemaGenerator(patterns=urlpatterns)
    schema = generator.get_schema(request=None, public=True)
    validate_schema(schema)
    assert len(schema['components']['schemas']) == 1
    assert 'X' in schema['components']['schemas']
    operation = schema['paths']['/api/x/']['get']
    assert '#/components/schemas/X' in get_response_schema(operation)['$ref']
def test_string_response_variations(no_warnings, responses):
    @extend_schema(responses=responses)
    @api_view(['GET'])
    def view_func(request, format=None):
        pass  # pragma: no cover

    schema = generate_schema('x', view_function=view_func)
    assert get_response_schema(schema['paths']['/x']['get'])['type'] == 'string'
def test_serializer_class_on_apiview(no_warnings):
    class XSerializer(serializers.Serializer):
        field = serializers.UUIDField()

    class XView(views.APIView):
        serializer_class = XSerializer  # not supported by DRF but pick it up anyway

        def get(self, request):
            pass  # pragma: no cover

        def post(self, request):
            pass  # pragma: no cover

    schema = generate_schema('x', view=XView)
    comp = '#/components/schemas/X'
    assert get_response_schema(schema['paths']['/x']['get'])['$ref'] == comp
    assert get_response_schema(schema['paths']['/x']['post'])['$ref'] == comp
    assert schema['paths']['/x']['post']['requestBody']['content']['application/json']['schema']['$ref'] == comp
Example #10
0
def test_api_view_decorator(no_warnings):
    @extend_schema(responses=OpenApiTypes.FLOAT)
    @api_view(['GET'])
    def pi(request):
        pass  # pragma: no cover

    schema = generate_schema('x', view_function=pi)
    operation = schema['paths']['/x']['get']
    assert get_response_schema(operation)['type'] == 'number'
Example #11
0
def test_viewset_list_with_envelope(no_warnings):
    class XSerializer(serializers.Serializer):
        x = serializers.IntegerField()

    def enveloper(serializer_class, list):
        @extend_schema_serializer(many=False)
        class EnvelopeSerializer(serializers.Serializer):
            status = serializers.BooleanField()
            data = XSerializer(many=list)

            class Meta:
                ref_name = 'Enveloped{}{}'.format(
                    serializer_class.__name__.replace("Serializer", ""),
                    "List" if list else "",
                )

        return EnvelopeSerializer

    class XViewset(mixins.ListModelMixin, mixins.RetrieveModelMixin,
                   viewsets.GenericViewSet):
        @extend_schema(responses=enveloper(XSerializer, True))
        def list(self, request, *args, **kwargs):
            return super().list(request, *args, **kwargs)  # pragma: no cover

        @extend_schema(
            responses=enveloper(XSerializer, False),
            parameters=[OpenApiParameter('id', int, OpenApiParameter.PATH)],
        )
        def retrieve(self, request, *args, **kwargs):
            return super().retrieve(request, *args,
                                    **kwargs)  # pragma: no cover

    schema = generate_schema('x', viewset=XViewset)

    operation_list = schema['paths']['/x/']['get']
    assert operation_list['operationId'] == 'x_list'
    assert get_response_schema(
        operation_list)['$ref'] == '#/components/schemas/EnvelopedXList'

    operation_retrieve = schema['paths']['/x/{id}/']['get']
    assert operation_retrieve['operationId'] == 'x_retrieve'
    assert get_response_schema(
        operation_retrieve)['$ref'] == '#/components/schemas/EnvelopedX'
Example #12
0
def test_list_api_view(no_warnings):
    class XSerializer(serializers.Serializer):
        id = serializers.IntegerField()

    class XView(generics.ListAPIView):
        serializer_class = XSerializer

    schema = generate_schema('/x', view=XView)
    operation = schema['paths']['/x']['get']
    assert operation['operationId'] == 'x_list'
    assert get_response_schema(operation)['type'] == 'array'
def test_view_function_extension(no_warnings):
    class FixXFunctionView(OpenApiViewExtension):
        target_class = 'tests.test_extensions.x_view_function'

        def view_replacement(self):
            fixed = extend_schema(responses=OpenApiTypes.FLOAT)(self.target_class)
            return fixed

    schema = generate_schema('x', view_function=x_view_function)
    operation = schema['paths']['/x']['get']
    assert get_response_schema(operation)['type'] == 'number'
def test_layered_extend_schema_on_view_and_method_with_serializer(no_warnings):
    class ASerializer(serializers.Serializer):
        field = serializers.IntegerField()

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

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

    @extend_schema(responses=BSerializer)
    class XViewset(mixins.ListModelMixin, mixins.CreateModelMixin,
                   viewsets.GenericViewSet):
        serializer_class = ASerializer

        @extend_schema(responses=CSerializer)
        def create(self, request, *args, **kwargs):
            super().create(request, *args, **kwargs)  # pragma: no cover

        @extend_schema(responses=CSerializer)
        @action(detail=False, methods=['GET'])
        def extended_action(self, request):
            return Response()  # pragma: no cover

        @action(detail=False, methods=['GET'])
        def raw_action(self, request):
            return Response()  # pragma: no cover

    schema = generate_schema('x', XViewset)
    create_op = get_response_schema(schema['paths']['/x/']['post'])
    list_op = get_response_schema(schema['paths']['/x/']['get'])
    raw_action_op = get_response_schema(
        schema['paths']['/x/raw_action/']['get'])
    extended_action_op = get_response_schema(
        schema['paths']['/x/extended_action/']['get'])

    assert create_op['$ref'].endswith('C')
    assert extended_action_op['$ref'].endswith('C')
    assert list_op['items']['$ref'].endswith('B')
    assert raw_action_op['$ref'].endswith('B')
def test_view_extension(no_warnings):
    class FixXView(OpenApiViewExtension):
        target_class = 'tests.test_extensions.XView'

        def view_replacement(self):
            class Fixed(self.target_class):
                @extend_schema(responses=OpenApiTypes.FLOAT)
                def get(self, request):
                    pass  # pragma: no cover

            return Fixed

    schema = generate_schema('x', view=XView)
    operation = schema['paths']['/x']['get']
    assert get_response_schema(operation)['type'] == 'number'
def test_list_serializer_with_field_child_on_extend_schema():
    class XAPIView(APIView):
        @extend_schema(
            request=serializers.ListSerializer(child=serializers.IntegerField()),
            responses=serializers.ListSerializer(child=serializers.IntegerField()),
        )
        def post(self, request):
            pass  # pragma: no cover

    schema = generate_schema('x', view=XAPIView)
    req_schema = get_request_schema(schema['paths']['/x']['post'])
    res_schema = get_response_schema(schema['paths']['/x']['post'])
    for s in [req_schema, res_schema]:
        assert s['type'] == 'array'
        assert s['items']['type'] == 'integer'
Example #17
0
def test_list_serializer_with_pagination(no_warnings):
    class GenreSerializer(serializers.Serializer):
        genre = serializers.CharField()

    class XViewSet(viewsets.GenericViewSet):
        pagination_class = pagination.LimitOffsetPagination

        @extend_schema(responses=GenreSerializer(many=True))
        @action(methods=["GET"], detail=False)
        def genre(self, request, *args, **kwargs):
            pass  # pragma: no cover

    schema = generate_schema('/x', XViewSet)
    response = get_response_schema(schema['paths']['/x/genre/']['get'])
    assert response['$ref'] == '#/components/schemas/PaginatedGenreList'
    assert 'PaginatedGenreList' in schema['components']['schemas']
    assert 'Genre' in schema['components']['schemas']
def test_file_field_duality_on_split_request(no_warnings):
    class XSerializer(serializers.Serializer):
        file = serializers.FileField()

    class XView(generics.ListCreateAPIView):
        serializer_class = XSerializer
        parser_classes = [parsers.MultiPartParser]

    schema = generate_schema('/x', view=XView)
    assert get_response_schema(
        schema['paths']['/x']['get']
    )['items']['$ref'] == '#/components/schemas/X'
    assert get_request_schema(
        schema['paths']['/x']['post'], content_type='multipart/form-data'
    )['$ref'] == '#/components/schemas/XRequest'

    assert schema['components']['schemas']['X']['properties']['file']['format'] == 'uri'
    assert schema['components']['schemas']['XRequest']['properties']['file']['format'] == 'binary'
def test_list_on_apiview_get(no_warnings):
    class XSerializer(serializers.Serializer):
        id = serializers.UUIDField()

    class XApiView(APIView):
        authentication_classes = []

        @extend_schema(
            parameters=[OpenApiParameter('id', OpenApiTypes.INT, OpenApiParameter.PATH)],
            responses={200: XSerializer(many=True)},
        )
        def get(self, request):
            pass  # pragma: no cover

    schema = generate_schema('x', view=XApiView)
    operation = schema['paths']['/x']['get']
    assert operation['operationId'] == 'x_list'
    operation_schema = get_response_schema(operation)
    assert operation_schema['type'] == 'array'
def test_list_serializer_with_field_child():
    class XSerializer(serializers.Serializer):
        field = serializers.ListSerializer(child=serializers.IntegerField())

    class XAPIView(views.APIView):
        serializer_class = XSerializer

        def post(self, request, *args, **kwargs):
            pass  # pragma: no cover

    # assumption on Serializer functionality
    assert XSerializer({'field': [1, 2, 3]}).data['field'] == [1, 2, 3]

    schema = generate_schema('x', view=XAPIView)
    assert get_request_schema(schema['paths']['/x']['post'])['$ref'] == '#/components/schemas/X'
    assert get_response_schema(schema['paths']['/x']['post'])['$ref'] == '#/components/schemas/X'

    properties = schema['components']['schemas']['X']['properties']
    assert properties['field']['type'] == 'array'
    assert properties['field']['items']['type'] == 'integer'
def test_component_split_request():
    class XSerializer(serializers.Serializer):
        ro = serializers.IntegerField(read_only=True)
        rw = serializers.IntegerField()
        wo = serializers.IntegerField(write_only=True)

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

    schema = generate_schema('/x', view_function=pi)

    operation = schema['paths']['/x']['post']

    assert get_response_schema(operation)['$ref'] == '#/components/schemas/X'
    assert get_request_schema(operation)['$ref'] == '#/components/schemas/XRequest'
    assert len(schema['components']['schemas']['X']['properties']) == 2
    assert 'wo' not in schema['components']['schemas']['X']['properties']
    assert len(schema['components']['schemas']['XRequest']['properties']) == 2
    assert 'ro' not in schema['components']['schemas']['XRequest']['properties']
Example #22
0
def test_many_polymorphic_proxy_serializer_extend_schema_field(
        no_warnings, explicit):
    if explicit:
        proxy_serializer = serializers.ListField(
            child=PolymorphicProxySerializer(**PROXY_SERIALIZER_PARAMS))
    else:
        proxy_serializer = PolymorphicProxySerializer(**
                                                      PROXY_SERIALIZER_PARAMS,
                                                      many=True)

    @extend_schema_field(proxy_serializer)
    class XField(serializers.DictField):
        pass  # pragma: no cover

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

    @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 'MetaPerson' in schema['components']['schemas']
    assert schema['components']['schemas']['X'] == {
        'type': 'object',
        'properties': {
            'field': {
                'type': 'array',
                'items': {
                    '$ref': '#/components/schemas/MetaPerson'
                }
            }
        },
        'required': ['field']
    }
    op = schema['paths']['/x/']['post']
    assert get_request_schema(op) == {'$ref': '#/components/schemas/X'}
    assert get_response_schema(op) == {'$ref': '#/components/schemas/X'}