From 58c1d038198046665317a0d00eb9630608349476 Mon Sep 17 00:00:00 2001 From: Holt Skinner <13262395+holtskinner@users.noreply.github.com> Date: Mon, 7 Oct 2024 10:47:08 -0500 Subject: [PATCH] fix: Changed name of methods `Blob.from_string()` and `Bucket.from_string()` to `from_uri()` (#1335) --- google/cloud/storage/blob.py | 37 ++++++++++++++++++++++++++++-- google/cloud/storage/bucket.py | 35 ++++++++++++++++++++++++++-- google/cloud/storage/client.py | 2 +- tests/unit/test_blob.py | 42 ++++++++++++++++++++++++++++------ tests/unit/test_bucket.py | 30 ++++++++++++++++++++---- tests/unit/test_client.py | 2 +- 6 files changed, 130 insertions(+), 18 deletions(-) diff --git a/google/cloud/storage/blob.py b/google/cloud/storage/blob.py index b7eb69928..b00568d92 100644 --- a/google/cloud/storage/blob.py +++ b/google/cloud/storage/blob.py @@ -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"(?Pgs)://(?P[a-z0-9_.-]+)/(?P.+)" ) @@ -389,7 +393,7 @@ 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 @@ -397,7 +401,7 @@ def from_string(cls, uri, client=None): 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. @@ -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, diff --git a/google/cloud/storage/bucket.py b/google/cloud/storage/bucket.py index 7cea15f4e..e6de1ac42 100644 --- a/google/cloud/storage/bucket.py +++ b/google/cloud/storage/bucket.py @@ -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): @@ -778,7 +781,7 @@ 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 @@ -786,7 +789,7 @@ def from_string(cls, uri, client=None): 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. @@ -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, diff --git a/google/cloud/storage/client.py b/google/cloud/storage/client.py index b1f48f97e..9e4d1f313 100644 --- a/google/cloud/storage/client.py +++ b/google/cloud/storage/client.py @@ -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, diff --git a/tests/unit/test_blob.py b/tests/unit/test_blob.py index 4a0488ba2..4a53e3d12 100644 --- a/tests/unit/test_blob.py +++ b/tests/unit/test_blob.py @@ -5905,12 +5905,12 @@ 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) @@ -5918,33 +5918,61 @@ def test_from_string_w_valid_uri(self): 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 diff --git a/tests/unit/test_bucket.py b/tests/unit/test_bucket.py index e6072ce5f..9818a9045 100644 --- a/tests/unit/test_bucket.py +++ b/tests/unit/test_bucket.py @@ -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() diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py index d3dd39422..68e471605 100644 --- a/tests/unit/test_client.py +++ b/tests/unit/test_client.py @@ -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