Skip to content

Commit 15e3501

Browse files
committed
Port botocore 3487
1 parent 8849708 commit 15e3501

File tree

2 files changed

+77
-0
lines changed

2 files changed

+77
-0
lines changed

awscli/botocore/serialize.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import base64
4242
import calendar
4343
import datetime
44+
import decimal
4445
import math
4546
import re
4647
import struct
@@ -434,6 +435,8 @@ def _serialize_type_blob(self, serialized, value, shape, key):
434435
serialized[key] = self._get_base64(value)
435436

436437
def _serialize_type_float(self, serialized, value, shape, prefix=''):
438+
if isinstance(value, decimal.Decimal):
439+
value = float(value)
437440
serialized[prefix] = self._handle_float(value)
438441

439442
def _serialize_type_double(self, serialized, value, shape, prefix=''):

tests/unit/botocore/test_serialize.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import base64
1616
import datetime
17+
import decimal
1718
import io
1819
import json
1920

@@ -377,6 +378,79 @@ def test_accepts_partial_iso_format(self):
377378
self.assertEqual(body['Timestamp'], 0)
378379

379380

381+
class TestJSONFloatSerialization(unittest.TestCase):
382+
def setUp(self):
383+
self.model = {
384+
'metadata': {
385+
'protocol': 'json',
386+
'apiVersion': '2014-01-01',
387+
'jsonVersion': '1.1',
388+
'targetPrefix': 'foo',
389+
},
390+
'documentation': '',
391+
'operations': {
392+
'TestOperation': {
393+
'name': 'TestOperation',
394+
'http': {
395+
'method': 'POST',
396+
'requestUri': '/',
397+
},
398+
'input': {'shape': 'InputShape'},
399+
}
400+
},
401+
'shapes': {
402+
'InputShape': {
403+
'type': 'structure',
404+
'members': {
405+
'Double': {'shape': 'DoubleType'},
406+
'Float': {'shape': 'FloatType'},
407+
},
408+
},
409+
'DoubleType': {
410+
'type': 'double',
411+
},
412+
'FloatType': {
413+
'type': 'float',
414+
},
415+
},
416+
}
417+
self.service_model = ServiceModel(self.model)
418+
419+
def serialize_to_request(self, input_params):
420+
request_serializer = serialize.create_serializer(
421+
self.service_model.metadata['protocol']
422+
)
423+
return request_serializer.serialize_to_request(
424+
input_params, self.service_model.operation_model('TestOperation')
425+
)
426+
427+
def test_accepts_decimal_with_precision_above_floats(self):
428+
float_string = '0.12345678901234567890'
429+
float_as_float = float(
430+
float_string
431+
) # This has less precision; it will be lost on serialization
432+
float_as_decimal = decimal.Decimal(float_string)
433+
body = json.loads(
434+
self.serialize_to_request({'Float': float_as_decimal})[
435+
'body'
436+
].decode('utf-8')
437+
)
438+
self.assertEqual(decimal.Decimal(body['Float']), float_as_float)
439+
440+
def test_accepts_decimal_with_precision_above_doubles(self):
441+
double_string = '0.12345678901234567890'
442+
double_as_float = float(
443+
double_string
444+
) # This has less precision; it will be lost on serialization
445+
double_as_decimal = decimal.Decimal(double_string)
446+
body = json.loads(
447+
self.serialize_to_request({'Double': double_as_decimal})[
448+
'body'
449+
].decode('utf-8')
450+
)
451+
self.assertEqual(decimal.Decimal(body['Double']), double_as_float)
452+
453+
380454
class TestInstanceCreation(unittest.TestCase):
381455
def setUp(self):
382456
self.model = {

0 commit comments

Comments
 (0)