Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[storage.blob] Remove requests as dependency for storage.blob #25017

Merged
merged 21 commits into from
Jul 29, 2022
4 changes: 4 additions & 0 deletions sdk/storage/azure-storage-blob/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@
### Features Added

### Bugs Fixed
- Removed forced `requests` import for sync calls. (25017)
- Adjusted type hints for `upload_blob` and `StorageStreamDownloader.readall`.

## 12.13.0 (2022-07-07)

### Bugs Fixed
- Stable release of features from 12.13.0b1.
- Added support for deleting versions in `delete_blobs` by supplying `version_id`.
- Stable release of features from 12.13.0b1.
- Added support for deleting versions in `delete_blobs` by supplying `version_id`.
- Removed forced `requests` import for sync calls. (#25017)
Stevenjin8 marked this conversation as resolved.
Show resolved Hide resolved

## 12.13.0b1 (2022-06-15)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
from io import BytesIO
from typing import Generic, Iterator, TypeVar

import requests
from azure.core.exceptions import HttpResponseError, ServiceResponseError
from azure.core.exceptions import DecodeError, HttpResponseError, ServiceResponseError, IncompleteReadError
from azure.core.tracing.common import with_current_context

from ._shared.request_handlers import validate_and_format_range_headers
Expand Down Expand Up @@ -213,7 +212,7 @@ def _download_chunk(self, chunk_start, chunk_end):
try:
chunk_data = process_content(response, offset[0], offset[1], self.encryption_options)
retry_active = False
except (requests.exceptions.ChunkedEncodingError, requests.exceptions.ConnectionError) as error:
jalauzon-msft marked this conversation as resolved.
Show resolved Hide resolved
except (IncompleteReadError, HttpResponseError, DecodeError) as error:
retry_total -= 1
if retry_total <= 0:
raise ServiceResponseError(error, error=error)
Expand Down Expand Up @@ -474,7 +473,7 @@ def _initial_request(self):
self._encryption_options
)
retry_active = False
except (requests.exceptions.ChunkedEncodingError, requests.exceptions.ConnectionError) as error:
except (IncompleteReadError, HttpResponseError, DecodeError) as error:
retry_total -= 1
if retry_total <= 0:
raise ServiceResponseError(error, error=error)
Expand Down
18 changes: 18 additions & 0 deletions sdk/storage/azure-storage-blob/tests/test_get_blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -1019,4 +1019,22 @@ def test_get_blob_progress_readinto(self, storage_account_name, storage_account_
progress.assert_complete()
self.assertEqual(len(data), read)

@BlobPreparer()
def test_unicode_get_blob_binary_data2(self, storage_account_name, storage_account_key):
Stevenjin8 marked this conversation as resolved.
Show resolved Hide resolved
self._setup(storage_account_name, storage_account_key)
base64_data = 'AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w=='
binary_data = base64.b64decode(base64_data)

blob_name = self._get_blob_reference()
blob = self.bsc.get_blob_client(self.container_name, blob_name)
blob.upload_blob(binary_data)

# Act
content = blob.download_blob()

# Assert
self.assertIsInstance(content.properties, BlobProperties)
self.assertEqual(content.readall(), binary_data)


# ------------------------------------------------------------------------------
33 changes: 28 additions & 5 deletions sdk/storage/azure-storage-blob/tests/test_retry.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------
import unittest
from unittest import mock
import pytest

from azure.core.exceptions import (
HttpResponseError,
ResourceExistsError,
AzureError,
ClientAuthenticationError
ClientAuthenticationError,
ServiceResponseError
)
from azure.core.pipeline.transport import(
RequestsTransport
Expand All @@ -24,6 +25,9 @@
LinearRetry,
ExponentialRetry,
)
from requests import Response
from requests.exceptions import ContentDecodingError, ChunkedEncodingError
from azure.core.exceptions import DecodeError

from settings.testcase import BlobPreparer
from devtools_testutils.storage import StorageTestCase
Expand Down Expand Up @@ -434,6 +438,25 @@ def test_invalid_account_key(self, storage_account_name, storage_account_key):
# No retry should be performed since the signing error is fatal
self.assertEqual(retry_counter.count, 0)


# ------------------------------------------------------------------------------

@pytest.mark.live_test_only
jalauzon-msft marked this conversation as resolved.
Show resolved Hide resolved
@BlobPreparer()
def test_streaming_retry(self, storage_account_name, storage_account_key):
"""Test that retry mechanisms are working when streaming data."""
container_name = self.get_resource_name('utcontainer')
service = self._create_storage_service(
BlobServiceClient, storage_account_name, storage_account_key)
container = service.get_container_client(container_name)
container.create_container()
assert container.exists()
blob_name = "myblob"
container.upload_blob(blob_name, b"abcde")

for error in (ContentDecodingError(), ChunkedEncodingError(), ChunkedEncodingError("IncompleteRead")):
iterator_mock = mock.MagicMock()
iterator_mock.__next__.side_effect = error
iter_content_mock = mock.Mock()
iter_content_mock.return_value = iterator_mock
with mock.patch.object(Response, "iter_content", iter_content_mock), pytest.raises(ServiceResponseError):
blob = container.get_blob_client(blob=blob_name)
blob.download_blob()
assert iterator_mock.__next__.call_count == 3