From 9b6058ec0632479372017563faf11aebd5e59bd7 Mon Sep 17 00:00:00 2001 From: Nick Gaya <> Date: Thu, 17 Oct 2019 22:46:05 -0700 Subject: [PATCH 1/4] Add option to automatically encode/decode strings with byte format --- bravado_core/formatter.py | 11 +++++++++++ bravado_core/spec.py | 6 ++++++ tests/formatter/to_python_test.py | 9 +++++++++ tests/formatter/to_wire_test.py | 9 +++++++++ 4 files changed, 35 insertions(+) diff --git a/bravado_core/formatter.py b/bravado_core/formatter.py index c5029c9a..a811fa2a 100644 --- a/bravado_core/formatter.py +++ b/bravado_core/formatter.py @@ -3,6 +3,7 @@ Support for the 'format' key in the swagger spec as outlined in https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#dataTypeFormat """ +import base64 import functools from collections import namedtuple @@ -106,6 +107,16 @@ def wrapper(validatable_primitive): return wrapper +BASE64_BYTE_FORMAT = SwaggerFormat( + format='byte', + # Note: In Python 3, this requires a bytes-like object as input + to_wire=lambda b: six.ensure_str(base64.b64encode(b), encoding='ascii'), + to_python=lambda s: base64.b64decode( + six.ensure_binary(s, encoding='ascii')), + validate=NO_OP, # jsonschema validates string + description='Converts [wire]string:byte <=> python bytes', +) + DEFAULT_FORMATS = { 'byte': SwaggerFormat( format='byte', diff --git a/bravado_core/spec.py b/bravado_core/spec.py index 805c14ec..28fe22ac 100644 --- a/bravado_core/spec.py +++ b/bravado_core/spec.py @@ -79,6 +79,10 @@ # If True, use the 'path' element of the URL the spec was retrieved from # If False, set basePath to '/' (conforms to Swagger 2.0 specification) 'use_spec_url_for_base_path': False, + + # If False, use str() function for 'byte' format + # If True, encode/decode base64 data for 'byte' format + 'use_base64_for_byte_format': False, } @@ -285,6 +289,8 @@ def get_format(self, name): user_defined_format = self.user_defined_formats.get(name) if user_defined_format is None: user_defined_format = formatter.DEFAULT_FORMATS.get(name) + if name == 'byte' and self.config['use_base64_for_byte_format']: + user_defined_format = formatter.BASE64_BYTE_FORMAT if user_defined_format is None: warnings.warn( diff --git a/tests/formatter/to_python_test.py b/tests/formatter/to_python_test.py index 6d4595b1..25b10234 100644 --- a/tests/formatter/to_python_test.py +++ b/tests/formatter/to_python_test.py @@ -94,6 +94,15 @@ def test_byte(minimal_swagger_spec): assert isinstance(result, str) +def test_byte_base64(minimal_swagger_dict): + swagger_spec = Spec.from_dict( + minimal_swagger_dict, config={'use_base64_for_byte_format': True}) + schema = {'type': 'string', 'format': 'byte'} + result = to_python(swagger_spec, schema, 'YWJj/w==') + assert b'abc\xff' == result + assert isinstance(result, bytes) + + def test_ref(minimal_swagger_dict): minimal_swagger_dict['definitions']['Int32'] = { 'type': 'integer', 'format': 'int32', diff --git a/tests/formatter/to_wire_test.py b/tests/formatter/to_wire_test.py index cdbf4a8e..c380bbf1 100644 --- a/tests/formatter/to_wire_test.py +++ b/tests/formatter/to_wire_test.py @@ -114,6 +114,15 @@ def test_byte_unicode(minimal_swagger_spec): assert isinstance(result, str) +def test_byte_base64(minimal_swagger_dict): + swagger_spec = Spec.from_dict( + minimal_swagger_dict, config={'use_base64_for_byte_format': True}) + schema = {'type': 'string', 'format': 'byte'} + result = to_wire(swagger_spec, schema, b'abc\xff') + assert 'YWJj/w==' == result + assert isinstance(result, str) + + def test_ref(minimal_swagger_dict): minimal_swagger_dict['definitions']['Int32'] = { 'type': 'integer', 'format': 'int32', From 0ab6aa6872863088318d313adc94c93731d7d83b Mon Sep 17 00:00:00 2001 From: Nick Gaya <> Date: Thu, 17 Oct 2019 23:13:31 -0700 Subject: [PATCH 2/4] Run pre-commit --- bravado_core/formatter.py | 3 ++- tests/formatter/to_python_test.py | 3 ++- tests/formatter/to_wire_test.py | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/bravado_core/formatter.py b/bravado_core/formatter.py index a811fa2a..6ceb3ad8 100644 --- a/bravado_core/formatter.py +++ b/bravado_core/formatter.py @@ -112,7 +112,8 @@ def wrapper(validatable_primitive): # Note: In Python 3, this requires a bytes-like object as input to_wire=lambda b: six.ensure_str(base64.b64encode(b), encoding='ascii'), to_python=lambda s: base64.b64decode( - six.ensure_binary(s, encoding='ascii')), + six.ensure_binary(s, encoding='ascii'), + ), validate=NO_OP, # jsonschema validates string description='Converts [wire]string:byte <=> python bytes', ) diff --git a/tests/formatter/to_python_test.py b/tests/formatter/to_python_test.py index 25b10234..9aa6fead 100644 --- a/tests/formatter/to_python_test.py +++ b/tests/formatter/to_python_test.py @@ -96,7 +96,8 @@ def test_byte(minimal_swagger_spec): def test_byte_base64(minimal_swagger_dict): swagger_spec = Spec.from_dict( - minimal_swagger_dict, config={'use_base64_for_byte_format': True}) + minimal_swagger_dict, config={'use_base64_for_byte_format': True}, + ) schema = {'type': 'string', 'format': 'byte'} result = to_python(swagger_spec, schema, 'YWJj/w==') assert b'abc\xff' == result diff --git a/tests/formatter/to_wire_test.py b/tests/formatter/to_wire_test.py index c380bbf1..204016e6 100644 --- a/tests/formatter/to_wire_test.py +++ b/tests/formatter/to_wire_test.py @@ -116,7 +116,8 @@ def test_byte_unicode(minimal_swagger_spec): def test_byte_base64(minimal_swagger_dict): swagger_spec = Spec.from_dict( - minimal_swagger_dict, config={'use_base64_for_byte_format': True}) + minimal_swagger_dict, config={'use_base64_for_byte_format': True}, + ) schema = {'type': 'string', 'format': 'byte'} result = to_wire(swagger_spec, schema, b'abc\xff') assert 'YWJj/w==' == result From ed85c4c31d797064a10226902e07cf675666672d Mon Sep 17 00:00:00 2001 From: Nick Gaya <> Date: Fri, 18 Oct 2019 00:00:48 -0700 Subject: [PATCH 3/4] Update changelog --- CHANGELOG.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2537cbf9..3f715de0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,8 @@ Changelog ========= .. Make sure to link Issue and PR information as `(PR|Issue) #xxx`_ and with a link at the bottom of the document +- Add option to automatically base64-encode/decode strings with byte format - `PR #351`_ + 5.13.2 (2019-09-04) ------------------- - Improve header validation error message - `PR #347`_ Thanks brycedrennan for your contribution! @@ -534,6 +536,7 @@ Changelog .. _PR #345: https://github.com/Yelp/bravado-core/pull/345 .. _PR #347: https://github.com/Yelp/bravado-core/pull/347 .. _PR #350: https://github.com/Yelp/bravado-core/pull/350 +.. _PR #351: https://github.com/Yelp/bravado-core/pull/351 .. Link To Documentation pages From 2a0e6c02c50fec785232f91a40c2bce5b9ae898d Mon Sep 17 00:00:00 2001 From: Nick Gaya <> Date: Fri, 18 Oct 2019 00:08:56 -0700 Subject: [PATCH 4/4] Update config documentation --- docs/source/config.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/source/config.rst b/docs/source/config.rst index 6c9d40de..2d0c891e 100644 --- a/docs/source/config.rst +++ b/docs/source/config.rst @@ -55,4 +55,7 @@ Config key Type Default Description | spec was retrieved from. | If disabled, set `basePath` to `/` (conforms to | the Swagger 2.0 specification) +----------------------------- --------------- --------- ---------------------------------------------------- +*use_base64_for_byte_format* boolean False | If true, base64-encode binary data to wire and + | base64-decode from wire for data with byte format. ============================= =============== ========= ====================================================