Skip to content

Commit

Permalink
fix: Changed name of methods Blob.from_string() and `Bucket.from_st…
Browse files Browse the repository at this point in the history
…ring()` to `from_uri()` (#1335)
  • Loading branch information
holtskinner authored and andrewsg committed Dec 11, 2024
1 parent df107d2 commit 58c1d03
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 18 deletions.
37 changes: 35 additions & 2 deletions google/cloud/storage/blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@
"Blob.download_as_string() is deprecated and will be removed in future. "
"Use Blob.download_as_bytes() instead."
)
_FROM_STRING_DEPRECATED = (
"Blob.from_string() is deprecated and will be removed in future. "
"Use Blob.from_uri() instead."
)
_GS_URL_REGEX_PATTERN = re.compile(
r"(?P<scheme>gs)://(?P<bucket_name>[a-z0-9_.-]+)/(?P<object_name>.+)"
)
Expand Down Expand Up @@ -389,15 +393,15 @@ def public_url(self):
)

@classmethod
def from_string(cls, uri, client=None):
def from_uri(cls, uri, client=None):
"""Get a constructor for blob object by URI.
.. code-block:: python
from google.cloud import storage
from google.cloud.storage.blob import Blob
client = storage.Client()
blob = Blob.from_string("gs://bucket/object", client=client)
blob = Blob.from_uri("gs://bucket/object", client=client)
:type uri: str
:param uri: The blob uri following a gs://bucket/object pattern.
Expand All @@ -419,6 +423,35 @@ def from_string(cls, uri, client=None):
bucket = Bucket(client, name=match.group("bucket_name"))
return cls(match.group("object_name"), bucket)

@classmethod
def from_string(cls, uri, client=None):
"""(Deprecated) Get a constructor for blob object by URI.
.. note::
Deprecated alias for :meth:`from_uri`.
.. code-block:: python
from google.cloud import storage
from google.cloud.storage.blob import Blob
client = storage.Client()
blob = Blob.from_string("gs://bucket/object", client=client)
:type uri: str
:param uri: The blob uri following a gs://bucket/object pattern.
Both a bucket and object name is required to construct a blob object.
:type client: :class:`~google.cloud.storage.client.Client`
:param client:
(Optional) The client to use. Application code should
*always* pass ``client``.
:rtype: :class:`google.cloud.storage.blob.Blob`
:returns: The blob object created.
"""
warnings.warn(_FROM_STRING_DEPRECATED, PendingDeprecationWarning, stacklevel=2)
return Blob.from_uri(uri=uri, client=client)

def generate_signed_url(
self,
expiration=None,
Expand Down
35 changes: 33 additions & 2 deletions google/cloud/storage/bucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@
"valid before the bucket is created. Instead, pass the location "
"to `Bucket.create`."
)
_FROM_STRING_MESSAGE = (
"Bucket.from_string() is deprecated. " "Use Bucket.from_uri() instead."
)


def _blobs_page_start(iterator, page, response):
Expand Down Expand Up @@ -778,15 +781,15 @@ def _query_params(self):
return params

@classmethod
def from_string(cls, uri, client=None):
def from_uri(cls, uri, client=None):
"""Get a constructor for bucket object by URI.
.. code-block:: python
from google.cloud import storage
from google.cloud.storage.bucket import Bucket
client = storage.Client()
bucket = Bucket.from_string("gs://bucket", client=client)
bucket = Bucket.from_uri("gs://bucket", client=client)
:type uri: str
:param uri: The bucket uri pass to get bucket object.
Expand All @@ -806,6 +809,34 @@ def from_string(cls, uri, client=None):

return cls(client, name=netloc)

@classmethod
def from_string(cls, uri, client=None):
"""Get a constructor for bucket object by URI.
.. note::
Deprecated alias for :meth:`from_uri`.
.. code-block:: python
from google.cloud import storage
from google.cloud.storage.bucket import Bucket
client = storage.Client()
bucket = Bucket.from_string("gs://bucket", client=client)
:type uri: str
:param uri: The bucket uri pass to get bucket object.
:type client: :class:`~google.cloud.storage.client.Client` or
``NoneType``
:param client: (Optional) The client to use. Application code should
*always* pass ``client``.
:rtype: :class:`google.cloud.storage.bucket.Bucket`
:returns: The bucket object created.
"""
warnings.warn(_FROM_STRING_MESSAGE, PendingDeprecationWarning, stacklevel=2)
return Bucket.from_uri(uri=uri, client=client)

def blob(
self,
blob_name,
Expand Down
2 changes: 1 addition & 1 deletion google/cloud/storage/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1202,7 +1202,7 @@ def download_blob_to_file(
"""

if not isinstance(blob_or_uri, Blob):
blob_or_uri = Blob.from_string(blob_or_uri)
blob_or_uri = Blob.from_uri(blob_or_uri)

blob_or_uri._prep_and_do_download(
file_obj,
Expand Down
42 changes: 35 additions & 7 deletions tests/unit/test_blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -5905,46 +5905,74 @@ def test_soft_hard_delte_time_unset(self):
self.assertIsNone(blob.soft_delete_time)
self.assertIsNone(blob.hard_delete_time)

def test_from_string_w_valid_uri(self):
def test_from_uri_w_valid_uri(self):
from google.cloud.storage.blob import Blob

client = self._make_client()
basic_uri = "gs://bucket_name/b"
blob = Blob.from_string(basic_uri, client)
blob = Blob.from_uri(basic_uri, client)

self.assertIsInstance(blob, Blob)
self.assertIs(blob.client, client)
self.assertEqual(blob.name, "b")
self.assertEqual(blob.bucket.name, "bucket_name")

nested_uri = "gs://bucket_name/path1/path2/b#name"
blob = Blob.from_string(nested_uri, client)
blob = Blob.from_uri(nested_uri, client)

self.assertIsInstance(blob, Blob)
self.assertIs(blob.client, client)
self.assertEqual(blob.name, "path1/path2/b#name")
self.assertEqual(blob.bucket.name, "bucket_name")

def test_from_string_w_invalid_uri(self):
def test_from_uri_w_invalid_uri(self):
from google.cloud.storage.blob import Blob

client = self._make_client()

with pytest.raises(ValueError):
Blob.from_string("http://bucket_name/b", client)
Blob.from_uri("http://bucket_name/b", client)

def test_from_string_w_domain_name_bucket(self):
def test_from_uri_w_domain_name_bucket(self):
from google.cloud.storage.blob import Blob

client = self._make_client()
uri = "gs://buckets.example.com/b"
blob = Blob.from_string(uri, client)
blob = Blob.from_uri(uri, client)

self.assertIsInstance(blob, Blob)
self.assertIs(blob.client, client)
self.assertEqual(blob.name, "b")
self.assertEqual(blob.bucket.name, "buckets.example.com")

@mock.patch("warnings.warn")
def test_from_string(self, mock_warn):
from google.cloud.storage.blob import _FROM_STRING_DEPRECATED
from google.cloud.storage.blob import Blob

client = self._make_client()
basic_uri = "gs://bucket_name/b"
blob = Blob.from_string(basic_uri, client)

self.assertIsInstance(blob, Blob)
self.assertIs(blob.client, client)
self.assertEqual(blob.name, "b")
self.assertEqual(blob.bucket.name, "bucket_name")

nested_uri = "gs://bucket_name/path1/path2/b#name"
blob = Blob.from_string(nested_uri, client)

self.assertIsInstance(blob, Blob)
self.assertIs(blob.client, client)
self.assertEqual(blob.name, "path1/path2/b#name")
self.assertEqual(blob.bucket.name, "bucket_name")

mock_warn.assert_any_call(
_FROM_STRING_DEPRECATED,
PendingDeprecationWarning,
stacklevel=2,
)

def test_open(self):
from io import TextIOWrapper
from google.cloud.storage.fileio import BlobReader
Expand Down
30 changes: 25 additions & 5 deletions tests/unit/test_bucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -4386,39 +4386,59 @@ def _generate_signed_url_helper(
}
signer.assert_called_once_with(expected_creds, **expected_kwargs)

def test_get_bucket_from_string_w_valid_uri(self):
def test_get_bucket_from_uri_w_valid_uri(self):
from google.cloud.storage.bucket import Bucket

client = self._make_client()
BUCKET_NAME = "BUCKET_NAME"
uri = "gs://" + BUCKET_NAME

bucket = Bucket.from_string(uri, client)
bucket = Bucket.from_uri(uri, client)

self.assertIsInstance(bucket, Bucket)
self.assertIs(bucket.client, client)
self.assertEqual(bucket.name, BUCKET_NAME)

def test_get_bucket_from_string_w_invalid_uri(self):
def test_get_bucket_from_uri_w_invalid_uri(self):
from google.cloud.storage.bucket import Bucket

client = self._make_client()

with pytest.raises(ValueError, match="URI scheme must be gs"):
Bucket.from_string("http://bucket_name", client)
Bucket.from_uri("http://bucket_name", client)

def test_get_bucket_from_string_w_domain_name_bucket(self):
def test_get_bucket_from_uri_w_domain_name_bucket(self):
from google.cloud.storage.bucket import Bucket

client = self._make_client()
BUCKET_NAME = "buckets.example.com"
uri = "gs://" + BUCKET_NAME

bucket = Bucket.from_uri(uri, client)

self.assertIsInstance(bucket, Bucket)
self.assertIs(bucket.client, client)
self.assertEqual(bucket.name, BUCKET_NAME)

@mock.patch("warnings.warn")
def test_get_bucket_from_string(self, mock_warn):
from google.cloud.storage.bucket import _FROM_STRING_MESSAGE
from google.cloud.storage.bucket import Bucket

client = self._make_client()
BUCKET_NAME = "BUCKET_NAME"
uri = "gs://" + BUCKET_NAME

bucket = Bucket.from_string(uri, client)

self.assertIsInstance(bucket, Bucket)
self.assertIs(bucket.client, client)
self.assertEqual(bucket.name, BUCKET_NAME)
mock_warn.assert_any_call(
_FROM_STRING_MESSAGE,
PendingDeprecationWarning,
stacklevel=2,
)

def test_generate_signed_url_no_version_passed_warning(self):
self._generate_signed_url_helper()
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1837,7 +1837,7 @@ def test_download_blob_to_file_with_uri(self):
_helpers, "_get_invocation_id", return_value=GCCL_INVOCATION_TEST_CONST
):
with mock.patch(
"google.cloud.storage.client.Blob.from_string", return_value=blob
"google.cloud.storage.client.Blob.from_uri", return_value=blob
):
client.download_blob_to_file(
"gs://bucket_name/path/to/object", file_obj
Expand Down

0 comments on commit 58c1d03

Please sign in to comment.