From 6f3a656fe26874a6296e7fe8aeb4056453afcc9a Mon Sep 17 00:00:00 2001 From: Eric Butler Date: Thu, 18 Jan 2024 15:29:12 -0500 Subject: [PATCH] fix: extend_schema_field with dict param and oas 3.1 the dict was being mutated, so every subsequent use of the field would have more stuff appended to the schema --- drf_spectacular/plumbing.py | 4 ++ tests/test_extend_schema.py | 22 +++++++ ..._extend_schema_field_with_dict_oas_3_1.yml | 64 +++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 tests/test_extend_schema_field_with_dict_oas_3_1.yml diff --git a/drf_spectacular/plumbing.py b/drf_spectacular/plumbing.py index 249083e0..e03b866b 100644 --- a/drf_spectacular/plumbing.py +++ b/drf_spectacular/plumbing.py @@ -1,4 +1,5 @@ import collections +import copy import functools import hashlib import inspect @@ -525,6 +526,9 @@ def safe_ref(schema: _SchemaType) -> _SchemaType: def append_meta(schema: _SchemaType, meta: _SchemaType) -> _SchemaType: if spectacular_settings.OAS_VERSION.startswith('3.1'): + schema = copy.deepcopy(schema) + meta = copy.deepcopy(meta) + schema_nullable = meta.pop('nullable', None) meta_nullable = schema.pop('nullable', None) diff --git a/tests/test_extend_schema.py b/tests/test_extend_schema.py index a9c64fe0..3dfedcf5 100644 --- a/tests/test_extend_schema.py +++ b/tests/test_extend_schema.py @@ -232,6 +232,28 @@ def test_extend_schema(no_warnings): ) +@mock.patch('drf_spectacular.settings.spectacular_settings.OAS_VERSION', '3.1.0') +def test_extend_schema_field_with_dict_oas_3_1(no_warnings): + @extend_schema_field({"type": "string"}) + class CustomField(serializers.CharField): + pass + + class XSerializer(serializers.Serializer): + field1 = CustomField(read_only=True, allow_null=True) + field2 = CustomField(read_only=True, allow_null=True) + field3 = CustomField(read_only=True, allow_null=True) + + @extend_schema(request=XSerializer, responses=XSerializer) + @api_view(['POST']) + def view_func(request, format=None): + pass # pragma: no cover + + assert_schema( + generate_schema('x', view_function=view_func), + 'tests/test_extend_schema_field_with_dict_oas_3_1.yml' + ) + + def test_layered_extend_schema_on_view_and_method_with_meta(no_warnings): class XSerializer(serializers.Serializer): field = serializers.IntegerField() diff --git a/tests/test_extend_schema_field_with_dict_oas_3_1.yml b/tests/test_extend_schema_field_with_dict_oas_3_1.yml new file mode 100644 index 00000000..ae8d8395 --- /dev/null +++ b/tests/test_extend_schema_field_with_dict_oas_3_1.yml @@ -0,0 +1,64 @@ +openapi: 3.1.0 +info: + title: '' + version: 0.0.0 +paths: + /x: + post: + operationId: x_create + tags: + - x + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/X' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/X' + multipart/form-data: + schema: + $ref: '#/components/schemas/X' + security: + - cookieAuth: [] + - basicAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/X' + description: '' +components: + schemas: + X: + type: object + properties: + field1: + type: + - string + - 'null' + readOnly: true + field2: + type: + - string + - 'null' + readOnly: true + field3: + type: + - string + - 'null' + readOnly: true + required: + - field1 + - field2 + - field3 + securitySchemes: + basicAuth: + type: http + scheme: basic + cookieAuth: + type: apiKey + in: cookie + name: sessionid