Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
48671cb
Refactored download stream API
annatisch Oct 12, 2019
c741675
Unskip tests
annatisch Oct 12, 2019
40914d9
Test warnings
annatisch Oct 12, 2019
ec2c05c
Missing await
annatisch Oct 12, 2019
4ba1b20
Fixed append tests
annatisch Oct 12, 2019
32db209
Fixed page tests
annatisch Oct 12, 2019
5bf0d7f
Pylint
annatisch Oct 12, 2019
3e063e4
Py2.7 iter support
annatisch Oct 12, 2019
cb3144c
Refactor downloaders
annatisch Oct 12, 2019
f1fadfe
Added missing async module functions
annatisch Oct 12, 2019
48ae6f5
Merge branch 'feature/storage-preview5' into storage-downloads
annatisch Oct 12, 2019
4b369a3
Updated release notes
annatisch Oct 14, 2019
8d90594
Merge branch 'storage-downloads' of https://github.com/annatisch/azur…
annatisch Oct 14, 2019
3b1d6b5
Keyword params
annatisch Oct 14, 2019
366847f
Merge branch 'feature/storage-preview5' into storage-downloads
annatisch Oct 14, 2019
12d2c11
Merge branch 'feature/storage-preview5' into storage-downloads
annatisch Oct 14, 2019
f6bee26
Merge branch 'feature/storage-preview5' into storage-downloads
annatisch Oct 14, 2019
31e38bd
Documented more keyword options
annatisch Oct 14, 2019
f929acc
Merge branch 'storage-downloads' of https://github.com/annatisch/azur…
annatisch Oct 14, 2019
d895acb
Added module functions to exports
annatisch Oct 15, 2019
d46f074
Merge branch 'feature/storage-preview5' into storage-downloads
annatisch Oct 16, 2019
51777cc
Fixed merge
annatisch Oct 16, 2019
d5911c3
Merge remote-tracking branch 'upstream/feature/storage-preview5' into…
annatisch Oct 17, 2019
cb17af9
Fix for Files download stream
annatisch Oct 17, 2019
233eb40
Pylint fix
annatisch Oct 17, 2019
75e4b33
Updated File stream downloads
annatisch Oct 17, 2019
8cbfb4e
Merge remote-tracking branch 'upstream/feature/storage-preview5' into…
annatisch Oct 17, 2019
7788730
Fix tests
annatisch Oct 17, 2019
e8878a1
Updated error message
annatisch Oct 17, 2019
145d6c1
Added Files release notes
annatisch Oct 17, 2019
e80b075
Pylint fix
annatisch Oct 17, 2019
5d08ca4
Download stream error handling
annatisch Oct 18, 2019
c8e8f7a
Fixed some tests
annatisch Oct 18, 2019
be38f71
Merge branch 'feature/storage-preview5' into storage-downloads
annatisch Oct 18, 2019
10a08d8
Merge branch 'feature/storage-preview5' into storage-downloads
annatisch Oct 19, 2019
a61d220
Merge branch 'feature/storage-preview5' into storage-downloads
annatisch Oct 19, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion sdk/storage/azure-storage-blob/HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,20 @@
**Breaking changes**

- `set_container_access_policy` has required parameter `signed_identifiers`.
- NoRetry policy has been removed. Use keyword argument `retry_total=0` for no retries.
- `NoRetry` policy has been removed. Use keyword argument `retry_total=0` for no retries.
- `StorageStreamDownloader` is no longer iterable. To iterate over the blob data stream, use `StorageStreamDownloader.chunks`.
- The public attributes of `StorageStreamDownloader` have been limited to:
- `name` (str): The name of the blob.
- `container` (str): The container the blob is being downloaded from.
- `properties` (`BlobProperties`): The properties of the blob.
- `size` (int): The size of the download. Either the total blob size, or the length of a subsection if sepcified. Previously called `download_size`.
- `StorageStreamDownloader` now has new functions:
- `readall()`: Reads the complete download stream, returning bytes. This replaces the functions `content_as_bytes` and `content_as_text` which have been deprecated.
- `readinto(stream)`: Download the complete stream into the supplied writable stream, returning the number of bytes written. This replaces the function `download_to_stream` which has been deprecated.
- Module level functions `upload_blob_to_url` and `download_blob_from_url` functions options are now keyword only:
- `overwrite`
- `max_concurrency`
- `encoding`
- Removed types that were accidentally exposed from two modules. Only `BlobServiceClient`, `ContainerClient`,
`BlobClient` and `LeaseClient` should be imported from azure.storage.blob.aio
- `Logging` has been renamed to `BlobAnalyticsLogging`.
Expand All @@ -14,6 +27,7 @@

**New features**

- Added async module-level `upload_blob_to_url` and `download_blob_from_url` functions.
- `ResourceTypes`, and `Services` now have method `from_string` which takes parameters as a string.

## Version 12.0.0b4:
Expand Down
4 changes: 2 additions & 2 deletions sdk/storage/azure-storage-blob/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ blob = BlobClient.from_connection_string("my_connection_string", container="myco

with open("./BlockDestination.txt", "wb") as my_blob:
blob_data = blob.download_blob()
my_blob.writelines(blob_data.content_as_bytes())
my_blob.writelines(blob_data.readall())
```

Download a blob asynchronously.
Expand All @@ -165,7 +165,7 @@ blob = BlobClient.from_connection_string("my_connection_string", container="myco

with open("./BlockDestination.txt", "wb") as my_blob:
stream = await blob.download_blob()
data = await stream.content_as_bytes()
data = await stream.readall()
my_blob.write(data)
```

Expand Down
162 changes: 95 additions & 67 deletions sdk/storage/azure-storage-blob/azure/storage/blob/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
CorsRule,
ContainerProperties,
BlobProperties,
BlobPrefix,
LeaseProperties,
ContentSettings,
CopyProperties,
Expand All @@ -54,54 +53,9 @@
__version__ = VERSION


__all__ = [
'BlobServiceClient',
'ContainerClient',
'BlobClient',
'BlobType',
'LeaseClient',
'StorageErrorCode',
'UserDelegationKey',
'ExponentialRetry',
'LinearRetry',
'LocationMode',
'BlockState',
'StandardBlobTier',
'PremiumPageBlobTier',
'SequenceNumberAction',
'PublicAccess',
'BlobAnalyticsLogging',
'Metrics',
'RetentionPolicy',
'StaticWebsite',
'CorsRule',
'ContainerProperties',
'BlobProperties',
'BlobPrefix',
'LeaseProperties',
'ContentSettings',
'CopyProperties',
'BlobBlock',
'PageRange',
'AccessPolicy',
'ContainerSasPermissions',
'BlobSasPermissions',
'ResourceTypes',
'AccountSasPermissions',
'StorageStreamDownloader',
'CustomerProvidedEncryptionKey',
'RehydratePriority',
'generate_account_sas',
'generate_container_sas',
'generate_blob_sas'
]


def upload_blob_to_url(
blob_url, # type: str
data, # type: Union[Iterable[AnyStr], IO[AnyStr]]
max_concurrency=1, # type: int
encoding='UTF-8', # type: str
credential=None, # type: Any
**kwargs):
# type: (...) -> dict[str, Any]
Expand All @@ -114,38 +68,50 @@ def upload_blob_to_url(
:param data:
The data to upload. This can be bytes, text, an iterable or a file-like object.
:type data: bytes or str or Iterable
:param bool overwrite:
Whether the blob to be uploaded should overwrite the current data.
If True, upload_blob_to_url will overwrite any existing data. If set to False, the
operation will fail with a ResourceExistsError.
:param credential:
The credentials with which to authenticate. This is optional if the
blob URL already has a SAS token. The value can be a SAS token string, an account
shared access key, or an instance of a TokenCredentials class from azure.identity.
If the URL already has a SAS token, specifying an explicit credential will take priority.
:keyword bool overwrite:
Whether the blob to be uploaded should overwrite the current data.
If True, upload_blob_to_url will overwrite any existing data. If set to False, the
operation will fail with a ResourceExistsError.
:keyword int max_concurrency:
The number of parallel connections with which to download.
:keyword int length:
Number of bytes to read from the stream. This is optional, but
should be supplied for optimal performance.
:keyword metadata:
Name-value pairs associated with the blob as metadata.
:type metadata: dict(str, str)
:keyword bool validate_content:
If true, calculates an MD5 hash for each chunk of the blob. The storage
service checks the hash of the content that has arrived with the hash
that was sent. This is primarily valuable for detecting bitflips on
the wire if using http instead of https as https (the default) will
already validate. Note that this MD5 hash is not stored with the
blob. Also note that if enabled, the memory-efficient upload algorithm
will not be used, because computing the MD5 hash requires buffering
entire blocks, and doing so defeats the purpose of the memory-efficient algorithm.
:keyword str encoding:
Encoding to use if text is supplied as input. Defaults to UTF-8.
:returns: Blob-updated property dict (Etag and last modified)
:rtype: dict(str, Any)
"""
with BlobClient.from_blob_url(blob_url, credential=credential) as client:
return client.upload_blob(
data=data,
blob_type=BlobType.BlockBlob,
max_concurrency=max_concurrency,
encoding=encoding,
**kwargs)
return client.upload_blob(data=data, blob_type=BlobType.BlockBlob, **kwargs)


def _download_to_stream(client, handle, max_concurrency, **kwargs):
def _download_to_stream(client, handle, **kwargs):
"""Download data to specified open file-handle."""
stream = client.download_blob(**kwargs)
stream.download_to_stream(handle, max_concurrency=max_concurrency)
stream.readinto(handle)


def download_blob_from_url(
blob_url, # type: str
output, # type: str
overwrite=False, # type: bool
max_concurrency=1, # type: int
credential=None, # type: Any
**kwargs):
# type: (...) -> None
Expand All @@ -157,23 +123,85 @@ def download_blob_from_url(
Where the data should be downloaded to. This could be either a file path to write to,
or an open IO handle to write to.
:type output: str or writable stream.
:param bool overwrite:
Whether the local file should be overwritten if it already exists. The default value is
`False` - in which case a ValueError will be raised if the file already exists. If set to
`True`, an attempt will be made to write to the existing file. If a stream handle is passed
in, this value is ignored.
:param credential:
The credentials with which to authenticate. This is optional if the
blob URL already has a SAS token or the blob is public. The value can be a SAS token string,
an account shared access key, or an instance of a TokenCredentials class from azure.identity.
If the URL already has a SAS token, specifying an explicit credential will take priority.
:keyword bool overwrite:
Whether the local file should be overwritten if it already exists. The default value is
`False` - in which case a ValueError will be raised if the file already exists. If set to
`True`, an attempt will be made to write to the existing file. If a stream handle is passed
in, this value is ignored.
:keyword int max_concurrency:
The number of parallel connections with which to download.
:keyword int offset:
Start of byte range to use for downloading a section of the blob.
Must be set if length is provided.
:keyword int length:
Number of bytes to read from the stream. This is optional, but
should be supplied for optimal performance.
:keyword bool validate_content:
If true, calculates an MD5 hash for each chunk of the blob. The storage
service checks the hash of the content that has arrived with the hash
that was sent. This is primarily valuable for detecting bitflips on
the wire if using http instead of https as https (the default) will
already validate. Note that this MD5 hash is not stored with the
blob. Also note that if enabled, the memory-efficient upload algorithm
will not be used, because computing the MD5 hash requires buffering
entire blocks, and doing so defeats the purpose of the memory-efficient algorithm.
:rtype: None
"""
overwrite = kwargs.pop('overwrite', False)
with BlobClient.from_blob_url(blob_url, credential=credential) as client:
if hasattr(output, 'write'):
_download_to_stream(client, output, max_concurrency, **kwargs)
_download_to_stream(client, output, **kwargs)
else:
if not overwrite and os.path.isfile(output):
raise ValueError("The file '{}' already exists.".format(output))
with open(output, 'wb') as file_handle:
_download_to_stream(client, file_handle, max_concurrency, **kwargs)
_download_to_stream(client, file_handle, **kwargs)


__all__ = [
'upload_blob_to_url',
'download_blob_from_url',
'BlobServiceClient',
'ContainerClient',
'BlobClient',
'BlobType',
'LeaseClient',
'StorageErrorCode',
'UserDelegationKey',
'ExponentialRetry',
'LinearRetry',
'LocationMode',
'BlockState',
'StandardBlobTier',
'PremiumPageBlobTier',
'SequenceNumberAction',
'PublicAccess',
'BlobAnalyticsLogging',
'Metrics',
'RetentionPolicy',
'StaticWebsite',
'CorsRule',
'ContainerProperties',
'BlobProperties',
'LeaseProperties',
'ContentSettings',
'CopyProperties',
'BlobBlock',
'PageRange',
'AccessPolicy',
'ContainerSasPermissions',
'BlobSasPermissions',
'ResourceTypes',
'AccountSasPermissions',
'StorageStreamDownloader',
'CustomerProvidedEncryptionKey',
'RehydratePriority',
'generate_account_sas',
'generate_container_sas',
'generate_blob_sas'
]
Loading