Skip to content

Commit

Permalink
handle Decimals for YAML #316
Browse files Browse the repository at this point in the history
  • Loading branch information
tfranzel committed Feb 26, 2021
1 parent 11059b6 commit 243445f
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 1 deletion.
11 changes: 11 additions & 0 deletions drf_spectacular/renderers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from decimal import Decimal

import yaml
from rest_framework.exceptions import ErrorDetail
from rest_framework.renderers import BaseRenderer, JSONRenderer
Expand All @@ -23,6 +25,15 @@ def multiline_str_representer(dumper, data):
return scalar
Dumper.add_representer(str, multiline_str_representer)

def decimal_representer(dumper, data):
# prevent emitting "!! float" tags on fractionless decimals
value = str(data)
if '.' in value:
return dumper.represent_scalar('tag:yaml.org,2002:float', value)
else:
return dumper.represent_scalar('tag:yaml.org,2002:int', value)
Dumper.add_representer(Decimal, decimal_representer)

return yaml.dump(
data,
default_flow_style=False,
Expand Down
3 changes: 2 additions & 1 deletion drf_spectacular/validation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def validate_schema(api_schema):
openapi3_schema_spec = json.load(fh)

# coerce any remnants of objects to basic types
api_schema = json.loads(json.dumps(api_schema))
from drf_spectacular.renderers import OpenApiJsonRenderer
api_schema = json.loads(OpenApiJsonRenderer().render(api_schema))

jsonschema.validate(instance=api_schema, schema=openapi3_schema_spec)
33 changes: 33 additions & 0 deletions tests/test_regressions.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import typing
import uuid
from decimal import Decimal
from unittest import mock

import pytest
Expand All @@ -19,6 +20,7 @@
from drf_spectacular.generators import SchemaGenerator
from drf_spectacular.hooks import preprocess_exclude_path_format
from drf_spectacular.openapi import AutoSchema
from drf_spectacular.renderers import OpenApiYamlRenderer
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import (
OpenApiParameter, extend_schema, extend_schema_field, extend_schema_serializer,
Expand Down Expand Up @@ -1250,6 +1252,37 @@ def view_func(request, format=None):
assert field['minimum'] == -100


def test_serialization_with_decimal_values(no_warnings):
class XSerializer(serializers.Serializer):
field = serializers.DecimalField(
decimal_places=2,
min_value=Decimal('1'),
max_value=Decimal('100.00'),
max_digits=5,
coerce_to_string=False,
)
field_coerced = serializers.DecimalField(
decimal_places=2,
min_value=Decimal('1'),
max_value=Decimal('100.00'),
max_digits=5,
coerce_to_string=True,
)

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

schema = generate_schema('/x/', view_function=view_func)
field = schema['components']['schemas']['X']['properties']['field']
assert field['minimum'] and field['maximum']

schema_yml = OpenApiYamlRenderer().render(schema, renderer_context={})
assert b'maximum: 100.00\n' in schema_yml
assert b'minimum: 1\n' in schema_yml


def test_non_supported_http_verbs(no_warnings):
HTTP_METHODS = [
'GET',
Expand Down

0 comments on commit 243445f

Please sign in to comment.