Skip to content

Commit 4d6bb35

Browse files
authored
[v2] Update JSON formatter to encode bytes as Base64 strings (#9424)
1 parent 6275015 commit 4d6bb35

File tree

3 files changed

+38
-2
lines changed

3 files changed

+38
-2
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"type": "bugfix",
3+
"category": "Formatter",
4+
"description": "Update JSON formatter to encode raw bytes as UTF-8."
5+
}

awscli/utils.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
1111
# ANY KIND, either express or implied. See the License for the specific
1212
# language governing permissions and limitations under the License.
13+
import base64
1314
import contextlib
1415
import csv
1516
import datetime
@@ -372,11 +373,14 @@ def operation_uses_document_types(operation_model):
372373

373374

374375
def json_encoder(obj):
375-
"""JSON encoder that formats datetimes as ISO8601 format."""
376+
"""JSON encoder that formats datetimes as ISO8601 format
377+
and encodes bytes to UTF-8 Base64 string."""
376378
if isinstance(obj, datetime.datetime):
377379
return obj.isoformat()
380+
elif isinstance(obj, bytes):
381+
return base64.b64encode(obj).decode("utf-8")
378382
else:
379-
return obj
383+
raise TypeError('Encountered unrecognized type in JSON encoder.')
380384

381385

382386
@contextlib.contextmanager

tests/unit/output/test_json_output.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@
1111
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
1212
# ANY KIND, either express or implied. See the License for the specific
1313
# language governing permissions and limitations under the License.
14+
import base64
15+
import contextlib
16+
import io
1417
import platform
18+
import sys
1519

1620
from botocore.compat import json
1721

@@ -134,3 +138,26 @@ def test_fully_buffered_handles_io_error(self):
134138
# we still should have called the flush() on the
135139
# stream.
136140
fake_closed_stream.flush.assert_called_with()
141+
142+
143+
class TestBinaryData(unittest.TestCase):
144+
def test_binary_data_gets_base64_encoded(self):
145+
args = mock.Mock(query=None)
146+
raw_bytes = b'foo'
147+
response = {'BinaryValue': raw_bytes}
148+
stdout_b = io.BytesIO()
149+
stdout = io.TextIOWrapper(stdout_b, newline='\n')
150+
formatter = JSONFormatter(args)
151+
152+
with contextlib.redirect_stdout(stdout):
153+
formatter('command-name', response, sys.stdout)
154+
stdout.flush()
155+
156+
assert (
157+
stdout_b.getvalue()
158+
== (
159+
'{\n'
160+
f' "BinaryValue": "{base64.b64encode(raw_bytes).decode("utf-8")}"\n'
161+
'}\n'
162+
).encode()
163+
)

0 commit comments

Comments
 (0)