10
10
Union , Optional , Any , IO , Iterable , AnyStr , Dict , List , Tuple ,
11
11
TYPE_CHECKING ,
12
12
TypeVar , Type )
13
+ import warnings
13
14
14
15
try :
15
16
from urllib .parse import urlparse , quote , unquote
16
17
except ImportError :
17
18
from urlparse import urlparse # type: ignore
18
19
from urllib2 import quote , unquote # type: ignore
19
20
import six
21
+ from azure .core .paging import ItemPaged
20
22
from azure .core .pipeline import Pipeline
21
23
from azure .core .tracing .decorator import distributed_trace
22
24
from azure .core .exceptions import ResourceNotFoundError , HttpResponseError , ResourceExistsError
55
57
upload_append_blob ,
56
58
upload_page_blob , _any_conditions )
57
59
from ._models import BlobType , BlobBlock , BlobProperties , BlobQueryError , QuickQueryDialect , \
58
- DelimitedJsonDialect , DelimitedTextDialect
60
+ DelimitedJsonDialect , DelimitedTextDialect , PageRangePaged , PageRange
59
61
from ._download import StorageStreamDownloader
60
62
from ._lease import BlobLeaseClient
61
63
@@ -1866,37 +1868,52 @@ def _start_copy_from_url_options(self, source_url, metadata=None, incremental_co
1866
1868
if 'source_lease' in kwargs :
1867
1869
source_lease = kwargs .pop ('source_lease' )
1868
1870
try :
1869
- headers ['x-ms-source-lease-id' ] = source_lease .id # type: str
1871
+ headers ['x-ms-source-lease-id' ] = source_lease .id
1870
1872
except AttributeError :
1871
1873
headers ['x-ms-source-lease-id' ] = source_lease
1872
1874
1873
1875
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
1874
1879
requires_sync = kwargs .pop ('requires_sync' , None )
1875
1880
encryption_scope_str = kwargs .pop ('encryption_scope' , None )
1876
1881
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." )
1877
1890
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
- #
1883
1891
# TODO: refactor start_copy_from_url api in _blob_client.py. Call _generated/_blob_operations.py copy_from_url
1884
1892
# when requires_sync=True is set.
1885
1893
# Currently both sync copy and async copy are calling _generated/_blob_operations.py start_copy_from_url.
1886
1894
# 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
-
1890
1895
if requires_sync is True :
1891
1896
headers ['x-ms-requires-sync' ] = str (requires_sync )
1897
+ if encryption_scope_str :
1898
+ headers ['x-ms-encryption-scope' ] = encryption_scope_str
1892
1899
if source_authorization :
1893
1900
headers ['x-ms-copy-source-authorization' ] = source_authorization
1901
+ if copy_source_tags :
1902
+ headers ['x-ms-copy-source-tag-option' ] = tags
1894
1903
else :
1904
+ if encryption_scope_str :
1905
+ raise ValueError (
1906
+ "Encryption_scope is only supported for sync copy, please specify requires_sync=True" )
1895
1907
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
+
1897
1914
timeout = kwargs .pop ('timeout' , None )
1898
1915
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
1900
1917
1901
1918
immutability_policy = kwargs .pop ('immutability_policy' , None )
1902
1919
if immutability_policy :
@@ -1985,11 +2002,14 @@ def start_copy_from_url(self, source_url, metadata=None, incremental_copy=False,
1985
2002
The tag set may contain at most 10 tags. Tag keys must be between 1 and 128 characters,
1986
2003
and tag values must be between 0 and 256 characters.
1987
2004
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`.
1989
2009
1990
2010
.. versionadded:: 12.4.0
1991
2011
1992
- :paramtype tags: dict(str, str)
2012
+ :paramtype tags: dict(str, str) or Literal["COPY"]
1993
2013
:keyword ~azure.storage.blob.ImmutabilityPolicy immutability_policy:
1994
2014
Specifies the immutability policy of a blob, blob snapshot or blob version.
1995
2015
@@ -2879,7 +2899,7 @@ def get_page_ranges( # type: ignore
2879
2899
** kwargs
2880
2900
):
2881
2901
# 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
2883
2903
of a page blob.
2884
2904
2885
2905
:param int offset:
@@ -2934,6 +2954,11 @@ def get_page_ranges( # type: ignore
2934
2954
The first element are filled page ranges, the 2nd element is cleared page ranges.
2935
2955
:rtype: tuple(list(dict(str, str), list(dict(str, str))
2936
2956
"""
2957
+ warnings .warn (
2958
+ "get_page_ranges is deprecated, use list_page_ranges instead" ,
2959
+ DeprecationWarning
2960
+ )
2961
+
2937
2962
options = self ._get_page_ranges_options (
2938
2963
offset = offset ,
2939
2964
length = length ,
@@ -2948,6 +2973,92 @@ def get_page_ranges( # type: ignore
2948
2973
process_storage_error (error )
2949
2974
return get_page_ranges_result (ranges )
2950
2975
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
+
2951
3062
@distributed_trace
2952
3063
def get_page_range_diff_for_managed_disk (
2953
3064
self , previous_snapshot_url , # type: str
0 commit comments