Skip to content

Commit 6e29da9

Browse files
[Storage] STG 82 (Azure#23937)
1 parent 8614158 commit 6e29da9

File tree

145 files changed

+15999
-956
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

145 files changed

+15999
-956
lines changed

sdk/storage/azure-storage-blob/CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
# Release History
22

3-
## 12.12.0b1 (Unreleased)
3+
## 12.12.0b1 (2022-04-14)
44

55
### Features Added
6+
- Added support for service version 2021-06-08.
7+
- Added a new paginated method for listing page ranges, `list_page_ranges()`. This replaces `get_page_ranges()` which has been deprecated.
8+
- Added support for copying source blob tags with `start_copy_from_url()` by specifying `"COPY"` for the `tags` keyword.
69

710
## 12.11.0 (2022-03-29)
811

sdk/storage/azure-storage-blob/azure/storage/blob/_blob_client.py

Lines changed: 126 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@
1010
Union, Optional, Any, IO, Iterable, AnyStr, Dict, List, Tuple,
1111
TYPE_CHECKING,
1212
TypeVar, Type)
13+
import warnings
1314

1415
try:
1516
from urllib.parse import urlparse, quote, unquote
1617
except ImportError:
1718
from urlparse import urlparse # type: ignore
1819
from urllib2 import quote, unquote # type: ignore
1920
import six
21+
from azure.core.paging import ItemPaged
2022
from azure.core.pipeline import Pipeline
2123
from azure.core.tracing.decorator import distributed_trace
2224
from azure.core.exceptions import ResourceNotFoundError, HttpResponseError, ResourceExistsError
@@ -55,7 +57,7 @@
5557
upload_append_blob,
5658
upload_page_blob, _any_conditions)
5759
from ._models import BlobType, BlobBlock, BlobProperties, BlobQueryError, QuickQueryDialect, \
58-
DelimitedJsonDialect, DelimitedTextDialect
60+
DelimitedJsonDialect, DelimitedTextDialect, PageRangePaged, PageRange
5961
from ._download import StorageStreamDownloader
6062
from ._lease import BlobLeaseClient
6163

@@ -1866,37 +1868,52 @@ def _start_copy_from_url_options(self, source_url, metadata=None, incremental_co
18661868
if 'source_lease' in kwargs:
18671869
source_lease = kwargs.pop('source_lease')
18681870
try:
1869-
headers['x-ms-source-lease-id'] = source_lease.id # type: str
1871+
headers['x-ms-source-lease-id'] = source_lease.id
18701872
except AttributeError:
18711873
headers['x-ms-source-lease-id'] = source_lease
18721874

18731875
tier = kwargs.pop('premium_page_blob_tier', None) or kwargs.pop('standard_blob_tier', None)
1876+
tags = kwargs.pop('tags', None)
1877+
1878+
# Options only available for sync copy
18741879
requires_sync = kwargs.pop('requires_sync', None)
18751880
encryption_scope_str = kwargs.pop('encryption_scope', None)
18761881
source_authorization = kwargs.pop('source_authorization', None)
1882+
# If tags is a str, interpret that as copy_source_tags
1883+
copy_source_tags = isinstance(tags, str)
1884+
1885+
if incremental_copy:
1886+
if source_authorization:
1887+
raise ValueError("Source authorization tokens are not applicable for incremental copying.")
1888+
if copy_source_tags:
1889+
raise ValueError("Copying source tags is not applicable for incremental copying.")
18771890

1878-
if not requires_sync and encryption_scope_str:
1879-
raise ValueError("Encryption_scope is only supported for sync copy, please specify requires_sync=True")
1880-
if source_authorization and incremental_copy:
1881-
raise ValueError("Source authorization tokens are not applicable for incremental copying.")
1882-
#
18831891
# TODO: refactor start_copy_from_url api in _blob_client.py. Call _generated/_blob_operations.py copy_from_url
18841892
# when requires_sync=True is set.
18851893
# Currently both sync copy and async copy are calling _generated/_blob_operations.py start_copy_from_url.
18861894
# As sync copy diverges more from async copy, more problem will surface.
1887-
if encryption_scope_str:
1888-
headers.update({'x-ms-encryption-scope': encryption_scope_str})
1889-
18901895
if requires_sync is True:
18911896
headers['x-ms-requires-sync'] = str(requires_sync)
1897+
if encryption_scope_str:
1898+
headers['x-ms-encryption-scope'] = encryption_scope_str
18921899
if source_authorization:
18931900
headers['x-ms-copy-source-authorization'] = source_authorization
1901+
if copy_source_tags:
1902+
headers['x-ms-copy-source-tag-option'] = tags
18941903
else:
1904+
if encryption_scope_str:
1905+
raise ValueError(
1906+
"Encryption_scope is only supported for sync copy, please specify requires_sync=True")
18951907
if source_authorization:
1896-
raise ValueError("Source authorization tokens are only applicable for synchronous copy operations.")
1908+
raise ValueError(
1909+
"Source authorization tokens are only supported for sync copy, please specify requires_sync=True")
1910+
if copy_source_tags:
1911+
raise ValueError(
1912+
"Copying source tags is only supported for sync copy, please specify requires_sync=True")
1913+
18971914
timeout = kwargs.pop('timeout', None)
18981915
dest_mod_conditions = get_modify_conditions(kwargs)
1899-
blob_tags_string = serialize_blob_tags_header(kwargs.pop('tags', None))
1916+
blob_tags_string = serialize_blob_tags_header(tags) if not copy_source_tags else None
19001917

19011918
immutability_policy = kwargs.pop('immutability_policy', None)
19021919
if immutability_policy:
@@ -1985,11 +2002,14 @@ def start_copy_from_url(self, source_url, metadata=None, incremental_copy=False,
19852002
The tag set may contain at most 10 tags. Tag keys must be between 1 and 128 characters,
19862003
and tag values must be between 0 and 256 characters.
19872004
Valid tag key and value characters include: lowercase and uppercase letters, digits (0-9),
1988-
space (` `), plus (+), minus (-), period (.), solidus (/), colon (:), equals (=), underscore (_)
2005+
space (` `), plus (+), minus (-), period (.), solidus (/), colon (:), equals (=), underscore (_).
2006+
2007+
The (case-sensitive) literal "COPY" can instead be passed to copy tags from the source blob.
2008+
This option is only available when `incremental_copy=False` and `requires_sync=True`.
19892009
19902010
.. versionadded:: 12.4.0
19912011
1992-
:paramtype tags: dict(str, str)
2012+
:paramtype tags: dict(str, str) or Literal["COPY"]
19932013
:keyword ~azure.storage.blob.ImmutabilityPolicy immutability_policy:
19942014
Specifies the immutability policy of a blob, blob snapshot or blob version.
19952015
@@ -2879,7 +2899,7 @@ def get_page_ranges( # type: ignore
28792899
**kwargs
28802900
):
28812901
# type: (...) -> Tuple[List[Dict[str, int]], List[Dict[str, int]]]
2882-
"""Returns the list of valid page ranges for a Page Blob or snapshot
2902+
"""DEPRECATED: Returns the list of valid page ranges for a Page Blob or snapshot
28832903
of a page blob.
28842904
28852905
:param int offset:
@@ -2934,6 +2954,11 @@ def get_page_ranges( # type: ignore
29342954
The first element are filled page ranges, the 2nd element is cleared page ranges.
29352955
:rtype: tuple(list(dict(str, str), list(dict(str, str))
29362956
"""
2957+
warnings.warn(
2958+
"get_page_ranges is deprecated, use list_page_ranges instead",
2959+
DeprecationWarning
2960+
)
2961+
29372962
options = self._get_page_ranges_options(
29382963
offset=offset,
29392964
length=length,
@@ -2948,6 +2973,92 @@ def get_page_ranges( # type: ignore
29482973
process_storage_error(error)
29492974
return get_page_ranges_result(ranges)
29502975

2976+
@distributed_trace
2977+
def list_page_ranges(
2978+
self,
2979+
*,
2980+
offset: Optional[int] = None,
2981+
length: Optional[int] = None,
2982+
previous_snapshot: Optional[Union[str, Dict[str, Any]]] = None,
2983+
**kwargs: Any
2984+
) -> ItemPaged[PageRange]:
2985+
"""Returns the list of valid page ranges for a Page Blob or snapshot
2986+
of a page blob. If `previous_snapshot` is specified, the result will be
2987+
a diff of changes between the target blob and the previous snapshot.
2988+
2989+
:keyword int offset:
2990+
Start of byte range to use for getting valid page ranges.
2991+
If no length is given, all bytes after the offset will be searched.
2992+
Pages must be aligned with 512-byte boundaries, the start offset
2993+
must be a modulus of 512 and the length must be a modulus of
2994+
512.
2995+
:keyword int length:
2996+
Number of bytes to use for getting valid page ranges.
2997+
If length is given, offset must be provided.
2998+
This range will return valid page ranges from the offset start up to
2999+
the specified length.
3000+
Pages must be aligned with 512-byte boundaries, the start offset
3001+
must be a modulus of 512 and the length must be a modulus of
3002+
512.
3003+
:keyword previous_snapshot:
3004+
A snapshot value that specifies that the response will contain only pages that were changed
3005+
between target blob and previous snapshot. Changed pages include both updated and cleared
3006+
pages. The target blob may be a snapshot, as long as the snapshot specified by `previous_snapshot`
3007+
is the older of the two.
3008+
:paramtype previous_snapshot: str or Dict[str, Any]
3009+
:keyword lease:
3010+
Required if the blob has an active lease. Value can be a BlobLeaseClient object
3011+
or the lease ID as a string.
3012+
:paramtype lease: ~azure.storage.blob.BlobLeaseClient or str
3013+
:keyword ~datetime.datetime if_modified_since:
3014+
A DateTime value. Azure expects the date value passed in to be UTC.
3015+
If timezone is included, any non-UTC datetimes will be converted to UTC.
3016+
If a date is passed in without timezone info, it is assumed to be UTC.
3017+
Specify this header to perform the operation only
3018+
if the resource has been modified since the specified time.
3019+
:keyword ~datetime.datetime if_unmodified_since:
3020+
A DateTime value. Azure expects the date value passed in to be UTC.
3021+
If timezone is included, any non-UTC datetimes will be converted to UTC.
3022+
If a date is passed in without timezone info, it is assumed to be UTC.
3023+
Specify this header to perform the operation only if
3024+
the resource has not been modified since the specified date/time.
3025+
:keyword str etag:
3026+
An ETag value, or the wildcard character (*). Used to check if the resource has changed,
3027+
and act according to the condition specified by the `match_condition` parameter.
3028+
:keyword ~azure.core.MatchConditions match_condition:
3029+
The match condition to use upon the etag.
3030+
:keyword str if_tags_match_condition:
3031+
Specify a SQL where clause on blob tags to operate only on blob with a matching value.
3032+
eg. ``\"\\\"tagname\\\"='my tag'\"``
3033+
3034+
.. versionadded:: 12.4.0
3035+
3036+
:keyword int results_per_page:
3037+
The maximum number of page ranges to retrieve per API call.
3038+
:keyword int timeout:
3039+
The timeout parameter is expressed in seconds.
3040+
:returns: An iterable (auto-paging) of PageRange.
3041+
:rtype: ~azure.core.paging.ItemPaged[~azure.storage.blob.PageRange]
3042+
"""
3043+
results_per_page = kwargs.pop('results_per_page', None)
3044+
options = self._get_page_ranges_options(
3045+
offset=offset,
3046+
length=length,
3047+
previous_snapshot_diff=previous_snapshot,
3048+
**kwargs)
3049+
3050+
if previous_snapshot:
3051+
command = partial(
3052+
self._client.page_blob.get_page_ranges_diff,
3053+
**options)
3054+
else:
3055+
command = partial(
3056+
self._client.page_blob.get_page_ranges,
3057+
**options)
3058+
return ItemPaged(
3059+
command, results_per_page=results_per_page,
3060+
page_iterator_class=PageRangePaged)
3061+
29513062
@distributed_trace
29523063
def get_page_range_diff_for_managed_disk(
29533064
self, previous_snapshot_url, # type: str

sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/operations/_blob_operations.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2049,6 +2049,7 @@ async def copy_from_url( # pylint: disable=inconsistent-return-statements
20492049
immutability_policy_mode: Optional[Union[str, "_models.BlobImmutabilityPolicyMode"]] = None,
20502050
legal_hold: Optional[bool] = None,
20512051
copy_source_authorization: Optional[str] = None,
2052+
copy_source_tags: Optional[Union[str, "_models.BlobCopySourceTags"]] = None,
20522053
source_modified_access_conditions: Optional["_models.SourceModifiedAccessConditions"] = None,
20532054
modified_access_conditions: Optional["_models.ModifiedAccessConditions"] = None,
20542055
lease_access_conditions: Optional["_models.LeaseAccessConditions"] = None,
@@ -2099,6 +2100,9 @@ async def copy_from_url( # pylint: disable=inconsistent-return-statements
20992100
:param copy_source_authorization: Only Bearer type is supported. Credentials should be a valid
21002101
OAuth access token to copy source. Default value is None.
21012102
:type copy_source_authorization: str
2103+
:param copy_source_tags: Optional, default 'replace'. Indicates if source tags should be
2104+
copied or replaced with the tags specified by x-ms-tags. Default value is None.
2105+
:type copy_source_tags: str or ~azure.storage.blob.models.BlobCopySourceTags
21022106
:param source_modified_access_conditions: Parameter group. Default value is None.
21032107
:type source_modified_access_conditions:
21042108
~azure.storage.blob.models.SourceModifiedAccessConditions
@@ -2178,6 +2182,7 @@ async def copy_from_url( # pylint: disable=inconsistent-return-statements
21782182
legal_hold=legal_hold,
21792183
copy_source_authorization=copy_source_authorization,
21802184
encryption_scope=_encryption_scope,
2185+
copy_source_tags=copy_source_tags,
21812186
template_url=self.copy_from_url.metadata['url'],
21822187
)
21832188
request = _convert_request(request)

sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/operations/_block_blob_operations.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ async def put_blob_from_url( # pylint: disable=inconsistent-return-statements
256256
blob_tags_string: Optional[str] = None,
257257
copy_source_blob_properties: Optional[bool] = None,
258258
copy_source_authorization: Optional[str] = None,
259+
copy_source_tags: Optional[Union[str, "_models.BlobCopySourceTags"]] = None,
259260
blob_http_headers: Optional["_models.BlobHTTPHeaders"] = None,
260261
lease_access_conditions: Optional["_models.LeaseAccessConditions"] = None,
261262
cpk_info: Optional["_models.CpkInfo"] = None,
@@ -311,6 +312,9 @@ async def put_blob_from_url( # pylint: disable=inconsistent-return-statements
311312
:param copy_source_authorization: Only Bearer type is supported. Credentials should be a valid
312313
OAuth access token to copy source. Default value is None.
313314
:type copy_source_authorization: str
315+
:param copy_source_tags: Optional, default 'replace'. Indicates if source tags should be
316+
copied or replaced with the tags specified by x-ms-tags. Default value is None.
317+
:type copy_source_tags: str or ~azure.storage.blob.models.BlobCopySourceTags
314318
:param blob_http_headers: Parameter group. Default value is None.
315319
:type blob_http_headers: ~azure.storage.blob.models.BlobHTTPHeaders
316320
:param lease_access_conditions: Parameter group. Default value is None.
@@ -427,6 +431,7 @@ async def put_blob_from_url( # pylint: disable=inconsistent-return-statements
427431
blob_tags_string=blob_tags_string,
428432
copy_source_blob_properties=copy_source_blob_properties,
429433
copy_source_authorization=copy_source_authorization,
434+
copy_source_tags=copy_source_tags,
430435
template_url=self.put_blob_from_url.metadata['url'],
431436
)
432437
request = _convert_request(request)

0 commit comments

Comments
 (0)