Skip to content

Commit

Permalink
[gcloud] fix saving content as gzipped (#1203)
Browse files Browse the repository at this point in the history
  • Loading branch information
jschneier committed Dec 23, 2022
1 parent ca228c8 commit 809c345
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 44 deletions.
23 changes: 15 additions & 8 deletions storages/backends/gcloud.py
@@ -1,3 +1,5 @@
import gzip
import io
import mimetypes
import warnings
from datetime import timedelta
Expand All @@ -11,11 +13,9 @@

from storages.base import BaseStorage
from storages.compress import CompressedFileMixin
from storages.compress import CompressStorageMixin
from storages.utils import check_location
from storages.utils import clean_name
from storages.utils import get_available_overwrite_name
from storages.utils import is_seekable
from storages.utils import safe_join
from storages.utils import setting
from storages.utils import to_bytes
Expand Down Expand Up @@ -102,7 +102,7 @@ def close(self):


@deconstructible
class GoogleCloudStorage(CompressStorageMixin, BaseStorage):
class GoogleCloudStorage(BaseStorage):
def __init__(self, **settings):
super().__init__(**settings)

Expand Down Expand Up @@ -174,6 +174,14 @@ def _open(self, name, mode='rb'):
raise FileNotFoundError('File does not exist: %s' % name)
return file_object

def _compress_content(self, content):
content.seek(0)
zbuf = io.BytesIO()
with gzip.GzipFile(mode='wb', fileobj=zbuf, mtime=0.0) as zfile:
zfile.write(to_bytes(content.read()))
zbuf.seek(0)
return zbuf

def _save(self, name, content):
cleaned_name = clean_name(name)
name = self._normalize_name(cleaned_name)
Expand All @@ -195,10 +203,9 @@ def _save(self, name, content):
for prop, val in blob_params.items():
setattr(file_object.blob, prop, val)

rewind = is_seekable(content)
file_object.blob.upload_from_file(
content,
rewind=rewind,
rewind=True,
retry=DEFAULT_RETRY,
size=getattr(content, 'size', None),
**upload_params
Expand Down Expand Up @@ -300,9 +307,9 @@ def get_created_time(self, name):

def url(self, name, parameters=None):
"""
Return public url or a signed url for the Blob.
This DOES NOT check for existance of Blob - that makes codes too slow
for many use cases.
Return public URL or a signed URL for the Blob.
The existnce of blobs are not verified for public URLs, it makes the code too slow.
"""
name = self._normalize_name(clean_name(name))
blob = self.bucket.blob(name)
Expand Down
41 changes: 5 additions & 36 deletions tests/test_gcloud.py
Expand Up @@ -14,7 +14,6 @@
from google.cloud.storage.retry import DEFAULT_RETRY

from storages.backends import gcloud
from tests.utils import NonSeekableContentFile


class GCloudTestCase(TestCase):
Expand Down Expand Up @@ -417,9 +416,7 @@ def test_cache_control(self):
self.assertEqual(blob.cache_control, cache_control)

def test_storage_save_gzip_twice(self):
"""
Test saving the same file content twice with gzip enabled.
"""
"""Test saving the same file content twice with gzip enabled."""
# Given
self.storage.gzip = True
name = 'test_storage_save.css'
Expand All @@ -435,7 +432,7 @@ def test_storage_save_gzip_twice(self):
self.assertEqual(obj.content_encoding, 'gzip')
obj.upload_from_file.assert_called_with(
mock.ANY,
rewind=False,
rewind=True,
retry=DEFAULT_RETRY,
size=None,
predefined_acl=None,
Expand All @@ -447,9 +444,7 @@ def test_storage_save_gzip_twice(self):
self.assertEqual(zfile.read(), b"I should be gzip'd")

def test_compress_content_len(self):
"""
Test that file returned by _compress_content() is readable.
"""
"""Test that file returned by _compress_content() is readable."""
self.storage.gzip = True
content = ContentFile("I should be gzip'd")
content = self.storage._compress_content(content)
Expand Down Expand Up @@ -532,7 +527,7 @@ def test_storage_save_gzipped(self, *args):
self.storage.save(name, content)
blob.upload_from_file.assert_called_with(
mock.ANY,
rewind=False,
rewind=True,
retry=DEFAULT_RETRY,
size=None,
predefined_acl=None,
Expand All @@ -541,32 +536,6 @@ def test_storage_save_gzipped(self, *args):
finally:
patcher.stop()

@mock.patch('google.cloud.storage.blob.Blob._do_upload')
@mock.patch('google.auth.default', return_value=['foo', None])
def test_storage_save_gzipped_non_seekable(self, *args):
"""
Test saving a gzipped file
"""
name = 'test_storage_save.gz'
content = NonSeekableContentFile("I am gzip'd")

blob = Blob('x', None)
blob.upload_from_file = mock.MagicMock(side_effect=blob.upload_from_file)
patcher = mock.patch('google.cloud.storage.Bucket.get_blob', return_value=blob)
try:
patcher.start()
self.storage.save(name, content)
blob.upload_from_file.assert_called_with(
mock.ANY,
rewind=False,
retry=DEFAULT_RETRY,
size=11,
predefined_acl=None,
content_type=None
)
finally:
patcher.stop()

@mock.patch('google.cloud.storage.blob.Blob._do_upload')
@mock.patch('google.auth.default', return_value=['foo', None])
def test_storage_save_gzip(self, *args):
Expand All @@ -587,7 +556,7 @@ def test_storage_save_gzip(self, *args):
obj = self.storage._bucket.get_blob()
obj.upload_from_file.assert_called_with(
mock.ANY,
rewind=False,
rewind=True,
retry=DEFAULT_RETRY,
size=None,
predefined_acl=None,
Expand Down

0 comments on commit 809c345

Please sign in to comment.