Skip to content

Commit

Permalink
Fix "ValueError: seek of closed file" bug - closes jschneier#382
Browse files Browse the repository at this point in the history
This is @mannpy's solution from:
jschneier#382 (comment)
  • Loading branch information
nikolas committed Jul 16, 2020
1 parent d36e309 commit 1577eab
Showing 1 changed file with 30 additions and 13 deletions.
43 changes: 30 additions & 13 deletions storages/backends/s3boto3.py
Expand Up @@ -436,20 +436,37 @@ def _open(self, name, mode='rb'):
return f

def _save(self, name, content):
cleaned_name = self._clean_name(name)
name = self._normalize_name(cleaned_name)
params = self._get_write_parameters(name, content)

if (self.gzip and
params['ContentType'] in self.gzip_content_types and
'ContentEncoding' not in params):
content = self._compress_content(content)
params['ContentEncoding'] = 'gzip'

obj = self.bucket.Object(name)
"""
We create a clone of the content file as when this is passed to
boto3 it wrongly closes the file upon upload where as the storage
backend expects it to still be open
"""
# Seek our content back to the start
content.seek(0, os.SEEK_SET)
obj.upload_fileobj(content, ExtraArgs=params)
return cleaned_name

# Create a temporary file that will write to disk after a specified
# size. This file will be automatically deleted when closed by
# boto3 or after exiting the `with` statement if the boto3 is fixed
with SpooledTemporaryFile() as content_autoclose:
# Write our original content into our copy that will be closed by boto3
content_autoclose.write(content.read())

# Upload the object which will auto close the
# content_autoclose instance
cleaned_name = self._clean_name(name)
name = self._normalize_name(cleaned_name)
params = self._get_write_parameters(name, content)

if (self.gzip and
params['ContentType'] in self.gzip_content_types and
'ContentEncoding' not in params):
content = self._compress_content(content)
params['ContentEncoding'] = 'gzip'

obj = self.bucket.Object(name)
content.seek(0, os.SEEK_SET)
obj.upload_fileobj(content, ExtraArgs=params)
return cleaned_name

def delete(self, name):
name = self._normalize_name(self._clean_name(name))
Expand Down

0 comments on commit 1577eab

Please sign in to comment.