Skip to content

Commit af0dc51

Browse files
HemangChothanitseaver
authored andcommitted
Add Blob.from_string and Bucket.from_string factories. (googleapis#9143)
1 parent 9240062 commit af0dc51

File tree

6 files changed

+138
-16
lines changed

6 files changed

+138
-16
lines changed

storage/google/cloud/storage/blob.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,37 @@ def public_url(self):
310310
quoted_name=_quote(self.name, safe=b"/~"),
311311
)
312312

313+
@classmethod
314+
def from_string(cls, uri, client=None):
315+
"""Get a constructor for blob object by URI.
316+
317+
:type uri: str
318+
:param uri: The blob uri pass to get blob object.
319+
320+
:type client: :class:`~google.cloud.storage.client.Client` or
321+
``NoneType``
322+
:param client: Optional. The client to use.
323+
324+
:rtype: :class:`google.cloud.storage.blob.Blob`
325+
:returns: The blob object created.
326+
327+
Example:
328+
Get a constructor for blob object by URI..
329+
330+
>>> from google.cloud import storage
331+
>>> from google.cloud.storage.blob import Blob
332+
>>> client = storage.Client()
333+
>>> blob = Blob.from_string("gs://bucket/object")
334+
"""
335+
from google.cloud.storage.bucket import Bucket
336+
337+
scheme, netloc, path, query, frag = urlsplit(uri)
338+
if scheme != "gs":
339+
raise ValueError("URI scheme must be gs")
340+
341+
bucket = Bucket(client, name=netloc)
342+
return cls(path[1:], bucket)
343+
313344
def generate_signed_url(
314345
self,
315346
expiration=None,

storage/google/cloud/storage/bucket.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import warnings
2222

2323
import six
24+
from six.moves.urllib.parse import urlsplit
2425

2526
from google.api_core import page_iterator
2627
from google.api_core import datetime_helpers
@@ -495,6 +496,35 @@ def user_project(self):
495496
"""
496497
return self._user_project
497498

499+
@classmethod
500+
def from_string(cls, uri, client=None):
501+
"""Get a constructor for bucket object by URI.
502+
503+
:type uri: str
504+
:param uri: The bucket uri pass to get bucket object.
505+
506+
:type client: :class:`~google.cloud.storage.client.Client` or
507+
``NoneType``
508+
:param client: Optional. The client to use.
509+
510+
:rtype: :class:`google.cloud.storage.bucket.Bucket`
511+
:returns: The bucket object created.
512+
513+
Example:
514+
Get a constructor for bucket object by URI..
515+
516+
>>> from google.cloud import storage
517+
>>> from google.cloud.storage.bucket import Bucket
518+
>>> client = storage.Client()
519+
>>> bucket = Bucket.from_string("gs://bucket",client)
520+
"""
521+
scheme, netloc, path, query, frag = urlsplit(uri)
522+
523+
if scheme != "gs":
524+
raise ValueError("URI scheme must be gs")
525+
526+
return cls(client, name=netloc)
527+
498528
def blob(
499529
self,
500530
blob_name,

storage/google/cloud/storage/client.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616

1717
import google.api_core.client_options
1818

19-
from six.moves.urllib.parse import urlsplit
20-
2119
from google.auth.credentials import AnonymousCredentials
2220

2321
from google.api_core import page_iterator
@@ -420,13 +418,8 @@ def download_blob_to_file(self, blob_or_uri, file_obj, start=None, end=None):
420418
try:
421419
blob_or_uri.download_to_file(file_obj, client=self, start=start, end=end)
422420
except AttributeError:
423-
scheme, netloc, path, query, frag = urlsplit(blob_or_uri)
424-
if scheme != "gs":
425-
raise ValueError("URI scheme must be gs")
426-
bucket = Bucket(self, name=netloc)
427-
blob_or_uri = Blob(path[1:], bucket)
428-
429-
blob_or_uri.download_to_file(file_obj, client=self, start=start, end=end)
421+
blob = Blob.from_string(blob_or_uri)
422+
blob.download_to_file(file_obj, client=self, start=start, end=end)
430423

431424
def list_blobs(
432425
self,

storage/tests/unit/test_blob.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
import google.cloud.storage.blob
2525
import mock
26+
import pytest
2627
import six
2728
from six.moves import http_client
2829

@@ -3171,6 +3172,41 @@ def test_updated_unset(self):
31713172
blob = self._make_one("blob-name", bucket=BUCKET)
31723173
self.assertIsNone(blob.updated)
31733174

3175+
def test_from_string_w_valid_uri(self):
3176+
from google.cloud.storage.blob import Blob
3177+
3178+
connection = _Connection()
3179+
client = _Client(connection)
3180+
uri = "gs://BUCKET_NAME/b"
3181+
blob = Blob.from_string(uri, client)
3182+
3183+
self.assertIsInstance(blob, Blob)
3184+
self.assertIs(blob.client, client)
3185+
self.assertEqual(blob.name, "b")
3186+
self.assertEqual(blob.bucket.name, "BUCKET_NAME")
3187+
3188+
def test_from_string_w_invalid_uri(self):
3189+
from google.cloud.storage.blob import Blob
3190+
3191+
connection = _Connection()
3192+
client = _Client(connection)
3193+
3194+
with pytest.raises(ValueError, match="URI scheme must be gs"):
3195+
Blob.from_string("http://bucket_name/b", client)
3196+
3197+
def test_from_string_w_domain_name_bucket(self):
3198+
from google.cloud.storage.blob import Blob
3199+
3200+
connection = _Connection()
3201+
client = _Client(connection)
3202+
uri = "gs://buckets.example.com/b"
3203+
blob = Blob.from_string(uri, client)
3204+
3205+
self.assertIsInstance(blob, Blob)
3206+
self.assertIs(blob.client, client)
3207+
self.assertEqual(blob.name, "b")
3208+
self.assertEqual(blob.bucket.name, "buckets.example.com")
3209+
31743210

31753211
class Test__quote(unittest.TestCase):
31763212
@staticmethod

storage/tests/unit/test_bucket.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import unittest
1717

1818
import mock
19+
import pytest
1920

2021

2122
def _create_signing_credentials():
@@ -2668,6 +2669,39 @@ def _generate_signed_url_helper(
26682669
}
26692670
signer.assert_called_once_with(expected_creds, **expected_kwargs)
26702671

2672+
def test_get_bucket_from_string_w_valid_uri(self):
2673+
from google.cloud.storage.bucket import Bucket
2674+
2675+
connection = _Connection()
2676+
client = _Client(connection)
2677+
BUCKET_NAME = "BUCKET_NAME"
2678+
uri = "gs://" + BUCKET_NAME
2679+
bucket = Bucket.from_string(uri, client)
2680+
self.assertIsInstance(bucket, Bucket)
2681+
self.assertIs(bucket.client, client)
2682+
self.assertEqual(bucket.name, BUCKET_NAME)
2683+
2684+
def test_get_bucket_from_string_w_invalid_uri(self):
2685+
from google.cloud.storage.bucket import Bucket
2686+
2687+
connection = _Connection()
2688+
client = _Client(connection)
2689+
2690+
with pytest.raises(ValueError, match="URI scheme must be gs"):
2691+
Bucket.from_string("http://bucket_name", client)
2692+
2693+
def test_get_bucket_from_string_w_domain_name_bucket(self):
2694+
from google.cloud.storage.bucket import Bucket
2695+
2696+
connection = _Connection()
2697+
client = _Client(connection)
2698+
BUCKET_NAME = "buckets.example.com"
2699+
uri = "gs://" + BUCKET_NAME
2700+
bucket = Bucket.from_string(uri, client)
2701+
self.assertIsInstance(bucket, Bucket)
2702+
self.assertIs(bucket.client, client)
2703+
self.assertEqual(bucket.name, BUCKET_NAME)
2704+
26712705
def test_generate_signed_url_no_version_passed_warning(self):
26722706
self._generate_signed_url_helper()
26732707

storage/tests/unit/test_client.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,9 @@ def test_download_blob_to_file_with_uri(self):
676676
blob = mock.Mock()
677677
file_obj = io.BytesIO()
678678

679-
with mock.patch("google.cloud.storage.client.Blob", return_value=blob):
679+
with mock.patch(
680+
"google.cloud.storage.client.Blob.from_string", return_value=blob
681+
):
680682
client.download_blob_to_file("gs://bucket_name/path/to/object", file_obj)
681683

682684
blob.download_to_file.assert_called_once_with(
@@ -687,14 +689,10 @@ def test_download_blob_to_file_with_invalid_uri(self):
687689
project = "PROJECT"
688690
credentials = _make_credentials()
689691
client = self._make_one(project=project, credentials=credentials)
690-
blob = mock.Mock()
691692
file_obj = io.BytesIO()
692693

693-
with mock.patch("google.cloud.storage.client.Blob", return_value=blob):
694-
with pytest.raises(ValueError, match="URI scheme must be gs"):
695-
client.download_blob_to_file(
696-
"http://bucket_name/path/to/object", file_obj
697-
)
694+
with pytest.raises(ValueError, match="URI scheme must be gs"):
695+
client.download_blob_to_file("http://bucket_name/path/to/object", file_obj)
698696

699697
def test_list_blobs(self):
700698
from google.cloud.storage.bucket import Bucket

0 commit comments

Comments
 (0)