summaryrefslogtreecommitdiff
path: root/swiftclient/utils.py
diff options
context:
space:
mode:
Diffstat (limited to 'swiftclient/utils.py')
-rw-r--r--swiftclient/utils.py96
1 files changed, 89 insertions, 7 deletions
diff --git a/swiftclient/utils.py b/swiftclient/utils.py
index 0f442b3..f0fcc01 100644
--- a/swiftclient/utils.py
+++ b/swiftclient/utils.py
@@ -44,7 +44,7 @@ def prt_bytes(bytes, human_flag):
mods = list('KMGTPEZY')
temp = float(bytes)
if temp > 0:
- while (temp > 1023):
+ while temp > 1023:
try:
suffix = mods.pop(0)
except IndexError:
@@ -60,7 +60,7 @@ def prt_bytes(bytes, human_flag):
else:
bytes = '%12s' % bytes
- return(bytes)
+ return bytes
def generate_temp_url(path, seconds, key, method):
@@ -104,23 +104,105 @@ def generate_temp_url(path, seconds, key, method):
'{sig}&temp_url_expires={exp}'.format(
path=path,
sig=sig,
- exp=expiration)
- )
+ exp=expiration))
+
+
+class NoopMD5(object):
+ def __init__(self, *a, **kw):
+ pass
+
+ def update(self, *a, **kw):
+ pass
+
+ def hexdigest(self, *a, **kw):
+ return ''
+
+
+class ReadableToIterable(object):
+ """
+ Wrap a filelike object and act as an iterator.
+
+ It is recommended to use this class only on files opened in binary mode.
+ Due to the Unicode changes in python 3 files are now opened using an
+ encoding not suitable for use with the md5 class and because of this
+ hit the exception on every call to next. This could cause problems,
+ especially with large files and small chunk sizes.
+ """
+
+ def __init__(self, content, chunk_size=65536, md5=False):
+ """
+ :param content: The filelike object that is yielded from.
+ :param chunk_size: The max size of each yielded item.
+ :param md5: Flag to enable calculating the MD5 of the content
+ as it is yielded.
+ """
+ self.md5sum = hashlib.md5() if md5 else NoopMD5()
+ self.content = content
+ self.chunk_size = chunk_size
+
+ def get_md5sum(self):
+ return self.md5sum.hexdigest()
+
+ def __next__(self):
+ """
+ Both ``__next__`` and ``next`` are provided to allow compatibility
+ with python 2 and python 3 and their use of ``iterable.next()``
+ and ``next(iterable)`` respectively.
+ """
+ chunk = self.content.read(self.chunk_size)
+ if not chunk:
+ raise StopIteration
+
+ try:
+ self.md5sum.update(chunk)
+ except TypeError:
+ self.md5sum.update(chunk.encode())
+
+ return chunk
+
+ def next(self):
+ return self.__next__()
+
+ def __iter__(self):
+ return self
class LengthWrapper(object):
+ """
+ Wrap a filelike object with a maximum length.
- def __init__(self, readable, length):
+ Fix for https://github.com/kennethreitz/requests/issues/1648
+ It is recommended to use this class only on files opened in binary mode.
+ """
+ def __init__(self, readable, length, md5=False):
+ """
+ :param readable: The filelike object to read from.
+ :param length: The maximum amount of content to that can be read from
+ the filelike object before it is simulated to be
+ empty.
+ :param md5: Flag to enable calculating the MD5 of the content
+ as it is read.
+ """
+ self.md5sum = hashlib.md5() if md5 else NoopMD5()
self._length = self._remaining = length
self._readable = readable
def __len__(self):
return self._length
+ def get_md5sum(self):
+ return self.md5sum.hexdigest()
+
def read(self, *args, **kwargs):
if self._remaining <= 0:
return ''
- chunk = self._readable.read(
- *args, **kwargs)[:self._remaining]
+
+ chunk = self._readable.read(*args, **kwargs)[:self._remaining]
self._remaining -= len(chunk)
+
+ try:
+ self.md5sum.update(chunk)
+ except TypeError:
+ self.md5sum.update(chunk.encode())
+
return chunk