Skip to content

Commit f4d6065

Browse files
[Storage] STG81 (Azure#22471)
1 parent d4d12b9 commit f4d6065

File tree

66 files changed

+10174
-71
lines changed

Some content is hidden

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

66 files changed

+10174
-71
lines changed

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

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

3-
## 12.10.0b3 (Unreleased)
3+
## 12.10.0b3 (2022-02-08)
44

55
This version and all future versions will require Python 3.6+. Python 2.7 is no longer supported.
66

77
### Features Added
8+
- Added support for service version 2021-04-10.
9+
- Added support for `find_blobs_by_tags()` on a container.
10+
- Added support for `Find (f)` container SAS permission.
811

912
### Bugs Fixed
1013
- Update `azure-core` dependency to avoid inconsistent dependencies from being installed.

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

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@
4040
from ._models import ( # pylint: disable=unused-import
4141
ContainerProperties,
4242
BlobProperties,
43-
BlobType)
44-
from ._list_blobs_helper import BlobPrefix, BlobPropertiesPaged
43+
BlobType,
44+
FilteredBlob)
45+
from ._list_blobs_helper import BlobPrefix, BlobPropertiesPaged, FilteredBlobPaged
4546
from ._lease import BlobLeaseClient
4647
from ._blob_client import BlobClient
4748

@@ -822,6 +823,38 @@ def walk_blobs(
822823
results_per_page=results_per_page,
823824
delimiter=delimiter)
824825

826+
@distributed_trace
827+
def find_blobs_by_tags(
828+
self, filter_expression, # type: str
829+
**kwargs # type: Optional[Any]
830+
):
831+
# type: (...) -> ItemPaged[FilteredBlob]
832+
"""Returns a generator to list the blobs under the specified container whose tags
833+
match the given search expression.
834+
The generator will lazily follow the continuation tokens returned by
835+
the service.
836+
837+
:param str filter_expression:
838+
The expression to find blobs whose tags matches the specified condition.
839+
eg. "\"yourtagname\"='firsttag' and \"yourtagname2\"='secondtag'"
840+
:keyword int results_per_page:
841+
The max result per page when paginating.
842+
:keyword int timeout:
843+
The timeout parameter is expressed in seconds.
844+
:returns: An iterable (auto-paging) response of FilteredBlob.
845+
:rtype: ~azure.core.paging.ItemPaged[~azure.storage.blob.BlobProperties]
846+
"""
847+
results_per_page = kwargs.pop('results_per_page', None)
848+
timeout = kwargs.pop('timeout', None)
849+
command = functools.partial(
850+
self._client.container.filter_blobs,
851+
timeout=timeout,
852+
where=filter_expression,
853+
**kwargs)
854+
return ItemPaged(
855+
command, results_per_page=results_per_page,
856+
page_iterator_class=FilteredBlobPaged)
857+
825858
@distributed_trace
826859
def upload_blob(
827860
self, name, # type: Union[str, BlobProperties]

sdk/storage/azure-storage-blob/azure/storage/blob/_generated/_configuration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def __init__(
3838
super(AzureBlobStorageConfiguration, self).__init__(**kwargs)
3939

4040
self.url = url
41-
self.version = "2021-02-12"
41+
self.version = "2021-04-10"
4242
kwargs.setdefault('sdk_moniker', 'azureblobstorage/{}'.format(VERSION))
4343
self._configure(**kwargs)
4444

sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/_configuration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def __init__(
3333
super(AzureBlobStorageConfiguration, self).__init__(**kwargs)
3434

3535
self.url = url
36-
self.version = "2021-02-12"
36+
self.version = "2021-04-10"
3737
kwargs.setdefault('sdk_moniker', 'azureblobstorage/{}'.format(VERSION))
3838
self._configure(**kwargs)
3939

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

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,106 @@ async def submit_batch(
877877
return deserialized
878878
submit_batch.metadata = {'url': '/{containerName}'} # type: ignore
879879

880+
async def filter_blobs(
881+
self,
882+
timeout: Optional[int] = None,
883+
request_id_parameter: Optional[str] = None,
884+
where: Optional[str] = None,
885+
marker: Optional[str] = None,
886+
maxresults: Optional[int] = None,
887+
**kwargs: Any
888+
) -> "_models.FilterBlobSegment":
889+
"""The Filter Blobs operation enables callers to list blobs in a container whose tags match a
890+
given search expression. Filter blobs searches within the given container.
891+
892+
:param timeout: The timeout parameter is expressed in seconds. For more information, see
893+
:code:`<a
894+
href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
895+
Timeouts for Blob Service Operations.</a>`.
896+
:type timeout: int
897+
:param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character
898+
limit that is recorded in the analytics logs when storage analytics logging is enabled.
899+
:type request_id_parameter: str
900+
:param where: Filters the results to return only to return only blobs whose tags match the
901+
specified expression.
902+
:type where: str
903+
:param marker: A string value that identifies the portion of the list of containers to be
904+
returned with the next listing operation. The operation returns the NextMarker value within the
905+
response body if the listing operation did not return all containers remaining to be listed
906+
with the current page. The NextMarker value can be used as the value for the marker parameter
907+
in a subsequent call to request the next page of list items. The marker value is opaque to the
908+
client.
909+
:type marker: str
910+
:param maxresults: Specifies the maximum number of containers to return. If the request does
911+
not specify maxresults, or specifies a value greater than 5000, the server will return up to
912+
5000 items. Note that if the listing operation crosses a partition boundary, then the service
913+
will return a continuation token for retrieving the remainder of the results. For this reason,
914+
it is possible that the service will return fewer results than specified by maxresults, or than
915+
the default of 5000.
916+
:type maxresults: int
917+
:keyword callable cls: A custom type or function that will be passed the direct response
918+
:return: FilterBlobSegment, or the result of cls(response)
919+
:rtype: ~azure.storage.blob.models.FilterBlobSegment
920+
:raises: ~azure.core.exceptions.HttpResponseError
921+
"""
922+
cls = kwargs.pop('cls', None) # type: ClsType["_models.FilterBlobSegment"]
923+
error_map = {
924+
401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError
925+
}
926+
error_map.update(kwargs.pop('error_map', {}))
927+
restype = "container"
928+
comp = "blobs"
929+
accept = "application/xml"
930+
931+
# Construct URL
932+
url = self.filter_blobs.metadata['url'] # type: ignore
933+
path_format_arguments = {
934+
'url': self._serialize.url("self._config.url", self._config.url, 'str', skip_quote=True),
935+
}
936+
url = self._client.format_url(url, **path_format_arguments)
937+
938+
# Construct parameters
939+
query_parameters = {} # type: Dict[str, Any]
940+
query_parameters['restype'] = self._serialize.query("restype", restype, 'str')
941+
query_parameters['comp'] = self._serialize.query("comp", comp, 'str')
942+
if timeout is not None:
943+
query_parameters['timeout'] = self._serialize.query("timeout", timeout, 'int', minimum=0)
944+
if where is not None:
945+
query_parameters['where'] = self._serialize.query("where", where, 'str')
946+
if marker is not None:
947+
query_parameters['marker'] = self._serialize.query("marker", marker, 'str')
948+
if maxresults is not None:
949+
query_parameters['maxresults'] = self._serialize.query("maxresults", maxresults, 'int', minimum=1)
950+
951+
# Construct headers
952+
header_parameters = {} # type: Dict[str, Any]
953+
header_parameters['x-ms-version'] = self._serialize.header("self._config.version", self._config.version, 'str')
954+
if request_id_parameter is not None:
955+
header_parameters['x-ms-client-request-id'] = self._serialize.header("request_id_parameter", request_id_parameter, 'str')
956+
header_parameters['Accept'] = self._serialize.header("accept", accept, 'str')
957+
958+
request = self._client.get(url, query_parameters, header_parameters)
959+
pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs)
960+
response = pipeline_response.http_response
961+
962+
if response.status_code not in [200]:
963+
map_error(status_code=response.status_code, response=response, error_map=error_map)
964+
error = self._deserialize.failsafe_deserialize(_models.StorageError, response)
965+
raise HttpResponseError(response=response, model=error)
966+
967+
response_headers = {}
968+
response_headers['x-ms-client-request-id']=self._deserialize('str', response.headers.get('x-ms-client-request-id'))
969+
response_headers['x-ms-request-id']=self._deserialize('str', response.headers.get('x-ms-request-id'))
970+
response_headers['x-ms-version']=self._deserialize('str', response.headers.get('x-ms-version'))
971+
response_headers['Date']=self._deserialize('rfc-1123', response.headers.get('Date'))
972+
deserialized = self._deserialize('FilterBlobSegment', pipeline_response)
973+
974+
if cls:
975+
return cls(pipeline_response, deserialized, response_headers)
976+
977+
return deserialized
978+
filter_blobs.metadata = {'url': '/{containerName}'} # type: ignore
979+
880980
async def acquire_lease(
881981
self,
882982
timeout: Optional[int] = None,

sdk/storage/azure-storage-blob/azure/storage/blob/_generated/operations/_container_operations.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,107 @@ def submit_batch(
890890
return deserialized
891891
submit_batch.metadata = {'url': '/{containerName}'} # type: ignore
892892

893+
def filter_blobs(
894+
self,
895+
timeout=None, # type: Optional[int]
896+
request_id_parameter=None, # type: Optional[str]
897+
where=None, # type: Optional[str]
898+
marker=None, # type: Optional[str]
899+
maxresults=None, # type: Optional[int]
900+
**kwargs # type: Any
901+
):
902+
# type: (...) -> "_models.FilterBlobSegment"
903+
"""The Filter Blobs operation enables callers to list blobs in a container whose tags match a
904+
given search expression. Filter blobs searches within the given container.
905+
906+
:param timeout: The timeout parameter is expressed in seconds. For more information, see
907+
:code:`<a
908+
href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
909+
Timeouts for Blob Service Operations.</a>`.
910+
:type timeout: int
911+
:param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character
912+
limit that is recorded in the analytics logs when storage analytics logging is enabled.
913+
:type request_id_parameter: str
914+
:param where: Filters the results to return only to return only blobs whose tags match the
915+
specified expression.
916+
:type where: str
917+
:param marker: A string value that identifies the portion of the list of containers to be
918+
returned with the next listing operation. The operation returns the NextMarker value within the
919+
response body if the listing operation did not return all containers remaining to be listed
920+
with the current page. The NextMarker value can be used as the value for the marker parameter
921+
in a subsequent call to request the next page of list items. The marker value is opaque to the
922+
client.
923+
:type marker: str
924+
:param maxresults: Specifies the maximum number of containers to return. If the request does
925+
not specify maxresults, or specifies a value greater than 5000, the server will return up to
926+
5000 items. Note that if the listing operation crosses a partition boundary, then the service
927+
will return a continuation token for retrieving the remainder of the results. For this reason,
928+
it is possible that the service will return fewer results than specified by maxresults, or than
929+
the default of 5000.
930+
:type maxresults: int
931+
:keyword callable cls: A custom type or function that will be passed the direct response
932+
:return: FilterBlobSegment, or the result of cls(response)
933+
:rtype: ~azure.storage.blob.models.FilterBlobSegment
934+
:raises: ~azure.core.exceptions.HttpResponseError
935+
"""
936+
cls = kwargs.pop('cls', None) # type: ClsType["_models.FilterBlobSegment"]
937+
error_map = {
938+
401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError
939+
}
940+
error_map.update(kwargs.pop('error_map', {}))
941+
restype = "container"
942+
comp = "blobs"
943+
accept = "application/xml"
944+
945+
# Construct URL
946+
url = self.filter_blobs.metadata['url'] # type: ignore
947+
path_format_arguments = {
948+
'url': self._serialize.url("self._config.url", self._config.url, 'str', skip_quote=True),
949+
}
950+
url = self._client.format_url(url, **path_format_arguments)
951+
952+
# Construct parameters
953+
query_parameters = {} # type: Dict[str, Any]
954+
query_parameters['restype'] = self._serialize.query("restype", restype, 'str')
955+
query_parameters['comp'] = self._serialize.query("comp", comp, 'str')
956+
if timeout is not None:
957+
query_parameters['timeout'] = self._serialize.query("timeout", timeout, 'int', minimum=0)
958+
if where is not None:
959+
query_parameters['where'] = self._serialize.query("where", where, 'str')
960+
if marker is not None:
961+
query_parameters['marker'] = self._serialize.query("marker", marker, 'str')
962+
if maxresults is not None:
963+
query_parameters['maxresults'] = self._serialize.query("maxresults", maxresults, 'int', minimum=1)
964+
965+
# Construct headers
966+
header_parameters = {} # type: Dict[str, Any]
967+
header_parameters['x-ms-version'] = self._serialize.header("self._config.version", self._config.version, 'str')
968+
if request_id_parameter is not None:
969+
header_parameters['x-ms-client-request-id'] = self._serialize.header("request_id_parameter", request_id_parameter, 'str')
970+
header_parameters['Accept'] = self._serialize.header("accept", accept, 'str')
971+
972+
request = self._client.get(url, query_parameters, header_parameters)
973+
pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs)
974+
response = pipeline_response.http_response
975+
976+
if response.status_code not in [200]:
977+
map_error(status_code=response.status_code, response=response, error_map=error_map)
978+
error = self._deserialize.failsafe_deserialize(_models.StorageError, response)
979+
raise HttpResponseError(response=response, model=error)
980+
981+
response_headers = {}
982+
response_headers['x-ms-client-request-id']=self._deserialize('str', response.headers.get('x-ms-client-request-id'))
983+
response_headers['x-ms-request-id']=self._deserialize('str', response.headers.get('x-ms-request-id'))
984+
response_headers['x-ms-version']=self._deserialize('str', response.headers.get('x-ms-version'))
985+
response_headers['Date']=self._deserialize('rfc-1123', response.headers.get('Date'))
986+
deserialized = self._deserialize('FilterBlobSegment', pipeline_response)
987+
988+
if cls:
989+
return cls(pipeline_response, deserialized, response_headers)
990+
991+
return deserialized
992+
filter_blobs.metadata = {'url': '/{containerName}'} # type: ignore
993+
893994
def acquire_lease(
894995
self,
895996
timeout=None, # type: Optional[int]

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -917,21 +917,24 @@ class ContainerSasPermissions(object):
917917
List blobs in the container.
918918
:param bool tag:
919919
Set or get tags on the blobs in the container.
920+
:keyword bool permanent_delete:
921+
To enable permanent delete on the blob is permitted.
922+
:keyword bool find:
923+
To enable finding blobs by tags
920924
:keyword bool set_immutability_policy:
921925
To enable operations related to set/delete immutability policy.
922926
To get immutability policy, you just need read permission.
923-
:keyword bool permanent_delete:
924-
To enable permanent delete on the blob is permitted.
925927
"""
926928
def __init__(self, read=False, write=False, delete=False,
927929
list=False, delete_previous_version=False, tag=False, **kwargs): # pylint: disable=redefined-builtin
928930
self.read = read
929931
self.write = write
930932
self.delete = delete
931-
self.list = list
932933
self.delete_previous_version = delete_previous_version
933934
self.permanent_delete = kwargs.pop('permanent_delete', False)
935+
self.list = list
934936
self.tag = tag
937+
self.find = kwargs.pop('find', False)
935938
self.set_immutability_policy = kwargs.pop('set_immutability_policy', False)
936939
self._str = (('r' if self.read else '') +
937940
('w' if self.write else '') +
@@ -940,6 +943,7 @@ def __init__(self, read=False, write=False, delete=False,
940943
('y' if self.permanent_delete else '') +
941944
('l' if self.list else '') +
942945
('t' if self.tag else '') +
946+
('f' if self.find else '') +
943947
('i' if self.set_immutability_policy else ''))
944948

945949
def __str__(self):
@@ -961,13 +965,14 @@ def from_string(cls, permission):
961965
p_read = 'r' in permission
962966
p_write = 'w' in permission
963967
p_delete = 'd' in permission
964-
p_list = 'l' in permission
965968
p_delete_previous_version = 'x' in permission
966969
p_permanent_delete = 'y' in permission
970+
p_list = 'l' in permission
967971
p_tag = 't' in permission
972+
p_find = 'f' in permission
968973
p_set_immutability_policy = 'i' in permission
969974
parsed = cls(read=p_read, write=p_write, delete=p_delete, list=p_list,
970-
delete_previous_version=p_delete_previous_version, tag=p_tag,
975+
delete_previous_version=p_delete_previous_version, tag=p_tag, find=p_find,
971976
set_immutability_policy=p_set_immutability_policy, permanent_delete=p_permanent_delete)
972977

973978
return parsed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@
4141
'2020-08-04',
4242
'2020-10-02',
4343
'2020-12-06',
44-
'2021-02-12'
44+
'2021-02-12',
45+
'2021-04-10'
4546
]
4647

4748

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,8 @@ def generate_container(self, container_name, permission=None, expiry=None,
153153
:param ContainerSasPermissions permission:
154154
The permissions associated with the shared access signature. The
155155
user is restricted to operations allowed by the permissions.
156-
Permissions must be ordered read, write, delete, list.
156+
Permissions must be ordered read, write, delete, delete version, permanent delete, list, tag, find,
157+
set immutability policy.
157158
Required unless an id is given referencing a stored access policy
158159
which contains this field. This field must be omitted if it has been
159160
specified in an associated stored access policy.
@@ -406,7 +407,8 @@ def generate_container_sas(
406407
:param permission:
407408
The permissions associated with the shared access signature. The
408409
user is restricted to operations allowed by the permissions.
409-
Permissions must be ordered read, write, delete, list.
410+
Permissions must be ordered read, write, delete, delete version, permanent delete, list, tag, find,
411+
set immutability policy.
410412
Required unless an id is given referencing a stored access policy
411413
which contains this field. This field must be omitted if it has been
412414
specified in an associated stored access policy.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
# license information.
55
# --------------------------------------------------------------------------
66

7-
VERSION = "12.10.0b2"
7+
VERSION = "12.10.0b3"

0 commit comments

Comments
 (0)