diff --git a/storages/backends/gcloud.py b/storages/backends/gcloud.py index 837b657bf..a18d5ac3f 100644 --- a/storages/backends/gcloud.py +++ b/storages/backends/gcloud.py @@ -1,3 +1,5 @@ +import gzip +import io import mimetypes import warnings from datetime import timedelta @@ -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 @@ -102,7 +102,7 @@ def close(self): @deconstructible -class GoogleCloudStorage(CompressStorageMixin, BaseStorage): +class GoogleCloudStorage(BaseStorage): def __init__(self, **settings): super().__init__(**settings) @@ -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) @@ -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 @@ -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) diff --git a/tests/test_gcloud.py b/tests/test_gcloud.py index 70e9ef52e..5896340be 100644 --- a/tests/test_gcloud.py +++ b/tests/test_gcloud.py @@ -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): @@ -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' @@ -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, @@ -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) @@ -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, @@ -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): @@ -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,