-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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
[POC] Blobs Partial list deserialization #19814
Changes from all commits
ab1fe0a
5f9d0ac
2bb536c
7b78ee7
12a96ab
85dd180
f984f61
5ccd5ea
5d868e2
9372dc1
406647f
e4e3450
24dbf61
95557f7
efb9c56
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1452,12 +1452,12 @@ async def list_blob_flat_segment( | |
response_headers['x-ms-request-id']=self._deserialize('str', response.headers.get('x-ms-request-id')) | ||
response_headers['x-ms-version']=self._deserialize('str', response.headers.get('x-ms-version')) | ||
response_headers['Date']=self._deserialize('rfc-1123', response.headers.get('Date')) | ||
deserialized = self._deserialize('ListBlobsFlatSegmentResponse', pipeline_response) | ||
#deserialized = self._deserialize('ListBlobsFlatSegmentResponse', pipeline_response) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is one of the bigger challenges to figure out. Currently the deserialization process is out of our hands. We would need to add directives to the autorest code gen for the list_blobs_flat_segment API to not deserialize the response payload. This should be possible by simply overwriting the output model to have no output. We then use the |
||
|
||
if cls: | ||
return cls(pipeline_response, deserialized, response_headers) | ||
return cls(pipeline_response, None, response_headers) | ||
|
||
return deserialized | ||
return None | ||
list_blob_flat_segment.metadata = {'url': '/{containerName}'} # type: ignore | ||
|
||
async def list_blob_hierarchy_segment( | ||
|
@@ -1564,12 +1564,12 @@ async def list_blob_hierarchy_segment( | |
response_headers['x-ms-request-id']=self._deserialize('str', response.headers.get('x-ms-request-id')) | ||
response_headers['x-ms-version']=self._deserialize('str', response.headers.get('x-ms-version')) | ||
response_headers['Date']=self._deserialize('rfc-1123', response.headers.get('Date')) | ||
deserialized = self._deserialize('ListBlobsHierarchySegmentResponse', pipeline_response) | ||
# deserialized = self._deserialize('ListBlobsHierarchySegmentResponse', pipeline_response) | ||
|
||
if cls: | ||
return cls(pipeline_response, deserialized, response_headers) | ||
return cls(pipeline_response, None, response_headers) | ||
|
||
return deserialized | ||
return None | ||
list_blob_hierarchy_segment.metadata = {'url': '/{containerName}'} # type: ignore | ||
|
||
async def get_account_info( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,14 +7,70 @@ | |
|
||
from azure.core.paging import PageIterator, ItemPaged | ||
from azure.core.exceptions import HttpResponseError | ||
|
||
from ._deserialize import get_blob_properties_from_generated_code, parse_tags | ||
from ._generated.models import BlobItemInternal, BlobPrefix as GenBlobPrefix, FilterBlobItem | ||
from ._generated.models import FilterBlobItem | ||
from ._models import BlobProperties, FilteredBlob | ||
from ._shared.models import DictMixin | ||
from ._shared.xml_deserialization import unpack_xml_content | ||
from ._shared.response_handlers import return_context_and_deserialized, process_storage_error | ||
|
||
|
||
class BlobPropertiesPaged(PageIterator): | ||
def deserialize_list_result(pipeline_response, *_): | ||
payload = unpack_xml_content(pipeline_response.http_response) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe this line here is replacing the ContentDecodePolicy that I removed from the pipeline. So this would already be unpacked if we put that policy back in. |
||
location = pipeline_response.http_response.location_mode | ||
return location, payload | ||
|
||
|
||
def load_xml_string(element, name): | ||
node = element.find(name) | ||
if node is None or not node.text: | ||
return None | ||
return node.text | ||
|
||
|
||
def load_xml_int(element, name): | ||
node = element.find(name) | ||
if node is None or not node.text: | ||
return None | ||
return int(node.text) | ||
|
||
|
||
def load_xml_bool(element, name): | ||
node = load_xml_string(element, name) | ||
if node and node.lower() == 'true': | ||
return True | ||
return False | ||
|
||
|
||
def load_single_node(element, name): | ||
return element.find(name) | ||
|
||
|
||
def load_many_nodes(element, name, wrapper=None): | ||
if wrapper: | ||
element = load_single_node(element, wrapper) | ||
return list(element.findall(name)) | ||
|
||
|
||
def blob_properties_from_xml(element, select, deserializer): | ||
if not select: | ||
generated = deserializer.deserialize_data(element, 'BlobItemInternal') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is using the old msrest deserializer - so once we've altered the generated layer to not deserialize for us - keeping this should mean that the existing |
||
return get_blob_properties_from_generated_code(generated) | ||
blob = BlobProperties() | ||
if 'name' in select: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I implemented this |
||
blob.name = load_xml_string(element, 'Name') | ||
if 'deleted' in select: | ||
blob.deleted = load_xml_bool(element, 'Deleted') | ||
if 'snapshot' in select: | ||
blob.snapshot = load_xml_string(element, 'Snapshot') | ||
if 'version' in select: | ||
blob.version_id = load_xml_string(element, 'VersionId') | ||
blob.is_current_version = load_xml_bool(element, 'IsCurrentVersion') | ||
return blob | ||
|
||
|
||
class BlobPropertiesPaged(PageIterator): # pylint: disable=too-many-instance-attributes | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like I updated the existing BlobPropertiesPaged - which means the perf of this model would be improved, however if we wanted to leave the original |
||
"""An Iterable of Blob properties. | ||
|
||
:ivar str service_endpoint: The service URL. | ||
|
@@ -49,6 +105,8 @@ def __init__( | |
container=None, | ||
prefix=None, | ||
results_per_page=None, | ||
select=None, | ||
deserializer=None, | ||
continuation_token=None, | ||
delimiter=None, | ||
location_mode=None): | ||
|
@@ -58,10 +116,12 @@ def __init__( | |
continuation_token=continuation_token or "" | ||
) | ||
self._command = command | ||
self._deserializer = deserializer | ||
self.service_endpoint = None | ||
self.prefix = prefix | ||
self.marker = None | ||
self.results_per_page = results_per_page | ||
self.select = select | ||
self.container = container | ||
self.delimiter = delimiter | ||
self.current_page = None | ||
|
@@ -73,30 +133,29 @@ def _get_next_cb(self, continuation_token): | |
prefix=self.prefix, | ||
marker=continuation_token or None, | ||
maxresults=self.results_per_page, | ||
cls=return_context_and_deserialized, | ||
cls=deserialize_list_result, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the |
||
use_location=self.location_mode) | ||
except HttpResponseError as error: | ||
process_storage_error(error) | ||
|
||
def _extract_data_cb(self, get_next_return): | ||
self.location_mode, self._response = get_next_return | ||
self.service_endpoint = self._response.service_endpoint | ||
self.prefix = self._response.prefix | ||
self.marker = self._response.marker | ||
self.results_per_page = self._response.max_results | ||
self.container = self._response.container_name | ||
self.current_page = [self._build_item(item) for item in self._response.segment.blob_items] | ||
self.service_endpoint = self._response.get('ServiceEndpoint') | ||
self.prefix = load_xml_string(self._response, 'Prefix') | ||
self.marker = load_xml_string(self._response, 'Marker') | ||
self.results_per_page = load_xml_int(self._response, 'MaxResults') | ||
self.container = self._response.get('ContainerName') | ||
|
||
return self._response.next_marker or None, self.current_page | ||
blobs = load_many_nodes(self._response, 'Blob', wrapper='Blobs') | ||
self.current_page = [self._build_item(blob) for blob in blobs] | ||
|
||
next_marker = load_xml_string(self._response, 'NextMarker') | ||
return next_marker or None, self.current_page | ||
|
||
def _build_item(self, item): | ||
if isinstance(item, BlobProperties): | ||
return item | ||
if isinstance(item, BlobItemInternal): | ||
blob = get_blob_properties_from_generated_code(item) # pylint: disable=protected-access | ||
blob.container = self.container | ||
return blob | ||
return item | ||
blob = blob_properties_from_xml(item, self.select, self._deserializer) | ||
blob.container = self.container | ||
return blob | ||
|
||
|
||
class BlobPrefixPaged(BlobPropertiesPaged): | ||
|
@@ -106,22 +165,26 @@ def __init__(self, *args, **kwargs): | |
|
||
def _extract_data_cb(self, get_next_return): | ||
continuation_token, _ = super(BlobPrefixPaged, self)._extract_data_cb(get_next_return) | ||
self.current_page = self._response.segment.blob_prefixes + self._response.segment.blob_items | ||
self.current_page = [self._build_item(item) for item in self.current_page] | ||
self.delimiter = self._response.delimiter | ||
|
||
blob_prefixes = load_many_nodes(self._response, 'BlobPrefix', wrapper='Blobs') | ||
blob_prefixes = [self._build_prefix(blob) for blob in blob_prefixes] | ||
|
||
self.current_page = blob_prefixes + self.current_page | ||
self.delimiter = load_xml_string(self._response, 'Delimiter') | ||
|
||
return continuation_token, self.current_page | ||
|
||
def _build_item(self, item): | ||
item = super(BlobPrefixPaged, self)._build_item(item) | ||
if isinstance(item, GenBlobPrefix): | ||
return BlobPrefix( | ||
self._command, | ||
container=self.container, | ||
prefix=item.name, | ||
results_per_page=self.results_per_page, | ||
location_mode=self.location_mode) | ||
return item | ||
def _build_prefix(self, item): | ||
return BlobPrefix( | ||
self._command, | ||
container=self.container, | ||
prefix=load_xml_string(item, 'Name'), | ||
results_per_page=self.results_per_page, | ||
location_mode=self.location_mode, | ||
select=self.select, | ||
deserializer=self._deserializer, | ||
delimiter=self.delimiter | ||
) | ||
|
||
|
||
class BlobPrefix(ItemPaged, DictMixin): | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removable. Same does for the all the clients.