summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Schwartz <mfschwartz@google.com>2019-03-26 18:07:03 -0700
committerGitHub <noreply@github.com>2019-03-26 18:07:03 -0700
commit9e1cd3bd76e738d80630f1bd9160fd87c8eab865 (patch)
tree8eaf0e0f477b7e11e85cb0e5f9b33844789d0c86
parentacd6a95ad953a4f1ac72adfc354a6c5aec74fbb0 (diff)
parent2b9fd4f699ae5d40b4773f19ea61489928ea2a22 (diff)
downloadboto-9e1cd3bd76e738d80630f1bd9160fd87c8eab865.tar.gz
Merge pull request #3859 from catleeball/fd-writer
Added print_to_fd to utils.py
-rw-r--r--boto/s3/key.py4
-rw-r--r--boto/utils.py82
2 files changed, 84 insertions, 2 deletions
diff --git a/boto/s3/key.py b/boto/s3/key.py
index 35f04c9f..f9260258 100644
--- a/boto/s3/key.py
+++ b/boto/s3/key.py
@@ -46,7 +46,7 @@ import boto.utils
from boto.utils import compute_md5, compute_hash
from boto.utils import find_matching_headers
from boto.utils import merge_headers_by_name
-
+from boto.utils import print_to_fd
class Key(object):
"""
@@ -1553,7 +1553,7 @@ class Key(object):
cb(data_len, cb_size)
try:
for key_bytes in self:
- print(key_bytes, file=fp, end='')
+ print_to_fd(six.ensure_binary(key_bytes), file=fp, end=b'')
data_len += len(key_bytes)
for alg in digesters:
digesters[alg].update(key_bytes)
diff --git a/boto/utils.py b/boto/utils.py
index 531a72d3..35637772 100644
--- a/boto/utils.py
+++ b/boto/utils.py
@@ -44,11 +44,13 @@ import time
import logging.handlers
import boto
import boto.provider
+import collections
import tempfile
import random
import smtplib
import datetime
import re
+import io
import email.mime.multipart
import email.mime.base
import email.mime.text
@@ -57,6 +59,7 @@ import email.encoders
import gzip
import threading
import locale
+import sys
from boto.compat import six, StringIO, urllib, encodebytes
from contextlib import contextmanager
@@ -1098,3 +1101,82 @@ def parse_host(hostname):
else:
return hostname.split(':', 1)[0]
+def print_to_fd(*objects, **kwargs):
+ """A Python 2/3 compatible analogue to the print function.
+
+ This function writes text to a file descriptor as the
+ builtin print function would, favoring utf-8 encoding.
+ Arguments and return values are the same as documented in
+ the Python 2 print function.
+ """
+ def _get_args(**kwargs):
+ """Validates keyword arguments that would be used in Print
+ Valid keyword arguments, mirroring print(), are 'sep',
+ 'end', and 'file'. These must be of types string, string,
+ and file / file interface respectively.
+ Returns the above kwargs of the above types.
+ """
+ expected_keywords = collections.OrderedDict([
+ ('sep', ' '),
+ ('end', '\n'),
+ ('file', sys.stdout)])
+
+ for key, value in kwargs.items():
+ if key not in expected_keywords:
+ error_msg = (
+ '{} is not a valid keyword argument. '
+ 'Please use one of: {}')
+ raise KeyError(
+ error_msg.format(
+ key,
+ ' '.join(expected_keywords.keys())))
+ else:
+ expected_keywords[key] = value
+
+ return expected_keywords.values()
+
+ def _get_byte_strings(*objects):
+ """Gets a `bytes` string for each item in list of printable objects."""
+ byte_objects = []
+ for item in objects:
+ if not isinstance(item, (six.binary_type, six.text_type)):
+ # If the item wasn't bytes or unicode, its __str__ method
+ # should return one of those types.
+ item = str(item)
+
+ if isinstance(item, six.binary_type):
+ byte_objects.append(item)
+ else:
+ # The item should be unicode. If it's not, ensure_binary()
+ # will throw a TypeError.
+ byte_objects.append(six.ensure_binary(item))
+ return byte_objects
+
+ sep, end, file = _get_args(**kwargs)
+ sep = six.ensure_binary(sep)
+ end = six.ensure_binary(end)
+ data = _get_byte_strings(*objects)
+ data = sep.join(data)
+ data += end
+ write_to_fd(file, data)
+
+
+def write_to_fd(fd, data):
+ """Write given data to given file descriptor, doing any conversions needed"""
+ if six.PY2:
+ fd.write(data)
+ return
+ # PY3 logic:
+ if isinstance(data, bytes):
+ if ((hasattr(fd, 'mode') and 'b' in fd.mode) or
+ isinstance(fd, io.BytesIO)):
+ fd.write(data)
+ elif hasattr(fd, 'buffer'):
+ fd.buffer.write(data)
+ else:
+ fd.write(six.ensure_text(data))
+ elif 'b' in fd.mode:
+ fd.write(six.ensure_binary(data))
+ else:
+ fd.write(data)
+